feat: local release workflow (signing + version sync); track updates.json; add .env.example
This commit is contained in:
parent
9d5a3e4224
commit
1c1f51a8b9
8 changed files with 158 additions and 3 deletions
5
.env.example
Normal file
5
.env.example
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Firefox AMO API credentials for web-ext signing
|
||||||
|
# Obtain from https://addons.mozilla.org/en-US/developers/addon/api/key/
|
||||||
|
AMO_JWT_ISSUER=your-amo-jwt-issuer
|
||||||
|
AMO_JWT_SECRET=your-amo-jwt-secret
|
||||||
|
|
||||||
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -1,4 +1,7 @@
|
||||||
dist/
|
dist/
|
||||||
.web-extension-id
|
.web-extension-id
|
||||||
node_modules/
|
node_modules/
|
||||||
|
.env
|
||||||
|
# Ignore all release artifacts except updates.json (tracked)
|
||||||
|
releases/*
|
||||||
|
!releases/updates.json
|
||||||
|
|
|
||||||
17
README.md
17
README.md
|
|
@ -130,3 +130,20 @@ Issues and PRs are welcome. If proposing new filters or aria2 options, please in
|
||||||
## Disclaimer
|
## Disclaimer
|
||||||
|
|
||||||
This project is not affiliated with archive.org or aria2. Use responsibly and respect site terms of service.
|
This project is not affiliated with archive.org or aria2. Use responsibly and respect site terms of service.
|
||||||
|
|
||||||
|
## Release Workflow
|
||||||
|
|
||||||
|
- Stable ID: set a permanent add-on ID in `manifest.json` at `applications.gecko.id` (replace the `@example` value with your ID). If you self-host updates, set `applications.gecko.update_url` to your `updates.json` URL.
|
||||||
|
- Prepare (version bump + sync):
|
||||||
|
- Patch: `npm run release:prepare:patch`
|
||||||
|
- Minor: `npm run release:prepare:minor`
|
||||||
|
- Major: `npm run release:prepare:major`
|
||||||
|
- Lint (Firefox): `npm run lint:fx`
|
||||||
|
- Dev ZIP: `npm run build:dev` → output in `dist/`
|
||||||
|
- Sign (unlisted):
|
||||||
|
- Set environment secrets locally (do not commit): `AMO_JWT_ISSUER=... AMO_JWT_SECRET=...`
|
||||||
|
- Run: `npm run release:sign`
|
||||||
|
- Artifacts land in `releases/<version>/`
|
||||||
|
- Self-hosted updates: copy `releases/updates.example.json` to `releases/updates.json` and update with the new version and `update_link` pointing to your hosted `.xpi`.
|
||||||
|
|
||||||
|
Notes: Keep AMO secrets local. CI is optional. You can tag releases with `git tag vX.Y.Z` and push tags if desired.
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,12 @@
|
||||||
"name": "Archive.org Link Grabber",
|
"name": "Archive.org Link Grabber",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"description": "Filter and export archive.org /download links; copy or send to aria2 RPC.",
|
"description": "Filter and export archive.org /download links; copy or send to aria2 RPC.",
|
||||||
|
"applications": {
|
||||||
|
"gecko": {
|
||||||
|
"id": "archive-org-link-grabber@example",
|
||||||
|
"update_url": "https://example.com/updates.json"
|
||||||
|
}
|
||||||
|
},
|
||||||
"browser_action": {
|
"browser_action": {
|
||||||
"default_title": "Archive.org Link Grabber",
|
"default_title": "Archive.org Link Grabber",
|
||||||
"default_popup": "src/popup/index.html"
|
"default_popup": "src/popup/index.html"
|
||||||
|
|
|
||||||
12
package.json
12
package.json
|
|
@ -8,7 +8,15 @@
|
||||||
"build": "web-ext build -o -a dist",
|
"build": "web-ext build -o -a dist",
|
||||||
"lint": "echo 'Add ESLint config to enable' && exit 0",
|
"lint": "echo 'Add ESLint config to enable' && exit 0",
|
||||||
"format": "echo 'Add Prettier config to enable' && exit 0",
|
"format": "echo 'Add Prettier config to enable' && exit 0",
|
||||||
"test": "echo 'No tests yet' && exit 0"
|
"test": "echo 'No tests yet' && exit 0",
|
||||||
|
"lint:fx": "web-ext lint --source-dir .",
|
||||||
|
"build:dev": "web-ext build -o -a dist",
|
||||||
|
"release:prepare:patch": "npm version patch && node scripts/sync-version.js",
|
||||||
|
"release:prepare:minor": "npm version minor && node scripts/sync-version.js",
|
||||||
|
"release:prepare:major": "npm version major && node scripts/sync-version.js",
|
||||||
|
"release:sign": "node scripts/release-sign.js"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"web-ext": "^8.3.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
14
releases/updates.json
Normal file
14
releases/updates.json
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"addons": {
|
||||||
|
"archive-org-link-grabber@example": {
|
||||||
|
"updates": [
|
||||||
|
{
|
||||||
|
"version": "0.1.0",
|
||||||
|
"update_link": "https://example.com/releases/0.1.0/archive-org-link-grabber-0.1.0.xpi",
|
||||||
|
"applications": { "gecko": { "strict_min_version": "91.0" } }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
63
scripts/release-sign.js
Normal file
63
scripts/release-sign.js
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
/*
|
||||||
|
* Signs an unlisted release via AMO using web-ext and outputs artifacts to releases/<version>/
|
||||||
|
* Requires env: AMO_JWT_ISSUER, AMO_JWT_SECRET
|
||||||
|
*/
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const { execSync } = require('child_process');
|
||||||
|
|
||||||
|
const root = path.join(__dirname, '..');
|
||||||
|
const pkg = require(path.join(root, 'package.json'));
|
||||||
|
const manifest = require(path.join(root, 'manifest.json'));
|
||||||
|
|
||||||
|
const issuer = process.env.AMO_JWT_ISSUER;
|
||||||
|
const secret = process.env.AMO_JWT_SECRET;
|
||||||
|
|
||||||
|
if (!issuer || !secret) {
|
||||||
|
console.error('Missing AMO credentials. Set AMO_JWT_ISSUER and AMO_JWT_SECRET.');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const addonId = manifest?.applications?.gecko?.id;
|
||||||
|
if (!addonId || addonId.includes('example')) {
|
||||||
|
console.error('Invalid add-on id. Set applications.gecko.id in manifest.json to your stable ID.');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const version = pkg.version;
|
||||||
|
if (!version) {
|
||||||
|
console.error('package.json is missing version');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const outDir = path.join(root, 'releases', version);
|
||||||
|
fs.mkdirSync(outDir, { recursive: true });
|
||||||
|
|
||||||
|
function run(cmd) {
|
||||||
|
console.log(`> ${cmd}`);
|
||||||
|
execSync(cmd, { stdio: 'inherit' });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Lint before signing
|
||||||
|
run('npx --yes web-ext lint --source-dir .');
|
||||||
|
|
||||||
|
// Sign (unlisted) and place artifacts in releases/<version>
|
||||||
|
const signCmd = [
|
||||||
|
'npx --yes web-ext sign',
|
||||||
|
'--channel=unlisted',
|
||||||
|
`--api-key="${issuer}"`,
|
||||||
|
`--api-secret="${secret}"`,
|
||||||
|
`--id="${addonId}"`,
|
||||||
|
`--artifacts-dir "${outDir}"`,
|
||||||
|
].join(' ');
|
||||||
|
run(signCmd);
|
||||||
|
|
||||||
|
console.log('\nSigned artifacts written to:', outDir);
|
||||||
|
console.log('Next: host .xpi and update updates.json (if self-hosting updates).');
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Release signing failed:', err.message);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
39
scripts/sync-version.js
Normal file
39
scripts/sync-version.js
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
// Syncs manifest.json version with package.json version
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const pkgPath = path.join(__dirname, '..', 'package.json');
|
||||||
|
const manifestPath = path.join(__dirname, '..', 'manifest.json');
|
||||||
|
|
||||||
|
function readJson(p) {
|
||||||
|
return JSON.parse(fs.readFileSync(p, 'utf8'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeJson(p, obj) {
|
||||||
|
fs.writeFileSync(p, JSON.stringify(obj, null, 2) + '\n', 'utf8');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const pkg = readJson(pkgPath);
|
||||||
|
const manifest = readJson(manifestPath);
|
||||||
|
const nextVersion = pkg.version;
|
||||||
|
|
||||||
|
if (!nextVersion) {
|
||||||
|
console.error('package.json is missing version');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (manifest.version === nextVersion) {
|
||||||
|
console.log(`manifest.json already at version ${nextVersion}`);
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
manifest.version = nextVersion;
|
||||||
|
writeJson(manifestPath, manifest);
|
||||||
|
console.log(`Updated manifest.json version to ${nextVersion}`);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to sync versions:', err.message);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue