-
-
Notifications
You must be signed in to change notification settings - Fork 594
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Extend release automation with GPG signing, assets & changelog merging (
#3852) * Tidy reusable release workflow Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Add ability to include upstream changes Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Add ability to upload assets and gpg sign them Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Update relative composite actions Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Wire up validating release tarball signature Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Validate release has expected assets Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Paths Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Use gpg outputs for email instead of scraping it ourselves Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * v6 Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Extract pre-release and post-merge-master scripts Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Reuse pre-release and post-merge-master scripts in gha Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Cull unused vars Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Revert Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Remove unused variables Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Simplify Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Simplify and fix merge-release-notes script Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Tidy release automation Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Update release.sh * Move environment Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * s/includes/contains/ Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate uses syntax Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix action-repo calls Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix RELEASE_NOTES env Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix if check Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix gpg tag signing Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Cull stale params Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix sign-release-tarball paths being outside the workspace Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix gpg validation (of course wget uses `-O` and not `-o`) Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix expected asset assertion Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix release publish mode Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --------- Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
- Loading branch information
Showing
4 changed files
with
290 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
name: Sign Release Tarball | ||
description: Generates signature for release tarball and uploads it as a release asset | ||
inputs: | ||
gpg-fingerprint: | ||
description: Fingerprint of the GPG key to use for signing the tarball. | ||
required: true | ||
upload-url: | ||
description: GitHub release upload URL to upload the signature file to. | ||
required: true | ||
runs: | ||
using: composite | ||
steps: | ||
- name: Generate tarball signature | ||
shell: bash | ||
run: | | ||
git -c tar.tar.gz.command='gzip -cn' archive --format=tar.gz --prefix="${REPO#*/}-${VERSION#v}/" -o "/tmp/${VERSION}.tar.gz" "${VERSION}" | ||
gpg -u "$GPG_FINGERPRINT" --armor --output "${VERSION}.tar.gz.asc" --detach-sig "/tmp/${VERSION}.tar.gz" | ||
rm "/tmp/${VERSION}.tar.gz" | ||
env: | ||
GPG_FINGERPRINT: ${{ inputs.gpg-fingerprint }} | ||
REPO: ${{ github.repository }} | ||
|
||
- name: Upload tarball signature | ||
if: ${{ inputs.upload-url }} | ||
uses: shogo82148/actions-upload-release-asset@dccd6d23e64fd6a746dce6814c0bde0a04886085 # v1 | ||
with: | ||
upload_url: ${{ inputs.upload-url }} | ||
asset_path: ${{ env.VERSION }}.tar.gz.asc |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
name: Upload release assets | ||
description: Uploads assets to an existing release and optionally signs them | ||
inputs: | ||
gpg-fingerprint: | ||
description: Fingerprint of the GPG key to use for signing the assets, if any. | ||
required: false | ||
upload-url: | ||
description: GitHub release upload URL to upload the assets to. | ||
required: true | ||
asset-path: | ||
description: | | ||
The path to the asset you want to upload, if any. You can use glob patterns here. | ||
Will be GPG signed and an `.asc` file included in the release artifacts if `gpg-fingerprint` is set. | ||
required: true | ||
runs: | ||
using: composite | ||
steps: | ||
- name: Sign assets | ||
if: inputs.gpg-fingerprint | ||
shell: bash | ||
run: | | ||
for FILE in $ASSET_PATH | ||
do | ||
gpg -u "$GPG_FINGERPRINT" --armor --output "$FILE".asc --detach-sig "$FILE" | ||
done | ||
env: | ||
GPG_FINGERPRINT: ${{ inputs.gpg-fingerprint }} | ||
ASSET_PATH: ${{ inputs.asset-path }} | ||
|
||
- name: Upload asset signatures | ||
if: inputs.gpg-fingerprint | ||
uses: shogo82148/actions-upload-release-asset@dccd6d23e64fd6a746dce6814c0bde0a04886085 # v1 | ||
with: | ||
upload_url: ${{ inputs.upload-url }} | ||
asset_path: ${{ inputs.asset-path }}.asc | ||
|
||
- name: Upload assets | ||
uses: shogo82148/actions-upload-release-asset@dccd6d23e64fd6a746dce6814c0bde0a04886085 # v1 | ||
with: | ||
upload_url: ${{ inputs.upload-url }} | ||
asset_path: ${{ inputs.asset-path }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
#!/usr/bin/env node | ||
|
||
const fs = require("fs"); | ||
|
||
async function getRelease(github, dependency) { | ||
const upstreamPackageJson = JSON.parse(fs.readFileSync(`./node_modules/${dependency}/package.json`, "utf8")); | ||
const [owner, repo] = upstreamPackageJson.repository.url.split("/").slice(-2); | ||
const tag = `v${upstreamPackageJson.version}`; | ||
|
||
const response = await github.rest.repos.getReleaseByTag({ | ||
owner, | ||
repo, | ||
tag, | ||
}); | ||
return response.data; | ||
} | ||
|
||
const main = async ({ github, releaseId, dependencies }) => { | ||
const { GITHUB_REPOSITORY } = process.env; | ||
const [owner, repo] = GITHUB_REPOSITORY.split("/"); | ||
|
||
const sections = new Map(); | ||
let heading = null; | ||
for (const dependency of dependencies) { | ||
const release = await getRelease(github, dependency); | ||
for (const line of release.body.split("\n")) { | ||
if (line.startsWith("#")) { | ||
heading = line; | ||
sections.set(heading, []); | ||
continue; | ||
} | ||
if (heading && line) { | ||
sections.get(heading).push(line); | ||
} | ||
} | ||
} | ||
|
||
const { data: release } = await github.rest.repos.getRelease({ | ||
owner, | ||
repo, | ||
release_id: releaseId, | ||
}); | ||
|
||
heading = null; | ||
const output = []; | ||
for (const line of [...release.body.split("\n"), null]) { | ||
if (line === null || line.startsWith("#")) { | ||
if (heading && sections.has(heading)) { | ||
const lastIsBlank = !output.at(-1)?.trim(); | ||
if (lastIsBlank) output.pop(); | ||
output.push(...sections.get(heading)); | ||
if (lastIsBlank) output.push(""); | ||
} | ||
heading = line; | ||
} | ||
output.push(line); | ||
} | ||
|
||
return output.join("\n"); | ||
}; | ||
|
||
// This is just for testing locally | ||
// Needs environment variables GITHUB_TOKEN & GITHUB_REPOSITORY | ||
if (require.main === module) { | ||
const { Octokit } = require("@octokit/rest"); | ||
const github = new Octokit({ auth: process.env.GITHUB_TOKEN }); | ||
if (process.argv.length < 4) { | ||
// eslint-disable-next-line no-console | ||
console.error("Usage: node merge-release-notes.js owner/repo:release_id npm-package-name ..."); | ||
process.exit(1); | ||
} | ||
const [releaseId, ...dependencies] = process.argv.slice(2); | ||
main({ github, releaseId, dependencies }).then((output) => { | ||
// eslint-disable-next-line no-console | ||
console.log(output); | ||
}); | ||
} | ||
|
||
module.exports = main; |