Skip to content

Commit e4e70f3

Browse files
committed
chore: set up proper publishing pipeline
1 parent d61d747 commit e4e70f3

File tree

10 files changed

+1196
-1212
lines changed

10 files changed

+1196
-1212
lines changed

.ado/jobs/npm-publish-dry-run.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,4 @@ jobs:
1313
submodules: recursive # set to 'true' for a single level of submodules or 'recursive' to get submodules of submodules
1414
persistCredentials: true # set to 'true' to leave the OAuth token in the Git config after the initial fetch
1515

16-
- template: /.ado/templates/apple-steps-publish.yml@self
17-
parameters:
18-
build_type: 'dry-run'
16+
- template: /.ado/templates/npm-publish.yml@self

.ado/scripts/prepublish-check.mjs

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
// @ts-check
2+
import { spawnSync } from "node:child_process";
3+
import * as fs from "node:fs";
4+
import * as util from "node:util";
5+
6+
/**
7+
* @typedef {typeof import("../../nx.json")} NxConfig
8+
* @typedef {{ tag?: string }} Options
9+
*/
10+
11+
/**
12+
* Exports a variable, `publish_react_native_macos`, to signal that we want to
13+
* enable publishing on Azure Pipelines.
14+
*
15+
* Note that pipelines need to read this variable separately and do the actual
16+
* work to publish bits.
17+
*/
18+
function enablePublishingOnAzurePipelines() {
19+
console.log(`##vso[task.setvariable variable=publish_react_native_macos]1`);
20+
}
21+
22+
/**
23+
* Loads Nx configuration.
24+
* @returns {NxConfig}
25+
*/
26+
function loadNxConfig(configFile = "nx.json") {
27+
const nx = fs.readFileSync(configFile, { encoding: "utf-8" });
28+
return JSON.parse(nx);
29+
}
30+
31+
/**
32+
* Returns the currently checked out branch. Note that this function prefers
33+
* predefined CI environment variables over local clone.
34+
* @returns {string}
35+
*/
36+
function getCurrentBranch() {
37+
// https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml#build-variables-devops-services
38+
const adoSourceBranchName = process.env["BUILD_SOURCEBRANCHNAME"];
39+
if (adoSourceBranchName) {
40+
return adoSourceBranchName.replace(/^refs\/heads\//g, "");
41+
}
42+
43+
// Depending on how the repo was cloned, HEAD may not exist. We only use this
44+
// method as fallback.
45+
const { stdout } = spawnSync("git", ["rev-parse", "--abbrev-ref", "HEAD"]);
46+
return stdout.toString().trim();
47+
}
48+
49+
/**
50+
* @param {string} branch
51+
* @param {Options} options
52+
* @returns {{ npmTag: string; prerelease?: string; }}
53+
*/
54+
function getStableTag(branch, { tag }) {
55+
switch (tag) {
56+
case "latest":
57+
return { npmTag: tag };
58+
59+
case "next":
60+
return { npmTag: tag, prerelease: "rc" };
61+
62+
default:
63+
return { npmTag: "v" + branch };
64+
}
65+
}
66+
67+
/**
68+
* Returns whether the given branch is considered main branch.
69+
* @param {string} branch
70+
*/
71+
function isMainBranch(branch) {
72+
// There is currently no good way to consistently get the main branch. We
73+
// hardcode the value for now.
74+
return branch === "main";
75+
}
76+
77+
/**
78+
* Returns whether the given branch is considered a stable branch.
79+
* @param {string} branch
80+
*/
81+
function isStableBranch(branch) {
82+
return /^\d+\.\d+-stable$/.test(branch);
83+
}
84+
85+
/**
86+
* Verifies the configuration and enables publishing on CI.
87+
* @param {NxConfig} config
88+
* @param {string} currentBranch
89+
* @param {string} tag
90+
* @param {string} [prerelease]
91+
* @returns {asserts config is NxConfig["release"]}
92+
*/
93+
function enablePublishing({ defaultBase, release: config }, currentBranch, tag, prerelease) {
94+
/** @type {string[]} */
95+
const errors = [];
96+
97+
// `defaultBase` determines what we diff against when looking for tags or
98+
// released version and must therefore be set to either the main branch or one
99+
// of the stable branches.
100+
if (currentBranch !== defaultBase) {
101+
errors.push(`'defaultBase' must be set to '${currentBranch}'`);
102+
}
103+
104+
// Determines whether we need to add "nightly" or "rc" to the version string.
105+
const { currentVersionResolverMetadata, preid } = config.version.generatorOptions;
106+
if (preid !== prerelease) {
107+
errors.push(`'release.version.generatorOptions.preid' must be set to '${prerelease || ""}'`);
108+
}
109+
110+
// What the published version should be tagged as e.g., "latest" or "nightly".
111+
if (currentVersionResolverMetadata.tag !== tag) {
112+
errors.push(`'release.version.generatorOptions.currentVersionResolverMetadata.tag' must be set to '${tag}'`);
113+
}
114+
115+
if (errors.length > 0) {
116+
for (const e of errors) {
117+
console.error("❌", e);
118+
}
119+
throw new Error("Nx Release is not correctly configured for the current branch");
120+
}
121+
122+
enablePublishingOnAzurePipelines();
123+
}
124+
125+
/**
126+
* @param {Options} options
127+
*/
128+
function main(options) {
129+
const branch = getCurrentBranch();
130+
if (!branch) {
131+
throw new Error("Could not get current branch");
132+
}
133+
134+
const config = loadNxConfig();
135+
if (isMainBranch(branch)) {
136+
enablePublishing(config, branch, "nightly", "nightly");
137+
} else if (isStableBranch(branch)) {
138+
const { npmTag, prerelease } = getStableTag(branch, options);
139+
enablePublishing(config, branch, npmTag, prerelease);
140+
}
141+
}
142+
143+
const { values } = util.parseArgs({
144+
args: process.argv.slice(2),
145+
options: {
146+
tag: {
147+
type: "string",
148+
default: "next",
149+
},
150+
},
151+
strict: true,
152+
allowNegative: true,
153+
});
154+
155+
main(values);

.ado/scripts/verdaccio.sh

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,9 @@ case ${1-} in
1919

2020
"publish")
2121
checkpoint=$(git rev-parse HEAD)
22-
yarn set-version 1000.0.0-pr
23-
git commit --all --message 'bump' --no-verify
24-
packages=()
25-
for json in $(yarn workspaces list --no-private --json); do
26-
packages+=(--package $(node --print "JSON.parse('$json').name"))
27-
done
28-
npx beachball change --no-fetch --type patch --message 'bump for testing purposes' ${packages[@]}
29-
npx beachball $* --no-push --registry $NPM_REGISTRY --yes --access public --no-generate-changelog
22+
cp nx.test.json nx.json
23+
yarn nx release version 1000.0.0
24+
yarn nx release publish --registry $NPM_REGISTRY
3025
git reset --hard $checkpoint
3126
;;
3227
esac

