/
githubmirror
/
react-native
Обзор
Документация
Войти
/
githubmirror
/
react-native
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
.github/workflows/publish-npm.yml
331 строка
15 KB
Nicola Corti
Split Android build from release publishing (#57714)
29 июл 2026, 00:03
29 июл 2026, 00:03
a44d68e
Код
Авторство
О чём код?
# Single top-level workflow for every npm publish in this repo. # # Why: npmjs.com Trusted Publishing matches the `workflow_ref` OIDC claim, # which is always the TOP-LEVEL workflow filename. npm allows only ONE # trusted publisher per package, so every `npm publish` must originate # from the same top-level file. By consolidating all publish triggers # here, the OIDC claim is always `publish-npm.yml`. # # This replaces the previous separate entry points: # - publish-release.yml (tag push) → mode=release # - nightly.yml (cron/dispatch) → mode=nightly # - publish-bumped-packages.yml (main/stable branch push) → mode=bumped-packages # # See https://docs.npmjs.com/trusted-publishers name: Publish to npm on: push: tags: - 'v0.*.*' # This should match v0.X.Y - 'v0.*.*-rc.*' # This should match v0.X.Y-RC.0 branches: - 'main' - '*-stable' workflow_dispatch: # nightly build @ 2:15 AM UTC schedule: - cron: '15 2 * * *' permissions: contents: read env: # Stable across partial reruns so later jobs can find the repository created by build_android. ORG_GRADLE_PROJECT_SONATYPE_REPOSITORY_DESCRIPTION: 'react-native:${{ github.ref_name }}:github-run-${{ github.run_id }}' jobs: # ─── Determine what kind of publish this is ────────────────────── determine_mode: runs-on: ubuntu-latest if: github.repository == 'react/react-native' outputs: mode: ${{ steps.mode.outputs.mode }} release-type: ${{ steps.mode.outputs.release-type }} steps: - id: mode run: | if [[ "${{ github.ref_type }}" == "tag" ]]; then echo "mode=release" >> $GITHUB_OUTPUT echo "release-type=release" >> $GITHUB_OUTPUT elif [[ "${{ github.event_name }}" == "schedule" || "${{ github.event_name }}" == "workflow_dispatch" ]]; then echo "mode=nightly" >> $GITHUB_OUTPUT echo "release-type=nightly" >> $GITHUB_OUTPUT elif [[ "${{ github.event_name }}" == "push" ]]; then echo "mode=bumped-packages" >> $GITHUB_OUTPUT echo "release-type=" >> $GITHUB_OUTPUT fi - run: | echo "Mode: ${{ steps.mode.outputs.mode }}" echo "Release type: ${{ steps.mode.outputs.release-type }}" # ─── Release-only: extract Hermes version for draft release ────── set_hermes_version: runs-on: ubuntu-latest if: github.ref_type == 'tag' outputs: HERMES_VERSION: ${{ steps.set_hermes_version.outputs.HERMES_VERSION }} steps: - name: Checkout uses: actions/checkout@v6 - id: set_hermes_version run: | hermes_version=$(grep -oE 'HERMES_VERSION_NAME=([0-9]+\.[0-9]+\.[0-9]+)' packages/react-native/sdks/hermes-engine/version.properties | cut -d'=' -f2) echo "HERMES_VERSION=$hermes_version" >> $GITHUB_OUTPUT echo "HERMES_VERSION=$hermes_version" # ─── Apple prebuilds (release + nightly) ───────────────────────── prebuild_apple_dependencies: needs: [determine_mode] if: needs.determine_mode.outputs.mode == 'release' || needs.determine_mode.outputs.mode == 'nightly' uses: ./.github/workflows/prebuild-ios-dependencies.yml secrets: inherit prebuild_react_native_core: needs: [determine_mode, prebuild_apple_dependencies] if: needs.determine_mode.outputs.mode == 'release' || needs.determine_mode.outputs.mode == 'nightly' uses: ./.github/workflows/prebuild-ios-core.yml secrets: inherit with: use-hermes-prebuilt: ${{ needs.determine_mode.outputs.mode == 'nightly' }} version-type: ${{ needs.determine_mode.outputs.mode == 'nightly' && 'nightly' || '' }} # ─── Android build (release + nightly) ─────────────────────────── build_android: needs: [determine_mode] if: needs.determine_mode.outputs.mode == 'release' || needs.determine_mode.outputs.mode == 'nightly' runs-on: ubuntu-latest container: image: reactnativecommunity/react-native-android:latest env: TERM: 'dumb' # Set the encoding to resolve a known character encoding issue with decompressing tar.gz files in containers # via Gradle: https://github.com/gradle/gradle/issues/23391#issuecomment-1878979127 LC_ALL: C.UTF8 GRADLE_OPTS: '-Dorg.gradle.daemon=false' ORG_GRADLE_PROJECT_SIGNING_PWD: ${{ secrets.ORG_GRADLE_PROJECT_SIGNING_PWD }} ORG_GRADLE_PROJECT_SIGNING_KEY: ${{ secrets.ORG_GRADLE_PROJECT_SIGNING_KEY }} ORG_GRADLE_PROJECT_SONATYPE_USERNAME: ${{ secrets.ORG_GRADLE_PROJECT_SONATYPE_USERNAME }} ORG_GRADLE_PROJECT_SONATYPE_PASSWORD: ${{ secrets.ORG_GRADLE_PROJECT_SONATYPE_PASSWORD }} REACT_NATIVE_DOWNLOADS_DIR: /opt/react-native-downloads steps: - name: Checkout uses: actions/checkout@v6 - name: Setup node.js for staging cleanup if: needs.determine_mode.outputs.mode == 'release' uses: ./.github/actions/setup-node - name: Drop stale Android staging repository if: needs.determine_mode.outputs.mode == 'release' run: node ./scripts/releases-ci/cleanup-maven-staging-repositories.js - name: Build Android uses: ./.github/actions/build-android with: release-type: ${{ needs.determine_mode.outputs.release-type }} gradle-cache-encryption-key: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }} # ─── Build + Publish: react-native + all @react-native/* packages # (release and nightly modes) ───────────────────────────────── publish_react_native: needs: [ determine_mode, build_android, prebuild_apple_dependencies, prebuild_react_native_core, ] # Use always() so the explicit status checks below control the gating. if: | always() && (needs.determine_mode.outputs.mode == 'release' || needs.determine_mode.outputs.mode == 'nightly') && needs.determine_mode.result == 'success' && needs.build_android.result == 'success' && needs.prebuild_apple_dependencies.result == 'success' && needs.prebuild_react_native_core.result == 'success' runs-on: ubuntu-latest environment: npm-publish # `id-token: write` is required so the npm CLI can mint the OIDC # token that npm Trusted Publishing exchanges for a publish token. permissions: contents: read id-token: write container: image: reactnativecommunity/react-native-android:latest env: TERM: 'dumb' # Set the encoding to resolve a known character encoding issue with decompressing tar.gz files in containers # via Gradle: https://github.com/gradle/gradle/issues/23391#issuecomment-1878979127 LC_ALL: C.UTF8 GRADLE_OPTS: '-Dorg.gradle.daemon=false' # By default we only build ARM64 to save time/resources. For release/nightlies, we override this value to build all archs. ORG_GRADLE_PROJECT_reactNativeArchitectures: 'arm64-v8a' REACT_NATIVE_DOWNLOADS_DIR: /opt/react-native-downloads env: ORG_GRADLE_PROJECT_SIGNING_PWD: ${{ secrets.ORG_GRADLE_PROJECT_SIGNING_PWD }} ORG_GRADLE_PROJECT_SIGNING_KEY: ${{ secrets.ORG_GRADLE_PROJECT_SIGNING_KEY }} ORG_GRADLE_PROJECT_SONATYPE_USERNAME: ${{ secrets.ORG_GRADLE_PROJECT_SONATYPE_USERNAME }} ORG_GRADLE_PROJECT_SONATYPE_PASSWORD: ${{ secrets.ORG_GRADLE_PROJECT_SONATYPE_PASSWORD }} steps: - name: Checkout uses: actions/checkout@v6 with: fetch-depth: 0 fetch-tags: true - name: Build and Publish NPM Package uses: ./.github/actions/build-npm-package with: release-type: ${{ needs.determine_mode.outputs.release-type }} gradle-cache-encryption-key: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }} # ─── Release-only: remove an unclosed Android staging repository # whenever the gated publish job does not complete successfully ─ cleanup_android_staging_repository: needs: [determine_mode, build_android, publish_react_native] if: | always() && needs.determine_mode.result == 'success' && needs.determine_mode.outputs.mode == 'release' && needs.build_android.result != 'skipped' && needs.publish_react_native.result != 'success' runs-on: ubuntu-latest env: ORG_GRADLE_PROJECT_SONATYPE_USERNAME: ${{ secrets.ORG_GRADLE_PROJECT_SONATYPE_USERNAME }} ORG_GRADLE_PROJECT_SONATYPE_PASSWORD: ${{ secrets.ORG_GRADLE_PROJECT_SONATYPE_PASSWORD }} steps: - name: Checkout uses: actions/checkout@v6 - name: Setup node.js uses: ./.github/actions/setup-node - name: Drop Android staging repository run: node ./scripts/releases-ci/cleanup-maven-staging-repositories.js # ─── Publish bumped monorepo packages (main/stable push) ───────── publish_bumped_packages: needs: [determine_mode] if: needs.determine_mode.outputs.mode == 'bumped-packages' runs-on: ubuntu-latest environment: npm-publish # `id-token: write` is required so the npm CLI can mint the OIDC # token that npm Trusted Publishing exchanges for a publish token. permissions: contents: read id-token: write steps: - name: Checkout uses: actions/checkout@v6 - name: Setup node.js uses: ./.github/actions/setup-node with: node-version: '24' registry-url: 'https://registry.npmjs.org' - name: Run Yarn Install uses: ./.github/actions/yarn-install - name: Build packages run: yarn build - name: Build types run: yarn build-types --skip-snapshot - name: Find and publish all bumped packages run: node ./scripts/releases-ci/publish-updated-packages.js # ─── Release-only: post-publish steps ──────────────────────────── post_publish: runs-on: ubuntu-latest needs: [determine_mode, publish_react_native] # Use always() so this job still runs in release mode even though some # upstream jobs (e.g. build_android) are skipped and would otherwise # poison the implicit success() gate. The explicit result checks below # handle the real gating: only run for a successful release publish. if: | always() && needs.determine_mode.result == 'success' && needs.publish_react_native.result == 'success' && needs.determine_mode.outputs.mode == 'release' env: REACT_NATIVE_BOT_GITHUB_TOKEN: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }} steps: - name: Checkout uses: actions/checkout@v6 with: fetch-depth: 0 fetch-tags: true - name: Publish @react-native-community/template id: publish-template-to-npm uses: actions/github-script@v8 with: github-token: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }} script: | const {publishTemplate} = require('./.github/workflow-scripts/publishTemplate.js') const version = "${{ github.ref_name }}" const isDryRun = false await publishTemplate(github, version, isDryRun); - name: Wait for template to be published timeout-minutes: 3 uses: actions/github-script@v8 with: github-token: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }} script: | const {verifyPublishedTemplate, isLatest} = require('./.github/workflow-scripts/publishTemplate.js') const version = "${{ github.ref_name }}" await verifyPublishedTemplate(version, isLatest()); - name: Update rn-diff-purge to generate upgrade-support diff run: | curl -X POST https://api.github.com/repos/react-native-community/rn-diff-purge/dispatches \ -H "Accept: application/vnd.github.v3+json" \ -H "Authorization: Bearer $REACT_NATIVE_BOT_GITHUB_TOKEN" \ -d "{\"event_type\": \"publish\", \"client_payload\": { \"version\": \"${{ github.ref_name }}\" }}" - name: Verify Release is on NPM timeout-minutes: 3 uses: actions/github-script@v8 with: github-token: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }} script: | const {verifyReleaseOnNpm} = require('./.github/workflow-scripts/verifyReleaseOnNpm.js'); const {isLatest} = require('./.github/workflow-scripts/publishTemplate.js'); const version = "${{ github.ref_name }}"; await verifyReleaseOnNpm(version, isLatest()); - name: Verify that artifacts are on Maven uses: actions/github-script@v8 with: script: | const {verifyArtifactsAreOnMaven} = require('./.github/workflow-scripts/verifyArtifactsAreOnMaven.js'); const version = "${{ github.ref_name }}"; await verifyArtifactsAreOnMaven(version); # ─── Release-only: changelog, podfile bump, draft release ──────── generate_changelog: needs: [determine_mode, publish_react_native] # always() + explicit result checks: run for a successful release publish # even when skipped upstream jobs would trip the implicit success() gate. if: | always() && needs.determine_mode.result == 'success' && needs.publish_react_native.result == 'success' && needs.determine_mode.outputs.mode == 'release' uses: ./.github/workflows/generate-changelog.yml secrets: inherit bump_podfile_lock: needs: [determine_mode, publish_react_native] # always() + explicit result checks: run for a successful release publish # even when skipped upstream jobs would trip the implicit success() gate. if: | always() && needs.determine_mode.result == 'success' && needs.publish_react_native.result == 'success' && needs.determine_mode.outputs.mode == 'release' uses: ./.github/workflows/bump-podfile-lock.yml secrets: inherit create_draft_release: needs: [determine_mode, generate_changelog, set_hermes_version] # always() + explicit result checks: run for a successful release even when # skipped upstream jobs would trip the implicit success() gate. if: | always() && needs.determine_mode.result == 'success' && needs.generate_changelog.result == 'success' && needs.set_hermes_version.result == 'success' && needs.determine_mode.outputs.mode == 'release' uses: ./.github/workflows/create-draft-release.yml secrets: inherit with: hermesVersion: ${{ needs.set_hermes_version.outputs.HERMES_VERSION }}