Skip to content

Remove our launcher entry instead of restoring the launcher's whole file #6

Remove our launcher entry instead of restoring the launcher's whole file

Remove our launcher entry instead of restoring the launcher's whole file #6

Workflow file for this run

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.