I have script I want to run upon merging a pull request in GitHub. The script is written in JavaScript using the ZX library.
The purpose of the script is to automatically determine the next version of a package to be published to npm and the actions including fetching the latest git tags from GitHub in order to negotiate what version to release under.
Unfortunately I'm struggling a lot with running a simple git pull --tags
action. I managed to install act which enables me to run the script locally.
When the script reaches the step where it pulls from git it times out. The error message is not very clear, but I see something with "Username" so I suspect it is trying to authenticate with GitHub using password instead of personal access token:
| Username for 'https://github.com': /Users/work/projects/aves/node_modules/zx/build/core.cjs:245
| const output = new ProcessOutput(
| ^
|
| ProcessOutput [Error]:
| at /Users/work/projects/aves/scripts/prepublish.js:609:37
| exit code: null
| signal: SIGTERM
| at EventEmitter.end (/Users/work/projects/aves/node_modules/zx/build/core.cjs:245:28)
| at EventEmitter.emit (node:events:519:28)
| at ChildProcess.<anonymous> (/Users/work/projects/aves/node_modules/zx/build/vendor.cjs:20283:16)
| at ChildProcess.emit (node:events:519:28)
| at maybeClose (node:internal/child_process:1105:16)
| at Socket.<anonymous> (node:internal/child_process:457:11)
| at Socket.emit (node:events:519:28)
| at Pipe.<anonymous> (node:net:338:12) {
| _code: null,
| _signal: 'SIGTERM',
| _stdout: '',
| _stderr: '',
| _combined: ''
| }
|
| Node.js v20.15.0
error Command failed with exit code 1.
This is my workflow:
name: Publish Package to npmjs
on:
pull_request:
branches:
- main
types: ['closed']
jobs:
build:
runs-on: ubuntu-latest
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Git checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js and copy .npmrc file
uses: actions/setup-node@v4
with:
node-version: '20.x'
registry-url: 'https://registry.npmjs.org'
- name: Configure git for HTTPS
run: |
git config --global url.https://github.com/.insteadOf git@github.com:
git config --global url.https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/.insteadOf https://github.com/
- name: Fetch tags
run: yarn && yarn zx ./scripts/prepublish.js --ci
Initially, instead of running prepublish.js
on the last line I ran:
run: git pull --tags
And it used to work for a short while until I made some change I don't remember and now it also fails if I pull directly from the workflow.
Inside prepublish.js
I tried various things:
I've tried printing the GITHUB_TOKEN
. It works.
I've tried calling git commands that don't require authenticating with the remote repo, such as git status
and it works fine.
I tried running git config --list
and printing the output. Interestingly I notice that the token is not included in the output. I'm not sure if there is some logic in github to remove sensitive tokens before printing, but I tried to remove the x-access-token line from the workflow and instead running it inside prepublish.js
like so:
await $`git config --global url.https://x-access-token:${process.env.GITHUB_TOKEN}@github.com/.insteadOf https://github.com/`;
Subsequently printing git config does include the token in the url, but calls to git push
still fails with the same error and I can't think of any other steps to try at this point.
Here is what I currently have in prepublish.js
#!/usr/bin/env zx
const zx = require('zx');
const { $, spinner } = zx;
(async () => {
await $`git config --global url.https://x-access-token:${process.env.GITHUB_TOKEN}@github.com/.insteadOf https://github.com/`;
const { stdout: gitConfig } = await $`git config --list`;
console.log({ gitConfig });
const { stdout, stderr } = await $`git pull --tags`.timeout('2m');
if (stderr) {
console.error('stderr:', stderr);
}
console.log('stdout:', stdout);
return;
})()
I managed to find a solution myself.
First, I was referencing the environment variable for GITHUB_TOKEN
wrong in the run section. Instead of ${{ secrets.GITHUB_TOKEN }}
I needed to use ${{ env.GITHUB_TOKEN }}
.
Second, instead of rewriting URLs I needed to re-add the remote with the correct URL format:
git remote remove origin
git remote add org https://<user>:${{ env.GITHUB_TOKEN }}@github.com/<organisation>/<repo>.git
So eventually my workflow ended up looking like this:
name: Publish Package to npmjs
on:
pull_request:
branches:
- main
types: ['closed']
jobs:
build:
runs-on: ubuntu-latest
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Git checkout
uses: actions/checkout@v4
- name: Setup Node.js and copy .npmrc file
uses: actions/setup-node@v4
with:
node-version: '20.x'
registry-url: 'https://registry.npmjs.org'
- name: Configure git for HTTPS
run: |
git remote remove origin
git remote add org https://GITHUB_ACTIONS_BOT:${{ env.GITHUB_TOKEN }}@github.com/<org>/<repo>.git
- name: Fetch tags
run: yarn && yarn zx ./scripts/prepublish.js --ci
Within prepublish.js
I'm now able to execute git commands:
...
const version = ...
await $`npm version ${version}`
await $`git push --tags`
...