Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
commit
09143eb29b
134 files changed
+27238
No files matched your search
@@ -0,0 +1,75 @@
|
||||
// Copies a release GoReleaser published on Gitea to the GitHub mirror:
|
||||
// the same notes and the same files (dist/), so lazysecrets can update
|
||||
// from either (internal/update tries GitHub first). Run by the release
|
||||
// workflow after GoReleaser; a release already on GitHub for the tag is
|
||||
// replaced, like GoReleaser's mode: replace on Gitea.
|
||||
//
|
||||
// TAG=v0.2.0 GH_TOKEN=… GITEA_TOKEN=… node scripts/github-release.mjs
|
||||
//
|
||||
// GH_TOKEN is a fine-grained token that can write the mirror's contents;
|
||||
// without it, this does nothing. No dependencies: Node 20's fetch.
|
||||
|
||||
import { readdir, readFile } from "node:fs/promises";
|
||||
|
||||
const github = "karleinarb/lazysecrets";
|
||||
const { TAG: tag, GH_TOKEN: token, GITEA_TOKEN: giteaToken, GITHUB_SHA: sha } = process.env;
|
||||
const gitea = `${process.env.GITHUB_SERVER_URL ?? "https://git.kebcloud.no"}/api/v1/repos/${process.env.GITHUB_REPOSITORY ?? "keb/lazysecrets"}`;
|
||||
|
||||
if (!token) {
|
||||
console.log("No GH_TOKEN: not copying the release to GitHub.");
|
||||
process.exit(0);
|
||||
}
|
||||
if (!tag) throw new Error("TAG isn't set");
|
||||
|
||||
const gh = (path, init = {}) =>
|
||||
fetch(path.startsWith("https://") ? path : `https://api.github.com/repos/${github}${path}`, {
|
||||
...init,
|
||||
headers: {
|
||||
Accept: "application/vnd.github+json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
"X-GitHub-Api-Version": "2022-11-28",
|
||||
...init.headers,
|
||||
},
|
||||
});
|
||||
|
||||
async function ok(res, what) {
|
||||
if (!res.ok) throw new Error(`${what}: ${res.status} ${await res.text()}`);
|
||||
return res;
|
||||
}
|
||||
|
||||
// The notes as GoReleaser wrote them on Gitea.
|
||||
const rel = await (
|
||||
await ok(await fetch(`${gitea}/releases/tags/${tag}`, { headers: giteaToken ? { Authorization: `token ${giteaToken}` } : {} }), "reading the Gitea release")
|
||||
).json();
|
||||
|
||||
// Replace what's there for the tag.
|
||||
const old = await gh(`/releases/tags/${tag}`);
|
||||
if (old.ok) {
|
||||
const { id } = await old.json();
|
||||
await ok(await gh(`/releases/${id}`, { method: "DELETE" }), "deleting the old GitHub release");
|
||||
console.log(`Deleted the GitHub release for ${tag}.`);
|
||||
}
|
||||
|
||||
// The mirror may not have the tag's commit yet: it pushes on its own.
|
||||
// Wait for it a while.
|
||||
const body = JSON.stringify({ tag_name: tag, target_commitish: sha, name: rel.name || tag, body: rel.body, prerelease: rel.prerelease });
|
||||
let created;
|
||||
for (let i = 0; ; i++) {
|
||||
const res = await gh("/releases", { method: "POST", body });
|
||||
if (res.ok) {
|
||||
created = await res.json();
|
||||
break;
|
||||
}
|
||||
if (res.status !== 422 || i === 9) await ok(res, "creating the GitHub release");
|
||||
console.log("GitHub doesn't have the commit yet; waiting for the mirror…");
|
||||
await new Promise((r) => setTimeout(r, 30_000));
|
||||
}
|
||||
|
||||
const files = (await readdir("dist")).filter((f) => f.endsWith(".tar.gz") || f === "checksums.txt");
|
||||
if (files.length === 0) throw new Error("nothing to upload in dist/");
|
||||
for (const f of files) {
|
||||
const url = `https://uploads.github.com/repos/${github}/releases/${created.id}/assets?name=${encodeURIComponent(f)}`;
|
||||
await ok(await gh(url, { method: "POST", headers: { "Content-Type": "application/octet-stream" }, body: await readFile(`dist/${f}`) }), `uploading ${f}`);
|
||||
console.log(`Uploaded ${f}.`);
|
||||
}
|
||||
console.log(`Published ${tag} on GitHub: ${created.html_url}`);
|
||||
Executable
+64
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env bash
|
||||
# Releases main: writes CHANGELOG.md with git-cliff (cliff.toml), commits
|
||||
# it, tags the commit and pushes both; the tag runs
|
||||
# .gitea/workflows/release.yml, which builds and publishes the release.
|
||||
#
|
||||
# scripts/release.sh v0.2.0 # or v0.2.0-rc.1 for a pre-release
|
||||
# scripts/release.sh --dry-run v0.2.0 # print the notes, change nothing
|
||||
#
|
||||
# A pre-release is tagged without touching CHANGELOG.md: its changes are
|
||||
# listed under the release that follows.
|
||||
set -euo pipefail
|
||||
|
||||
dry=false
|
||||
if [ "${1:-}" = "--dry-run" ]; then
|
||||
dry=true
|
||||
shift
|
||||
fi
|
||||
tag="${1:?usage: $0 [--dry-run] <tag, e.g. v0.2.0>}"
|
||||
if ! [[ "$tag" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
|
||||
echo "$tag is not vMAJOR.MINOR.PATCH (optionally -suffix)" >&2
|
||||
exit 1
|
||||
fi
|
||||
command -v git-cliff >/dev/null || { echo "git-cliff is needed: brew install git-cliff" >&2; exit 1; }
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
notes=$(git cliff --unreleased --tag "$tag" --strip all)
|
||||
if ! grep -q '^- ' <<<"$notes"; then
|
||||
echo "Nothing for the changelog since the last release (no feat/fix/perf pull requests)." >&2
|
||||
$dry || exit 1
|
||||
fi
|
||||
echo "$notes"
|
||||
$dry && exit 0
|
||||
|
||||
if [ "$(git branch --show-current)" != main ]; then
|
||||
echo "Release from main." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ -n "$(git status --porcelain)" ]; then
|
||||
echo "The working tree has changes; commit or stash them first." >&2
|
||||
exit 1
|
||||
fi
|
||||
git fetch -q origin main --tags
|
||||
if [ "$(git rev-parse HEAD)" != "$(git rev-parse origin/main)" ]; then
|
||||
echo "main isn't origin/main; pull (or push) first." >&2
|
||||
exit 1
|
||||
fi
|
||||
if git rev-parse -q --verify "refs/tags/$tag" >/dev/null; then
|
||||
echo "$tag exists already." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo
|
||||
read -r -p "Release $tag with these notes? [y/N] " ok
|
||||
[ "$ok" = y ] || [ "$ok" = Y ] || exit 1
|
||||
|
||||
if [[ "$tag" != *-* ]]; then
|
||||
git cliff --tag "$tag" -o CHANGELOG.md
|
||||
git add CHANGELOG.md
|
||||
git commit -q -m "chore(release): $tag"
|
||||
fi
|
||||
git tag -a "$tag" -m "$tag"
|
||||
git push -q origin main "$tag"
|
||||
echo "Pushed $tag: the release workflow builds and publishes it."
|
||||
Reference in new issue
Block a user