Skip to content

Generate and Publish Release Notes JSON #167

Generate and Publish Release Notes JSON

Generate and Publish Release Notes JSON #167

Workflow file for this run

name: Generate and Publish Release Notes JSON
on:
workflow_dispatch:
release:
types:
- released # A release was published, or a pre-release was changed to a release.
jobs:
generate:
permissions:
contents: read # to fetch code (actions/checkout) and to read releases (actions/github-script)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: dev
- name: Setup pnpm
uses: pnpm/action-setup@v3
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- name: Install dependencies
run: pnpm i
- name: Generate Release Notes
uses: actions/github-script@v7
with:
script: |
const { mkdir, writeFile } = require('node:fs/promises');
const { join } = require('node:path');
const { default: markdown } = await import('${{ github.workspace }}/docs/build/release-notes/md.mjs');
/**
* `/[\w/\-@]+/` is the name of the package. (e.g. @quasar/app-vite)
* `v` is the literal letter v between the package name and the version.
* `/[\d.\-\w]+/` is the version of the package after `v`. (e.g. 1.0.0, 1.0.0-beta.1)
*/
const versionPattern = /([\w/\-@]+)[- ]v([\d.\-\w]+)/;
/**
* GitHub issue reference (e.g. #123)
*/
const gitHubReferencePattern = /#(\d+)/g;
const gitHubReferenceToMarkdownLink = (content) =>
content.replace(
gitHubReferencePattern,
`[$1](https://github.com/${context.repo.owner}/${context.repo.repo}/issues/$1)`
);
const groups = {
v2: {
versionPatterns: {
quasar: /^2./,
'@quasar/app-webpack': /^(3|4)./,
'@quasar/app-vite': /^(1|2)./,
},
packages: {
quasar: [],
'@quasar/app-vite': [],
'@quasar/app-webpack': [],
'@quasar/cli': [],
'@quasar/extras': [],
'@quasar/icongenie': [],
'@quasar/vite-plugin': [],
},
},
};
const allPackageNames = new Set(
Object.values(groups).flatMap(({ packages }) => Object.keys(packages))
);
const releases = await github.paginate(
github.rest.repos.listReleases,
{
owner: context.repo.owner,
repo: context.repo.repo,
per_page: 100,
},
({ data }) =>
data
.map((release) => {
// Split by space and use the first part for cases like this: `@quasar/app-v1.0.4 - Security update`
const matchesList = release.name.split(' ')[0].match(versionPattern);
if (!matchesList || matchesList.length < 2) {
return;
}
let [, packageName, version] = matchesList;
if (!version) {
return;
}
if (packageName === '@quasar/app') {
packageName = '@quasar/app-webpack';
}
if (!allPackageNames.has(packageName)) {
return;
}
return {
packageName,
version,
date: release.created_at,
body: release.body,
};
})
.filter((release) => release !== undefined)
);
for (const [group, { versionPatterns, packages }] of Object.entries(groups)) {
console.log('Started processing group', group);
const packageNameList = Object.keys(packages);
for (const { packageName, version, date, body } of releases) {
if (!packageNameList.includes(packageName)) {
continue;
}
if (
versionPatterns[packageName] &&
versionPatterns[packageName].test(version) === false
) {
continue;
}
packages[packageName].push({
version,
date,
body: markdown.render(gitHubReferenceToMarkdownLink(body)),
});
}
console.log('Completed processing group', group);
}
// The data goes above GitHub Actions 1 MB output limit, so we write the results to files and use actions/upload-artifact and actions/download-artifact to transfer it
const directory = './docs/dist/release-notes';
await mkdir(directory, { recursive: true });
const writeJsonFile = (name, data) =>
writeFile(
join(directory, `${name}.json`),
JSON.stringify(data),
'utf8'
);
await Promise.all(
Object.entries(groups).map(([groupName, { packages }]) => writeJsonFile(groupName, packages))
);
- name: Upload release notes JSON files
uses: actions/upload-artifact@v4
with:
name: release-notes
path: docs/dist/release-notes
# As we commit them in the `publish` job, we don't really need to keep them for long.
# We can't use 0, so we use the minimum possible, 1: https://github.com/actions/upload-artifact/issues/290
retention-days: 1
publish:
permissions: {} # No permissions needed for the active repo
runs-on: ubuntu-latest
needs: generate
steps:
- uses: actions/checkout@v4
with:
repository: quasarframework/cdn
token: ${{ secrets.CDN_REPO_PAT }}
- name: Download generated release notes JSON files
uses: actions/download-artifact@v4
with:
name: release-notes
path: release-notes
- uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: |
Generated release notes for Quasar packages
Triggered by: ${{ github.event.release.name || 'manual execution' }}
${{ github.event.release.html_url }}