diff options
author | Darius Jahandarie <djahandarie@gmail.com> | 2023-03-11 21:17:55 +0900 |
---|---|---|
committer | Darius Jahandarie <djahandarie@gmail.com> | 2023-03-18 10:45:57 +0900 |
commit | 06251f190b9d04a5ef60480e218a7c5d6ffe9be4 (patch) | |
tree | 202c4cb0eca1c0ee6dd13a5fe65dddae49c3919e | |
parent | 0314a8620f952aa5b0129e93f2d0956b0e0cc7c2 (diff) |
Add CD to build and publish extension to Chrome & Firefox stores
Resolves #85.
-rw-r--r-- | .github/release.yml | 17 | ||||
-rw-r--r-- | .github/workflows/ci.yml | 4 | ||||
-rw-r--r-- | .github/workflows/create-prerelease-on-tag.yml | 35 | ||||
-rw-r--r-- | .github/workflows/publish-chrome-development.yml | 100 | ||||
-rw-r--r-- | .github/workflows/publish-chrome.yml | 100 | ||||
-rw-r--r-- | .github/workflows/publish-firefox-development.yml | 86 | ||||
-rw-r--r-- | .github/workflows/publish-firefox.yml | 34 | ||||
-rw-r--r-- | .github/workflows/touch-google-refresh-token.yml | 16 | ||||
-rw-r--r-- | .node-version | 1 |
9 files changed, 391 insertions, 2 deletions
diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 00000000..c3cb6841 --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,17 @@ +changelog: + exclude: + labels: + - kind/meta + categories: + - title: Breaking Changes + labels: + - kind/breaking-change + - title: Enhancement + labels: + - kind/enhancement + - title: Bug Fixes + labels: + - kind/bug + - title: Dependencies + labels: + - area/dependencies diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 99f3f518..3b7fc69c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,9 +14,9 @@ jobs: uses: actions/checkout@v3 - name: Setup node - uses: actions/setup-node@v1 + uses: actions/setup-node@v3 with: - node-version: "16.x" + node-version-file: ".node-version" - name: Install dependencies run: npm ci diff --git a/.github/workflows/create-prerelease-on-tag.yml b/.github/workflows/create-prerelease-on-tag.yml new file mode 100644 index 00000000..a2d5fc57 --- /dev/null +++ b/.github/workflows/create-prerelease-on-tag.yml @@ -0,0 +1,35 @@ +name: Create prerelease on tag +on: + push: + tags: + - "*.*.*.*" + workflow_dispatch: +permissions: + contents: write +jobs: + build-release-publish: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Validate manifest.json of the extension + uses: cardinalby/schema-validator-action@c2da05377e89dd0c9b7be9420da0b3534b1efcce # pin@v1 + with: + file: ext/manifest.json + schema: "https://json.schemastore.org/webextension.json" + + - name: Setup node + uses: actions/setup-node@v3 + with: + node-version-file: ".node-version" + + - name: Lint + run: npm run-script build + shell: bash + + - name: Release + uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # pin@v0.1.15 + with: + generate_release_notes: true + prerelease: true + files: builds/* diff --git a/.github/workflows/publish-chrome-development.yml b/.github/workflows/publish-chrome-development.yml new file mode 100644 index 00000000..669a6b57 --- /dev/null +++ b/.github/workflows/publish-chrome-development.yml @@ -0,0 +1,100 @@ +name: publish-chrome-development +on: + release: + types: [prereleased] + workflow_dispatch: + inputs: + attemptNumber: + description: "Attempt number" + required: false + default: "1" + maxAttempts: + description: "Max attempts" + required: false + default: "10" +permissions: + actions: write + contents: read +jobs: + upload-on-webstore: + runs-on: ubuntu-latest + environment: cd + outputs: + result: ${{ steps.webStorePublish.outcome }} + releaseUploadUrl: ${{ steps.getZipAsset.outputs.releaseUploadUrl }} + steps: + - name: Get the next attempt number + id: getNextAttemptNumber + uses: cardinalby/js-eval-action@b34865f1d9cfdf35356013627474857cfe0d5091 # pin@v1.0.7 + env: + attemptNumber: ${{ github.event.inputs.attemptNumber }} + maxAttempts: ${{ github.event.inputs.maxAttempts }} + with: + expression: | + { + const + attempt = parseInt(env.attemptNumber), + max = parseInt(env.maxAttempts); + assert(attempt && max && max >= attempt); + return attempt < max ? attempt + 1 : ''; + } + + - uses: actions/checkout@v3 + + - uses: robinraju/release-downloader@768b85c8d69164800db5fc00337ab917daf3ce68 # pin@v1.7 + with: + tag: ${{ github.ref_name }} + fileName: "*" + + - name: Fetch Google API access token + id: fetchAccessToken + uses: cardinalby/google-api-fetch-token-action@24c99245e2a2494cc4c4b1037203d319a184b15b # pin@v1.0.3 + with: + clientId: ${{ secrets.G_CLIENT_ID }} + clientSecret: ${{ secrets.G_CLIENT_SECRET }} + refreshToken: ${{ secrets.G_REFRESH_TOKEN }} + + - name: Upload to Google Web Store + id: webStoreUpload + continue-on-error: true + uses: cardinalby/webext-buildtools-chrome-webstore-upload-action@8db7a005529498d95d3e2e0166f6f4050d2b96a5 # pin@v1.0.10 + with: + zipFilePath: builds/yomitan-chrome-dev.zip + extensionId: ${{ secrets.G_DEVELOPMENT_EXTENSION_ID }} + apiAccessToken: ${{ steps.fetchAccessToken.outputs.accessToken }} + waitForUploadCheckCount: 10 + waitForUploadCheckIntervalMs: 180000 # 3 minutes + + # Schedule a next attempt if store refused to accept new version because it + # still has a previous one in review + - name: Start the next attempt with the delay + uses: aurelien-baudet/workflow-dispatch@93e95b157d791ae7f42aef8f8a0d3d723eba1c31 # pin@v2 + if: | + steps.getNextAttemptNumber.outputs.result && + steps.webStoreUpload.outputs.inReviewError == 'true' + with: + workflow: delay + token: ${{ secrets.GITHUB_TOKEN }} + wait-for-completion: false + inputs: | + { + "attemptNumber": "${{ steps.getNextAttemptNumber.outputs.result }}", + "maxAttempts": "${{ github.event.inputs.maxAttempts }}", + "workflow": "${{ github.workflow }}" + } + + - name: Abort on unrecoverable upload error + if: | + !steps.webStoreUpload.outputs.newVersion && + steps.webStoreUpload.outputs.sameVersionAlreadyUploadedError != 'true' + run: exit 1 + + - name: Publish on Google Web Store + id: webStorePublish + if: | + steps.webStoreUpload.outputs.newVersion || + steps.webStoreUpload.outputs.sameVersionAlreadyUploadedError == 'true' + uses: cardinalby/webext-buildtools-chrome-webstore-publish-action@d39ebd4ab4ea4b44498bf5fc34d4b3db7706f1ed # pin@v1.0.7 + with: + extensionId: ${{ secrets.G_DEVELOPMENT_EXTENSION_ID }} + apiAccessToken: ${{ steps.fetchAccessToken.outputs.accessToken }} diff --git a/.github/workflows/publish-chrome.yml b/.github/workflows/publish-chrome.yml new file mode 100644 index 00000000..cb47d565 --- /dev/null +++ b/.github/workflows/publish-chrome.yml @@ -0,0 +1,100 @@ +name: publish-chrome +on: + release: + types: [released] + workflow_dispatch: + inputs: + attemptNumber: + description: "Attempt number" + required: false + default: "1" + maxAttempts: + description: "Max attempts" + required: false + default: "10" +permissions: + actions: write + contents: read +jobs: + upload-on-webstore: + runs-on: ubuntu-latest + environment: cd + outputs: + result: ${{ steps.webStorePublish.outcome }} + releaseUploadUrl: ${{ steps.getZipAsset.outputs.releaseUploadUrl }} + steps: + - name: Get the next attempt number + id: getNextAttemptNumber + uses: cardinalby/js-eval-action@b34865f1d9cfdf35356013627474857cfe0d5091 # pin@v1.0.7 + env: + attemptNumber: ${{ github.event.inputs.attemptNumber }} + maxAttempts: ${{ github.event.inputs.maxAttempts }} + with: + expression: | + { + const + attempt = parseInt(env.attemptNumber), + max = parseInt(env.maxAttempts); + assert(attempt && max && max >= attempt); + return attempt < max ? attempt + 1 : ''; + } + + - uses: actions/checkout@v3 + + - uses: robinraju/release-downloader@768b85c8d69164800db5fc00337ab917daf3ce68 # pin@v1.7 + with: + tag: ${{ github.ref_name }} + fileName: "*" + + - name: Fetch Google API access token + id: fetchAccessToken + uses: cardinalby/google-api-fetch-token-action@24c99245e2a2494cc4c4b1037203d319a184b15b # pin@v1.0.3 + with: + clientId: ${{ secrets.G_CLIENT_ID }} + clientSecret: ${{ secrets.G_CLIENT_SECRET }} + refreshToken: ${{ secrets.G_REFRESH_TOKEN }} + + - name: Upload to Google Web Store + id: webStoreUpload + continue-on-error: true + uses: cardinalby/webext-buildtools-chrome-webstore-upload-action@8db7a005529498d95d3e2e0166f6f4050d2b96a5 # pin@v1.0.10 + with: + zipFilePath: builds/yomitan-chrome.zip + extensionId: ${{ secrets.G_STABLE_EXTENSION_ID }} + apiAccessToken: ${{ steps.fetchAccessToken.outputs.accessToken }} + waitForUploadCheckCount: 10 + waitForUploadCheckIntervalMs: 180000 # 3 minutes + + # Schedule a next attempt if store refused to accept new version because it + # still has a previous one in review + - name: Start the next attempt with the delay + uses: aurelien-baudet/workflow-dispatch@93e95b157d791ae7f42aef8f8a0d3d723eba1c31 # pin@v2 + if: | + steps.getNextAttemptNumber.outputs.result && + steps.webStoreUpload.outputs.inReviewError == 'true' + with: + workflow: delay + token: ${{ secrets.GITHUB_TOKEN }} + wait-for-completion: false + inputs: | + { + "attemptNumber": "${{ steps.getNextAttemptNumber.outputs.result }}", + "maxAttempts": "${{ github.event.inputs.maxAttempts }}", + "workflow": "${{ github.workflow }}" + } + + - name: Abort on unrecoverable upload error + if: | + !steps.webStoreUpload.outputs.newVersion && + steps.webStoreUpload.outputs.sameVersionAlreadyUploadedError != 'true' + run: exit 1 + + - name: Publish on Google Web Store + id: webStorePublish + if: | + steps.webStoreUpload.outputs.newVersion || + steps.webStoreUpload.outputs.sameVersionAlreadyUploadedError == 'true' + uses: cardinalby/webext-buildtools-chrome-webstore-publish-action@d39ebd4ab4ea4b44498bf5fc34d4b3db7706f1ed # pin@v1.0.7 + with: + extensionId: ${{ secrets.G_STABLE_EXTENSION_ID }} + apiAccessToken: ${{ steps.fetchAccessToken.outputs.accessToken }} diff --git a/.github/workflows/publish-firefox-development.yml b/.github/workflows/publish-firefox-development.yml new file mode 100644 index 00000000..5699311f --- /dev/null +++ b/.github/workflows/publish-firefox-development.yml @@ -0,0 +1,86 @@ +# For the Firefox development addon, people install it manually, +# and updates are distributed via the JSON file created in this +# action which is stored in the metadata branch of this repo. + +name: publish-firefox-development +on: + release: + types: [prereleased] +permissions: + contents: write +jobs: + build-signed-xpi-asset: + needs: ensure-zip + runs-on: ubuntu-latest + environment: cd + steps: + - uses: actions/checkout@v3 + + - uses: robinraju/release-downloader@768b85c8d69164800db5fc00337ab917daf3ce68 # pin@v1.7 + with: + release: ${{ github.event.release.id }} + fileName: "*" + + - name: Sign Firefox xpi for offline distribution + id: ffSignXpi + continue-on-error: true + uses: cardinalby/webext-buildtools-firefox-sign-xpi-action@94a2e58141e33c4306a72a93f191e8540189df92 # pin@v1.0.6 + with: + timeoutMs: 1200000 + extensionId: ${{ secrets.FF_OFFLINE_EXT_ID }} + zipFilePath: builds/yomitan-firefox-dev.zip + xpiFilePath: builds/yomitan-firefox-dev.xpi + jwtIssuer: ${{ secrets.FF_JWT_ISSUER }} + jwtSecret: ${{ secrets.FF_JWT_SECRET }} + + - name: Abort on sign error + if: | + steps.ffSignXpi.outcome == 'failure' && + steps.ffSignXpi.outputs.sameVersionAlreadyUploadedError != 'true' + run: exit 1 + + - name: Upload offline xpi release asset + id: uploadReleaseAsset + if: steps.ffSignXpi.outcome == 'success' + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ github.event.release.upload_url }} + asset_path: builds/yomitan-firefox.xpi + asset_name: yomitan-firefox.xpi + asset_content_type: application/x-xpinstall + + # update update.json so that all people who have the dev version installed get the new update + + - uses: actions/checkout@v3 + with: + ref: metadata + + - name: Recreate update.json + run: | + cat > update.json << EOF + { + "addons": { + "themoeway+development@googlegroups.com": { + "updates": [ + { + "version": "${{ github.event.release.name }}", + "update_link": "${{ uploadReleaseAsset.browser_download_url }}" + } + ] + } + } + } + EOF + + - name: Commit files + run: | + git config --local user.email "github-actions[bot]@users.noreply.github.com" + git config --local user.name "github-actions[bot]" + git commit -a -m "${{ github.event.release.name }} - ${{ github.event.release.html_url }}" + + - name: Push changes + uses: ad-m/github-push-action@0fafdd62b84042d49ec0cb92d9cac7f7ce4ec79e # pin@master + with: + branch: metadata diff --git a/.github/workflows/publish-firefox.yml b/.github/workflows/publish-firefox.yml new file mode 100644 index 00000000..7b2037af --- /dev/null +++ b/.github/workflows/publish-firefox.yml @@ -0,0 +1,34 @@ +name: publish-firefox +on: + release: + types: [released] +permissions: + contents: read +jobs: + publish: + runs-on: ubuntu-latest + environment: cd + steps: + - uses: actions/checkout@v3 + + - uses: robinraju/release-downloader@768b85c8d69164800db5fc00337ab917daf3ce68 # pin@v1.7 + with: + tag: ${{ github.ref_name }} + fileName: "*" + + - name: Deploy to Firefox Addons + id: addonsDeploy + uses: cardinalby/webext-buildtools-firefox-addons-action@924ad87df7e4af50a654c164ad9e498dce260ffa # pin@v1.0.9 + continue-on-error: true + with: + zipFilePath: builds/yomitan-firefox.zip + extensionId: ${{ secrets.FF_EXTENSION_ID }} + jwtIssuer: ${{ secrets.FF_JWT_ISSUER }} + jwtSecret: ${{ secrets.FF_JWT_SECRET }} + + - name: Abort on upload error + if: | + steps.addonsDeploy.outcome == 'failure' && + steps.addonsDeploy.outputs.sameVersionAlreadyUploadedError != 'true' && + steps.addonsDeploy.outputs.timeoutError != 'true' + run: exit 1 diff --git a/.github/workflows/touch-google-refresh-token.yml b/.github/workflows/touch-google-refresh-token.yml new file mode 100644 index 00000000..9c4e2ec9 --- /dev/null +++ b/.github/workflows/touch-google-refresh-token.yml @@ -0,0 +1,16 @@ +name: Touch google token +on: + schedule: + - cron: "0 3 2 * *" # At 03:00 on day-of-month 2 + workflow_dispatch: +permissions: {} +jobs: + fetchToken: + runs-on: ubuntu-latest + environment: cd + steps: + - uses: cardinalby/google-api-fetch-token-action@24c99245e2a2494cc4c4b1037203d319a184b15b # pin@v1.0.3 + with: + clientId: ${{ secrets.G_CLIENT_ID }} + clientSecret: ${{ secrets.G_CLIENT_SECRET }} + refreshToken: ${{ secrets.G_REFRESH_TOKEN }} diff --git a/.node-version b/.node-version new file mode 100644 index 00000000..6f7f377b --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +v16 |