This commit is contained in:
Louis Lam 2026-01-13 10:13:24 +08:00
parent 96459d240d
commit 42c7b1a0e4
5 changed files with 842 additions and 796 deletions

View File

@ -11,6 +11,11 @@ on:
description: 'Previous version tag for changelog (e.g., 1.23.0)'
required: true
type: string
dry_run:
description: 'If true, the release will be a dry run without pushing changes'
required: false
type: boolean
default: true
permissions:
contents: write
@ -41,95 +46,6 @@ jobs:
- name: Install dependencies
run: npm clean-install --no-fund
- name: Generate changelog
id: changelog
run: |
echo "Generating changelog since ${{ inputs.previous_version }}"
npm run generate-changelog ${{ inputs.previous_version }} > changelog-output.txt 2>&1
cat changelog-output.txt
- name: Sort and categorize changelog with Copilot
id: categorize
run: |
echo "Processing changelog with GitHub Copilot..."
# Extract the raw PR list from changelog output (before the template)
sed -n '/^- #/p' changelog-output.txt > raw-changelog.txt
# Get the template/prompt
sed -n '/LLM Task:/,$p' changelog-output.txt > changelog-prompt.txt
# Combine them into a single file for Copilot
cat raw-changelog.txt > changelog-for-copilot.txt
echo "" >> changelog-for-copilot.txt
cat changelog-prompt.txt >> changelog-for-copilot.txt
echo "Changelog content prepared for Copilot categorization"
cat changelog-for-copilot.txt
- name: Create formatted changelog
run: |
echo "# Changelog for ${{ inputs.version }}" > FORMATTED_CHANGELOG.md
echo "" >> FORMATTED_CHANGELOG.md
echo "**Note:** This changelog was generated from merged PRs since ${{ inputs.previous_version }}" >> FORMATTED_CHANGELOG.md
echo "" >> FORMATTED_CHANGELOG.md
echo "## Pull Requests" >> FORMATTED_CHANGELOG.md
echo "" >> FORMATTED_CHANGELOG.md
cat raw-changelog.txt >> FORMATTED_CHANGELOG.md
echo "" >> FORMATTED_CHANGELOG.md
echo "---" >> FORMATTED_CHANGELOG.md
echo "" >> FORMATTED_CHANGELOG.md
echo "**Instructions for manual categorization:**" >> FORMATTED_CHANGELOG.md
cat changelog-prompt.txt >> FORMATTED_CHANGELOG.md
- name: Commit changelog
run: |
git add FORMATTED_CHANGELOG.md
git commit -m "Add changelog for ${{ inputs.version }}"
- name: Push branch
run: |
git push origin release
- name: Create draft pull request
id: create-pr
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
PR_URL=$(gh pr create \
--base master \
--head release \
--title "Update to ${{ inputs.version }}" \
--body "## Beta Release ${{ inputs.version }}
This PR prepares the beta release for version ${{ inputs.version }}.
### Release Steps Completed:
- [x] Create draft pull request
- [x] Generate changelog from ${{ inputs.previous_version }}
- [ ] Manually categorize changelog (see comment below)
- [ ] Run release-beta
- [ ] Upload dist.tar.gz
### Next Steps:
1. Review the changelog comment below
2. Manually categorize the PRs using the template provided
3. Run the release-beta build job by triggering it manually
" \
--draft)
echo "pr_url=$PR_URL" >> $GITHUB_OUTPUT
echo "PR created: $PR_URL"
# Extract PR number from URL
PR_NUMBER=$(basename "$PR_URL")
echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT
- name: Post changelog comment
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh pr comment ${{ steps.create-pr.outputs.pr_number }} --body-file FORMATTED_CHANGELOG.md
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db # v3.6.1
@ -152,31 +68,14 @@ jobs:
- name: Run release-beta
env:
RELEASE_BETA_VERSION: ${{ inputs.version }}
PREVIOUS_VERSION: ${{ inputs.previous_version }}
DRY_RUN: ${{ inputs.dry_run }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npm run release-beta
- name: Create dist tarball
- name: Push branch
run: |
if [ -d dist ]; then
tar -zcvf dist.tar.gz dist
else
echo "Error: dist directory not found"
exit 1
fi
- name: Upload dist.tar.gz to PR
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Upload the tarball as a release asset comment
echo "Uploading dist.tar.gz to PR #${{ steps.create-pr.outputs.pr_number }}"
# Create a comment with instructions
gh pr comment ${{ steps.create-pr.outputs.pr_number }} --body "## Distribution Archive
The \`dist.tar.gz\` archive has been created and is available as an artifact in this workflow run.
Download it from: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
"
git push origin release
- name: Upload dist.tar.gz as artifact
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3

View File

@ -52,60 +52,63 @@ async function main() {
}
console.log(`Generating changelog since version ${previousVersion}...`);
console.log(await generateChangelog(previousVersion));
}
try {
const prList = await getPullRequestList(previousVersion);
const list = [];
/**
* Generate Changelog
* @param {string} previousVersion Previous Version Tag
* @returns {Promise<string>} Changelog Content
*/
export async function generateChangelog(previousVersion) {
const prList = await getPullRequestList(previousVersion);
const list = [];
let content = "";
let i = 1;
for (const pr of prList) {
console.log(`Progress: ${i++}/${prList.length}`);
let authorSet = await getAuthorList(pr.number);
authorSet = await mainAuthorToFront(pr.author.login, authorSet);
let i = 1;
for (const pr of prList) {
console.log(`Progress: ${i++}/${prList.length}`);
let authorSet = await getAuthorList(pr.number);
authorSet = await mainAuthorToFront(pr.author.login, authorSet);
if (mergeList.includes(pr.title)) {
// Check if it is already in the list
const existingItem = list.find(item => item.title === pr.title);
if (existingItem) {
existingItem.numbers.push(pr.number);
for (const author of authorSet) {
existingItem.authors.add(author);
// Sort the authors
existingItem.authors = new Set([ ...existingItem.authors ].sort((a, b) => a.localeCompare(b)));
}
continue;
if (mergeList.includes(pr.title)) {
// Check if it is already in the list
const existingItem = list.find(item => item.title === pr.title);
if (existingItem) {
existingItem.numbers.push(pr.number);
for (const author of authorSet) {
existingItem.authors.add(author);
// Sort the authors
existingItem.authors = new Set([ ...existingItem.authors ].sort((a, b) => a.localeCompare(b)));
}
continue;
}
const item = {
numbers: [ pr.number ],
title: pr.title,
authors: authorSet,
};
list.push(item);
}
for (const item of list) {
// Concat pr numbers into a string like #123 #456
const prPart = item.numbers.map(num => `#${num}`).join(" ");
const item = {
numbers: [ pr.number ],
title: pr.title,
authors: authorSet,
};
// Concat authors into a string like @user1 @user2
let authorPart = [ ...item.authors ].map(author => `@${author}`).join(" ");
if (authorPart) {
authorPart = `(Thanks ${authorPart})`;
}
console.log(`- ${prPart} ${item.title} ${authorPart}`);
}
console.log(template);
} catch (e) {
console.error("Failed to get pull request list:", e);
process.exit(1);
list.push(item);
}
for (const item of list) {
// Concat pr numbers into a string like #123 #456
const prPart = item.numbers.map(num => `#${num}`).join(" ");
// Concat authors into a string like @user1 @user2
let authorPart = [ ...item.authors ].map(author => `@${author}`).join(" ");
if (authorPart) {
authorPart = `(Thanks ${authorPart})`;
}
content += `- ${prPart} ${item.title} ${authorPart}\n`;
}
return content + "\n" + template;
}
/**

View File

@ -9,11 +9,19 @@ import {
getRepoNames,
execSync,
checkReleaseBranch,
createDistTarGz,
createReleasePR,
} from "./lib.mjs";
import semver from "semver";
const repoNames = getRepoNames();
const version = process.env.RELEASE_BETA_VERSION;
const dryRun = process.env.DRY_RUN === "true";
const previousVersion = process.env.RELEASE_PREVIOUS_VERSION;
if (dryRun) {
console.log("Dry run mode enabled. No images will be pushed.");
}
console.log("RELEASE_BETA_VERSION:", version);
@ -43,14 +51,29 @@ execSync("node ./extra/beta/update-version.js");
// Build frontend dist
buildDist();
// Build slim image (rootless)
buildImage(repoNames, [ "beta-slim-rootless", ver(version, "slim-rootless") ], "rootless", "BASE_IMAGE=louislam/uptime-kuma:base2-slim");
// TODO: Create Pull Request
await createReleasePR(version, previousVersion, dryRun);
// Build full image (rootless)
buildImage(repoNames, [ "beta-rootless", ver(version, "rootless") ], "rootless");
if (!dryRun) {
// Build slim image (rootless)
buildImage(
repoNames,
["beta-slim-rootless", ver(version, "slim-rootless")],
"rootless",
"BASE_IMAGE=louislam/uptime-kuma:base2-slim"
);
// Build slim image
buildImage(repoNames, [ "beta-slim", ver(version, "slim") ], "release", "BASE_IMAGE=louislam/uptime-kuma:base2-slim");
// Build full image (rootless)
buildImage(repoNames, ["beta-rootless", ver(version, "rootless")], "rootless");
// Build full image
buildImage(repoNames, [ "beta", version ], "release");
// Build slim image
buildImage(repoNames, ["beta-slim", ver(version, "slim")], "release", "BASE_IMAGE=louislam/uptime-kuma:base2-slim");
// Build full image
buildImage(repoNames, ["beta", version], "release");
} else {
console.log("Dry run mode - skipping image build and push.");
}
// TODO: Create
await createDistTarGz();

View File

@ -1,6 +1,7 @@
import "dotenv/config";
import * as childProcess from "child_process";
import semver from "semver";
import {generateChangelog} from "../generate-changelog.mjs";
export const dryRun = process.env.RELEASE_DRY_RUN === "1";
@ -202,6 +203,7 @@ export function ver(version, identifier) {
* @param {string} version Version
* @param {string} githubToken GitHub token
* @returns {void}
* @deprecated
*/
export function uploadArtifacts(version, githubToken) {
let args = [
@ -262,3 +264,28 @@ export function checkReleaseBranch() {
process.exit(1);
}
}
/**
* TODO: similar to "tar -zcvf dist.tar.gz dist", but using nodejs
*/
export async function createDistTarGz() {
// TODO
}
/**
* TODO: Create a draft release PR
* @param version
* @param previousVersion
* @param dryRun Still create the PR, but add "[DRY RUN]" to the title
*/
export async function createReleasePR(version, previousVersion, dryRun) {
const changelog = await generateChangelog(previousVersion);
// TODO
// gh pr create \
// --title "Beta Release: ${{ inputs.version }}" \
// --body "This PR prepares the beta release version ${{ inputs.version }}. \`dist.tar.gz\` : ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
// --base master \
// --head release \
// --draft
}

1358
package-lock.json generated

File diff suppressed because it is too large Load Diff