- Shell 46.7%
- JavaScript 28.4%
- Python 24.9%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .forgejo/workflows | ||
| build-plugins | ||
| checkout-releases | ||
| checkout-repository | ||
| publish-releases | ||
| scripts | ||
| setup-android-toolchain | ||
| setup-bun | ||
| setup-node | ||
| setup-plugin-deps | ||
| templates | ||
| .gitignore | ||
| LICENSE | ||
| README.md | ||
RNDUP Shared Actions
Reusable Forgejo Actions for the repositories in the RNDUP organization: building Revenge Next plugins and publishing the result into a shared releases repository.
Nothing in here is specific to one plugin repository. If a repository needs the same CI logic twice, it belongs here instead.
How a release works
push to main
│
├── checkout-repository clone the exact commit that was pushed
├── setup-android-toolchain Temurin JDK, Android SDK, licences
├── setup-bun JS runtime
├── setup-plugin-deps JS dependencies, plugin CLI, Revenge API -> ~/.m2
├── checkout-releases clone RNDUP/releases into dist/
├── (your repository) anything that has to exist before compilation
├── build-plugins dist/<id>@<version>.zip, dist/index.json, companion APK
└── publish-releases commit dist/ and push it to RNDUP/releases
dist/ is a clone of the releases repository, so the build output is the published tree. The
clone has to be made before the build: the build writes into it, and a checkout afterwards
would overwrite fresh artifacts with the previously published ones.
Because the artifacts land in a separate repository, one organization's plugins can be served from a single index, and a repository can be renamed or moved without invalidating any download URL.
Actions
| Action | Kind | What it does |
|---|---|---|
checkout-repository |
composite | Forgejo does not check anything out for you. Installs git if the image has none, then clones the commit the run was triggered for, authenticated, with safe.directory set. |
setup-android-toolchain |
composite | Installs a Temurin JDK and Android SDK (platforms, build-tools, licences) and exports JAVA_HOME, ANDROID_HOME, PATH. |
setup-node |
composite | Installs the Node.js runtime that JavaScript actions such as actions/cache are executed with. Leaves an image that already has the right version alone. |
setup-bun |
composite | Installs Bun and puts it on PATH. Installs curl first if the image has none. |
setup-plugin-deps |
composite | bun install, builds @revenge-mod/plugin-cli from source, publishes io.github.revenge:api to the local Maven repository. |
checkout-releases |
composite | Clones the shared releases repository into dist/, creating the branch if it does not exist yet. |
build-plugins |
composite | Builds and packages every plugin, generates index.json, verifies the artifacts are readable. |
publish-releases |
node20 | Commits the artifacts in the releases clone, pushes, optionally prunes superseded ones and mirrors the tree to a Pages branch. |
Using them in your own repository
Cross instance references need the full URL. A bare owner/repo/path@ref is resolved against
the marketplace instance (github.com), not against git.gay, so uses: RNDUP/Shared-Actions/...
does not work here.
- uses: https://git.gay/RNDUP/Shared-Actions/build-plugins@v1
with:
base-url: https://example.org/plugins
Any repository on git.gay can use these, as long as its Actions are enabled and a token it can authenticate with may write to the releases repository.
The automatic workflow token is not that token. It is minted for the repository the workflow runs in and is scoped to it, so it cannot write to a separate releases repository — not even inside the same organization, and granting the runner user more access does not change it:
This token can only be used for interactions with the repository it was created for. — Forgejo Actions | Security
So publishing always needs an explicit token. Mint one under a user that may write to the
releases repository: Settings → Applications → Generate New Token, scope write:repository, and
set Repository access to Specific repositories listing only the repositories that token may
touch. Store it as a secret and pass it to both actions — checkout-releases needs it to clone
privately, and publish-releases to push:
- uses: https://git.gay/RNDUP/Shared-Actions/checkout-releases@v1
with:
token: ${{ secrets.PUBLISH_TOKEN }}
- uses: https://git.gay/RNDUP/Shared-Actions/publish-releases@v1
with:
token: ${{ secrets.PUBLISH_TOKEN }}
One credential covers every push the job makes. If you mirror with mirror-to-repository, add
that repository to the token's list as well, because the mirror is pushed with the same token.
A token belongs to the account that minted it, so prefer a dedicated machine user over your own: the pushes stop depending on a person, and the token can be rotated without touching a human account.
A complete working example is in templates/plugin-release.yml.
The container image needs nothing prepared in advance. checkout-repository is normally the first
step of a job and cannot rely on an earlier step having installed anything, so it installs git
itself when the image has none (apt, apk, dnf or yum). The same goes for setup-node, which
installs the Node.js that actions/cache is executed with, and for setup-bun, which needs
curl. A plain ubuntu:22.04 therefore works as it is.
Pinning
@v1 is a tag that always points at the newest commit of the v1 line, which keeps consumers
working while changes stay opt in. If you need a build that cannot change under you, pin a
commit instead:
- uses: https://git.gay/RNDUP/Shared-Actions/build-plugins@<sha>
What every repository still has to do itself
.gitignoremust containdist/.checkout-releaseswarns when it does not, because a nested clone that gets committed turns the next checkout into a conflict.- Secrets stay in the repository that owns them. The passkey injection of
kmmiio99o-pluginsis deliberately an inline step: the value never passes through a shared action, andAGENTS.mdin that repository forbids moving it. Shared actions take build inputs, not credentials that decide what a build contains. - The
base-urlis yours to choose. It is the URL the artifacts will be served from. It has to be the releases repository, not the source repository, or every download link inindex.json404s.
Serving the releases
publish-releases can mirror the published tree onto a branch of your own repository:
with:
mirror-to-repository: RNDUP/kmmiio99o-plugins
mirror-to-branch: gh-pages
That keeps an already configured Pages domain working without moving DNS, while the releases
repository stays the single source of truth. To serve RNDUP/releases directly instead, enable
Pages for it and point the domain there; the mirror is then unnecessary.
Developing
Validate every action and workflow after a change:
python3 scripts/validate-actions.py .
Run a composite action's steps locally, with the same INPUT_* variables a runner would set:
python3 scripts/run-composite.py setup-android-toolchain/action.yml "Install Android SDK components"
publish-releases is a plain Node script with no dependencies, so it can be exercised against a
throwaway repository:
git init --bare -b main /tmp/remote.git
mkdir -p /tmp/work/dist && git -C /tmp/work/dist init -q -b main
INPUT_DIST_DIR=/tmp/work/dist INPUT_PRUNE=true node publish-releases/publish.js
dry-run: 'true' reports what would be committed without pushing and leaves the clone in its
original state.