# Builds and releases Active plugin pull requests into `main` run Maven verification with Java unit tests enabled and publish development artifacts. Pushes to `main` run the same verification without publishing development artifacts. CoreProtect uses its default branch, `master`, as well. A failed test fails the build. Test reports are uploaded when present, including after test failures; repositories without test sources report no tests. Development builds use `DEV-YYYYMMDD-HHmm`, with the date and time in UTC. The runtime JAR filename and embedded plugin version match, for example `armourshop-DEV-20260922-1500.jar` and `DEV-20260922-1500`. Active plugins keep `main-SNAPSHOT` in the committed POM as a local-build marker; it is not a release number. CI sets the build version in its temporary checkout. GitHub artifact names include the run ID and attempt to distinguish builds within the same minute. ## Plugin releases 1. Select the commit to release. No version-bump commit is needed. Keep the plugin descriptor's version as `${project.version}` so Maven supplies it. 2. Push a release tag, such as `v1.2`, `v1.2.3`, or `v1.2.3-rc.1`. The tag is the only source of the release version. 3. The release workflow validates the tag, prepares dependencies, sets Maven's project version from the tag without its leading `v`, and runs `mvn clean verify` with tests enabled. It does not commit the version change back to the branch. 4. It validates and uploads the exact runtime JAR, `SHA256SUMS`, and `build.json` to a draft GitHub release. 5. Download and inspect the artifacts, review the generated notes, and publish the draft. Tags with prerelease suffixes create prereleases. Snapshot versions are rejected. An existing release causes the run to fail; use a new version for corrections. The workflow does not deploy to a Minecraft server. Dependency and build-tool versions remain pinned in the POM; those select build inputs and are independent of the plugin's own release version. ### Release presentation Use the exact tag as the release title, such as `v2.0.1` or `v0.2.1`. Every release uses the same two top-level sections: - **Changes**: concise user-facing changes. The first release starts with `Initial release.`; later drafts include generated changes for review. - **Downloads**: links to the attached runtime JAR or archives, followed by `SHA256SUMS` and `build.json`. Keep project versions independent. Active plugins run in production and use stable numeric release versions. Do not add project names, build timestamps, or feature subtitles to release titles. Put compatibility requirements and relevant limitations in the Changes section. Source-only releases must say explicitly that they contain no plugin binary. Apply this format to manually published releases as well as automated drafts. `build.json` records the source commit, repository, tag, workflow run, JAR name, checksum, and dependency inputs. Locally built releases record their build method and use `run: null`. Verify draft assets before publication. Release publication does not deploy a Minecraft server. All plugins target **Java 21 / Minecraft 1.21.10**; see the [shared platform baseline](PLATFORM.md). ## Build dependencies Plugins with file dependencies use `.github/scripts/prepare-release.sh` to download their private build inputs from a pinned commit in [ServerAssets](https://github.com/TF-Minecraft/ServerAssets). The committed `.github/dependencies.sha256` verifies the downloaded bytes. JARs go in `libs/`, outside Maven's cleaned `target/` directory, and are ignored by Git. After download, `prepare-release.sh` calls `.github/scripts/install-local-dependencies.sh`. This script verifies every pinned checksum before installing the JARs into the local Maven repository using `maven-install-plugin:3.1.4`. POMs declare these inputs with `provided` scope; versions end in `-tfmc-` so different private JARs cannot overwrite one another under the same Maven coordinates. Generated POMs have no transitive dependencies. The input bytes and runtime plugin requirements are unchanged. For already downloaded `libs/`, run `bash .github/scripts/install-local-dependencies.sh`. Pass Maven options such as `-Dmaven.repo.local=/path/to/cache` to either preparation script and to the subsequent build. Keep the checksum file, install commands, and POM versions together when updating an input. Rollback consists of reverting those files together; no runtime data migration is involved. `DEPS_TOKEN` is an organisation Actions secret with Contents read access to ServerAssets. Grant the consuming repositories access to this one secret. A separate token for each repository is unnecessary. The workflow passes it only to dependency preparation steps. Fork pull requests do not receive Actions secrets and cannot run builds that require these private inputs. Shared TFMC plugins use their Maven coordinates with `provided` scope. Development and release workflows run the [shared plugin installer](https://github.com/TF-Minecraft/TLibs/blob/main/DEPENDENCIES.md) with `mode: pinned`. It resolves each direct dependency at the version committed in the POM, verifies the JAR checksum, and installs a minimal Maven POM. The action is pinned to a reviewed commit SHA. Provider build dependencies are not installed recursively or shaded into consumers. Shared APIs use public source-built releases. Providers use stable releases. Drafts and development artifacts are excluded. Missing releases, artifacts, credentials, or matching checksums fail the build. Public release lookup uses `github.token`; licensed third-party inputs use `DEPS_TOKEN`. Builds record coordinates, checksums, and sources in `.build/plugin-dependencies.json`. Development artifacts preserve this file; release metadata includes the same inputs in `build.json`. Local builds use: ```sh python3 ../tlibs/tools/install-plugins.py --pom pom.xml --mode pinned ``` To upgrade dependencies, run the installer locally with `--mode latest`, review the POM changes, and commit the chosen versions. ServerAssets' `manifest.json` is authoritative for filenames, hashes, embedded plugin versions, and sources. Keep licensed dependency JARs in that private repository and out of public release assets. ## Workflow configuration Plugin repositories contain `build.yml`, `release.yml`, and the reusable `maven-release.yml` under `.github/workflows/`. The release caller selects the JDK and passes `DEPS_TOKEN` explicitly where needed. Both development and release jobs obtain the runtime JAR path from Maven's `project.build.finalName`: `target/.jar`. The usual Maven name is `-`. Runtime filenames must use a lowercase alphanumeric plugin name followed by the version: `-.jar`. Do not add underscores, word separators or a `-plugin` suffix. Examples are `tlibs-2.0.0.jar`, `archaeo-1.0.1.jar` and `geigercounters-2.0.0.jar`. A POM `finalName` override normalizes legacy Maven artifact IDs without changing dependency coordinates. Keep that filename decision in the POM. Bukkit identifiers and data-folder names remain stable; the filename convention does not rename them. Shaded plugins replace the main runtime JAR; `original-*`, sources and test JARs are not release artifacts. The identical `.github/scripts/plugin-artifact.py` helper in each plugin repository checks the lowercase alphanumeric filename, resolved JAR path, archive integrity, and embedded `plugin.yml` or `paper-plugin.yml` version before either build type uploads it. Releases use the same helper to stage the runtime JAR, `SHA256SUMS` and `build.json`, including resolved plugin dependency metadata where applicable. Both build types run Maven verification with tests enabled. Plugin `.gitignore` files share rules for build output, downloaded JARs, Maven backup files, dependency-resolution metadata, IDE files and local caches. Maven wrapper JARs and launchers, source/tests, dependency checksums and README files remain trackable. Repository-specific runtime data exclusions follow the common rules. Workflows use Ubuntu 24.04 and actions with Node.js 24 runtimes. Plugin workflows build with Temurin JDK 21. ## Pull request size Plugin repositories run the **PR size** check on every pull request. It labels the pull request by its effective changed lines: | Label | Lines | |---|---| | `size:XS` | 0–9 | | `size:S` | 10–29 | | `size:M` | 30–99 | | `size:L` | 100–499 | | `size:XL` | 500–999 | | `size:XXL` | 1,000+ | Effective lines are the insertions plus deletions from the merge base to the head commit. Whitespace-only changes and hunks of only blank lines do not count, and binary files count as zero. Test files (`src/test/`, `test/`, `tests/`) are left out when the pull request changes anything else; a test-only pull request is sized by its tests. The label is informational: the check does not block merging, and no approval is required at any size. Each repository's `Protect main - reviewed squash PRs` ruleset requires squash merges and linear history; only ryanbarlow97 and Drefvelin can bypass it. The logic lives in TLibs: [`tools/pr-size.py`](https://github.com/TF-Minecraft/TLibs/blob/main/tools/pr-size.py) and the `pr-size` action. Each plugin's `.github/workflows/pr-size.yml` pins the action to a reviewed TLibs commit; TLibs runs its own copy. ## Documentation and assets Docs checks local links and section anchors in every Markdown page, verifies navigation between the project list and project indexes, and builds CoreProtect's MkDocs site in strict mode. ServerAssets verifies every entry in its file manifest. Plugin build dependencies are downloaded from pinned ServerAssets commits and verified against their checksums. Both repositories run these checks for pull requests and pushes to `main`. They do not package archives, upload build artifacts, or publish GitHub releases. Use `main` for current content and commit SHAs when an exact revision is needed. ## ProvinceSystem PRs run frontend Vitest and backend pytest suites, upload JUnit reports, and build the Next.js frontend. CI uses Node 22 and Python 3.12; the backend tests use SQLite's connection-limit testing API. A failed suite prevents application artifact publication. Development artifacts include timestamped source and frontend archives, checksums, and build metadata. Both archives share the same root directory; extracting the frontend archive over the source archive supplies the compiled `.next` output and generated public assets. Dependencies and configuration must be installed separately to run the application. The frontend bundle uses `NEXT_PUBLIC_API_URL=http://127.0.0.1:8000` at build time. Build with the intended URL for a deployment that needs a different API endpoint. The pipeline does not deploy the application. Numeric `v*` tags must match `frontend/package.json`. The release workflow runs the same tests and build, then creates a draft archive release. ## Verification scope A successful pull request build verifies compilation, available unit tests, and packaging. Check the downloaded JAR's embedded version as well as its filename. A tagged release run additionally verifies draft publication and release assets. Minecraft runtime and integration tests are separate checks.