From e9b35f52484c436ac4bb2187f00d0fb14058d1ed Mon Sep 17 00:00:00 2001 From: Jan Buchar Date: Thu, 7 Nov 2024 13:56:37 +0100 Subject: [PATCH] ci: Set up an automated release process (#691) - closes #496 --------- Co-authored-by: Vlad Frangu --- .github/workflows/check.yaml | 128 +----------------- .github/workflows/pre_release.yaml | 133 +++++++++++++++++++ .github/workflows/release.yaml | 205 +++++++++++++++++++++++++++++ 3 files changed, 340 insertions(+), 126 deletions(-) create mode 100644 .github/workflows/pre_release.yaml create mode 100644 .github/workflows/release.yaml diff --git a/.github/workflows/check.yaml b/.github/workflows/check.yaml index 3fb38818..27262597 100644 --- a/.github/workflows/check.yaml +++ b/.github/workflows/check.yaml @@ -1,6 +1,6 @@ # This workflow runs for every pull request to lint and test the proposed changes. -name: Check & Release +name: Check on: # Push to master will deploy a beta version @@ -25,11 +25,6 @@ jobs: node-version: [18, 20, 22] steps: - - name: Cancel Workflow Action - uses: styfle/cancel-workflow-action@0.12.1 - with: - access_token: ${{ github.token }} - - uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} @@ -128,6 +123,7 @@ jobs: cd website yarn yarn build + lint: name: Lint runs-on: ubuntu-latest @@ -158,123 +154,3 @@ jobs: - name: Run format checks run: yarn format - - # The deploy job is long but there are only 2 important parts. NPM publish - # and triggering of docker image builds in the apify-actor-docker repo. - deploy: - name: Publish to NPM - if: github.repository_owner == 'apify' && (github.ref == 'refs/heads/master' || github.event_name == 'release') && !contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, 'docs:') - needs: [build_and_test, test_python_support, lint] - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - token: ${{ secrets.APIFY_SERVICE_ACCOUNT_GITHUB_TOKEN }} - fetch-depth: 0 - - - name: Use Node.js 20 - uses: actions/setup-node@v4 - with: - node-version: 20 - registry-url: https://registry.npmjs.org - - - name: Enable corepack - run: | - corepack enable - corepack prepare yarn@stable --activate - - - name: Activate cache for Node.js 20 - uses: actions/setup-node@v4 - with: - cache: yarn - - - name: Set git identity - run: | - git config --global user.name 'Apify Service Account' - git config --global user.email 'apify-service-account@users.noreply.github.com' - - - name: Install Dependencies - run: yarn - - # Determine if this is a beta or latest release - - name: Set Release Tag - run: echo "RELEASE_TAG=$(if [ ${{ github.event_name }} = release ]; then echo latest; else echo beta; fi)" >> $GITHUB_ENV - - # Check version consistency and increment pre-release version number for beta only. - - name: Bump pre-release version - if: env.RELEASE_TAG == 'beta' - run: yarn tsx ./.github/scripts/before-beta-release.ts - - - name: Publish to NPM - run: | - yarn config set npmAuthToken ${NODE_AUTH_TOKEN} - yarn npm publish --tag ${{ env.RELEASE_TAG }} --access public - env: - NODE_AUTH_TOKEN: ${{ secrets.APIFY_SERVICE_ACCOUNT_NPM_TOKEN }} - - # Latest version is tagged by the release process so we only tag beta here. - - name: Tag Version - if: env.RELEASE_TAG == 'beta' - run: | - git_tag=v`node -p "require('./package.json').version"` - git tag $git_tag - git push origin $git_tag - - - name: Update readme - if: env.RELEASE_TAG == 'latest' - run: | - git update-index --assume-unchanged .yarnrc.yml - git add . - git diff-index --quiet HEAD || git commit -m "[skip ci] update README with latest command reference" - git push origin HEAD:master - - update_homebrew_formula: - name: Update Homebrew Formula - needs: [deploy] - runs-on: ubuntu-latest - if: github.repository_owner == 'apify' && github.event_name == 'release' && github.event.action == 'published' - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Set git identity - run: | - git config --global user.name 'Apify Service Account' - git config --global user.email 'apify-service-account@users.noreply.github.com' - - - name: Set up Homebrew - uses: Homebrew/actions/setup-homebrew@master - - # It can happen that the updated package version is not available right after the `npm publish` command finishes - # Try waiting 3 minutes until the updated package version is available - - name: Wait for updated package to be available on NPM - run: | - PACKAGE_VERSION=`node -p "require('./package.json').version"` - PACKAGE_DEFINITION_URL="https://registry.npmjs.org/apify-cli/${PACKAGE_VERSION}" - - for _i in {1..30}; do - curl -sf "${PACKAGE_DEFINITION_URL}" &> /dev/null && exit 0; - echo "Package 'apify-cli' version '${PACKAGE_VERSION}' is not available yet, will retry in 10 seconds." - sleep 10; - done - curl -sf "${PACKAGE_DEFINITION_URL}" &> /dev/null || exit 1; - - - name: Update Homebrew formula in apify/homebrew-tap repo - run: | - PACKAGE_VERSION=`node -p "require('./package.json').version"` - gh workflow run update_formula.yaml --repo apify/homebrew-tap --field package=apify-cli --field version=$PACKAGE_VERSION - env: - GH_TOKEN: ${{ secrets.APIFY_SERVICE_ACCOUNT_GITHUB_TOKEN }} - - - name: Send PR with formula update to homebrew/homebrew-core repo - run: | - PACKAGE_VERSION=`node -p "require('./package.json').version"` - brew tap --force homebrew/core - brew bump-formula-pr apify-cli \ - --version ${PACKAGE_VERSION} \ - --no-browse \ - --message "Automatic update of the \`apify-cli\` formula. - - CC @B4nan @vladfrangu" - env: - HOMEBREW_GITHUB_API_TOKEN: ${{ secrets.APIFY_SERVICE_ACCOUNT_GITHUB_TOKEN }} diff --git a/.github/workflows/pre_release.yaml b/.github/workflows/pre_release.yaml new file mode 100644 index 00000000..901b60b1 --- /dev/null +++ b/.github/workflows/pre_release.yaml @@ -0,0 +1,133 @@ +name: Create a pre-release + +on: + # Push to master will deploy a beta version + push: + branches: + - master + tags-ignore: + - "**" # Ignore all tags to prevent duplicate builds when tags are pushed. + +concurrency: + group: release + cancel-in-progress: false + +jobs: + release_metadata: + if: "!startsWith(github.event.head_commit.message, 'docs') && !startsWith(github.event.head_commit.message, 'ci') && startsWith(github.repository, 'apify/')" + name: Prepare release metadata + runs-on: ubuntu-latest + outputs: + version_number: ${{ steps.release_metadata.outputs.version_number }} + changelog: ${{ steps.release_metadata.outputs.changelog }} + steps: + - uses: apify/workflows/git-cliff-release@main + name: Prepare release metadata + id: release_metadata + with: + release_type: prerelease + existing_changelog_path: CHANGELOG.md + + wait_for_checks: + name: Wait for code checks to pass + runs-on: ubuntu-latest + steps: + - uses: lewagon/wait-on-check-action@v1.3.4 + with: + ref: ${{ github.ref }} + repo-token: ${{ secrets.GITHUB_TOKEN }} + check-regexp: (Build & Test .*|Test Python template support|Lint|Docs build) + wait-interval: 5 + + update_changelog: + needs: [release_metadata, wait_for_checks] + name: Update changelog + runs-on: ubuntu-latest + outputs: + changelog_commitish: ${{ steps.commit.outputs.commit_long_sha || github.sha }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + token: ${{ secrets.APIFY_SERVICE_ACCOUNT_GITHUB_TOKEN }} + + - name: Use Node.js 22 + uses: actions/setup-node@v4 + with: + node-version: 22 + registry-url: https://registry.npmjs.org + + - name: Enable corepack + run: | + corepack enable + corepack prepare yarn@stable --activate + git update-index --assume-unchanged .yarnrc.yml + + - name: Activate cache for Node.js 22 + uses: actions/setup-node@v4 + with: + cache: yarn + + - name: Update README + run: | + yarn npm pack + + - name: Update package version in package.json + run: yarn npm version --no-git-tag-version --allow-same-version ${{ needs.release_metadata.outputs.version_number }} + + - name: Update CHANGELOG.md + uses: DamianReeves/write-file-action@master + with: + path: CHANGELOG.md + write-mode: overwrite + contents: ${{ needs.release_metadata.outputs.changelog }} + + - name: Commit changes + id: commit + uses: EndBug/add-and-commit@v9 + with: + author_name: Apify Release Bot + author_email: noreply@apify.com + message: "chore(release): Update changelog and package version [skip ci]" + + publish_to_npm: + name: Publish to NPM + needs: [update_changelog] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ needs.update_changelog.changelog_commitish }} + + - name: Use Node.js 22 + uses: actions/setup-node@v4 + with: + node-version: 22 + registry-url: https://registry.npmjs.org + + - name: Enable corepack + run: | + corepack enable + corepack prepare yarn@stable --activate + + - name: Activate cache for Node.js 22 + uses: actions/setup-node@v4 + with: + cache: yarn + + - name: Install dependencies + run: yarn + + # Check version consistency and increment pre-release version number for beta only. + - name: Bump pre-release version + run: yarn tsx ./.github/scripts/before-beta-release.ts + + - name: Build module + run: yarn build + + - name: Publish to NPM + run: | + yarn config set npmAuthToken ${NODE_AUTH_TOKEN} + yarn npm publish --tag beta --access public + env: + NODE_AUTH_TOKEN: ${{ secrets.APIFY_SERVICE_ACCOUNT_NPM_TOKEN }} diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 00000000..27f4830f --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,205 @@ +name: Create a release + +on: + # Trigger a stable version release via GitHub's UI, with the ability to specify the type of release. + workflow_dispatch: + inputs: + release_type: + description: Release type + required: true + type: choice + default: auto + options: + - auto + - custom + - patch + - minor + - major + custom_version: + description: The custom version to bump to (only for "custom" type) + required: false + type: string + default: "" + +concurrency: + group: release + cancel-in-progress: false + +jobs: + release_metadata: + name: Prepare release metadata + runs-on: ubuntu-latest + outputs: + version_number: ${{ steps.release_metadata.outputs.version_number }} + tag_name: ${{ steps.release_metadata.outputs.tag_name }} + changelog: ${{ steps.release_metadata.outputs.changelog }} + release_notes: ${{ steps.release_metadata.outputs.release_notes }} + steps: + - uses: apify/workflows/git-cliff-release@main + name: Prepare release metadata + id: release_metadata + with: + release_type: ${{ inputs.release_type }} + custom_version: ${{ inputs.custom_version }} + existing_changelog_path: CHANGELOG.md + + + wait_for_checks: + name: Wait for code checks to pass + runs-on: ubuntu-latest + steps: + - uses: lewagon/wait-on-check-action@v1.3.4 + with: + ref: ${{ github.ref }} + repo-token: ${{ secrets.GITHUB_TOKEN }} + check-regexp: (Build & Test .*|Test Python template support|Lint|Docs build) + wait-interval: 5 + + update_changelog: + needs: [ release_metadata, wait_for_checks ] + name: Update changelog + runs-on: ubuntu-latest + outputs: + changelog_commitish: ${{ steps.commit.outputs.commit_long_sha || github.sha }} + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + token: ${{ secrets.APIFY_SERVICE_ACCOUNT_GITHUB_TOKEN }} + + - name: Use Node.js 22 + uses: actions/setup-node@v4 + with: + node-version: 22 + + - name: Enable corepack + run: | + corepack enable + corepack prepare yarn@stable --activate + + - name: Activate cache for Node.js 22 + uses: actions/setup-node@v4 + with: + cache: yarn + + - name: Update package version in package.json + run: npm version --no-git-tag-version --allow-same-version ${{ needs.release_metadata.outputs.version_number }} + + - name: Update CHANGELOG.md + uses: DamianReeves/write-file-action@master + with: + path: CHANGELOG.md + write-mode: overwrite + contents: ${{ needs.release_metadata.outputs.changelog }} + + - name: Commit changes + id: commit + uses: EndBug/add-and-commit@v9 + with: + author_name: Apify Release Bot + author_email: noreply@apify.com + message: "chore(release): Update changelog and package version [skip ci]" + + create_github_release: + name: Create github release + needs: [release_metadata, update_changelog] + runs-on: ubuntu-latest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - name: Create release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ needs.release_metadata.outputs.tag_name }} + name: ${{ needs.release_metadata.outputs.version_number }} + target_commitish: ${{ needs.update_changelog.outputs.changelog_commitish }} + body: ${{ needs.release_metadata.outputs.release_notes }} + + publish_to_npm: + name: Publish to NPM + needs: [update_changelog] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ needs.update_changelog.changelog_commitish }} + + - name: Use Node.js 22 + uses: actions/setup-node@v4 + with: + node-version: 22 + registry-url: https://registry.npmjs.org + + - name: Enable corepack + run: | + corepack enable + corepack prepare yarn@stable --activate + + - name: Activate cache for Node.js 22 + uses: actions/setup-node@v4 + with: + cache: yarn + + - name: Install dependencies + run: yarn + + - name: Build module + run: yarn build + + - name: Publish to NPM + run: | + yarn config set npmAuthToken ${NODE_AUTH_TOKEN} + yarn npm publish --tag latest --access public + env: + NODE_AUTH_TOKEN: ${{ secrets.APIFY_SERVICE_ACCOUNT_NPM_TOKEN }} + + update_homebrew_formula: + name: Update Homebrew Formula + needs: [publish_to_npm] + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set git identity + run: | + git config --global user.name 'Apify Service Account' + git config --global user.email 'apify-service-account@users.noreply.github.com' + + - name: Set up Homebrew + uses: Homebrew/actions/setup-homebrew@master + + # It can happen that the updated package version is not available right after the `npm publish` command finishes + # Try waiting 3 minutes until the updated package version is available + - name: Wait for updated package to be available on NPM + run: | + PACKAGE_VERSION=`node -p "require('./package.json').version"` + PACKAGE_DEFINITION_URL="https://registry.npmjs.org/apify-cli/${PACKAGE_VERSION}" + + for _i in {1..30}; do + curl -sf "${PACKAGE_DEFINITION_URL}" &> /dev/null && exit 0; + echo "Package 'apify-cli' version '${PACKAGE_VERSION}' is not available yet, will retry in 10 seconds." + sleep 10; + done + curl -sf "${PACKAGE_DEFINITION_URL}" &> /dev/null || exit 1; + + - name: Update Homebrew formula in apify/homebrew-tap repo + run: | + PACKAGE_VERSION=`node -p "require('./package.json').version"` + gh workflow run update_formula.yaml --repo apify/homebrew-tap --field package=apify-cli --field version=$PACKAGE_VERSION + env: + GH_TOKEN: ${{ secrets.APIFY_SERVICE_ACCOUNT_GITHUB_TOKEN }} + + - name: Send PR with formula update to homebrew/homebrew-core repo + run: | + PACKAGE_VERSION=`node -p "require('./package.json').version"` + brew tap --force homebrew/core + brew bump-formula-pr apify-cli \ + --version ${PACKAGE_VERSION} \ + --no-browse \ + --message "Automatic update of the \`apify-cli\` formula. + + CC @B4nan @vladfrangu" + env: + HOMEBREW_GITHUB_API_TOKEN: ${{ secrets.APIFY_SERVICE_ACCOUNT_GITHUB_TOKEN }}