Releasing and maintaining actions
Problem statement
So you have created an action…now what? This pattern guide shows a minimal solution to releasing and maintaining actions in open source, favoring automation whenever possible, providing value while keeping overhead at a minimum.
The solution should:
-
Leverage GitHub Actions for continuous integration, dependency updates, release management, and task automation.
-
Promote discoverability with regular publishing to GitHub Marketplace.
-
Provide confidence through automated tests and build badges.
-
Indicate how the action can be used, ideally as part of a broader workflow.
-
Signal what type of community contributions you welcome, e.g. issues, pull requests, or vulnerability reports.
Solution
We recommend that Technology Partners build actions with JavaScript instead of in containers for speed and cross-platform functionality, so this guide will focus on JavaScript actions.
Though they are “just” Node.js repositories with metadata in an action.yml
file, JavaScript actions have a few interesting properties compared to traditional Node.js projects:
-
Dependent packages are committed alongside the code, typically in a compiled and minified form, so automated builds and secure community contributions are important.
-
Tagged releases can be published directly to GitHub Marketplace and consumed by workflows across GitHub, making sensible releasing and tagging of special interest.
-
Many actions make use of the GitHub API and third party APIs, so we encourage robust end-to-end testing.
We base a solution on actions/javascript-action, putting special focus on solving the problem areas identified above. We use GitHub Actions to automate releasing the action and publishing to GitHub Marketplace, and open source best practices to increase confidence and usage.
Implementation
Automate release management
GitHub recommends creating releases using semantically versioned tags – for example, v1.1.3
– and keeping major (v1
) and minor (v1.1
) tags current to the latest appropriate commit. When a release is created, it can be published to GitHub Marketplace for increased discoverability.
^
|
|
| * commit 9a4eb0d (tag: v1, tag: v1.1, tag: v1.1.0)
|/ Author: Octocat <octocat@github.com>
|
| New features!
|
|
| * commit ac2415 (tag: v1.0, tag: v1.0.3)
|/ Author: Octocat <octocat@github.com>
|
| Initial release
|
*
|
main
We let GitHub Actions do the automation for us to enable this workflow:
- Do feature work in branches per GitHub flow.
- When a feature branch commit is pushed, GitHub Actions runs a
test
workflow from which you can call unit and integration tests.
- Create pull requests to the
main
branch to initiate discussion and review, merging when ready.
-
When a pull request is opened, either from a branch or a fork, GitHub Actions again runs the
test
workflow, this time with the merge commit. Alabel
workflow also runs to add appropriate labels to the pull request depending on which file path is being changed. -
Note: for security reasons, workflows triggered by
pull_request
from forks have restrictedGITHUB_TOKEN
permissions and do not have access to secrets. If your tests or other workflows triggered upon pull request require access to secrets, consider using a different event like a manual trigger or apull_request_target
. Read more here.
- Create a semantically tagged release using the GitHub UI, also publishing to GitHub Marketplace with a simple checkbox.
- When the release is created, GitHub Actions runs a
publish
workflow that uses a community action, JasonEtco/build-and-tag-action to compile and bundle the JavaScript and metadata file and force push semantic major, minor, and patch tags as visualized above.
Unlike some other automated release management strategies, we intentionally do not commit dependencies to the main
branch, only to the tagged release commits. By doing so, we encourage users of our action to reference named tags or sha
s, and we help ensure the security of third party pull requests by doing the build ourselves during a release.
Committing to semantic releases means that the users of your actions can pin their workflows to a version and know that they might continue to receive the latest stable, non-breaking features, depending on their comfort level:
### A workflow consuming your action
# The latest major release version:
uses: github-developer/javascript-action@v1
# Or, the latest minor release version:
uses: github-developer/javascript-action@v1.1
# Or, the latest patch release version:
uses: github-developer/javascript-action@v1.1.0
# Or, a specific commit sha:
uses: github-developer/javascript-action@ff958b3d4b36abb3d3058e1e866695ce6111d213
Open source like the best
Working in the open can be hard, but fortunately, GitHub provides tools and guides to make it easier. Here are a few structures we recommend setting up for healthy bidirectional communication.
By providing the following signals to the community, we encourage use, modification, and contribution to our action:
- Maintain a great README with plenty of usage examples, guidance, and badges
- How to add a workflow status badge (docs)
- Other metadata badges (shields.io)
-
Set up community health files like
CODE_OF_CONDUCT
,CONTRIBUTING
, andSECURITY
, either organization-wide or in your action repository. - Keep issues current by utilizing actions like stale
Check out more resources for building in the open here.
Concrete implementation
Template repository: https://github.com/github-developer/javascript-action
Examples
Examples where similar patterns are employed include: