Vai al contenuto

Releasing

Versions, branches and releases. How the project is built: Development.

In short

  1. Work on rc (or on branches merged into rc), noting changes under ## [Unreleased] in CHANGELOG.md.
  2. When ready, on rc, bump the version:
  3. gradle.properties: mod_version=0.5.0
  4. CHANGELOG.md: under the empty ## [Unreleased], add ## [0.5.0] - 2026-10-15 with what changed (square brackets and this exact format: the release notes are taken from it).
  5. Optionally run the Game tests workflow on rc (Actions tab → Game tests → Run workflow, Use workflow from: rc): CI doesn't play them.
  6. Open a pull request from rc into main, wait for CI (its release check confirms the new version), merge.
  7. Done. GitHub creates release/0.5.0, the tag v0.5.0-fabload0.19.5+api0.162.0-mc26.3 and the release (a pre-release, Beta on Modrinth: promote it by hand) with the jar, the .mrpack and the Default Content datapack zip, then uploads the jar to Modrinth (about a minute: Actions tab, then Releases).
  8. rc is brought up to date with main automatically; locally, run git pull on rc.
  9. If the release should have MineDnD Studio installers, run the Studio installers workflow with its tag (see below).

The sections below explain each part.

Version numbers

MineDnD uses Semantic Versioning: MAJOR.MINOR.PATCH.

Change Bump Example
Bug fixes only PATCH 0.0.1 → 0.0.2
New features, new datapack formats, balance changes MINOR 0.0.2 → 0.1.0
Changes that break existing worlds or datapacks (after 1.0.0) MAJOR 1.4.2 → 2.0.0

While the version starts with 0., anything can still change between minor versions.

The version lives in one place: mod_version in gradle.properties. It flows into the jar name (MineDnD-<version>.jar), fabric.mod.json (shown in the mods list) and the modpack (MineDnD-<version>.mrpack).

Branches and tags

Name What it is
main What's released. Every merge into main is a release: pull requests into it come from rc and carry a new version.
rc Release candidate: where changes collect and get tested (installToModrinth, playtests) before a release.
feature/..., fix/..., chore/... Short-lived work branches, merged into rc by pull request (or commit straight on rc).
release/X.Y.Z Frozen copy of a released version, to fix it later without taking new features. Created automatically.
tag vX.Y.Z-fabloadL+apiA-mcM The exact commit that was released, e.g. v0.4.2-fabload0.19.5+api0.162.0-mc26.3: mod version, Fabric Loader version (loader_version), Fabric API version (fabric_version without +<minecraft>) and Minecraft version (minecraft_version). Created automatically. Up to 0.4.1 tags were plain vX.Y.Z.

Making a release

