Remove our launcher entry instead of restoring the launcher's whole file #6
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: release | |
| on: | |
| push: | |
| tags: ['v*'] | |
| workflow_dispatch: | |
| permissions: | |
| contents: write | |
| jobs: | |
| cli: | |
| name: CLI ${{ matrix.goos }}/${{ matrix.goarch }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| strategy: | |
| matrix: | |
| include: | |
| - goos: windows | |
| goarch: amd64 | |
| ext: .exe | |
| archive: zip | |
| - goos: linux | |
| goarch: amd64 | |
| ext: '' | |
| archive: tar.gz | |
| - goos: darwin | |
| goarch: arm64 | |
| ext: '' | |
| archive: tar.gz | |
| steps: | |
| - name: Check out source | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - name: Set up Go | |
| uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 | |
| with: | |
| go-version: '1.23.12' | |
| cache: true | |
| - name: Verify before packaging | |
| run: | | |
| go run ./cmd/mcjava-fixtures | |
| go test -count=1 ./... | |
| go vet ./... | |
| # Reproducible: trimmed paths, no VCS stamp, no cgo. The same source | |
| # produces the same binary, which matters for a tool whose output people | |
| # are asked to trust. | |
| # The tag is the version. A downloaded binary that reports 0.1.0-dev is | |
| # the one field a person checks when working out whether the bug they hit | |
| # is already fixed, and an injection that silently stops working produces | |
| # exactly that, so the next step proves the version reached the binary. | |
| - name: Build | |
| env: | |
| GOOS: ${{ matrix.goos }} | |
| GOARCH: ${{ matrix.goarch }} | |
| CGO_ENABLED: '0' | |
| run: | | |
| version="${GITHUB_REF_NAME#v}" | |
| if [ "$GITHUB_REF_TYPE" != "tag" ]; then version="0.0.0-untagged"; fi | |
| echo "version=${version}" >> "$GITHUB_ENV" | |
| mkdir -p dist | |
| go build -trimpath -buildvcs=false \ | |
| -ldflags="-s -w -X main.version=${version}" \ | |
| -o "dist/worldledger${{ matrix.ext }}" ./cmd/worldledger | |
| # mcprofile ships as well. The packaged documents promise that whoever | |
| # holds a release's jar can produce its profile, and tell the reader to | |
| # compare two of them after a Minecraft upgrade. Without the binary in | |
| # the archive, keeping that promise needs a source checkout and a Go | |
| # toolchain, which is not what the documents say. | |
| go build -trimpath -buildvcs=false \ | |
| -ldflags="-s -w" \ | |
| -o "dist/mcprofile${{ matrix.ext }}" ./cmd/mcprofile | |
| # The desktop application is a separate module, so it is built from | |
| # its own directory rather than by a relative package path, which does | |
| # not work across a module boundary. -H=windowsgui keeps a console | |
| # window from appearing behind the application's own: somebody who | |
| # double-clicks this should get one window, not two. | |
| gui="" | |
| if [ "${{ matrix.goos }}" = "windows" ]; then gui="-H=windowsgui"; fi | |
| # Where the application will fetch its own mod jar from. It is this | |
| # release's own asset, named by the same version the mod job builds | |
| # under, so a released build installs without being told anything and | |
| # a build from source still refuses rather than guessing. | |
| # | |
| # The URL is resolved when somebody installs, not now, so it does not | |
| # matter that the asset is uploaded by a different job or that the | |
| # release is still a draft at this point. | |
| mod_url="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/releases/download/${GITHUB_REF_NAME}/worldledger-fabric-${version}.jar" | |
| ( cd desktop && go build -trimpath -buildvcs=false \ | |
| -ldflags="-s -w ${gui} -X main.version=${version} \ | |
| -X github.com/worldledger/worldledger-mc/desktop/internal/api.ModSource=${mod_url}" \ | |
| -o "../dist/worldledger-desktop${{ matrix.ext }}" . ) | |
| # The native build is asked directly. A cross-compiled one cannot run | |
| # here, so its binary is checked for the string instead, which is weaker | |
| # but still fails when the injection is dropped. | |
| - name: Check the release version reached the binary | |
| run: | | |
| if [ "${{ matrix.goos }}" = "linux" ] && [ "${{ matrix.goarch }}" = "amd64" ]; then | |
| reported="$(./dist/worldledger version)" | |
| if [ "$reported" != "worldledger ${version}" ]; then | |
| echo "the binary reports '${reported}', expected 'worldledger ${version}'" >&2 | |
| exit 1 | |
| fi | |
| echo "${reported}" | |
| else | |
| if ! grep -qa -- "${version}" "dist/worldledger${{ matrix.ext }}"; then | |
| echo "the ${{ matrix.goos }}/${{ matrix.goarch }} binary does not carry version ${version}" >&2 | |
| exit 1 | |
| fi | |
| echo "version ${version} is embedded in the ${{ matrix.goos }}/${{ matrix.goarch }} binary" | |
| fi | |
| # Windows gets a zip. tar.gz is openable there now, but handing a Windows | |
| # user an archive their file manager will not expand is a needless first | |
| # obstacle from a project whose problem is already that nobody gets past | |
| # the install. | |
| - name: Package with the documents a user needs | |
| run: | | |
| cd dist | |
| cp ../LICENSE ../NOTICE ../README.md ../CHANGELOG.md ../CONTRIBUTING.md ../SECURITY.md . | |
| mkdir -p profiles adapters/fabric | |
| cp ../profiles/*.json profiles/ | |
| cp -r ../docs ../spec ../examples . | |
| cp ../adapters/fabric/README.md ../adapters/fabric/gradle.properties adapters/fabric/ | |
| # -X against a package path that does not match writes nothing and says | |
| # nothing. A desktop application that came out of that would look fine, | |
| # start fine, and refuse to install, which is the whole of what this | |
| # release is for. So the address is looked for in the binary. | |
| - name: Check the desktop application knows where its mod is | |
| run: | | |
| mod_url="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/releases/download/${GITHUB_REF_NAME}/worldledger-fabric-${version}.jar" | |
| if ! grep -qa -- "${mod_url}" "dist/worldledger-desktop${{ matrix.ext }}"; then | |
| echo "the ${{ matrix.goos }}/${{ matrix.goarch }} desktop binary does not carry ${mod_url};" >&2 | |
| echo "the -X package path is probably wrong, and it would refuse to install" >&2 | |
| exit 1 | |
| fi | |
| echo "it will fetch the mod from ${mod_url}" | |
| # ci.yml runs on pushes to main and on pull requests, not on tags, so a | |
| # tag is the one push where this would otherwise not be checked -- and it | |
| # is the push that produces the archive. | |
| - name: Check the packaged documents only invoke commands the release builds | |
| run: ./scripts/check-packaged-commands.sh | |
| # A README whose links go nowhere is worse than one that says less. The | |
| # packaged set is checked against what the packaged documents actually | |
| # reference, so adding a link without adding the file fails the release | |
| # rather than shipping a dead end. | |
| - name: Check every packaged link resolves inside the package | |
| working-directory: dist | |
| run: | | |
| while IFS= read -r document; do | |
| directory=$(dirname "$document") | |
| grep -oE '\]\([^)#][^)]*\)' "$document" 2>/dev/null | | |
| sed 's/](//; s/)$//; s/#.*$//' | | |
| grep -vE '^[a-z]+:' | | |
| while IFS= read -r target; do | |
| [ -z "$target" ] && continue | |
| [ -e "$directory/$target" ] || echo "$document -> $target" | |
| done | |
| done < <(find . -name '*.md') > /tmp/broken-links | |
| if [ -s /tmp/broken-links ]; then | |
| echo "the packaged documents reference files the package does not contain:" >&2 | |
| sed 's/^/ /' /tmp/broken-links >&2 | |
| exit 1 | |
| fi | |
| echo "every relative link in the packaged documents resolves" | |
| - name: Archive | |
| run: | | |
| cd dist | |
| name="worldledger-${{ matrix.goos }}-${{ matrix.goarch }}" | |
| if [ "${{ matrix.archive }}" = "zip" ]; then | |
| zip -qr "../${name}.zip" . | |
| else | |
| tar -czf "../${name}.tar.gz" . | |
| fi | |
| cd .. | |
| sha256sum "${name}.${{ matrix.archive }}" > "${name}.${{ matrix.archive }}.sha256" | |
| # The desktop application also goes up on its own, not only inside the | |
| # archive. Somebody who is here because they do not want a terminal | |
| # should not have to download a zip, find the right file inside it and | |
| # know which one it is; the releases page should have a thing to click. | |
| desktop="worldledger-desktop-${{ matrix.goos }}-${{ matrix.goarch }}${{ matrix.ext }}" | |
| cp "dist/worldledger-desktop${{ matrix.ext }}" "${desktop}" | |
| sha256sum "${desktop}" > "${desktop}.sha256" | |
| - name: Upload | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: worldledger-${{ matrix.goos }}-${{ matrix.goarch }} | |
| path: | | |
| worldledger-*.tar.gz | |
| worldledger-*.zip | |
| worldledger-*.sha256 | |
| worldledger-desktop-* | |
| mod: | |
| name: Fabric mod JAR | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| steps: | |
| - name: Check out source | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - name: Set up Java 25 | |
| uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5.7.0 | |
| with: | |
| distribution: temurin | |
| java-version: '25' | |
| - name: Validate wrapper and set up Gradle | |
| uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6.3.0 | |
| with: | |
| cache-provider: basic | |
| # Same reasoning as the CLI: the JAR filename and the version the loader | |
| # reports both come from this, and a release that installs as 0.1.0-dev | |
| # cannot be told apart from a local build. | |
| - name: Build | |
| working-directory: adapters/fabric | |
| run: | | |
| version="${GITHUB_REF_NAME#v}" | |
| if [ "$GITHUB_REF_TYPE" != "tag" ]; then version="0.0.0-untagged"; fi | |
| ./gradlew --no-daemon clean build --warning-mode all "-Pmod_version=${version}" | |
| # Only the mod. A sources JAR published beside it has a near-identical | |
| # name, and installing the wrong one fails silently: the loader finds no | |
| # mod and the player finds no explanation. Source is on the repository | |
| # page for anyone who wants it. | |
| - name: Checksum the installable JAR | |
| working-directory: adapters/fabric/build/libs | |
| run: | | |
| rm -f ./*-sources.jar ./*-javadoc.jar | |
| count=$(ls -1 ./*.jar | wc -l) | |
| if [ "$count" != "1" ]; then | |
| echo "expected exactly one installable JAR, found ${count}:" >&2 | |
| ls -1 ./*.jar >&2 | |
| exit 1 | |
| fi | |
| sha256sum ./*.jar > SHA256SUMS.txt | |
| cat SHA256SUMS.txt | |
| - name: Upload | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: worldledger-fabric-mod | |
| path: | | |
| adapters/fabric/build/libs/*.jar | |
| adapters/fabric/build/libs/SHA256SUMS.txt | |
| publish: | |
| name: Publish release | |
| needs: [cli, mod] | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - name: Check out source | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - name: Collect artifacts | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | |
| with: | |
| path: artifacts | |
| merge-multiple: true | |
| # The body is this version's entry, not the whole file. A release note | |
| # that repeats every previous release buries what changed, and the check | |
| # below stops a build from publishing the previous version's notes under | |
| # a new tag. | |
| - name: Take this version's notes from the changelog | |
| run: | | |
| awk '/^## /{ if (seen) exit; seen = 1 } seen' CHANGELOG.md > release-notes.md | |
| if [ ! -s release-notes.md ]; then | |
| echo "CHANGELOG.md has no version entry to publish" >&2 | |
| exit 1 | |
| fi | |
| version="${GITHUB_REF_NAME#v}" | |
| if ! head -1 release-notes.md | grep -qF -- "${version}"; then | |
| echo "the changelog's top entry is '$(head -1 release-notes.md)', which is not ${version}" >&2 | |
| exit 1 | |
| fi | |
| head -1 release-notes.md | |
| # Drafted rather than published: a release carries a capture adapter and a | |
| # world exporter, and a person should look at what is being handed out | |
| # before it reaches anyone. | |
| - name: Draft the release | |
| uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2 | |
| with: | |
| draft: true | |
| files: | | |
| artifacts/**/*.tar.gz | |
| artifacts/**/*.zip | |
| artifacts/**/*.sha256 | |
| artifacts/**/*.jar | |
| artifacts/**/SHA256SUMS.txt | |
| artifacts/**/worldledger-desktop-* | |
| body_path: release-notes.md | |
| **Java Edition 26.2 only.** The adapter is pinned to one Minecraft | |
| release; see `docs/adapter-versioning.md`. | |
| Read `NOTICE` before use. |