build: release on GitHub, crudylabs/pgmorbac and pgmorbac.crudy.fr
The signed distribution is published as a GitHub release by the release workflow on v* tags, replacing the Gitea release and its Drone pipeline. The release body and the dist README take the homepage from META.json.
This commit is contained in:
@@ -66,7 +66,7 @@ include $(PGXS)
|
||||
|
||||
writeFileSync(join(stageDir, 'README-INSTALL.md'), `# Installing pgmorbac ${version}
|
||||
|
||||
Full documentation: https://pgmorbac.villains.fr
|
||||
Full documentation: ${meta.resources.homepage}
|
||||
|
||||
## As a PostgreSQL extension (recommended)
|
||||
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
// Creates (or reuses) release v<version> on Gitea and attaches the dist assets.
|
||||
// Run after build-dist.mjs. Requires GITEA_URL, GITEA_REPO, GITEA_TOKEN.
|
||||
|
||||
import { readFileSync, existsSync } from 'fs';
|
||||
import { dirname, join } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const root = join(dirname(fileURLToPath(import.meta.url)), '..');
|
||||
const version = readFileSync(join(root, 'pgmorbac.control'), 'utf8').match(/default_version\s*=\s*'([^']+)'/)?.[1];
|
||||
if (!version) {
|
||||
console.error('[gitea-release] could not read default_version from pgmorbac.control');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const base = process.env.GITEA_URL;
|
||||
const repo = process.env.GITEA_REPO;
|
||||
const token = process.env.GITEA_TOKEN;
|
||||
if (!base || !repo || !token) {
|
||||
console.error('[gitea-release] GITEA_URL, GITEA_REPO and GITEA_TOKEN are required');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const distDir = join(root, 'dist');
|
||||
const files = [
|
||||
`pgmorbac-${version}.zip`,
|
||||
`pgmorbac-${version}.zip.sha256`,
|
||||
`pgmorbac-${version}.manifest.jwt`,
|
||||
`pgmorbac-${version}.pub.pem`,
|
||||
];
|
||||
for (const f of files) {
|
||||
if (!existsSync(join(distDir, f))) {
|
||||
console.error(`[gitea-release] Missing artifact ${f} - run build-dist.mjs first`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
const api = (path) => `${base}/api/v1/repos/${repo}${path}`;
|
||||
const headers = { Authorization: `token ${token}` };
|
||||
|
||||
async function ensureRelease() {
|
||||
const create = await fetch(api('/releases'), {
|
||||
method: 'POST',
|
||||
headers: { ...headers, 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
tag_name: `v${version}`,
|
||||
name: `pgmorbac ${version}`,
|
||||
body: `PGXN-compatible SQL distribution. Verify with sha256sum -c and the signed manifest (public key attached; see https://pgmorbac.villains.fr/download).`,
|
||||
draft: false,
|
||||
prerelease: false,
|
||||
}),
|
||||
});
|
||||
if (create.ok) return (await create.json()).id;
|
||||
if (create.status !== 409) {
|
||||
console.error(`[gitea-release] Release creation failed: ${create.status} ${await create.text()}`);
|
||||
process.exit(1);
|
||||
}
|
||||
const existing = await fetch(api(`/releases/tags/v${version}`), { headers });
|
||||
if (!existing.ok) {
|
||||
console.error(`[gitea-release] Release exists but lookup failed: ${existing.status}`);
|
||||
process.exit(1);
|
||||
}
|
||||
return (await existing.json()).id;
|
||||
}
|
||||
|
||||
const releaseId = await ensureRelease();
|
||||
for (const f of files) {
|
||||
const form = new FormData();
|
||||
form.set('attachment', new Blob([readFileSync(join(distDir, f))]), f);
|
||||
const res = await fetch(api(`/releases/${releaseId}/assets?name=${encodeURIComponent(f)}`), {
|
||||
method: 'POST', headers, body: form,
|
||||
});
|
||||
if (!res.ok) {
|
||||
const text = await res.text();
|
||||
if (res.status === 409 || text.includes('already exist')) {
|
||||
console.log(`[gitea-release] ${f} already attached - skipping`);
|
||||
continue;
|
||||
}
|
||||
console.error(`[gitea-release] Upload of ${f} failed: ${res.status} ${text}`);
|
||||
process.exit(1);
|
||||
}
|
||||
console.log(`[gitea-release] Attached ${f}`);
|
||||
}
|
||||
console.log(`[gitea-release] Release v${version} ready on ${repo}`);
|
||||
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env node
|
||||
// Creates (or reuses) release v<version> on GitHub and attaches the dist assets.
|
||||
// Run after build-dist.mjs. Requires GITHUB_REPOSITORY (owner/name) and GITHUB_TOKEN.
|
||||
|
||||
import { readFileSync, existsSync } from 'fs';
|
||||
import { dirname, join } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const root = join(dirname(fileURLToPath(import.meta.url)), '..');
|
||||
const version = readFileSync(join(root, 'pgmorbac.control'), 'utf8').match(/default_version\s*=\s*'([^']+)'/)?.[1];
|
||||
if (!version) {
|
||||
console.error('[github-release] could not read default_version from pgmorbac.control');
|
||||
process.exit(1);
|
||||
}
|
||||
const homepage = JSON.parse(readFileSync(join(root, 'META.json'), 'utf8')).resources.homepage;
|
||||
|
||||
const repo = process.env.GITHUB_REPOSITORY;
|
||||
const token = process.env.GITHUB_TOKEN;
|
||||
if (!repo || !token) {
|
||||
console.error('[github-release] GITHUB_REPOSITORY and GITHUB_TOKEN are required');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const distDir = join(root, 'dist');
|
||||
const files = [
|
||||
`pgmorbac-${version}.zip`,
|
||||
`pgmorbac-${version}.zip.sha256`,
|
||||
`pgmorbac-${version}.manifest.jwt`,
|
||||
`pgmorbac-${version}.pub.pem`,
|
||||
];
|
||||
for (const f of files) {
|
||||
if (!existsSync(join(distDir, f))) {
|
||||
console.error(`[github-release] Missing artifact ${f} - run build-dist.mjs first`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
const headers = { Authorization: `Bearer ${token}`, Accept: 'application/vnd.github+json', 'X-GitHub-Api-Version': '2022-11-28' };
|
||||
const api = (path) => `https://api.github.com/repos/${repo}${path}`;
|
||||
|
||||
async function ensureRelease() {
|
||||
const existing = await fetch(api(`/releases/tags/v${version}`), { headers });
|
||||
if (existing.ok) return existing.json();
|
||||
if (existing.status !== 404) {
|
||||
console.error(`[github-release] Release lookup failed: ${existing.status}`);
|
||||
process.exit(1);
|
||||
}
|
||||
const create = await fetch(api('/releases'), {
|
||||
method: 'POST',
|
||||
headers: { ...headers, 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
tag_name: `v${version}`,
|
||||
name: `pgmorbac ${version}`,
|
||||
body: `PGXN-compatible SQL distribution. Verify with sha256sum -c and the signed manifest (public key attached; see ${homepage}/download).`,
|
||||
draft: false,
|
||||
prerelease: false,
|
||||
}),
|
||||
});
|
||||
if (!create.ok) {
|
||||
console.error(`[github-release] Release creation failed: ${create.status} ${await create.text()}`);
|
||||
process.exit(1);
|
||||
}
|
||||
return create.json();
|
||||
}
|
||||
|
||||
const release = await ensureRelease();
|
||||
const attached = new Set((release.assets ?? []).map((a) => a.name));
|
||||
for (const f of files) {
|
||||
if (attached.has(f)) {
|
||||
console.log(`[github-release] ${f} already attached - skipping`);
|
||||
continue;
|
||||
}
|
||||
const res = await fetch(`https://uploads.github.com/repos/${repo}/releases/${release.id}/assets?name=${encodeURIComponent(f)}`, {
|
||||
method: 'POST',
|
||||
headers: { ...headers, 'Content-Type': 'application/octet-stream' },
|
||||
body: readFileSync(join(distDir, f)),
|
||||
});
|
||||
if (!res.ok) {
|
||||
console.error(`[github-release] Upload of ${f} failed: ${res.status} ${await res.text()}`);
|
||||
process.exit(1);
|
||||
}
|
||||
console.log(`[github-release] Attached ${f}`);
|
||||
}
|
||||
console.log(`[github-release] Release v${version} ready on ${repo}`);
|
||||
Reference in New Issue
Block a user