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