Skip to content

Commit 1c0a788

Browse files
committed
Add workflow to automatically update the bundle
1 parent e85546c commit 1c0a788

3 files changed

Lines changed: 160 additions & 0 deletions

File tree

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
name: Update default CodeQL bundle
2+
description: Updates 'src/defaults.json' to point to a new CodeQL bundle release.
3+
4+
runs:
5+
using: composite
6+
steps:
7+
- name: Install ts-node
8+
shell: bash
9+
run: npm install -g ts-node
10+
11+
- name: Run update script
12+
working-directory: ${{ github.action_path }}
13+
shell: bash
14+
run: ts-node ./index.ts
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import * as fs from 'fs';
2+
import * as github from '@actions/github';
3+
4+
interface BundleInfo {
5+
bundleVersion: string;
6+
cliVersion: string;
7+
}
8+
9+
interface Defaults {
10+
bundleVersion: string;
11+
cliVersion: string;
12+
priorBundleVersion: string;
13+
priorCliVersion: string;
14+
}
15+
16+
const CODEQL_BUNDLE_PREFIX = 'codeql-bundle-';
17+
18+
function getCodeQLCliVersionForRelease(release): string {
19+
const cliVersionsFromMarkerFiles = release.assets
20+
.map((asset) => asset.name.match(/cli-version-(.*)\.txt/)?.[1])
21+
.filter((v) => v)
22+
.map((v) => v as string);
23+
if (cliVersionsFromMarkerFiles.length > 1) {
24+
throw new Error(
25+
`Release ${release.tag_name} has multiple CLI version marker files.`
26+
);
27+
} else if (cliVersionsFromMarkerFiles.length === 0) {
28+
throw new Error(
29+
`Failed to find the CodeQL CLI version for release ${release.tag_name}.`
30+
);
31+
}
32+
return cliVersionsFromMarkerFiles[0];
33+
}
34+
35+
async function getBundleInfoFromRelease(release): Promise<BundleInfo> {
36+
return {
37+
bundleVersion: release.tag_name.substring(CODEQL_BUNDLE_PREFIX.length),
38+
cliVersion: getCodeQLCliVersionForRelease(release)
39+
};
40+
}
41+
42+
async function getNewDefaults(currentDefaults: Defaults): Promise<Defaults> {
43+
const release = github.context.payload.release;
44+
console.log('Updating default bundle as a result of the following release: ' +
45+
`${JSON.stringify(release)}.`)
46+
47+
const bundleInfo = await getBundleInfoFromRelease(release);
48+
return {
49+
bundleVersion: bundleInfo.bundleVersion,
50+
cliVersion: bundleInfo.cliVersion,
51+
priorBundleVersion: currentDefaults.bundleVersion,
52+
priorCliVersion: currentDefaults.cliVersion
53+
};
54+
}
55+
56+
async function main() {
57+
const previousDefaults: Defaults = JSON.parse(fs.readFileSync('../../../src/defaults.json', 'utf8'));
58+
const newDefaults = await getNewDefaults(previousDefaults);
59+
fs.writeFileSync('../../../src/defaults.json', JSON.stringify(newDefaults, null, 2) + "\n");
60+
}
61+
62+
// Ideally, we'd await main() here, but that doesn't work well with `ts-node`.
63+
// So instead we rely on the fact that Node won't exit until the event loop is empty.
64+
main();
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
name: Update default CodeQL bundle
2+
3+
on:
4+
release:
5+
types: [prereleased]
6+
7+
jobs:
8+
update-bundle:
9+
if: startsWith(github.event.release.tag_name, 'codeql-bundle-')
10+
runs-on: ubuntu-latest
11+
steps:
12+
- name: Dump environment
13+
run: env
14+
15+
- name: Dump GitHub context
16+
env:
17+
GITHUB_CONTEXT: '${{ toJson(github) }}'
18+
run: echo "${GITHUB_CONTEXT}"
19+
20+
- uses: actions/checkout@v3
21+
22+
- name: Update git config
23+
run: |
24+
git config --global user.email "github-actions@github.com"
25+
git config --global user.name "github-actions[bot]"
26+
27+
- name: Update bundle
28+
uses: ./.github/actions/update-bundle
29+
30+
- name: Rebuild Action
31+
run: npm run build
32+
33+
- name: Commit and push changes
34+
env:
35+
RELEASE_TAG: "${{ github.event.release.tag_name }}"
36+
run: |
37+
git checkout -b "update-bundle/${RELEASE_TAG}"
38+
git commit -am "Update default bundle to ${RELEASE_TAG}"
39+
git push --set-upstream origin "update-bundle/${RELEASE_TAG}"
40+
41+
- name: Open pull request
42+
env:
43+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
44+
run: |
45+
cli_version=$(jq -r '.cliVersion' src/defaults.json)
46+
pr_url=$(gh pr create \
47+
--title "Update default bundle to $cli_version" \
48+
--body "This pull request updates the default CodeQL bundle, as used with \`tools: latest\` and on GHES, to $cli_version." \
49+
--assignee "${GITHUB_ACTOR}" \
50+
--draft \
51+
)
52+
echo "CLI_VERSION=$cli_version" >> $GITHUB_ENV
53+
echo "PR_URL=$pr_url" >> $GITHUB_ENV
54+
55+
- name: Create changelog note
56+
shell: python
57+
run: |
58+
import os
59+
import re
60+
61+
# Get the PR number from the PR URL.
62+
pr_number = os.environ['PR_URL'].split('/')[-1]
63+
changelog_note = f"- Update default CodeQL bundle version to {os.environ['CLI_VERSION']}. [#{pr_number}]({os.environ['PR_URL']})"
64+
65+
# If the "[UNRELEASED]" section starts with "no user facing changes", remove that line.
66+
# Use perl to avoid having to escape the newline character.
67+
68+
with open('CHANGELOG.md', 'r') as f:
69+
changelog = f.read()
70+
71+
changelog = changelog.replace('## [UNRELEASED]\n\nNo user facing changes.', '## [UNRELEASED]\n')
72+
73+
# Add the changelog note to the bottom of the "[UNRELEASED]" section.
74+
changelog = re.sub(r'\n## (\d+\.\d+\.\d+)', f'{changelog_note}\n\n## \\1', changelog, count=1)
75+
76+
with open('CHANGELOG.md', 'w') as f:
77+
f.write(changelog)
78+
79+
- name: Push changelog note
80+
run: |
81+
git commit -am "Add changelog note"
82+
git push

0 commit comments

Comments
 (0)