22
33set -xe
44
5+ GITHUB_REPOSITORY=${GITHUB_REPOSITORY:- nodejs/ node}
6+ BOT_TOKEN=${BOT_TOKEN:- }
7+
58RELEASE_DATE=$1
69RELEASE_LINE=$2
710
@@ -10,24 +13,114 @@ if [ -z "$RELEASE_DATE" ] || [ -z "$RELEASE_LINE" ]; then
1013 exit 1
1114fi
1215
16+ if [ -z " $GITHUB_REPOSITORY " ] || [ -z " $BOT_TOKEN " ]; then
17+ echo " Invalid value in env for GITHUB_REPOSITORY and BOT_TOKEN"
18+ exit 1
19+ fi
20+
21+ if ! command -v node || ! command -v gh || ! command -v git || ! command -v awk; then
22+ echo " Missing required dependencies"
23+ exit 1
24+ fi
25+
1326git node release --prepare --skipBranchDiff --yes --releaseDate " $RELEASE_DATE "
14- # We use it to not specify the branch name as it changes based on
15- # the commit list (semver-minor/semver-patch)
16- git config push.default current
17- git push
27+
28+ HEAD_BRANCH=" $( git rev-parse --abbrev-ref HEAD) "
29+ HEAD_SHA=" $( git rev-parse HEAD^) "
1830
1931TITLE=$( awk " /^## ${RELEASE_DATE} / { print substr(\$ 0, 4) }" " doc/changelogs/CHANGELOG_V${RELEASE_LINE} .md" )
2032
2133# Use a temporary file for the PR body
2234TEMP_BODY=" $( awk " /## ${RELEASE_DATE} /,/^<a id=/{ if (!/^<a id=/) print }" " doc/changelogs/CHANGELOG_V${RELEASE_LINE} .md" ) "
2335
24- PR_URL=" $( gh pr create --title " $TITLE " --body " $TEMP_BODY " --base " v$RELEASE_LINE .x" ) "
36+ # Create the proposal branch
37+ gh api \
38+ --method POST \
39+ -H " Accept: application/vnd.github+json" \
40+ -H " X-GitHub-Api-Version: 2022-11-28" \
41+ " /repos/${GITHUB_REPOSITORY} /git/refs" \
42+ -f " ref=refs/heads/$HEAD_BRANCH " -f " sha=$HEAD_SHA "
43+
44+ # Create the proposal PR
45+ PR_URL=" $( gh api \
46+ --method POST \
47+ --jq .html_url \
48+ -H " Accept: application/vnd.github+json" \
49+ -H " X-GitHub-Api-Version: 2022-11-28" \
50+ " /repos/${GITHUB_REPOSITORY} /pulls" \
51+ -f " title=$TITLE " -f " body=$TEMP_BODY " -f " head=$HEAD_BRANCH " -f " base=v$RELEASE_LINE .x" ) "
2552
26- # Amend commit message so it contains the correct PR-URL trailer.
27- AMENDED_COMMIT_MSG=" $( git log -1 --pretty=%B | sed " s|PR-URL: TODO|PR-URL: $PR_URL |" ) "
53+ # Push the release commit to the proposal branch using `BOT_TOKEN` from the env
54+ node --input-type=module - \
55+ " $GITHUB_REPOSITORY " \
56+ " $HEAD_BRANCH " \
57+ " $HEAD_SHA " \
58+ " $( git log -1 HEAD --format=%s || true) " \
59+ " $( git log -1 HEAD --format=%b | awk -v PR_URL=" $PR_URL " ' {sub(/^PR-URL: TODO$/, "PR-URL: " PR_URL)} 1' || true) " \
60+ " $( git show HEAD --diff-filter=d --name-only --format= || true) " \
61+ " $( git show HEAD --diff-filter=D --name-only --format= || true) " \
62+ << 'EOF '
63+ const [,,
64+ repo,
65+ branch,
66+ parentCommitSha,
67+ commit_title,
68+ commit_body,
69+ modifiedOrAddedFiles,
70+ deletedFiles,
71+ ] = process.argv;
2872
29- # Replace "TODO" with the PR URL in the last commit
30- git commit --amend --no-edit -m " $AMENDED_COMMIT_MSG " || true
73+ import { readFileSync } from 'node:fs';
74+ import util from 'node:util';
3175
32- # Force-push the amended commit
33- git push --force
76+ const query = `
77+ mutation ($repo: String! $branch: String!, $parentCommitSha: GitObjectID!, $changes: FileChanges!, $commit_title: String!, $commit_body: String) {
78+ createCommitOnBranch(input: {
79+ branch: {
80+ repositoryNameWithOwner: $repo,
81+ branchName: $branch
82+ },
83+ message: {
84+ headline: $commit_title,
85+ body: $commit_body
86+ },
87+ expectedHeadOid: $parentCommitSha,
88+ fileChanges: $changes
89+ }) {
90+ commit {
91+ url
92+ }
93+ }
94+ }
95+ `;
96+ const response = await fetch('https://api.github.com/graphql', {
97+ method: 'POST',
98+ headers: {
99+ 'Authorization': `bearer ${process.env.BOT_TOKEN}`,
100+ },
101+ body: JSON.stringify({
102+ query,
103+ variables: {
104+ repo,
105+ branch,
106+ parentCommitSha,
107+ commit_title,
108+ commit_body,
109+ changes: {
110+ additions: modifiedOrAddedFiles.split('\n').filter(Boolean)
111+ .map(path => ({ path, contents: readFileSync(path).toString('base64') })),
112+ deletions: deletedFiles.split('\n').filter(Boolean),
113+ }
114+ },
115+ })
116+ });
117+ if (!response.ok) {
118+ console.log({statusCode: response.status, statusText: response.statusText});
119+ process.exitCode ||= 1;
120+ }
121+ const data = await response.json();
122+ if (data.errors?.length) {
123+ throw new Error('Endpoint returned an error', { cause: data });
124+ }
125+ console.log(util.inspect(data, { depth: Infinity }));
126+ EOF
0 commit comments