.ado/templates/npm-publish.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
parameters:
2+
build_type: ''
3+
4+
steps:
5+
- script: |
6+
yarn install
7+
displayName: Install npm dependencies
8+
9+
- script: |
10+
# If this is a new stable branch, change to `--tag latest` when going stable
11+
# If this is the previous stable branch, remove `--tag` before the new stable is live
12+
node .ado/scripts/prepublish-check.mjs --tag next
13+
displayName: Verify release config
14+
15+
- script: |
16+
yarn nx release --dry-run
17+
displayName: Version and publish packages (dry run)
18+
condition: ne(variables['publish_react_native_macos'], '1')
19+
20+
- script: |
21+
#yarn nx release --yes
22+
yarn nx release --dry-run
23+
displayName: Version and publish packages
24+
condition: eq(variables['publish_react_native_macos'], '1')

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,4 +174,8 @@ vendor/
174174
.ado/Brewfile.lock.json
175175
.ado/verdaccio/htpasswd
176176
.ado/verdaccio/storage/.verdaccio-db.json
177+
178+
# Nx
179+
.nx/cache
180+
.nx/workspace-data
177181
# macOS]

nx.json

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"$schema": "./node_modules/nx/schemas/nx-schema.json",
3+
"defaultBase": "main",
4+
"targetDefaults": {
5+
"build": {
6+
"dependsOn": ["^build"]
7+
}
8+
},
9+
"release": {
10+
"changelog": {
11+
"projectChangelogs": false,
12+
"workspaceChangelog": false
13+
},
14+
"projects": ["packages/react-native", "packages/virtualized-lists"],
15+
"projectsRelationship": "independent",
16+
"versionPlans": true,
17+
"version": {
18+
"generatorOptions": {
19+
"currentVersionResolver": "registry",
20+
"currentVersionResolverMetadata": {
21+
"tag": "nightly"
22+
},
23+
"fallbackCurrentVersionResolver": "disk",
24+
"preid": "nightly",
25+
"skipLockFileUpdate": true
26+
}
27+
}
28+
}
29+
}

nx.test.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"$schema": "./node_modules/nx/schemas/nx-schema.json",
3+
"defaultBase": "main",
4+
"targetDefaults": {
5+
"build": {
6+
"dependsOn": ["^build"]
7+
}
8+
},
9+
"release": {
10+
"changelog": {
11+
"projectChangelogs": false,
12+
"workspaceChangelog": false
13+
},
14+
"projects": ["packages/*"],
15+
"projectsRelationship": "independent",
16+
"versionPlans": true,
17+
"version": {
18+
"generatorOptions": {
19+
"currentVersionResolver": "disk",
20+
"currentVersionResolverMetadata": {
21+
"tag": "latest"
22+
},
23+
"skipLockFileUpdate": true
24+
}
25+
}
26+
}
27+
}

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
"@babel/preset-flow": "^7.24.7",
5353
"@definitelytyped/dtslint": "^0.0.127",
5454
"@jest/create-cache-key-function": "^29.6.3",
55+
"@nx/js": "~20.0.0",
5556
"@pkgjs/parseargs": "^0.11.0",
5657
"@react-native/metro-babel-transformer": "0.76.0-main",
5758
"@react-native/metro-config": "0.76.0-main",
@@ -96,6 +97,7 @@
9697
"mkdirp": "^0.5.1",
9798
"node-fetch": "^2.2.0",
9899
"nullthrows": "^1.1.1",
100+
"nx": "~20.0.0",
99101
"prettier": "2.8.8",
100102
"prettier-plugin-hermes-parser": "0.23.1",
101103
"react": "19.0.0-rc-fb9a90fa48-20240614",

packages/react-native/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@
112112
},
113113
"dependencies": {
114114
"@jest/create-cache-key-function": "^29.6.3",
115-
"@react-native-mac/virtualized-lists": "0.76.0-main",
115+
"@react-native-mac/virtualized-lists": "workspace:*",
116116
"@react-native/assets-registry": "0.76.0-main",
117117
"@react-native/codegen": "0.76.0-main",
118118
"@react-native/community-cli-plugin": "0.76.0-main",

0 commit comments

Comments
 (0)