Skip to content

Commit

Permalink
Add workflow to automatically update the bundle
Browse files Browse the repository at this point in the history
  • Loading branch information
Henry Mercer committed Apr 3, 2023
1 parent e85546c commit 1c0a788
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 0 deletions.
14 changes: 14 additions & 0 deletions .github/actions/update-bundle/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
name: Update default CodeQL bundle
description: Updates 'src/defaults.json' to point to a new CodeQL bundle release.

runs:
using: composite
steps:
- name: Install ts-node
shell: bash
run: npm install -g ts-node

- name: Run update script
working-directory: ${{ github.action_path }}
shell: bash
run: ts-node ./index.ts
64 changes: 64 additions & 0 deletions .github/actions/update-bundle/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import * as fs from 'fs';
import * as github from '@actions/github';

interface BundleInfo {
bundleVersion: string;
cliVersion: string;
}

interface Defaults {
bundleVersion: string;
cliVersion: string;
priorBundleVersion: string;
priorCliVersion: string;
}

const CODEQL_BUNDLE_PREFIX = 'codeql-bundle-';

function getCodeQLCliVersionForRelease(release): string {
const cliVersionsFromMarkerFiles = release.assets
.map((asset) => asset.name.match(/cli-version-(.*)\.txt/)?.[1])
.filter((v) => v)
.map((v) => v as string);
if (cliVersionsFromMarkerFiles.length > 1) {
throw new Error(
`Release ${release.tag_name} has multiple CLI version marker files.`
);
} else if (cliVersionsFromMarkerFiles.length === 0) {
throw new Error(
`Failed to find the CodeQL CLI version for release ${release.tag_name}.`
);
}
return cliVersionsFromMarkerFiles[0];
}

async function getBundleInfoFromRelease(release): Promise<BundleInfo> {
return {
bundleVersion: release.tag_name.substring(CODEQL_BUNDLE_PREFIX.length),
cliVersion: getCodeQLCliVersionForRelease(release)
};
}

async function getNewDefaults(currentDefaults: Defaults): Promise<Defaults> {
const release = github.context.payload.release;
console.log('Updating default bundle as a result of the following release: ' +
`${JSON.stringify(release)}.`)

const bundleInfo = await getBundleInfoFromRelease(release);
return {
bundleVersion: bundleInfo.bundleVersion,
cliVersion: bundleInfo.cliVersion,
priorBundleVersion: currentDefaults.bundleVersion,
priorCliVersion: currentDefaults.cliVersion
};
}

async function main() {
const previousDefaults: Defaults = JSON.parse(fs.readFileSync('../../../src/defaults.json', 'utf8'));
const newDefaults = await getNewDefaults(previousDefaults);
fs.writeFileSync('../../../src/defaults.json', JSON.stringify(newDefaults, null, 2) + "\n");
}

// Ideally, we'd await main() here, but that doesn't work well with `ts-node`.
// So instead we rely on the fact that Node won't exit until the event loop is empty.
main();
82 changes: 82 additions & 0 deletions .github/workflows/update-bundle.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
name: Update default CodeQL bundle

on:
release:
types: [prereleased]

jobs:
update-bundle:
if: startsWith(github.event.release.tag_name, 'codeql-bundle-')
runs-on: ubuntu-latest
steps:
- name: Dump environment
run: env

- name: Dump GitHub context
env:
GITHUB_CONTEXT: '${{ toJson(github) }}'
run: echo "${GITHUB_CONTEXT}"

- uses: actions/checkout@v3

- name: Update git config
run: |
git config --global user.email "github-actions@github.com"
git config --global user.name "github-actions[bot]"
- name: Update bundle
uses: ./.github/actions/update-bundle

- name: Rebuild Action
run: npm run build

- name: Commit and push changes
env:
RELEASE_TAG: "${{ github.event.release.tag_name }}"
run: |
git checkout -b "update-bundle/${RELEASE_TAG}"
git commit -am "Update default bundle to ${RELEASE_TAG}"
git push --set-upstream origin "update-bundle/${RELEASE_TAG}"
- name: Open pull request
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
cli_version=$(jq -r '.cliVersion' src/defaults.json)
pr_url=$(gh pr create \
--title "Update default bundle to $cli_version" \
--body "This pull request updates the default CodeQL bundle, as used with \`tools: latest\` and on GHES, to $cli_version." \
--assignee "${GITHUB_ACTOR}" \
--draft \
)
echo "CLI_VERSION=$cli_version" >> $GITHUB_ENV
echo "PR_URL=$pr_url" >> $GITHUB_ENV
- name: Create changelog note
shell: python
run: |
import os
import re
# Get the PR number from the PR URL.
pr_number = os.environ['PR_URL'].split('/')[-1]
changelog_note = f"- Update default CodeQL bundle version to {os.environ['CLI_VERSION']}. [#{pr_number}]({os.environ['PR_URL']})"
# If the "[UNRELEASED]" section starts with "no user facing changes", remove that line.
# Use perl to avoid having to escape the newline character.
with open('CHANGELOG.md', 'r') as f:
changelog = f.read()
changelog = changelog.replace('## [UNRELEASED]\n\nNo user facing changes.', '## [UNRELEASED]\n')
# Add the changelog note to the bottom of the "[UNRELEASED]" section.
changelog = re.sub(r'\n## (\d+\.\d+\.\d+)', f'{changelog_note}\n\n## \\1', changelog, count=1)
with open('CHANGELOG.md', 'w') as f:
f.write(changelog)
- name: Push changelog note
run: |
git commit -am "Add changelog note"
git push

0 comments on commit 1c0a788

Please sign in to comment.