Skip to content

Commit

Permalink
refactor: automation to tag and version the template when releasing (#30
Browse files Browse the repository at this point in the history
)

There was a discussion on Discord, where we looked at implementing what was originally proposed.  This is that implementation.  It'll need to land with a [cli](react-native-community/cli#2422) change to use the update template + tagging.

- feat: add mutating react-native & @react-native/ packages

    Support for doing this on nightly and release workflows

- feat: added node ./scripts/updateReactNativeVersion.js <version>

    Sets the version of react-native and the @react-native/ scoped packages.
    It will also normalize tags to concrete versions. E.g. latest -> 0.74.2

- refactor: move scripts into a ./scripts folder
blakef authored Jun 21, 2024
1 parent 3bb13d3 commit 893dcc8
Showing 7 changed files with 116 additions and 4 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/nightly.yaml
Original file line number Diff line number Diff line change
@@ -21,7 +21,9 @@ jobs:
node-version: 18
registry-url: 'https://registry.npmjs.org'
- name: Update versions to nightly
run: node updateTemplateVersion.js nightly
run: node ./scripts/updateTemplateVersion.js nightly
- name: Update template/package.json to nightly react-native + @react-native
run: node ./scripts/updateReactNativeVersion.js nightly
- name: Publish NPM as Nightly
run: npm publish --tag nightly
env:
4 changes: 3 additions & 1 deletion .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -31,7 +31,9 @@ jobs:
node-version: 18
registry-url: 'https://registry.npmjs.org'
- name: Update versions to input one
run: node updateTemplateVersion.js "${{ inputs.version }}"
run: node ./scripts/updateTemplateVersion.js "${{ inputs.version }}"
- name: Update template/package.json to nightly react-native + @react-native
run: node ./scripts/updateReactNativeVersion.js "${{ inputs.version }}"
- name: Create corresponding commit & git tag
run: |
git config --global user.name 'React Native Bot'
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1 @@
scripts/

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -6,7 +6,6 @@
"publishConfig": {
"access": "public"
},
"type": "module",
"files": [
"template/*",
"template.config.js"
25 changes: 25 additions & 0 deletions scripts/lib/lib.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
const {execSync} = require('child_process');

const registry = getNpmRegistryUrl();

function getNpmRegistryUrl() {
try {
return execSync("npm config get registry").toString().trim();
} catch {
return "https://registry.npmjs.org/";
}
}

/**
* Convert an npm tag to a concrete version, for example:
* - next -> 0.75.0-rc.0
* - nightly -> 0.75.0-nightly-20240618-5df5ed1a8
*/
async function npmMaterializeVersion(packageName, tagOrVersion) {
const url = new URL(registry);
url.pathname = `${packageName}/${tagOrVersion}`;
const json = await fetch(url).then((resp) => resp.json());
return json.version;
}

module.exports.npmMaterializeVersion = npmMaterializeVersion;
84 changes: 84 additions & 0 deletions scripts/updateReactNativeVersion.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
const fs = require("fs");
const { npmMaterializeVersion } = require("./lib/lib.js");

function updateDependencies(pkgJson, update) {
console.log("Changing package.json dependencies:");

for (const [pkg, value] of Object.entries(update.dependencies ?? {})) {
const old = pkgJson.dependencies[pkg];
if (old) {
console.log(` - ${pkg}: ${old}${value}`);
} else {
console.log(` - ${pkg}: ${value}`);
}
pkgJson.dependencies[pkg] = value;
}

for (const [pkg, value] of Object.entries(update.devDependencies ?? {})) {
const old = pkgJson.devDependencies[pkg];
if (old) {
console.log(` - ${pkg}: ${old}${value}`);
} else {
console.log(` - ${pkg}: ${value}`);
}
pkgJson.devDependencies[pkg] = value;
}

return pkgJson;
}

const REACT_NATIVE_SCOPE = "@react-native/";

/**
* Packages that are scoped under @react-native need a consistent version
*/
function normalizeReactNativeDeps(deps, version) {
const updated = {};
for (const key of Object.keys(deps ?? {}).filter((pkg) =>
pkg.startsWith(REACT_NATIVE_SCOPE),
)) {
updated[key] = version;
}
return updated;
}

async function main(version) {
const PKG_JSON_PATH = "template/package.json";
// Update the react-native dependency if using the new @react-native-community/template.
// We can figure this out as it ships with [email protected] set to a dummy version.
let pkgJson = JSON.parse(fs.readFileSync(PKG_JSON_PATH, "utf8"));

// Materialize a tag to a version. E.g. next -> 0.75.0-rc.0
const concreteVersion = await npmMaterializeVersion("react-native", version);
console.log(
`Normalizing: react-native@${version} -> react-native@${concreteVersion}`,
);

pkgJson = updateDependencies(pkgJson, {
dependencies: {
"react-native": concreteVersion,
...normalizeReactNativeDeps(pkgJson.dependencies, concreteVersion),
},
devDependencies: {
...normalizeReactNativeDeps(pkgJson.devDependencies, concreteVersion),
},
});

const updated = JSON.stringify(pkgJson, null, 2);
console.log(`Writing update package.json to ${PKG_JSON_PATH}:\n\n${updated}`);
fs.writeFileSync(PKG_JSON_PATH, updated);
}

if (require.main === module) {
if (process.argv.length < 3) {
console.log(`USAGE: updateReactNativeVersion.js <version>
Updates 'react-native' and '@react-native/' scoped packages to a common version within
the template.
`);
process.exit(1);
}
main(process.argv.pop()).catch((e) => {
throw e;
});
}
File renamed without changes.

0 comments on commit 893dcc8

Please sign in to comment.