From e58a1c2c00df22a499bf6d0986811164e3ec4dfa Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sat, 30 Nov 2024 18:22:05 +0100 Subject: [PATCH] tools: add a backport queue cron action --- .github/workflows/backport-queue.yml | 137 +++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 .github/workflows/backport-queue.yml diff --git a/.github/workflows/backport-queue.yml b/.github/workflows/backport-queue.yml new file mode 100644 index 00000000000000..ca43da060e9944 --- /dev/null +++ b/.github/workflows/backport-queue.yml @@ -0,0 +1,137 @@ +name: Backport Commit Queue + +on: + schedule: + - cron: '0 0 * * *' # Every day at midnight + workflow_dispatch: + +concurrency: ${{ github.workflow }} + +env: + NODE_VERSION: lts/* + +permissions: + contents: write + +jobs: + commitQueue: + runs-on: ubuntu-latest + if: github.repository == 'nodejs/node' || github.event_name == 'workflow_dispatch' + strategy: + matrix: + branch: + - { release-line: v23.x, base-branch: main } + - { release-line: v22.x, base-branch: v23.x } + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + # Needs the whole git history for ncu to work + # See https://github.com/nodejs/node-core-utils/pull/486 + fetch-depth: 0 + ref: ${{ matrix.branch.release-line }}-staging + + # Install dependencies + - name: Install Node.js + uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 + with: + node-version: ${{ env.NODE_VERSION }} + - name: Install @node-core/utils + run: npm install -g @node-core/utils branch-diff + + - name: Setup git author + run: | + git config --local user.email "github-bot@iojs.org" + git config --local user.name "Node.js GitHub Bot" + + - name: Fetch base branch + run: | + git remote set-branches --add origin "$BASE_BRANCH" + git fetch origin "$BASE_BRANCH" + env: + BASE_BRANCH: ${{ matrix.branch.base-branch }} + + - name: Fetch auto-backport branch if it exists + id: fetch + run: | + if git fetch origin "$BACKPORT_BRANCH"; then + STAGING_BRANCH_TIP="$(git rev-parse HEAD)" + WORKING_BRANCH_TIP="$(git rev-parse FETCH_HEAD)" + echo "WORKING_BRANCH_TIP=$WORKING_BRANCH_TIP" >> "$GITHUB_OUTPUT" + if [ "$WORKING_BRANCH_TIP" != "$STAGING_BRANCH_TIP" ]; then + git reset "$WORKING_BRANCH_TIP" --hard + git rebase "$STAGING_BRANCH_TIP" --empty=drop || git reset "$STAGING_BRANCH_TIP" --hard + else + else + echo "Branch doesn't exist yet" + fi + env: + BACKPORT_BRANCH: ${{ matrix.branch.release-branch }}-staging-auto-backport + + - name: Run the queue + id: queue + run: | + backport() { + COMMIT="$1" + git cherry-pick "$COMMIT" + NODE="$(command -v node)" make lint-js + NODE="$(command -v node)" make test-doc "-j${PARALLELIZATION}" + make jstest "-j${PARALLELIZATION}" + } + + [ "$MAX_COMMITS" != "0" ] &&\ + branch-diff "${CURRENT_RELEASE_LINE}-staging" "$BASE_REF" \ + --exclude-label="semver-major,dont-land-on-${CURRENT_RELEASE_LINE},backport-requested-${CURRENT_RELEASE_LINE},backport-blocked-${CURRENT_RELEASE_LINE},backport-open-${CURRENT_RELEASE_LINE},backported-to-${CURRENT_RELEASE_LINE}"\ + --filter-release --format=sha --reverse | while read -r COMMIT ; do + if backport "$COMMIT" 2>&1 >output; then + MAX_COMMITS="$((MAX_COMMITS-1))" + else + { + EOF="$(node -p 'crypto.randomUUID()')" + echo "$COMMIT<<$EOF" + cat output + echo "$EOF" + } >> "$GITHUB_OUTPUT" + git cherry-pick --skip || true + fi + cat output + [ "$MAX_COMMITS" = "0" ] && break + done + rm output + env: + MAX_COMMITS: 9 # backport commits 9 at a time to limit the risk of timeout + CURRENT_RELEASE_LINE: ${{ matrix.branch.release-branch }} + BASE_REF: ${{ matrix.branch.base-branch }} + BACKPORT_BRANCH: ${{ matrix.branch.release-branch }}-staging-auto-backport + + - name: Get local HEAD + id: head + run: echo "HEAD=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" + + - name: Push to working branch + if: ${{ steps.fetch.outputs.WORKING_BRANCH_TIP != steps.head.outputs.HEAD }} + run: git push origin "HEAD:refs/heads/$BACKPORT_BRANCH" --force + env: + BACKPORT_BRANCH: ${{ matrix.branch.release-branch }}-staging-auto-backport + + - name: Report errors + if: ${{ + steps.fetch.outputs.WORKING_BRANCH_TIP != steps.head.outputs.HEAD && + toJson(steps.queue.outputs) != '{}' + }} + run: | + node | gh issue create --repo "$GITHUB_REPOSITORY_OWNER/Releast"\ + -t "Autobackport is failing on $CURRENT_RELEASE_LINE" --file-body -<<'EOF' + console.log(''); + EOF + env: + GH_TOKEN: ${{ secrets.GH_USER_TOKEN }} + FAILED_BACKPORTS: ${{ toJson(steps.queue.outputs) }} + CURRENT_RELEASE_LINE: ${{ matrix.branch.release-branch }} +