From 54b66d90a12a1b276ae0b93cb8b4f7781c99605f Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Thu, 28 Nov 2024 00:03:30 +0100 Subject: [PATCH 1/7] tools: update `create-release-proposal` workflow --- .github/workflows/create-release-proposal.yml | 31 ++++--- tools/actions/create-release.sh | 87 ++++++++++++++++--- 2 files changed, 93 insertions(+), 25 deletions(-) diff --git a/.github/workflows/create-release-proposal.yml b/.github/workflows/create-release-proposal.yml index 6155b5da75f17b..319d6864e15995 100644 --- a/.github/workflows/create-release-proposal.yml +++ b/.github/workflows/create-release-proposal.yml @@ -1,7 +1,6 @@ # This action requires the following secrets to be set on the repository: # GH_USER_NAME: GitHub user whose Jenkins and GitHub token are defined below # GH_USER_TOKEN: GitHub user token, to be used by ncu and to push changes -# JENKINS_TOKEN: Jenkins token, to be used to check CI status name: Create Release Proposal @@ -24,6 +23,7 @@ env: permissions: contents: write + pull-requests: write jobs: releasePrepare: @@ -37,9 +37,7 @@ jobs: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ env.STAGING_BRANCH }} - # Needs the whole git history for ncu to work - # See https://github.com/nodejs/node-core-utils/pull/486 - fetch-depth: 0 + persist-credentials: false # Install dependencies - name: Install Node.js @@ -56,29 +54,36 @@ jobs: ncu-config set upstream origin ncu-config set username "$USERNAME" ncu-config set token "$GH_TOKEN" - ncu-config set jenkins_token "$JENKINS_TOKEN" ncu-config set repo "$(echo "$GITHUB_REPOSITORY" | cut -d/ -f2)" ncu-config set owner "${GITHUB_REPOSITORY_OWNER}" env: USERNAME: ${{ secrets.JENKINS_USER }} - GH_TOKEN: ${{ secrets.GH_USER_TOKEN }} - JENKINS_TOKEN: ${{ secrets.JENKINS_TOKEN }} + GH_TOKEN: ${{ github.token }} - name: Set up ghauth config (Ubuntu) run: | - mkdir -p ~/.config/changelog-maker/ - echo '{ - "user": "'$(ncu-config get username)'", - "token": "'$(ncu-config get token)'" - }' > ~/.config/changelog-maker/config.json + mkdir -p "${XDG_CONFIG_HOME:-~/.config}/changelog-maker" + echo '{}' | jq '{user: env.USERNAME, token: env.TOKEN}' > "${XDG_CONFIG_HOME:-~/.config}/changelog-maker/config.json" + env: + USERNAME: ${{ secrets.JENKINS_USER }} + TOKEN: ${{ github.token }} - name: Setup git author run: | git config --local user.email "github-bot@iojs.org" git config --local user.name "Node.js GitHub Bot" + # Workaround, can be removed after https://github.com/nodejs/node-core-utils/pull/876 is released. + - name: Deepen the shallow clone + run: | + git fetch "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git" --shallow-exclude "v${RELEASE_LINE}.0.0" "$STAGING_BRANCH" + - name: Start git node release prepare + # The curl command is to make sure we run the version of the script corresponding to the current workflow. run: | + curl -L https://github.com/${GITHUB_REPOSITORY}/raw/${GITHUB_SHA}/tools/actions/create-release.sh > tools/actions/create-release.sh ./tools/actions/create-release.sh "${RELEASE_DATE}" "${RELEASE_LINE}" env: - GH_TOKEN: ${{ secrets.GH_USER_TOKEN }} + GH_TOKEN: ${{ github.token }} + # We want the bot to push the push the release commit so Ci runs on it. + BOT_TOKEN: ${{ secrets.GH_USER_TOKEN }} diff --git a/tools/actions/create-release.sh b/tools/actions/create-release.sh index 3a69b3f5602ffc..cf442ebd47d55f 100755 --- a/tools/actions/create-release.sh +++ b/tools/actions/create-release.sh @@ -10,24 +10,87 @@ if [ -z "$RELEASE_DATE" ] || [ -z "$RELEASE_LINE" ]; then exit 1 fi +createCommitAPICall() { + commit="${1:-HEAD}" + cat - <<'EOF' +mutation ($repo: String! $branch: String!, $parent: GitObjectID!, $commit_title: String!, $commit_body: String) { + createCommitOnBranch(input: { + branch: { + repositoryNameWithOwner: $repo, + branchName: $branch + }, + message: { + headline: $commit_title, + body: $commit_body + }, + expectedHeadOid: $parent, + fileChanges: { + additions: [ +EOF + git show "$commit" --diff-filter=d --name-only --format= | while read -r FILE; do + printf " { path: " + node -p 'JSON.stringify(process.argv[1])' "$FILE" + printf " , contents: \"" + base64 -w 0 -i "$FILE" + echo "\"}," + done + echo ' ], deletions: [' + git show "$commit" --diff-filter=D --name-only --format= | while read -r FILE; do + echo " $(node -p 'JSON.stringify(process.argv[1])' "$FILE")," + done + cat - <<'EOF' + ] + } + }) { + commit { + url + } + } +} +EOF +} + git node release --prepare --skipBranchDiff --yes --releaseDate "$RELEASE_DATE" -# We use it to not specify the branch name as it changes based on -# the commit list (semver-minor/semver-patch) -git config push.default current -git push + +HEAD_BRANCH="$(git rev-parse --abbrev-ref HEAD)" +HEAD_SHA="$(git rev-parse HEAD^)" TITLE=$(awk "/^## ${RELEASE_DATE}/ { print substr(\$0, 4) }" "doc/changelogs/CHANGELOG_V${RELEASE_LINE}.md") # Use a temporary file for the PR body TEMP_BODY="$(awk "/## ${RELEASE_DATE}/,/^ Date: Thu, 28 Nov 2024 16:13:12 +0100 Subject: [PATCH 2/7] fixup! tools: update `create-release-proposal` workflow --- tools/actions/create-release.sh | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/tools/actions/create-release.sh b/tools/actions/create-release.sh index cf442ebd47d55f..24d92794c1f384 100755 --- a/tools/actions/create-release.sh +++ b/tools/actions/create-release.sh @@ -2,6 +2,9 @@ set -xe +GITHUB_REPOSITORY=${GITHUB_REPOSITORY:-nodejs/node} +BOT_TOKEN=${BOT_TOKEN:-} + RELEASE_DATE=$1 RELEASE_LINE=$2 @@ -10,6 +13,11 @@ if [ -z "$RELEASE_DATE" ] || [ -z "$RELEASE_LINE" ]; then exit 1 fi +if [ -z "$GITHUB_REPOSITORY" ] || [ -z "$BOT_TOKEN" ]; then + echo "Invalid value in env for GITHUB_REPOSITORY and BOT_TOKEN" + exit 1 +fi + createCommitAPICall() { commit="${1:-HEAD}" cat - <<'EOF' @@ -36,7 +44,7 @@ EOF done echo ' ], deletions: [' git show "$commit" --diff-filter=D --name-only --format= | while read -r FILE; do - echo " $(node -p 'JSON.stringify(process.argv[1])' "$FILE")," + node -p '" " + JSON.stringify(process.argv[1]) + ","' "$FILE" done cat - <<'EOF' ] @@ -78,7 +86,7 @@ PR_URL="$(gh api \ -f "title=$TITLE" -f "body=$TEMP_BODY" -f "head=$HEAD_BRANCH" -f "base=v$RELEASE_LINE.x")" # Push the release commit to the proposal branch -createCommitAPICall | node --input-type=module -e 'console.log(JSON.stringify({ +createCommitAPICall HEAD | node --input-type=module -e 'console.log(JSON.stringify({ query: Buffer.concat(await process.stdin.toArray()).toString(), variables: { repo: process.argv[1], @@ -91,6 +99,6 @@ createCommitAPICall | node --input-type=module -e 'console.log(JSON.stringify({ "$GITHUB_REPOSITORY" \ "$HEAD_BRANCH" \ "$HEAD_SHA" \ - "$(git log -1 HEAD --format=%s)" \ - "$(git log -1 HEAD --format=%b | sed "s|PR-URL: TODO|PR-URL: $PR_URL|")" \ + "$(git log -1 HEAD --format=%s || true)" \ + "$(git log -1 HEAD --format=%b | sed "s|PR-URL: TODO|PR-URL: $PR_URL|" || true)" \ | curl -fS -H "Authorization: bearer ${BOT_TOKEN}" -X POST --data @- https://api.github.com/graphql From dd3494123d239a542345fdc193384b6895b5f5f8 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Thu, 28 Nov 2024 16:21:30 +0100 Subject: [PATCH 3/7] fixup! tools: update `create-release-proposal` workflow --- .github/workflows/create-release-proposal.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/create-release-proposal.yml b/.github/workflows/create-release-proposal.yml index 319d6864e15995..1f9719164c841d 100644 --- a/.github/workflows/create-release-proposal.yml +++ b/.github/workflows/create-release-proposal.yml @@ -81,6 +81,7 @@ jobs: - name: Start git node release prepare # The curl command is to make sure we run the version of the script corresponding to the current workflow. run: | + git update-index --assume-unchanged tools/actions/create-release.sh curl -L https://github.com/${GITHUB_REPOSITORY}/raw/${GITHUB_SHA}/tools/actions/create-release.sh > tools/actions/create-release.sh ./tools/actions/create-release.sh "${RELEASE_DATE}" "${RELEASE_LINE}" env: From cf9ed03d1eef483fbf474bad0dbf76cc5fb0a01a Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Thu, 28 Nov 2024 16:24:44 +0100 Subject: [PATCH 4/7] fixup! tools: update `create-release-proposal` workflow --- .github/workflows/create-release-proposal.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/create-release-proposal.yml b/.github/workflows/create-release-proposal.yml index 1f9719164c841d..6a53646a985787 100644 --- a/.github/workflows/create-release-proposal.yml +++ b/.github/workflows/create-release-proposal.yml @@ -82,7 +82,7 @@ jobs: # The curl command is to make sure we run the version of the script corresponding to the current workflow. run: | git update-index --assume-unchanged tools/actions/create-release.sh - curl -L https://github.com/${GITHUB_REPOSITORY}/raw/${GITHUB_SHA}/tools/actions/create-release.sh > tools/actions/create-release.sh + curl -fsSLo tools/actions/create-release.sh https://github.com/${GITHUB_REPOSITORY}/raw/${GITHUB_SHA}/tools/actions/create-release.sh ./tools/actions/create-release.sh "${RELEASE_DATE}" "${RELEASE_LINE}" env: GH_TOKEN: ${{ github.token }} From 4ccd855c0c35b3c30df0ed84b84fb0cf5d66ebb9 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Thu, 28 Nov 2024 00:03:30 +0100 Subject: [PATCH 5/7] fixup! tools: update `create-release-proposal` workflow --- tools/actions/create-release.sh | 126 +++++++++++++++++++------------- 1 file changed, 74 insertions(+), 52 deletions(-) diff --git a/tools/actions/create-release.sh b/tools/actions/create-release.sh index 24d92794c1f384..1bfb436d162178 100755 --- a/tools/actions/create-release.sh +++ b/tools/actions/create-release.sh @@ -18,45 +18,10 @@ if [ -z "$GITHUB_REPOSITORY" ] || [ -z "$BOT_TOKEN" ]; then exit 1 fi -createCommitAPICall() { - commit="${1:-HEAD}" - cat - <<'EOF' -mutation ($repo: String! $branch: String!, $parent: GitObjectID!, $commit_title: String!, $commit_body: String) { - createCommitOnBranch(input: { - branch: { - repositoryNameWithOwner: $repo, - branchName: $branch - }, - message: { - headline: $commit_title, - body: $commit_body - }, - expectedHeadOid: $parent, - fileChanges: { - additions: [ -EOF - git show "$commit" --diff-filter=d --name-only --format= | while read -r FILE; do - printf " { path: " - node -p 'JSON.stringify(process.argv[1])' "$FILE" - printf " , contents: \"" - base64 -w 0 -i "$FILE" - echo "\"}," - done - echo ' ], deletions: [' - git show "$commit" --diff-filter=D --name-only --format= | while read -r FILE; do - node -p '" " + JSON.stringify(process.argv[1]) + ","' "$FILE" - done - cat - <<'EOF' - ] - } - }) { - commit { - url - } - } -} -EOF -} +if ! command -v node || ! command -v gh || ! command -v git || ! command -v awk; then + echo "Missing required dependencies" + exit 1 +fi git node release --prepare --skipBranchDiff --yes --releaseDate "$RELEASE_DATE" @@ -85,20 +50,77 @@ PR_URL="$(gh api \ "/repos/${GITHUB_REPOSITORY}/pulls" \ -f "title=$TITLE" -f "body=$TEMP_BODY" -f "head=$HEAD_BRANCH" -f "base=v$RELEASE_LINE.x")" -# Push the release commit to the proposal branch -createCommitAPICall HEAD | node --input-type=module -e 'console.log(JSON.stringify({ - query: Buffer.concat(await process.stdin.toArray()).toString(), - variables: { - repo: process.argv[1], - branch: process.argv[2], - parent: process.argv[3], - commit_title: process.argv[4], - commit_body: process.argv[5] - } -}))' \ +# Push the release commit to the proposal branch using `BOT_TOKEN` from the env +node --input-type=module - \ "$GITHUB_REPOSITORY" \ "$HEAD_BRANCH" \ "$HEAD_SHA" \ "$(git log -1 HEAD --format=%s || true)" \ - "$(git log -1 HEAD --format=%b | sed "s|PR-URL: TODO|PR-URL: $PR_URL|" || true)" \ -| curl -fS -H "Authorization: bearer ${BOT_TOKEN}" -X POST --data @- https://api.github.com/graphql + "$(git log -1 HEAD --format=%b | awk -v PR_URL="$PR_URL" '{sub(/^PR-URL: TODO$/, "PR-URL: " PR_URL)} 1' || true)" \ + "$(git show HEAD --diff-filter=d --name-only --format= || true)" \ + "$(git show HEAD --diff-filter=D --name-only --format= || true)" \ +<<'EOF' +const [,, + repo, + branch, + parentCommitSha, + commit_title, + commit_body, + modifiedOrAddedFiles, + deletedFiles, +] = process.argv; + +import { readFileSync } from 'node:fs'; +import util from 'node:util'; + +const query = ` +mutation ($repo: String! $branch: String!, $parentCommitSha: GitObjectID!, $changes: FileChanges!, $commit_title: String!, $commit_body: String) { + createCommitOnBranch(input: { + branch: { + repositoryNameWithOwner: $repo, + branchName: $branch + }, + message: { + headline: $commit_title, + body: $commit_body + }, + expectedHeadOid: $parentCommitSha, + fileChanges: $changes + }) { + commit { + url + } + } +} +`; +const response = await fetch('https://api.github.com/graphql', { + method: 'POST', + headers: { + 'Authorization': `bearer ${process.env.BOT_TOKEN}`, + }, + body: JSON.stringify({ + query, + variables: { + repo, + branch, + parentCommitSha, + commit_title, + commit_body, + changes: { + additions: modifiedOrAddedFiles.split('\n').filter(Boolean) + .map(path => ({ path, contents: readFileSync(path).toString('base64') })), + deletions: deletedFiles.split('\n').filter(Boolean), + } + }, + }) +}); +if (!response.ok) { + console.log({statusCode: response.statusCode, status: response.status}); + process.exitCode ||= 1; +} +const data = await response.json(); +if (data.errors?.length) { + throw new Error('Endpoint returned an error', { cause: data }); +} +console.log(util.inspect(data, { depth: Infinity })); +EOF From 32c035b140239f28cacce1c5c167f8fc7c4ab729 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sat, 30 Nov 2024 13:06:55 +0100 Subject: [PATCH 6/7] fixup! fixup! tools: update `create-release-proposal` workflow --- tools/actions/create-release.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/actions/create-release.sh b/tools/actions/create-release.sh index 1bfb436d162178..e3cfd76952a18b 100755 --- a/tools/actions/create-release.sh +++ b/tools/actions/create-release.sh @@ -115,7 +115,7 @@ const response = await fetch('https://api.github.com/graphql', { }) }); if (!response.ok) { - console.log({statusCode: response.statusCode, status: response.status}); + console.log({statusCode: response.status, statusText: response.statusText}); process.exitCode ||= 1; } const data = await response.json(); From 003594200615600ec41b65845bc015b289f92ab5 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Wed, 4 Dec 2024 00:36:49 +0100 Subject: [PATCH 7/7] Apply suggestions from code review --- .github/workflows/create-release-proposal.yml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/.github/workflows/create-release-proposal.yml b/.github/workflows/create-release-proposal.yml index 6a53646a985787..d3ffa3ad49b5e2 100644 --- a/.github/workflows/create-release-proposal.yml +++ b/.github/workflows/create-release-proposal.yml @@ -73,11 +73,6 @@ jobs: git config --local user.email "github-bot@iojs.org" git config --local user.name "Node.js GitHub Bot" - # Workaround, can be removed after https://github.com/nodejs/node-core-utils/pull/876 is released. - - name: Deepen the shallow clone - run: | - git fetch "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git" --shallow-exclude "v${RELEASE_LINE}.0.0" "$STAGING_BRANCH" - - name: Start git node release prepare # The curl command is to make sure we run the version of the script corresponding to the current workflow. run: | @@ -86,5 +81,5 @@ jobs: ./tools/actions/create-release.sh "${RELEASE_DATE}" "${RELEASE_LINE}" env: GH_TOKEN: ${{ github.token }} - # We want the bot to push the push the release commit so Ci runs on it. + # We want the bot to push the push the release commit so CI runs on it. BOT_TOKEN: ${{ secrets.GH_USER_TOKEN }}