Write release notification comments to PRs (#3622)
This commit is contained in:
155
.github/scripts/notify-release-on-prs.ts
vendored
Normal file
155
.github/scripts/notify-release-on-prs.ts
vendored
Normal file
@@ -0,0 +1,155 @@
|
||||
import { Octokit } from '@octokit/rest';
|
||||
import { parseArgs } from 'node:util';
|
||||
import * as core from "@actions/core";
|
||||
|
||||
const { values } = parseArgs({
|
||||
options: {
|
||||
tag: { type: 'string', short: 't' }
|
||||
},
|
||||
allowPositionals: false,
|
||||
strict: true
|
||||
});
|
||||
|
||||
function errMessage(err: unknown) {
|
||||
return err instanceof Error ? err.message : `${err}`;
|
||||
}
|
||||
|
||||
const owner = 'maplibre';
|
||||
const repo = 'maplibre-native';
|
||||
|
||||
function extractPrNumbers(params: {
|
||||
releaseBody: string;
|
||||
owner: string;
|
||||
repo: string;
|
||||
}): Set<number> {
|
||||
const { releaseBody, owner, repo } = params;
|
||||
const prs = new Set<number>();
|
||||
|
||||
const esc = (s: string) => s.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
|
||||
const urlRegex = new RegExp(
|
||||
`https?:\\/\\/github\\.com\\/${esc(owner)}\\/${esc(repo)}\\/pull\\/(\\d+)`,
|
||||
'g'
|
||||
);
|
||||
|
||||
for (const match of releaseBody.matchAll(urlRegex)) {
|
||||
prs.add(Number(match[1]));
|
||||
}
|
||||
|
||||
return prs;
|
||||
}
|
||||
|
||||
async function createOrUpdateReleaseNotification({
|
||||
octokit,
|
||||
prNumber,
|
||||
tag,
|
||||
owner,
|
||||
repo
|
||||
}: {
|
||||
owner: string,
|
||||
repo: string,
|
||||
octokit: Octokit,
|
||||
prNumber: number,
|
||||
tag: string
|
||||
}) {
|
||||
|
||||
const m = tag.match(/^([A-Za-z0-9]+)-v(.+)$/i);
|
||||
const platform = m?.[1]?.toLowerCase();
|
||||
const version = m?.[2] ?? '';
|
||||
|
||||
if (!platform || !version) {
|
||||
throw new Error(`Failed to parse platform or version from ${tag}`);
|
||||
}
|
||||
|
||||
const MARKER = `<!-- release-notification-${platform} -->`;
|
||||
|
||||
function linkText() {
|
||||
if (platform === 'ios') {
|
||||
return `MapLibre iOS ${version}`;
|
||||
} else if (platform === 'android') {
|
||||
return `MapLibre Android ${version}`;
|
||||
}
|
||||
return tag;
|
||||
}
|
||||
|
||||
const { data: comments } = await octokit.issues.listComments({
|
||||
owner,
|
||||
repo,
|
||||
issue_number: prNumber
|
||||
});
|
||||
|
||||
const existing = comments.find((({ body }) => body?.includes(MARKER)));
|
||||
|
||||
const releaseUrl = `https://github.com/${owner}/${repo}/releases/tag/${tag}`;
|
||||
releaseUrl
|
||||
const body = `
|
||||
${MARKER}
|
||||
🚀 This PR has been included in the [${linkText()}](${releaseUrl}) release.
|
||||
`.trim();
|
||||
|
||||
if (existing) {
|
||||
await octokit.issues.updateComment({
|
||||
owner,
|
||||
repo,
|
||||
comment_id: existing.id,
|
||||
body
|
||||
});
|
||||
console.log(`Updated comment on PR #${prNumber}`);
|
||||
} else {
|
||||
await octokit.issues.createComment({
|
||||
owner,
|
||||
repo,
|
||||
issue_number: prNumber,
|
||||
body
|
||||
});
|
||||
console.log(`Created comment on PR #${prNumber}`);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const { tag } = values;
|
||||
|
||||
if (!tag) {
|
||||
throw new Error("pass tag with --tag");
|
||||
}
|
||||
|
||||
const token = process.env.GITHUB_TOKEN;
|
||||
if (!token) {
|
||||
throw new Error('GITHUB_TOKEN environment variable is required');
|
||||
}
|
||||
|
||||
const octokit = new Octokit({ auth: token });
|
||||
|
||||
const release = await octokit.repos.getReleaseByTag({ owner, repo, tag });
|
||||
const releaseBody = release.data.body || '';
|
||||
|
||||
if (!releaseBody) {
|
||||
throw new Error(`No release notes found for tag '${tag}'.`);
|
||||
}
|
||||
|
||||
const prs = extractPrNumbers({
|
||||
owner,
|
||||
releaseBody,
|
||||
repo
|
||||
});
|
||||
|
||||
if (prs.size === 0) {
|
||||
console.log(`No PR references found in release notes for tag '${tag}'.`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
for (const prNumber of prs) {
|
||||
try {
|
||||
await createOrUpdateReleaseNotification({
|
||||
octokit,
|
||||
owner,
|
||||
prNumber,
|
||||
repo,
|
||||
tag
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(`Failed to comment on PR #${prNumber}: ${errMessage(err)}`);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
core.setFailed(errMessage(err));
|
||||
}
|
||||
2
.github/workflows/android-device-test.yml
vendored
2
.github/workflows/android-device-test.yml
vendored
@@ -84,6 +84,8 @@ jobs:
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
|
||||
- run: npm install
|
||||
|
||||
- name: Check if android-build was skipped
|
||||
id: parent_workflow
|
||||
run: node .github/scripts/check-job-skipped.ts
|
||||
|
||||
13
.github/workflows/android-release.yml
vendored
13
.github/workflows/android-release.yml
vendored
@@ -83,6 +83,10 @@ jobs:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: "temurin"
|
||||
@@ -151,3 +155,12 @@ jobs:
|
||||
SIGNING_KEY_ID: ${{ secrets.SIGNING_KEY_ID }}
|
||||
SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }}
|
||||
SONATYPE_STAGING_PROFILE_ID: ${{ secrets.SONATYPE_STAGING_PROFILE_ID }}
|
||||
|
||||
- run: npm install
|
||||
working-directory: .
|
||||
|
||||
- name: Write release notifications
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: node .github/scripts/notify-release-on-prs.ts --tag ${{ needs.android-create-release.outputs.version_tag }}
|
||||
working-directory: .
|
||||
|
||||
17
.github/workflows/ios-ci.yml
vendored
17
.github/workflows/ios-ci.yml
vendored
@@ -29,6 +29,7 @@ on:
|
||||
permissions:
|
||||
id-token: write # needed for AWS
|
||||
contents: write # allow making a release
|
||||
actions: write # for triggering ios-release-cocoapods.yml
|
||||
|
||||
jobs:
|
||||
pre_job:
|
||||
@@ -244,6 +245,11 @@ jobs:
|
||||
(github.event_name == 'push' && steps.version-file-ios-changed.outputs.any_changed == 'true')
|
||||
run: echo make_release=true >> "$GITHUB_ENV"
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
if: env.make_release
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- name: Build XCFramework
|
||||
if: env.make_release
|
||||
run: |
|
||||
@@ -348,12 +354,21 @@ jobs:
|
||||
"version":"${{ env.version }}",
|
||||
"download_url":"${{ fromJSON(steps.github_release.outputs.assets)[0].browser_download_url }}"}}'
|
||||
|
||||
- run: npm install
|
||||
working-directory: .
|
||||
|
||||
- name: Release (CocoaPods)
|
||||
shell: bash -leo pipefail {0} # so pod is found
|
||||
if: env.make_release
|
||||
run: gh workflow run ios-release-cocoapods.yml --field version=${{ env.version }}
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Write release notifications
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: node .github/scripts/notify-release-on-prs.ts --tag ios-v${{ env.version }}
|
||||
working-directory: .
|
||||
|
||||
ios-build-cmake:
|
||||
needs: pre_job
|
||||
|
||||
Reference in New Issue
Block a user