Make build_android publish to the staging repositories (#45468)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/45468

This should greatly reduce the time spent on build_npm_package
because we're moving all the publishing logic to build_android.

I need to do a bit more testing with nightlies to make sure that everything is published correctly.

Changelog:
[Internal] [Changed] - Make build_android publish to the stating repositories

Reviewed By: cipolleschi

Differential Revision: D59804015

fbshipit-source-id: be3f0b6e16f5fdbf760ec7a5e16c8e258e06dd28
This commit is contained in:
Nicola Corti 2024-07-16 13:58:43 -07:00 committed by Facebook GitHub Bot
parent 892c8352ca
commit 8d0cbbf0e6
9 changed files with 101 additions and 65 deletions

View File

@ -1068,18 +1068,8 @@ jobs:
export ORG_GRADLE_PROJECT_reactNativeArchitectures="armeabi-v7a,arm64-v8a,x86,x86_64"
fi
node ./scripts/releases-ci/publish-npm.js -t << parameters.release_type >>
- run:
name: Zip Maven Artifacts from /tmp/maven-local
command: zip -r /tmp/maven-local.zip /tmp/maven-local
- store_artifacts:
path: /tmp/maven-local.zip
- store_artifacts:
path: /root/.npm/_logs
- persist_to_workspace:
root: /tmp
paths:
- maven-local
# START: Dry-run
# Provide a react-native package for this commit as a Circle CI release artifact.

View File

@ -25,17 +25,23 @@ runs:
- name: Build and publish all the Android Artifacts to /tmp/maven-local
shell: bash
run: |
# By default we only build ARM64 to save time/resources. For release/nightlies/prealpha, we override this value to build all archs.
if [[ "${{ inputs.RELEASE_TYPE }}" == "dry-run" ]]; then
# dry-run: we only build ARM64 to save time/resources. For release/nightlies the default is to build all archs.
export ORG_GRADLE_PROJECT_reactNativeArchitectures="arm64-v8a"
TASKS="publishAllToMavenTempLocal build"
elif [[ "${{ inputs.RELEASE_TYPE }}" == "nightly" ]]; then
# nightly: we set isSnapshot to true so artifacts are sent to the right repository on Maven Central.
export ORG_GRADLE_PROJECT_isSnapshot="true"
TASKS="publishAllToMavenTempLocal publishAndroidToSonatype build"
else
export ORG_GRADLE_PROJECT_reactNativeArchitectures="armeabi-v7a,arm64-v8a,x86,x86_64"
# release: we want to build all archs (default)
TASKS="publishAllToMavenTempLocal publishAndroidToSonatype build"
fi
./gradlew publishAllToMavenTempLocal build -PenableWarningsAsErrors=true
./gradlew $TASKS -PenableWarningsAsErrors=true
- name: Upload Maven Artifacts
uses: actions/upload-artifact@v4
with:
name: maven-local-build-android
name: maven-local
path: /tmp/maven-local
- name: Upload test results
if: ${{ always() }}

View File

@ -280,14 +280,6 @@ jobs:
echo "GRADLE_OPTS = $GRADLE_OPTS"
export ORG_GRADLE_PROJECT_reactNativeArchitectures="armeabi-v7a,arm64-v8a,x86,x86_64"
node ./scripts/releases-ci/publish-npm.js -t nightly
- name: Zip Maven Artifacts from /tmp/maven-local
working-directory: /tmp
run: zip -r maven-local.zip maven-local
- name: Upload Maven Artifacts
uses: actions/upload-artifact@v4
with:
name: maven-local
path: /tmp/maven-local.zip
- name: Upload npm logs
uses: actions/upload-artifact@v4
with:

View File

@ -54,7 +54,6 @@ jobs:
HERMES_VERSION: ${{ needs.prepare_hermes_workspace.output.HERMES_VERSION }}
REACT_NATIVE_VERSION: ${{ needs.prepare_hermes_workspace.output.REACT_NATIVE_VERSION }}
build_apple_slices_hermes:
runs-on: macos-14
needs: [build_hermesc_apple, prepare_hermes_workspace]
@ -286,14 +285,6 @@ jobs:
echo "GRADLE_OPTS = $GRADLE_OPTS"
export ORG_GRADLE_PROJECT_reactNativeArchitectures="armeabi-v7a,arm64-v8a,x86,x86_64"
node ./scripts/releases-ci/publish-npm.js -t release
- name: Zip Maven Artifacts from /tmp/maven-local
working-directory: /tmp
run: zip -r maven-local.zip maven-local
- name: Upload Maven Artifacts
uses: actions/upload-artifact@v4
with:
name: maven-local
path: /tmp/maven-local.zip
- name: Upload npm logs
uses: actions/upload-artifact@v4
with:

View File

@ -212,7 +212,6 @@ jobs:
HERMES_VERSION: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
REACT_NATIVE_VERSION: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
build_android:
runs-on: 8-core-ubuntu
needs: [set_release_type]
@ -366,14 +365,6 @@ jobs:
export ORG_GRADLE_PROJECT_reactNativeArchitectures="armeabi-v7a,arm64-v8a,x86,x86_64"
fi
node ./scripts/releases-ci/publish-npm.js -t ${{ needs.set_release_type.outputs.RELEASE_TYPE }}
- name: Zip Maven Artifacts from /tmp/maven-local
working-directory: /tmp
run: zip -r maven-local.zip maven-local
- name: Upload Maven Artifacts
uses: actions/upload-artifact@v4
with:
name: maven-local
path: /tmp/maven-local.zip
- name: Upload npm logs
uses: actions/upload-artifact@v4
with:

View File

@ -97,10 +97,9 @@ tasks.register("publishAllToMavenTempLocal") {
":packages:react-native:ReactAndroid:hermes-engine:publishAllPublicationsToMavenTempLocalRepository")
}
tasks.register("publishAllToSonatype") {
description = "Publish all the artifacts to Sonatype (Maven Central or Snapshot repository)"
tasks.register("publishAndroidToSonatype") {
description = "Publish the Android artifacts to Sonatype (Maven Central or Snapshot repository)"
dependsOn(":packages:react-native:ReactAndroid:publishToSonatype")
dependsOn(":packages:react-native:ReactAndroid:external-artifacts:publishToSonatype")
dependsOn(":packages:react-native:ReactAndroid:hermes-engine:publishToSonatype")
}

View File

@ -15,6 +15,7 @@ const isTaggedLatestMock = jest.fn();
const setVersionMock = jest.fn();
const updateReactNativeArtifactsMock = jest.fn();
const publishAndroidArtifactsToMavenMock = jest.fn();
const publishExternalArtifactsToMavenMock = jest.fn();
const removeNewArchFlags = jest.fn();
const env = process.env;
const publishPackageMock = jest.fn();
@ -42,6 +43,7 @@ describe('publish-npm', () => {
.mock('../../releases/utils/release-utils', () => ({
generateAndroidArtifacts: generateAndroidArtifactsMock,
publishAndroidArtifactsToMaven: publishAndroidArtifactsToMavenMock,
publishExternalArtifactsToMaven: publishExternalArtifactsToMavenMock,
}))
.mock('../../releases/set-version', () => ({
setVersion: setVersionMock,
@ -106,13 +108,16 @@ describe('publish-npm', () => {
expect(setVersionMock).not.toBeCalled();
expect(updateReactNativeArtifactsMock).toBeCalledWith(version, 'dry-run');
expect(generateAndroidArtifactsMock).toBeCalledWith(version);
// Generate Android artifacts is now delegate to build_android entirely
expect(generateAndroidArtifactsMock).not.toHaveBeenCalled();
expect(consoleLogMock).toHaveBeenCalledWith(
'Skipping `npm publish` because --dry-run is set.',
);
// Expect termination
expect(publishAndroidArtifactsToMavenMock).not.toHaveBeenCalled();
expect(publishExternalArtifactsToMavenMock).not.toHaveBeenCalled();
expect(publishPackageMock).not.toHaveBeenCalled();
});
});
@ -156,7 +161,10 @@ describe('publish-npm', () => {
expect(removeNewArchFlags).not.toHaveBeenCalled();
expect(setVersionMock).toBeCalledWith(expectedVersion);
expect(generateAndroidArtifactsMock).toHaveBeenCalled();
// Generate Android artifacts is now delegate to build_android entirely
expect(generateAndroidArtifactsMock).not.toHaveBeenCalled();
expect(publishPackageMock.mock.calls).toEqual([
[
'path/to/monorepo/pkg-a',
@ -175,6 +183,10 @@ describe('publish-npm', () => {
expectedVersion,
'nightly',
);
expect(publishExternalArtifactsToMavenMock).toHaveBeenCalledWith(
expectedVersion,
'nightly',
);
expect(consoleLogMock.mock.calls).toEqual([
['Publishing monorepo/pkg-a...'],
[`Published monorepo/pkg-a@${expectedVersion} to npm`],
@ -205,6 +217,7 @@ describe('publish-npm', () => {
expect(publishPackageMock).not.toBeCalled();
expect(generateAndroidArtifactsMock).not.toHaveBeenCalled();
expect(publishAndroidArtifactsToMavenMock).not.toBeCalled();
expect(publishExternalArtifactsToMavenMock).not.toHaveBeenCalled();
});
it('should fail to publish react-native if some monorepo packages fail', async () => {
@ -269,6 +282,7 @@ describe('publish-npm', () => {
['Publishing monorepo/pkg-b...'],
]);
expect(publishAndroidArtifactsToMavenMock).not.toHaveBeenCalled();
expect(publishExternalArtifactsToMavenMock).not.toHaveBeenCalled();
});
});
@ -290,11 +304,18 @@ describe('publish-npm', () => {
expect(removeNewArchFlags).not.toHaveBeenCalled();
expect(updateReactNativeArtifactsMock).not.toHaveBeenCalled();
expect(setVersionMock).not.toBeCalled();
expect(generateAndroidArtifactsMock).toHaveBeenCalled();
// Generate Android artifacts is now delegate to build_android entirely
expect(generateAndroidArtifactsMock).not.toHaveBeenCalled();
expect(publishAndroidArtifactsToMavenMock).toHaveBeenCalledWith(
expectedVersion,
'release',
);
expect(publishExternalArtifactsToMavenMock).toHaveBeenCalledWith(
expectedVersion,
'release',
);
expect(publishPackageMock.mock.calls).toEqual([
[
@ -325,11 +346,18 @@ describe('publish-npm', () => {
expect(removeNewArchFlags).not.toHaveBeenCalled();
expect(setVersionMock).not.toBeCalled();
expect(updateReactNativeArtifactsMock).not.toBeCalled();
expect(generateAndroidArtifactsMock).toHaveBeenCalled();
// Generate Android artifacts is now delegate to build_android entirely
expect(generateAndroidArtifactsMock).not.toHaveBeenCalled();
expect(publishAndroidArtifactsToMavenMock).toHaveBeenCalledWith(
expectedVersion,
'release',
);
expect(publishExternalArtifactsToMavenMock).toHaveBeenCalledWith(
expectedVersion,
'release',
);
expect(publishPackageMock.mock.calls).toEqual([
[
@ -367,11 +395,18 @@ describe('publish-npm', () => {
expect(removeNewArchFlags).not.toHaveBeenCalled();
expect(setVersionMock).not.toBeCalled();
expect(updateReactNativeArtifactsMock).not.toHaveBeenCalled();
expect(generateAndroidArtifactsMock).toHaveBeenCalled();
// Generate Android artifacts is now delegate to build_android entirely
expect(generateAndroidArtifactsMock).not.toHaveBeenCalled();
expect(publishAndroidArtifactsToMavenMock).toHaveBeenCalledWith(
expectedVersion,
'release',
);
expect(publishExternalArtifactsToMavenMock).toHaveBeenCalledWith(
expectedVersion,
'release',
);
expect(publishPackageMock.mock.calls).toEqual([
[
@ -399,11 +434,18 @@ describe('publish-npm', () => {
expect(removeNewArchFlags).not.toHaveBeenCalled();
expect(updateReactNativeArtifactsMock).not.toHaveBeenCalled();
expect(setVersionMock).not.toBeCalled();
expect(generateAndroidArtifactsMock).toHaveBeenCalled();
// Generate Android artifacts is now delegate to build_android entirely
expect(generateAndroidArtifactsMock).not.toHaveBeenCalled();
expect(publishAndroidArtifactsToMavenMock).toHaveBeenCalledWith(
expectedVersion,
'release',
);
expect(publishExternalArtifactsToMavenMock).toHaveBeenCalledWith(
expectedVersion,
'release',
);
expect(publishPackageMock.mock.calls).toEqual([
[

View File

@ -23,8 +23,8 @@ const {
} = require('../releases/set-rn-artifacts-version');
const {setVersion} = require('../releases/set-version');
const {
generateAndroidArtifacts,
publishAndroidArtifactsToMaven,
publishExternalArtifactsToMaven,
} = require('../releases/utils/release-utils');
const {getPackages} = require('../utils/monorepo');
const path = require('path');
@ -111,14 +111,16 @@ async function publishNpm(buildType /*: BuildType */) /*: Promise<void> */ {
}
}
generateAndroidArtifacts(version);
if (buildType === 'dry-run') {
console.log('Skipping `npm publish` because --dry-run is set.');
return;
}
// We first publish on Maven Central all the necessary artifacts.
// We first publish on Maven Central the external artifacts
// produced by iOS
publishExternalArtifactsToMaven(version, buildType);
// We the publish on Maven Central all the Android artifacts.
// NPM publishing is done just after.
publishAndroidArtifactsToMaven(version, buildType);

View File

@ -62,24 +62,45 @@ function publishAndroidArtifactsToMaven(
releaseVersion /*: string */,
buildType /*: BuildType */,
) {
// -------- Publish every artifact to Maven Central
// The GPG key is base64 encoded on CircleCI and then decoded here
// $FlowFixMe[prop-missing]
let buff = Buffer.from(env.ORG_GRADLE_PROJECT_SIGNING_KEY_ENCODED, 'base64');
// $FlowFixMe[prop-missing]
env.ORG_GRADLE_PROJECT_SIGNING_KEY = buff.toString('ascii');
// We want to gate ourselves against accidentally publishing a 1.x or a 1000.x on
// maven central which will break the semver for our artifacts.
if (buildType === 'release' && releaseVersion.startsWith('0.')) {
// -------- For stable releases, we also need to close and release the staging repository.
if (
exec(
'./gradlew publishAllToSonatype closeAndReleaseSonatypeStagingRepository',
'./gradlew findSonatypeStagingRepository closeAndReleaseSonatypeStagingRepository',
).code
) {
echo(
'Failed to close and release the staging repository on Sonatype (Maven Central)',
'Failed to close and release the staging repository on Sonatype (Maven Central) for Android artifacts',
);
exit(1);
}
} else {
echo(
'Nothing to do as this is not a stable release - Nightlies Android artifacts are published by build_android',
);
}
echo('Finished publishing Android artifacts to Maven Central');
}
function publishExternalArtifactsToMaven(
releaseVersion /*: string */,
buildType /*: BuildType */,
) {
// We want to gate ourselves against accidentally publishing a 1.x or a 1000.x on
// maven central which will break the semver for our artifacts.
if (buildType === 'release' && releaseVersion.startsWith('0.')) {
// -------- For stable releases, we do the publishing and close the staging repository.
// This can't be done earlier in build_android because this artifact are partially built by the iOS jobs.
if (
exec(
'./gradlew :packages:react-native:ReactAndroid:external-artifacts:publishToSonatype :packages:react-native:ReactAndroid:external-artifacts:closeAndReleaseSonatypeStagingRepository',
).code
) {
echo(
'Failed to close and release the staging repository on Sonatype (Maven Central) for external artifacts',
);
exit(1);
}
@ -88,15 +109,16 @@ function publishAndroidArtifactsToMaven(
// -------- For nightly releases, we only need to publish the snapshot to Sonatype snapshot repo.
if (
exec(
'./gradlew publishAllToSonatype -PisSnapshot=' + isSnapshot.toString(),
'./gradlew :packages:react-native:ReactAndroid:external-artifacts:publishToSonatype -PisSnapshot=' +
isSnapshot.toString(),
).code
) {
echo('Failed to publish artifacts to Sonatype (Maven Central)');
echo('Failed to publish external artifacts to Sonatype (Maven Central)');
exit(1);
}
}
echo('Published artifacts to Maven Central');
echo('Finished publishing external artifacts to Maven Central');
}
function generateiOSArtifacts(
@ -156,5 +178,6 @@ module.exports = {
generateAndroidArtifacts,
generateiOSArtifacts,
publishAndroidArtifactsToMaven,
publishExternalArtifactsToMaven,
failIfTagExists,
};