Files
Modrinth-Enhanced/.github/workflows/upstream-release.yml
T

162 lines
5.4 KiB
YAML

name: Upstream release
# Watches Modrinth for a new Modrinth App release, rebuilds Modrinth Enhanced
# on top of it, and publishes a release of our own if everything still works.
# When the patches changed since our last release of that upstream version,
# it publishes them again as a revision: v1.2.3-2, v1.2.3-3, ...
#
# Nothing is published unless the patches applied, the checks passed and all
# three platforms built, so an upstream change that breaks a patch stops here
# and reports a failure instead of shipping a broken build.
on:
schedule:
- cron: '17 6 * * *'
workflow_dispatch:
inputs:
upstream-ref:
description: Build this upstream tag instead of the newest one
type: string
required: false
permissions:
contents: write
concurrency:
group: upstream-release
cancel-in-progress: false
jobs:
detect:
name: Detect
runs-on: ubuntu-latest
outputs:
upstream: ${{ steps.check.outputs.upstream }}
tag: ${{ steps.check.outputs.tag }}
proceed: ${{ steps.check.outputs.proceed }}
steps:
- uses: actions/checkout@v4
- name: Decide what to release
id: check
env:
REQUESTED: ${{ inputs.upstream-ref }}
run: |
set -euo pipefail
current="$(tr -d '[:space:]' < upstream.txt)"
upstream="${REQUESTED:-$(scripts/latest-upstream.sh)}"
echo "upstream=$upstream" >> "$GITHUB_OUTPUT"
echo "Upstream release: $upstream (we are on $current)"
# Our newest release of it, as "<revision> <tag>". The plain tag is
# revision 1.
last="$(
git ls-remote --tags --refs origin "$upstream" "$upstream-*" |
sed 's#.*refs/tags/##' |
awk -v up="$upstream" '
$0 == up { print 1, $0; next }
index($0, up "-") == 1 {
n = substr($0, length(up) + 2)
if (n ~ /^[0-9]+$/) print n, $0
}' |
sort -n |
tail -1
)"
if [ -z "$last" ]; then
tag="$upstream"
else
revision="${last%% *}"
last_tag="${last#* }"
git fetch --no-tags --depth=1 origin "refs/tags/$last_tag:refs/tags/$last_tag"
# Only what goes into the build counts, not docs or CI.
if git diff --quiet "$last_tag" HEAD -- patches scripts; then
echo "$last_tag already ships the current patches; nothing to do."
echo "proceed=false" >> "$GITHUB_OUTPUT"
exit 0
fi
tag="$upstream-$((revision + 1))"
fi
echo "tag=$tag" >> "$GITHUB_OUTPUT"
echo "proceed=true" >> "$GITHUB_OUTPUT"
echo "Releasing $tag"
build:
name: Build
needs: detect
if: needs.detect.outputs.proceed == 'true'
uses: ./.github/workflows/build.yml
with:
upstream-ref: ${{ needs.detect.outputs.upstream }}
release:
name: Release
needs: [detect, build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Record the upstream release we build against
env:
UPSTREAM: ${{ needs.detect.outputs.upstream }}
run: |
set -euo pipefail
printf '%s\n' "$UPSTREAM" > upstream.txt
if git diff --quiet -- upstream.txt; then
echo "upstream.txt already points at $UPSTREAM"
exit 0
fi
git config user.name 'github-actions[bot]'
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
git commit -m "Track upstream $UPSTREAM" -- upstream.txt
git push origin HEAD:${{ github.event.repository.default_branch }}
- name: Download installers
uses: actions/download-artifact@v4
with:
path: artifacts
merge-multiple: true
- name: Publish the release
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ needs.detect.outputs.tag }}
UPSTREAM: ${{ needs.detect.outputs.upstream }}
run: |
set -euo pipefail
ls -la artifacts
# Every patch by its subject, so the list never falls behind.
patches="$(
for patch in patches/0*.patch; do
awk '/^Subject: /{
s = $0
sub(/^Subject: (\[PATCH[^]]*\] )?/, "", s)
while ((getline line) > 0 && line ~ /^ /) s = s line
print "- " s
exit
}' "$patch"
done
)"
notes="$(cat <<EOF
Modrinth Enhanced $TAG, built from [Modrinth App $UPSTREAM](https://github.com/modrinth/code/releases/tag/$UPSTREAM).
Same app as upstream, with the patches in \`patches/\` applied:
$patches
It keeps using the same data directory as the official Modrinth App,
so instances, settings and accounts carry over. Do not run both at
the same time.
See the upstream release notes for everything else that changed.
EOF
)"
# The tag goes on the commit that was built, not on whatever main is
# by now, so the next run compares against the patches it shipped.
gh release create "$TAG" \
--target "$(git rev-parse HEAD)" \
--title "Modrinth Enhanced $TAG" \
--notes "$notes" \
artifacts/*