mirror of
https://github.com/louislam/uptime-kuma.git
synced 2026-03-03 02:47:02 +00:00
chore: Add automated beta release workflow (#6692)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: louislam <1336778+louislam@users.noreply.github.com> Co-authored-by: Louis Lam <louislam@users.noreply.github.com>
This commit is contained in:
82
.github/workflows/beta-release.yml
vendored
Normal file
82
.github/workflows/beta-release.yml
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
name: Beta Release
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: "Beta version number (e.g., 2.0.0-beta.0)"
|
||||
required: true
|
||||
type: string
|
||||
previous_version:
|
||||
description: "Previous version tag for changelog (e.g., 1.23.0)"
|
||||
required: true
|
||||
type: string
|
||||
dry_run:
|
||||
description: "If true, the docker image will not be pushed to registries. PR will still be created."
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
beta-release:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 120
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
ref: master
|
||||
persist-credentials: false
|
||||
fetch-depth: 0 # Fetch all history for changelog generation
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
|
||||
with:
|
||||
node-version: 24
|
||||
|
||||
- name: Create release branch
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git checkout -b release
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm clean-install --no-fund
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db # v3.6.1
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ secrets.GHCR_USERNAME }}
|
||||
password: ${{ secrets.GHCR_TOKEN }}
|
||||
|
||||
- name: Run release-beta
|
||||
env:
|
||||
RELEASE_BETA_VERSION: ${{ inputs.version }}
|
||||
RELEASE_PREVIOUS_VERSION: ${{ inputs.previous_version }}
|
||||
DRY_RUN: ${{ inputs.dry_run }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: npm run release-beta
|
||||
|
||||
- name: Upload dist.tar.gz as artifact
|
||||
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
|
||||
with:
|
||||
name: dist-${{ inputs.version }}
|
||||
path: ./tmp/dist.tar.gz
|
||||
retention-days: 90
|
||||
@@ -4,22 +4,13 @@
|
||||
|
||||
import * as childProcess from "child_process";
|
||||
|
||||
const ignoreList = [
|
||||
"louislam",
|
||||
"CommanderStorm",
|
||||
"UptimeKumaBot",
|
||||
"weblate",
|
||||
"Copilot"
|
||||
];
|
||||
const ignoreList = ["louislam", "CommanderStorm", "UptimeKumaBot", "weblate", "Copilot"];
|
||||
|
||||
const mergeList = [
|
||||
"Translations Update from Weblate",
|
||||
"Update dependencies",
|
||||
];
|
||||
const mergeList = ["Translations Update from Weblate", "Update dependencies"];
|
||||
|
||||
const template = `
|
||||
|
||||
LLM Task: Please help to put above PRs into the following sections based on their content. If a PR fits multiple sections, choose the most relevant one. If a PR doesn't fit any section, place it in "Others". If there are grammatical errors in the PR titles, please correct them. Don't change the PR numbers and authors, and keep the format. Output as markdown.
|
||||
LLM Task: Please help to put above PRs into the following sections based on their content. If a PR fits multiple sections, choose the most relevant one. If a PR doesn't fit any section, place it in "Others". If there are grammatical errors in the PR titles, please correct them. Don't change the PR numbers and authors, and keep the format. Output as markdown file format.
|
||||
|
||||
Changelog:
|
||||
|
||||
@@ -37,7 +28,9 @@ Changelog:
|
||||
- Other small changes, code refactoring and comment/doc updates in this repo:
|
||||
`;
|
||||
|
||||
await main();
|
||||
if (import.meta.main) {
|
||||
await main();
|
||||
}
|
||||
|
||||
/**
|
||||
* Main Function
|
||||
@@ -52,60 +45,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;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -114,28 +110,37 @@ async function main() {
|
||||
*/
|
||||
async function getPullRequestList(previousVersion) {
|
||||
// Get the date of previousVersion in YYYY-MM-DD format from git
|
||||
const previousVersionDate = childProcess.execSync(`git log -1 --format=%cd --date=short ${previousVersion}`).toString().trim();
|
||||
const previousVersionDate = childProcess
|
||||
.execSync(`git log -1 --format=%cd --date=short ${previousVersion}`)
|
||||
.toString()
|
||||
.trim();
|
||||
|
||||
if (!previousVersionDate) {
|
||||
throw new Error(`Unable to find the date of version ${previousVersion}. Please make sure the version tag exists.`);
|
||||
throw new Error(
|
||||
`Unable to find the date of version ${previousVersion}. Please make sure the version tag exists.`
|
||||
);
|
||||
}
|
||||
|
||||
const ghProcess = childProcess.spawnSync("gh", [
|
||||
"pr",
|
||||
"list",
|
||||
"--state",
|
||||
"merged",
|
||||
"--base",
|
||||
"master",
|
||||
"--search",
|
||||
`merged:>=${previousVersionDate}`,
|
||||
"--json",
|
||||
"number,title,author",
|
||||
"--limit",
|
||||
"1000"
|
||||
], {
|
||||
encoding: "utf-8"
|
||||
});
|
||||
const ghProcess = childProcess.spawnSync(
|
||||
"gh",
|
||||
[
|
||||
"pr",
|
||||
"list",
|
||||
"--state",
|
||||
"merged",
|
||||
"--base",
|
||||
"master",
|
||||
"--search",
|
||||
`merged:>=${previousVersionDate}`,
|
||||
"--json",
|
||||
"number,title,author",
|
||||
"--limit",
|
||||
"1000",
|
||||
],
|
||||
{
|
||||
encoding: "utf-8",
|
||||
}
|
||||
);
|
||||
|
||||
if (ghProcess.error) {
|
||||
throw ghProcess.error;
|
||||
@@ -153,14 +158,8 @@ async function getPullRequestList(previousVersion) {
|
||||
* @returns {Promise<Set<string>>} Set of Authors' GitHub Usernames
|
||||
*/
|
||||
async function getAuthorList(prID) {
|
||||
const ghProcess = childProcess.spawnSync("gh", [
|
||||
"pr",
|
||||
"view",
|
||||
prID,
|
||||
"--json",
|
||||
"commits"
|
||||
], {
|
||||
encoding: "utf-8"
|
||||
const ghProcess = childProcess.spawnSync("gh", ["pr", "view", prID, "--json", "commits"], {
|
||||
encoding: "utf-8",
|
||||
});
|
||||
|
||||
if (ghProcess.error) {
|
||||
@@ -185,7 +184,7 @@ async function getAuthorList(prID) {
|
||||
}
|
||||
|
||||
// Sort the set
|
||||
return new Set([ ...set ].sort((a, b) => a.localeCompare(b)));
|
||||
return new Set([...set].sort((a, b) => a.localeCompare(b)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -197,5 +196,5 @@ async function mainAuthorToFront(mainAuthor, authorSet) {
|
||||
if (ignoreList.includes(mainAuthor)) {
|
||||
return authorSet;
|
||||
}
|
||||
return new Set([ mainAuthor, ...authorSet ]);
|
||||
return new Set([mainAuthor, ...authorSet]);
|
||||
}
|
||||
|
||||
@@ -7,22 +7,24 @@ import {
|
||||
checkTagExists,
|
||||
checkVersionFormat,
|
||||
getRepoNames,
|
||||
pressAnyKey,
|
||||
execSync, uploadArtifacts, checkReleaseBranch,
|
||||
execSync,
|
||||
checkReleaseBranch,
|
||||
createDistTarGz,
|
||||
createReleasePR,
|
||||
} from "./lib.mjs";
|
||||
import semver from "semver";
|
||||
|
||||
const repoNames = getRepoNames();
|
||||
const version = process.env.RELEASE_BETA_VERSION;
|
||||
const githubToken = process.env.RELEASE_GITHUB_TOKEN;
|
||||
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);
|
||||
|
||||
if (!githubToken) {
|
||||
console.error("GITHUB_TOKEN is required");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Check if the current branch is "release"
|
||||
checkReleaseBranch();
|
||||
|
||||
@@ -46,22 +48,32 @@ await checkTagExists(repoNames, version);
|
||||
// node extra/beta/update-version.js
|
||||
execSync("node ./extra/beta/update-version.js");
|
||||
|
||||
// Create Pull Request
|
||||
await createReleasePR(version, previousVersion, dryRun);
|
||||
|
||||
// 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");
|
||||
if (!dryRun) {
|
||||
// Build slim image (rootless)
|
||||
buildImage(
|
||||
repoNames,
|
||||
["beta-slim-rootless", ver(version, "slim-rootless")],
|
||||
"rootless",
|
||||
"BASE_IMAGE=louislam/uptime-kuma:base2-slim"
|
||||
);
|
||||
|
||||
// Build full image (rootless)
|
||||
buildImage(repoNames, [ "beta-rootless", ver(version, "rootless") ], "rootless");
|
||||
// Build full image (rootless)
|
||||
buildImage(repoNames, ["beta-rootless", ver(version, "rootless")], "rootless");
|
||||
|
||||
// Build slim image
|
||||
buildImage(repoNames, [ "beta-slim", ver(version, "slim") ], "release", "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
|
||||
buildImage(repoNames, [ "beta", version ], "release");
|
||||
// Build full image
|
||||
buildImage(repoNames, ["beta", version], "release");
|
||||
} else {
|
||||
console.log("Dry run mode - skipping image build and push.");
|
||||
}
|
||||
|
||||
await pressAnyKey();
|
||||
|
||||
// npm run upload-artifacts
|
||||
uploadArtifacts(version, githubToken);
|
||||
// Create dist.tar.gz
|
||||
await createDistTarGz();
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import "dotenv/config";
|
||||
import * as childProcess from "child_process";
|
||||
import semver from "semver";
|
||||
import { generateChangelog } from "../generate-changelog.mjs";
|
||||
import fs from "fs";
|
||||
import tar from "tar";
|
||||
|
||||
export const dryRun = process.env.RELEASE_DRY_RUN === "1";
|
||||
|
||||
@@ -23,16 +26,14 @@ export function checkDocker() {
|
||||
|
||||
/**
|
||||
* Get Docker Hub repository name
|
||||
* @returns {string[]} List of repository names
|
||||
*/
|
||||
export function getRepoNames() {
|
||||
if (process.env.RELEASE_REPO_NAMES) {
|
||||
// Split by comma
|
||||
return process.env.RELEASE_REPO_NAMES.split(",").map((name) => name.trim());
|
||||
}
|
||||
return [
|
||||
"louislam/uptime-kuma",
|
||||
"ghcr.io/louislam/uptime-kuma",
|
||||
];
|
||||
return ["louislam/uptime-kuma", "ghcr.io/louislam/uptime-kuma"];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,15 +58,15 @@ export function buildDist() {
|
||||
* @param {string} platform Build platform
|
||||
* @returns {void}
|
||||
*/
|
||||
export function buildImage(repoNames, tags, target, buildArgs = "", dockerfile = "docker/dockerfile", platform = "linux/amd64,linux/arm64,linux/arm/v7") {
|
||||
let args = [
|
||||
"buildx",
|
||||
"build",
|
||||
"-f",
|
||||
dockerfile,
|
||||
"--platform",
|
||||
platform,
|
||||
];
|
||||
export function buildImage(
|
||||
repoNames,
|
||||
tags,
|
||||
target,
|
||||
buildArgs = "",
|
||||
dockerfile = "docker/dockerfile",
|
||||
platform = "linux/amd64,linux/arm64,linux/arm/v7"
|
||||
) {
|
||||
let args = ["buildx", "build", "-f", dockerfile, "--platform", platform];
|
||||
|
||||
for (let repoName of repoNames) {
|
||||
// Add tags
|
||||
@@ -74,22 +75,14 @@ export function buildImage(repoNames, tags, target, buildArgs = "", dockerfile =
|
||||
}
|
||||
}
|
||||
|
||||
args = [
|
||||
...args,
|
||||
"--target",
|
||||
target,
|
||||
];
|
||||
args = [...args, "--target", target];
|
||||
|
||||
// Add build args
|
||||
if (buildArgs) {
|
||||
args.push("--build-arg", buildArgs);
|
||||
}
|
||||
|
||||
args = [
|
||||
...args,
|
||||
".",
|
||||
"--push",
|
||||
];
|
||||
args = [...args, ".", "--push"];
|
||||
|
||||
if (!dryRun) {
|
||||
childProcess.spawnSync("docker", args, { stdio: "inherit" });
|
||||
@@ -172,11 +165,13 @@ export function pressAnyKey() {
|
||||
console.log("Git Push and Publish the release note on github, then press any key to continue");
|
||||
process.stdin.setRawMode(true);
|
||||
process.stdin.resume();
|
||||
return new Promise(resolve => process.stdin.once("data", data => {
|
||||
process.stdin.setRawMode(false);
|
||||
process.stdin.pause();
|
||||
resolve();
|
||||
}));
|
||||
return new Promise((resolve) =>
|
||||
process.stdin.once("data", (data) => {
|
||||
process.stdin.setRawMode(false);
|
||||
process.stdin.pause();
|
||||
resolve();
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -189,9 +184,9 @@ export function ver(version, identifier) {
|
||||
const obj = semver.parse(version);
|
||||
|
||||
if (obj.prerelease.length === 0) {
|
||||
obj.prerelease = [ identifier ];
|
||||
obj.prerelease = [identifier];
|
||||
} else {
|
||||
obj.prerelease[0] = [ obj.prerelease[0], identifier ].join("-");
|
||||
obj.prerelease[0] = [obj.prerelease[0], identifier].join("-");
|
||||
}
|
||||
return obj.format();
|
||||
}
|
||||
@@ -202,6 +197,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 = [
|
||||
@@ -255,10 +251,104 @@ export function execSync(cmd) {
|
||||
* @returns {void}
|
||||
*/
|
||||
export function checkReleaseBranch() {
|
||||
const res = childProcess.spawnSync("git", [ "rev-parse", "--abbrev-ref", "HEAD" ]);
|
||||
const res = childProcess.spawnSync("git", ["rev-parse", "--abbrev-ref", "HEAD"]);
|
||||
const branch = res.stdout.toString().trim();
|
||||
if (branch !== "release") {
|
||||
console.error(`Current branch is ${branch}, please switch to "release" branch`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create dist.tar.gz from the dist directory
|
||||
* Similar to "tar -zcvf dist.tar.gz dist", but using nodejs
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function createDistTarGz() {
|
||||
const distPath = "dist";
|
||||
const outputPath = "./tmp/dist.tar.gz";
|
||||
const tmpDir = "./tmp";
|
||||
|
||||
// Ensure tmp directory exists
|
||||
if (!fs.existsSync(tmpDir)) {
|
||||
fs.mkdirSync(tmpDir, { recursive: true });
|
||||
}
|
||||
|
||||
// Check if dist directory exists
|
||||
if (!fs.existsSync(distPath)) {
|
||||
console.error("Error: dist directory not found");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`Creating ${outputPath} from ${distPath}...`);
|
||||
|
||||
try {
|
||||
await tar.create(
|
||||
{
|
||||
gzip: true,
|
||||
file: outputPath,
|
||||
},
|
||||
[distPath]
|
||||
);
|
||||
console.log(`Successfully created ${outputPath}`);
|
||||
} catch (error) {
|
||||
console.error(`Failed to create tarball: ${error.message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a draft release PR
|
||||
* @param {string} version Version
|
||||
* @param {string} previousVersion Previous version tag
|
||||
* @param {boolean} dryRun Still create the PR, but add "[DRY RUN]" to the title
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function createReleasePR(version, previousVersion, dryRun) {
|
||||
const changelog = await generateChangelog(previousVersion);
|
||||
|
||||
const title = dryRun ? `build: update to ${version} (dry run)` : `build: update to ${version}`;
|
||||
const body = `## Release ${version}
|
||||
|
||||
This PR prepares the release for version ${version}.
|
||||
|
||||
### Manual Steps Required
|
||||
- [ ] Merge this PR (squash and merge)
|
||||
- [ ] Create a new release on GitHub with the tag \`${version}\`.
|
||||
- [ ] Ask any LLM to categorize the changelog into sections.
|
||||
- [ ] Place the changelog in the release note.
|
||||
- [ ] Download and upload the \`dist.tar.gz\` artifact to the release.
|
||||
- [ ] (Beta only) Set prerelease
|
||||
- [ ] Publish the release note on GitHub.
|
||||
|
||||
### Changelog
|
||||
|
||||
\`\`\`md
|
||||
${changelog}
|
||||
\`\`\`
|
||||
|
||||
### Release Artifacts
|
||||
The \`dist.tar.gz\` archive will be available as an artifact in the workflow run.
|
||||
`;
|
||||
|
||||
// Create the PR using gh CLI
|
||||
const args = ["pr", "create", "--title", title, "--body", body, "--base", "master", "--head", "release", "--draft"];
|
||||
|
||||
console.log(`Creating draft PR: ${title}`);
|
||||
|
||||
const result = childProcess.spawnSync("gh", args, {
|
||||
encoding: "utf-8",
|
||||
stdio: "inherit",
|
||||
env: {
|
||||
...process.env,
|
||||
GH_TOKEN: process.env.GH_TOKEN || process.env.GITHUB_TOKEN,
|
||||
},
|
||||
});
|
||||
|
||||
if (result.status !== 0) {
|
||||
console.error("Failed to create pull request");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log("Successfully created draft pull request");
|
||||
}
|
||||
|
||||
1358
package-lock.json
generated
1358
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user