Introduction
In this article, I'm going to share my approach of preparing a complete CI/CD solution for building and publishing a browser extension (WebExtension) based on GitHub Actions:
- Reusable building and testing pipeline.
- Releasing and building artifacts for offline distribution.
- Publishing an extension on Chrome Web Store and Firefox Add-ons store.
The described workflows are based on the existing and tested workflows for my "Memrise Audio Uploader" extension.
From this series of posts you can learn:
- How to develop an architecture of interconnected GitHub Action workflows that is flexible and handy for developers and minimizes code duplication.
- Tricky approach of deferring and repeating a task in GitHub Actions
- Peculiarities of interacting with stores API
I assume that:
- You have a GitHub repo with your WebExtension.
- You have already created developer accounts on Chrome Web Store and Firefox Add-ons store.
- You have published the extension on both stores. The approach described here is only suitable for extensions that are already published. The initial publishing involves adding screenshots, a description, assigning categories, etc.
- You are familiar with the basics of Actions: a workflow file structure, inputs/outputs, env variables, and secrets concepts.
More about used techniques
Actions used in the workflows
In this article, I try not to focus on implementation details of individual actions so as not to overcomplicate the article. I have created a set of webext-buildtools-... actions to perform steps that are specific for releasing of WebExtension and also several general-purpose actions (if I didn't manage to find existing ones).
Not all of the actions used are production-ready. Nobody can guarantee that the actions which you use will still exist in a month. Also, pointing to an action using @master
or @v1
, you can't be sure what will be executed. It's the glitter and misery of GitHub Actions Marketplace. Don't forget that you pass your sensitive data to them. Possible solutions to protect yourself are: making forks of third-party actions or pinning them to SHA.
Secrets and env variables
We are going to store all sensitive data (access tokens, private key, etc.) in the repo's Encrypted secrets.
Also, creating multiple workflows we want to reuse some not secret constants inside them. I extracted the constants to .env
file and used export-env-action to export constants to environment variables at the beginning of each job.
.github/workflows/constants.env:
# Dir where the extension is located
EXTENSION_DIR=extension/
# Dir for build artifacts
BUILD_DIR=build/
# Packed extension file name and path
ZIP_FILE_NAME=extension.zip
ZIP_FILE_PATH=${BUILD_DIR}${ZIP_FILE_NAME}
# File name and path of crx file
# downloaded from Chrome Web Store
WEBSTORE_CRX_FILE_NAME=extension.webstore.crx
WEBSTORE_CRX_FILE_PATH=${BUILD_DIR}${WEBSTORE_CRX_FILE_NAME}
# File name and path of crx file built
# for offline distribution
OFFLINE_CRX_FILE_NAME=extension.offline.crx
OFFLINE_CRX_FILE_PATH=${BUILD_DIR}${OFFLINE_CRX_FILE_NAME}
# File name and path of xpi file built
# for offline distribution
XPI_FILE_NAME=extension.offline.xpi
XPI_FILE_PATH=${BUILD_DIR}${XPI_FILE_NAME}
Versioning
We will mark each release of the extension with a corresponding tag. This tag should be the same as an extension version in manifest.json
file. Pushing this tag will trigger our releasing process. So, you should add a new tag after you have incremented manifest.json
version.
Top comments (2)
Wow Amazingly explanation Very well. Appreciated.
Hi! Thanks for the interest. Now the article is not completed, it's a copy of the original series at my blog (where I have already finished it): cardinalby.github.io/blog/post/git...