Compare commits

...
2 Commits
Author SHA1 Message Date
wt 2f5568fb37 ci: build and publish extension packages from GitHub Actions
Build and publish extension / Build extension packages (push) Failing after 2m2s
Build and publish extension / Publish stores and attach release assets (push) Skipped
- build Firefox XPI and Chrome ZIP on every push
- upload packages as downloadable workflow artifacts
- sign and submit Firefox releases to AMO
- upload and publish Chrome releases to Chrome Web Store
- attach signed packages to GitHub release cards
- document required publishing secrets and release workflow
2026-10-09 16:34:05 +07:00
wt 1926ac166b ci: build and publish extension packages from GitHub Actions
- build Firefox XPI and Chrome ZIP on every push
- upload packages as downloadable workflow artifacts
- sign and submit Firefox releases to AMO
- upload and publish Chrome releases to Chrome Web Store
- attach signed packages to GitHub release cards
- document required publishing secrets and release workflow
2026-10-09 16:34:02 +07:00
3 changed files with 210 additions and 0 deletions

No files matched your search

+196
View File
@@ -0,0 +1,196 @@
name: Build and publish extension
on:
push:
branches:
- "**"
release:
types: [published]
workflow_dispatch:
inputs:
version:
description: "Version to validate (for example 1.0.1)"
required: true
type: string
permissions:
contents: read
jobs:
build:
name: Build extension packages
runs-on: ubuntu-latest
steps:
- name: Check out source
uses: actions/checkout@v4
with:
ref: ${{ github.event.release.tag_name || github.ref }}
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 22
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.x"
- name: Validate release version
if: github.event_name == 'release' || github.event_name == 'workflow_dispatch'
env:
RELEASE_VERSION: ${{ github.event.release.tag_name || inputs.version }}
run: |
python - <<'PY'
import json, os, re
expected = os.environ["RELEASE_VERSION"].removeprefix("v")
for path in ("manifest.json", "manifest.chrome.json"):
actual = json.load(open(path, encoding="utf-8"))["version"]
if actual != expected:
raise SystemExit(f"{path}: version {actual!r} does not match release {expected!r}")
if not re.fullmatch(r"\d+(\.\d+){1,3}", expected):
raise SystemExit(f"Release version must be numeric, got {expected!r}")
PY
- name: Install web-ext
run: npm install --global web-ext
- name: Prepare Firefox source
run: |
mkdir -p dist/firefox-source
rsync -a \
--exclude '.git/' \
--exclude '.github/' \
--exclude 'web-ext-artifacts/' \
--exclude 'manifest.chrome.json' \
--exclude 'background-chrome.js' \
--exclude 'background-service-worker.js' \
--exclude 'browser-api.js' \
--exclude 'scripts/' \
./ dist/firefox-source/
- name: Build Firefox package
run: |
web-ext build \
--source-dir dist/firefox-source \
--artifacts-dir dist/firefox \
--filename proxyswitcherforkbywt-firefox.xpi \
--overwrite-dest
- name: Build Chrome package
run: python scripts/build-chrome.py
- name: Upload packages for this push
uses: actions/upload-artifact@v4
with:
name: extension-packages-${{ github.sha }}
if-no-files-found: error
path: |
dist/firefox/proxyswitcherforkbywt-firefox.xpi
web-ext-artifacts/proxyswitcherforkbywt-chrome.zip
publish:
name: Publish stores and attach release assets
if: github.event_name == 'release' && github.event.action == 'published'
needs: build
runs-on: ubuntu-latest
permissions:
contents: write
env:
AMO_JWT_ISSUER: ${{ secrets.AMO_JWT_ISSUER }}
AMO_JWT_SECRET: ${{ secrets.AMO_JWT_SECRET }}
CWS_PUBLISHER_ID: ${{ secrets.CWS_PUBLISHER_ID }}
CWS_EXTENSION_ID: ${{ secrets.CWS_EXTENSION_ID }}
CWS_CLIENT_ID: ${{ secrets.CWS_CLIENT_ID }}
CWS_CLIENT_SECRET: ${{ secrets.CWS_CLIENT_SECRET }}
CWS_REFRESH_TOKEN: ${{ secrets.CWS_REFRESH_TOKEN }}
steps:
- name: Check out release source
uses: actions/checkout@v4
with:
ref: ${{ github.event.release.tag_name }}
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 22
- name: Download build packages
uses: actions/download-artifact@v4
with:
name: extension-packages-${{ github.sha }}
path: dist/packages
- name: Set up Firefox signing tools
run: |
npm install --global web-ext
mkdir -p dist/firefox-source
rsync -a \
--exclude '.git/' \
--exclude '.github/' \
--exclude 'web-ext-artifacts/' \
--exclude 'manifest.chrome.json' \
--exclude 'background-chrome.js' \
--exclude 'background-service-worker.js' \
--exclude 'browser-api.js' \
--exclude 'scripts/' \
./ dist/firefox-source/
- name: Sign and submit Firefox package to AMO
run: |
test -n "$AMO_JWT_ISSUER" || { echo 'Missing AMO_JWT_ISSUER secret'; exit 1; }
test -n "$AMO_JWT_SECRET" || { echo 'Missing AMO_JWT_SECRET secret'; exit 1; }
web-ext sign \
--source-dir dist/firefox-source \
--artifacts-dir dist/firefox-signed \
--api-key "$AMO_JWT_ISSUER" \
--api-secret "$AMO_JWT_SECRET" \
--channel listed \
--approval-timeout 900000 \
--no-input
firefox_xpi=$(find dist/firefox-signed -maxdepth 1 -name '*.xpi' -print -quit)
test -n "$firefox_xpi" || { echo 'AMO did not return a signed XPI'; exit 1; }
cp "$firefox_xpi" dist/packages/proxyswitcherforkbywt-firefox-signed.xpi
- name: Upload Chrome package to Chrome Web Store
run: |
set -euo pipefail
for name in CWS_PUBLISHER_ID CWS_EXTENSION_ID CWS_CLIENT_ID CWS_CLIENT_SECRET CWS_REFRESH_TOKEN; do
test -n "${!name}" || { echo "Missing $name secret"; exit 1; }
done
token=$(curl --fail --silent --show-error \
--data-urlencode "client_id=$CWS_CLIENT_ID" \
--data-urlencode "client_secret=$CWS_CLIENT_SECRET" \
--data-urlencode "refresh_token=$CWS_REFRESH_TOKEN" \
--data-urlencode 'grant_type=refresh_token' \
https://oauth2.googleapis.com/token | python -c 'import json,sys; print(json.load(sys.stdin)["access_token"])')
chrome_zip=$(find dist/packages -name 'proxyswitcherforkbywt-chrome.zip' -print -quit)
test -f "$chrome_zip" || { echo "Missing Chrome package: $chrome_zip"; exit 1; }
curl --fail --silent --show-error \
-X POST \
-H "Authorization: Bearer $token" \
-H 'Content-Type: application/zip' \
--data-binary "@$chrome_zip" \
"https://chromewebstore.googleapis.com/upload/v2/publishers/$CWS_PUBLISHER_ID/items/$CWS_EXTENSION_ID:upload"
curl --fail --silent --show-error \
-X POST \
-H "Authorization: Bearer $token" \
"https://chromewebstore.googleapis.com/v2/publishers/$CWS_PUBLISHER_ID/items/$CWS_EXTENSION_ID:publish"
- name: Attach signed Firefox and Chrome packages to release
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release upload "${{ github.event.release.tag_name }}" \
dist/packages/proxyswitcherforkbywt-firefox-signed.xpi \
"$chrome_zip" \
--clobber
- name: Upload signed packages as workflow artifacts
uses: actions/upload-artifact@v4
with:
name: signed-extension-packages-${{ github.event.release.tag_name }}
if-no-files-found: error
path: |
dist/packages/proxyswitcherforkbywt-firefox-signed.xpi
dist/packages/**/proxyswitcherforkbywt-chrome.zip
+2
View File
@@ -16,6 +16,7 @@ This repository contains the Firefox WebExtension **Proxy Switcher Fork By WT**.
- `options.html`, `options.js`, `options.css` — profiles, domains, management actions, and Advanced Settings.
- `icons/` — extension icon sizes referenced by `manifest.json`.
- `Makefile` — build and cleanup commands.
- `.github/workflows/release.yml` — per-push package builds, workflow artifacts, and release-triggered AMO/Chrome Web Store publishing.
## Development rules
@@ -28,6 +29,7 @@ This repository contains the Firefox WebExtension **Proxy Switcher Fork By WT**.
- When changing an icon, update every size referenced by the manifest and verify the XPI contains the new paths.
- Never hand-edit or retain stale `META-INF` signatures after changing files. Build artifacts must be signed again before distribution.
- Do not commit generated `web-ext-artifacts/` packages unless explicitly requested.
- Keep publishing credentials only in GitHub Secrets. The release workflow expects AMO JWT credentials and Chrome Web Store OAuth credentials.
## Validation
+12
View File
@@ -94,6 +94,18 @@ The package is created at `web-ext-artifacts/proxyswitcherforkbywt.xpi`. This lo
For Chrome/Chromium, run `make build-chrome`. That creates `web-ext-artifacts/proxyswitcherforkbywt-chrome.zip` from `manifest.chrome.json` and the shared UI files.
## GitHub Actions release publishing
`.github/workflows/release.yml` builds both packages on every push. The run exposes a downloadable `extension-packages-<commit>` artifact containing the Firefox XPI and Chrome ZIP. When a GitHub Release is published, it checks that both manifests match the release tag, submits the Firefox package to AMO for signing and review, uploads and submits the Chrome package through the Chrome Web Store API v2, and attaches the signed Firefox XPI and Chrome ZIP to the release card.
Configure these repository or environment secrets before publishing:
- `AMO_JWT_ISSUER` and `AMO_JWT_SECRET` — AMO API credentials for `web-ext sign`.
- `CWS_PUBLISHER_ID` and `CWS_EXTENSION_ID` — Chrome Web Store publisher and existing item IDs.
- `CWS_CLIENT_ID`, `CWS_CLIENT_SECRET`, and `CWS_REFRESH_TOKEN` — Google OAuth credentials with Chrome Web Store API access.
The stores must already contain their initial listings and required privacy information. Store review still applies; the workflow submits the update and does not bypass review. Never commit any of these credentials.
To remove generated packages:
```sh