name: CI
on:
push:
branches: [main, master]
tags: ["v*"]
pull_request:
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ !startsWith(github.ref, 'refs/tags/') }}
jobs:
wrappers-and-docs:
name: Wrappers and API specification
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate Gradle wrappers against the official checksum database
uses: gradle/actions/wrapper-validation@v4
- name: Verify repository-pinned wrapper checksums
run: bash scripts/verify-wrappers.sh
- name: Lint OpenAPI 3.1
run: npx --yes @redocly/cli@1.34.5 lint --config docs/redocly.yaml docs/openapi.yaml
- name: Lint Bash scripts
run: shellcheck scripts/*.sh
- name: Lint PowerShell scripts
shell: pwsh
run: |
Set-PSRepository PSGallery -InstallationPolicy Trusted
Install-Module PSScriptAnalyzer -Scope CurrentUser -Force
$issues = Invoke-ScriptAnalyzer -Path scripts -Recurse -Severity Error,Warning
$issues | Format-Table -AutoSize
if ($issues) { exit 1 }
web-ui:
name: Web UI
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 24
cache: npm
cache-dependency-path: web-ui/package-lock.json
- run: npm ci
working-directory: web-ui
- run: npm test
working-directory: web-ui
- run: npm run build
working-directory: web-ui
- uses: actions/upload-artifact@v4
with:
name: web-ui-dist
path: web-ui/dist
if-no-files-found: error
retention-days: 3
common:
name: Common modules (${{ matrix.os }})
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "17"
cache: gradle
- uses: gradle/actions/setup-gradle@v4
- name: Test common modules and SQLite native loading
shell: bash
run: bash ./gradlew --no-daemon check
- name: Enforce clean dependency resolution
shell: bash
run: bash ./gradlew --no-daemon dependencies
forge:
name: Forge ${{ matrix.minecraft }}
needs: [wrappers-and-docs, web-ui, common]
strategy:
fail-fast: false
matrix:
include:
- minecraft: "1.20.1"
java: "17"
- minecraft: "1.20.6"
java: "21"
- minecraft: "1.21.1"
java: "21"
- minecraft: "1.21.11"
java: "21"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: ${{ matrix.java }}
cache: gradle
- uses: gradle/actions/setup-gradle@v4
- uses: actions/download-artifact@v4
with:
name: web-ui-dist
path: web-ui/dist
- name: Resolve release version
shell: bash
run: |
if [[ "$GITHUB_REF" == refs/tags/v* ]]; then
echo "MOD_VERSION=${GITHUB_REF_NAME#v}" >> "$GITHUB_ENV"
else
echo "MOD_VERSION=0.1.0-SNAPSHOT" >> "$GITHUB_ENV"
fi
- name: Build and test Forge adapter
working-directory: platform/forge-${{ matrix.minecraft }}
run: bash ./gradlew --no-daemon clean check assemble -Pmod_version="$MOD_VERSION"
- name: Stage distributable JAR
shell: bash
run: |
mkdir -p staging
jar="$(find "platform/forge-${{ matrix.minecraft }}/build/libs" -maxdepth 1 -type f \
-name 'xfeservermanager-forge-${{ matrix.minecraft }}-*.jar' \
! -name '*-slim.jar' ! -name '*-sources.jar' ! -name '*-javadoc.jar' \
-print -quit)"
test -n "$jar"
cp "$jar" "staging/xfeservermanager-forge-${{ matrix.minecraft }}-${MOD_VERSION}.jar"
- uses: actions/upload-artifact@v4
with:
name: forge-${{ matrix.minecraft }}
path: staging/*.jar
if-no-files-found: error
retention-days: 14
sbom:
name: SBOM
needs: forge
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
pattern: forge-*
path: release
merge-multiple: true
- name: Generate CycloneDX SBOM
uses: anchore/sbom-action@v0
with:
path: release
format: cyclonedx-json
output-file: release/xfeservermanager-sbom.cdx.json
upload-artifact: false
- uses: actions/upload-artifact@v4
with:
name: sbom
path: release/xfeservermanager-sbom.cdx.json
if-no-files-found: error
retention-days: 14
release:
name: GitHub Release
if: startsWith(github.ref, 'refs/tags/v')
needs: [forge, sbom]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/download-artifact@v4
with:
pattern: forge-*
path: release
merge-multiple: true
- uses: actions/download-artifact@v4
with:
name: sbom
path: release
- name: Write SHA-256 checksums
working-directory: release
run: sha256sum xfeservermanager-forge-*.jar xfeservermanager-sbom.cdx.json > SHA256SUMS
- name: Publish immutable release assets
uses: softprops/action-gh-release@v2
with:
fail_on_unmatched_files: true
generate_release_notes: true
files: |
release/xfeservermanager-forge-*.jar
release/xfeservermanager-sbom.cdx.json
release/SHA256SUMS
name: CI
on:
push:
branches: [main, master]
tags: ["v*"]
pull_request:
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ !startsWith(github.ref, 'refs/tags/') }}
jobs:
wrappers-and-docs:
name: Wrappers and API specification
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate Gradle wrappers against the official checksum database
uses: gradle/actions/wrapper-validation@v4
- name: Verify repository-pinned wrapper checksums
run: bash scripts/verify-wrappers.sh
- name: Lint OpenAPI 3.1
run: npx --yes @redocly/cli@1.34.5 lint --config docs/redocly.yaml docs/openapi.yaml
- name: Lint Bash scripts
run: shellcheck scripts/*.sh
- name: Lint PowerShell scripts
shell: pwsh
run: |
Set-PSRepository PSGallery -InstallationPolicy Trusted
Install-Module PSScriptAnalyzer -Scope CurrentUser -Force
$issues = Invoke-ScriptAnalyzer -Path scripts -Recurse -Severity Error,Warning
$issues | Format-Table -AutoSize
if ($issues) { exit 1 }
web-ui:
name: Web UI
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 24
cache: npm
cache-dependency-path: web-ui/package-lock.json
- run: npm ci
working-directory: web-ui
- run: npm test
working-directory: web-ui
- run: npm run build
working-directory: web-ui
- uses: actions/upload-artifact@v4
with:
name: web-ui-dist
path: web-ui/dist
if-no-files-found: error
retention-days: 3
common:
name: Common modules (${{ matrix.os }})
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "17"
cache: gradle
- uses: gradle/actions/setup-gradle@v4
- name: Test common modules and SQLite native loading
shell: bash
run: bash ./gradlew --no-daemon check
- name: Enforce clean dependency resolution
shell: bash
run: bash ./gradlew --no-daemon dependencies
forge:
name: Forge ${{ matrix.minecraft }}
needs: [wrappers-and-docs, web-ui, common]
strategy:
fail-fast: false
matrix:
include:
- minecraft: "1.20.1"
java: "17"
- minecraft: "1.20.6"
java: "21"
- minecraft: "1.21.1"
java: "21"
- minecraft: "1.21.11"
java: "21"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: ${{ matrix.java }}
cache: gradle
- uses: gradle/actions/setup-gradle@v4
- uses: actions/download-artifact@v4
with:
name: web-ui-dist
path: web-ui/dist
- name: Resolve release version
shell: bash
run: |
if [[ "$GITHUB_REF" == refs/tags/v* ]]; then
echo "MOD_VERSION=${GITHUB_REF_NAME#v}" >> "$GITHUB_ENV"
else
echo "MOD_VERSION=0.1.0-SNAPSHOT" >> "$GITHUB_ENV"
fi
- name: Build and test Forge adapter
working-directory: platform/forge-${{ matrix.minecraft }}
run: bash ./gradlew --no-daemon clean check assemble -Pmod_version="$MOD_VERSION"
- name: Stage distributable JAR
shell: bash
run: |
mkdir -p staging
jar="$(find "platform/forge-${{ matrix.minecraft }}/build/libs" -maxdepth 1 -type f \
-name 'xfeservermanager-forge-${{ matrix.minecraft }}-*.jar' \
! -name '*-slim.jar' ! -name '*-sources.jar' ! -name '*-javadoc.jar' \
-print -quit)"
test -n "$jar"
cp "$jar" "staging/xfeservermanager-forge-${{ matrix.minecraft }}-${MOD_VERSION}.jar"
- uses: actions/upload-artifact@v4
with:
name: forge-${{ matrix.minecraft }}
path: staging/*.jar
if-no-files-found: error
retention-days: 14
sbom:
name: SBOM
needs: forge
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
pattern: forge-*
path: release
merge-multiple: true
- name: Generate CycloneDX SBOM
uses: anchore/sbom-action@v0
with:
path: release
format: cyclonedx-json
output-file: release/xfeservermanager-sbom.cdx.json
upload-artifact: false
- uses: actions/upload-artifact@v4
with:
name: sbom
path: release/xfeservermanager-sbom.cdx.json
if-no-files-found: error
retention-days: 14
release:
name: GitHub Release
if: startsWith(github.ref, 'refs/tags/v')
needs: [forge, sbom]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/download-artifact@v4
with:
pattern: forge-*
path: release
merge-multiple: true
- uses: actions/download-artifact@v4
with:
name: sbom
path: release
- name: Write SHA-256 checksums
working-directory: release
run: sha256sum xfeservermanager-forge-*.jar xfeservermanager-sbom.cdx.json > SHA256SUMS
- name: Publish immutable release assets
uses: softprops/action-gh-release@v2
with:
fail_on_unmatched_files: true
generate_release_notes: true
files: |
release/xfeservermanager-forge-*.jar
release/xfeservermanager-sbom.cdx.json
release/SHA256SUMS