Work happens on rc; merging rc into main releases.

  1. Make changes on rc (commits, or pull requests from feature/... branches into rc). CI builds every push to rc. Note them under [Unreleased] in CHANGELOG.md. Try them in game with gradlew installToModrinth -Pinstance="<folder>".
  2. When rc is ready: on rc, set mod_version in gradle.properties and move the [Unreleased] notes in CHANGELOG.md under a new ## [X.Y.Z] - YYYY-MM-DD heading.
  3. Open a pull request from rc into main. Its release-check job fails if the version is already released or the changelog has no section for it, so every merge into main really is a release.
  4. Merge it. On every push to main, the Release workflow (.github/workflows/release.yml) checks whether X.Y.Z already has a tag:
  5. No: it creates release/X.Y.Z and the tag (e.g. v0.4.2-fabload0.19.5+api0.162.0-mc26.3, also the release title), builds, and publishes a GitHub Release with MineDnD-X.Y.Z.jar, the sources jar, MineDnD-X.Y.Z.mrpack and MineDnD-Default-Content-X.Y.Z.zip (the datapack), using the version's CHANGELOG.md section as notes. Every release is a pre-release on GitHub and Beta on Modrinth: promote it by hand when it's ready (Modrinth: the version's Edit → release channel; GitHub: Edit release). Then it uploads the jar to Modrinth (see below).
  6. Yes: nothing is released (the workflow says so in its summary).
  7. rc is brought up to date with main automatically: the Release workflow's last step merges main into rc (usually a fast-forward). Only after a conflict, which can happen if rc got new commits in the meantime, does it warn and ask you to run git checkout rc && git merge origin/main && git push yourself. Locally, git pull on rc gets the update.

Watch it in the repository's Actions tab; the release appears on the Releases page and on Modrinth.

Studio installers

The MineDnD Studio installers (Windows, macOS, Linux) are built only by hand, so a release doesn't wait for three runners and pull requests don't pay for them. Actions tab → Studio installers → Run workflow (.github/workflows/studio.yml):

  • Release tag filled in (e.g. v0.9.0-fabload0.19.5+api0.162.0-mc26.3): builds that tag on one runner per OS and adds the installers to its GitHub release. The release must exist already; running it again replaces the files.
  • Release tag empty: builds the branch chosen in Use workflow from and keeps the installers as the run's artifacts for 14 days, e.g. to check that packaging still works after changing Studio's dependencies.

From a terminal: gh workflow run studio.yml -f release_tag=<tag> (or without -f to only build).

Documentation site

The docs are also a website, https://minednd.pages.dev/ (MkDocs Material, English and Italian, with search), on Cloudflare Pages: free, and the repository can stay private. The Docs workflow (.github/workflows/docs.yml) builds and publishes it on every push to main that changes docs/, so the site always describes the released version; it can also be run by hand from the Actions tab.

Set up once:

  1. Account ID: on dash.cloudflare.com, open Workers & Pages (or the account's home): the Account ID is in the right-hand column (also in the address bar: dash.cloudflare.com/<account id>/…). Store it as the secret CLOUDFLARE_ACCOUNT_ID: gh secret set CLOUDFLARE_ACCOUNT_ID (paste it when asked).
  2. API token: avatar → Profile → API Tokens → Create Token → Custom token. Permissions: Account → Cloudflare Pages → Edit; Account resources: your account. Store it as the secret CLOUDFLARE_API_TOKEN: gh secret set CLOUDFLARE_API_TOKEN.
  3. Run the Docs workflow (Actions tab → Docs → Run workflow, on main). The first run creates the Pages project minednd (another name: the repository variable CLOUDFLARE_PAGES_PROJECT, and site_url in mkdocs.yml).

Until the secrets are set, the workflow builds the site and only warns. CI builds the site on every pull request (the docs job), so a broken link or anchor in either language fails there. How the site is made: Development.

Modrinth uploads

The Release workflow runs .github/scripts/modrinth-upload.sh after the GitHub release. It uploads MineDnD-X.Y.Z.jar as version X.Y.Z: Fabric, the Minecraft version from gradle.properties, Fabric API as a required dependency, the release notes as changelog, always Beta (promoted by hand). A version already on Modrinth is skipped, so re-running is safe.

Set up once (until then the step only prints "skipped"):

  1. On modrinth.com: avatar → Settings → Personal access tokens → create one with the Create versions scope (and Read projects, to find the project while it's a draft or private).
  2. Store it in the repository as the secret MODRINTH_TOKEN: gh secret set MODRINTH_TOKEN (paste it when asked), or Settings → Secrets and variables → Actions → New repository secret.
  3. Store the project's slug (e.g. minednd) as the variable MODRINTH_PROJECT: gh variable set MODRINTH_PROJECT --body minednd.

CI also runs two checks on every pull request: - a dry run of the upload (MODRINTH_DRY_RUN=1), which checks the data without contacting Modrinth; - an access check (MODRINTH_CHECK=1), which reads the project with the token and lists its versions. It shows up in the run as "Modrinth project OK: …", or as an error when the slug or token is wrong.

Fixing an old release

  1. Branch from release/X.Y.Z, fix, bump PATCH (X.Y.Z+1), add a changelog entry, open a pull request into release/X.Y.Z.
  2. After merging, tag the release branch by hand: git tag -a "$(bash .github/scripts/release-tag.sh)" -m "MineDnD X.Y.(Z+1)" and push the tag. Pushing a release tag also publishes a release (the tag must be the one gradle.properties gives).
  3. Bring the fix to main too (another pull request or a cherry-pick).

Reviews and branch protection

.github/CODEOWNERS makes the owner the required reviewer of every file, and CI (.github/workflows/ci.yml) builds the mod and runs the editor tests on every pull request.

The rules that enforce this (pull request required, code owner approval, CI must pass, no force pushes or deletions on main and release/*; release tags can't be moved or deleted) are prepared in .github/rulesets/. GitHub only enforces rulesets on private repositories with a paid plan (GitHub Pro or Team); on a public repository they're free. To apply them, once that's the case:

gh api -X POST repos/less-hub/MineDnD/rulesets --input .github/rulesets/branches.json
gh api -X POST repos/less-hub/MineDnD/rulesets --input .github/rulesets/tags.json

The repository admin can still merge their own pull requests (GitHub doesn't let authors approve their own pull requests); everyone else's pull requests need the owner's approval.