Post 6 of 9 in "Releasing WebExtension using GitHub Actions" series

In this part we are going to create the workflow that will be responsible for publishing the extension on Firefox Add-ons marketplace.

🧱 Prepare

First, you need to find out your extension UUID. You can find it on your extension’s page at Add-on Developer Hub in the “Technical Details” section.

Next, follow the official documentation and obtain jwtIssuer and jwtSecret values required for accessing the API.

🔒 Add these values to secrets:

  • FF_EXTENSION_ID - UUID of your extension (e.g. {c23c69a7-f889-447c-9d6b-7694be8035bc})
  • FF_JWT_ISSUER
  • FF_JWT_SECRET

publish-on-firefox-add-ons workflow

The workflow will have the only trigger: workflow_dispatch event. It can be dispatched:

  1. Manually specifying any branch or tag as workflow ref.
  2. By publish-release-on-tag workflow after it has prepared a release with zip asset.

We will utilize already created get-zip-asset composite action to obtain packed zip that is needed for deploying the extension.

.github/workflows/publish-on-firefox-add-ons.yml :

name: publish-on-firefox-add-ons
on:
  workflow_dispatch:
jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      - uses: cardinalby/export-env-action@v1
        with:
          envFile: './.github/workflows/constants.env'
          expand: true

      - name: Obtain packed zip
        uses: ./.github/workflows/actions/get-zip-asset
        with:
          githubToken: ${{ secrets.GITHUB_TOKEN }}

      - name: Deploy to Firefox Addons
        id: addonsDeploy
        uses: cardinalby/webext-buildtools-firefox-addons-action@v1
        continue-on-error: true
        with:
          zipFilePath: ${{ env.ZIP_FILE_PATH }}
          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'          
        run: exit 1
  1. As usual, at the beginning of each workflow we check out the repo and export env variables from constants.env file.
  2. After calling get-zip-asset composite action we expect to have zip file with packed and built extension at env.ZIP_FILE_PATH path.
  3. We pass its path along with other required inputs to webext-buildtools-firefox-addons-action action to publish the extension. We use continue-on-error: true flag to prevent the step from failing immediately in case of error and validate the result at the following step according to our preferences.
  4. Examining addonsDeploy step outputs we can find out the reason of its failure. If it failed because the version we try to publish is already published, we don’t consider it as error.

Timeout notes

Also, the publishing action can sometimes fail with timeoutError == 'true' output. It means, the extension was uploaded but the waiting for its processing by Addons server was timed out. I didn’t include a handling of this error to the workflow, but you can:

  • Specify longer timeout with timeoutMs input of webext-buildtools-firefox-addons-action action. Default timeout is 600000 ms (10 min).
  • Do not fail the job in the last step if steps.addonsDeploy.outputs.timeoutError == 'true'.
  • Just rerun the workflow after a while in the case of timeout. If the extension has been processed after the first run, the workflow will pass (with steps.addonsDeploy.outputs.sameVersionAlreadyUploadedError == 'true').

Not covered: sources uploading

Tthe topic I didn’t touch in the article for the sake of simplicity is providing sources of the extension for Firefox Add-ons reviewers. In my example sources and packed extension are the same. But any little bit complicated extension will probably have build process including compiling TypeScript, packing css, minifying JS files, etc. In this case Firefox Add-ons requires you to provide source codes separately.

Using webext-buildtools-firefox-addons-action you can do it by specifying sourcesZipFilePath input pointing to the zip file containing sources. To produce this file you need to add an extra step in the workflow, though.

Post 6 of 9 in "Releasing WebExtension using GitHub Actions" series