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/
|
||||
.web-extension-id
|
||||
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
|
||||
|
||||
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",
|
||||
"version": "0.1.0",
|
||||
"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": {
|
||||
"default_title": "Archive.org Link Grabber",
|
||||
"default_popup": "src/popup/index.html"
|
||||
|
|
|
|||
12
package.json
12
package.json
|
|
@ -8,7 +8,15 @@
|
|||
"build": "web-ext build -o -a dist",
|
||||
"lint": "echo 'Add ESLint 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