Skip to content

Commit

Permalink
Make build_android publish to the staging repositories (facebook#45468)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: facebook#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
  • Loading branch information
cortinico authored and facebook-github-bot committed Jul 16, 2024
1 parent 892c835 commit 8d0cbbf
Show file tree
Hide file tree
Showing 9 changed files with 101 additions and 65 deletions.
10 changes: 0 additions & 10 deletions .circleci/configurations/jobs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
14 changes: 10 additions & 4 deletions .github/actions/build-android/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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() }}
Expand Down
8 changes: 0 additions & 8 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
9 changes: 0 additions & 9 deletions .github/workflows/publish-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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:
Expand Down
9 changes: 0 additions & 9 deletions .github/workflows/test-all.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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:
Expand Down
5 changes: 2 additions & 3 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}

Expand Down
54 changes: 48 additions & 6 deletions scripts/releases-ci/__tests__/publish-npm-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -42,6 +43,7 @@ describe('publish-npm', () => {
.mock('../../releases/utils/release-utils', () => ({
generateAndroidArtifacts: generateAndroidArtifactsMock,
publishAndroidArtifactsToMaven: publishAndroidArtifactsToMavenMock,
publishExternalArtifactsToMaven: publishExternalArtifactsToMavenMock,
}))
.mock('../../releases/set-version', () => ({
setVersion: setVersionMock,
Expand Down Expand Up @@ -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();
});
});
Expand Down Expand Up @@ -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',
Expand All @@ -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`],
Expand Down Expand Up @@ -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 () => {
Expand Down Expand Up @@ -269,6 +282,7 @@ describe('publish-npm', () => {
['Publishing monorepo/pkg-b...'],
]);
expect(publishAndroidArtifactsToMavenMock).not.toHaveBeenCalled();
expect(publishExternalArtifactsToMavenMock).not.toHaveBeenCalled();
});
});

Expand All @@ -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([
[
Expand Down Expand Up @@ -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([
[
Expand Down Expand Up @@ -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([
[
Expand Down Expand Up @@ -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([
[
Expand Down
10 changes: 6 additions & 4 deletions scripts/releases-ci/publish-npm.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -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);

Expand Down
47 changes: 35 additions & 12 deletions scripts/releases/utils/release-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) 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)',
'Failed to close and release the staging repository on Sonatype (Maven Central) for external artifacts',
);
exit(1);
}
Expand All @@ -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(
Expand Down Expand Up @@ -156,5 +178,6 @@ module.exports = {
generateAndroidArtifacts,
generateiOSArtifacts,
publishAndroidArtifactsToMaven,
publishExternalArtifactsToMaven,
failIfTagExists,
};

0 comments on commit 8d0cbbf

Please sign in to comment.