Install ReUI (MCP, skill, @reui registry, Tailwind v4, shadcn base-nova) and move the shared UI onto it: Button, Tag, Check, Input/Textarea, Segmented, Alert, Panel, Dialog, Tooltip, Menu and Select (Popover), Toast (sonner), the Table frame (DataGrid), the Dashboard KPI strip, the shnt Ops palette, Geist and the type scale. Design only: behaviour, texts and roles are unchanged. Tests that asserted the old DOM were updated; the tests now format numbers in English wherever they run. docs/reui-migration-plan.md records the plan and its decisions. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
201 lines
9.6 KiB
YAML
201 lines
9.6 KiB
YAML
# Builds the console and attaches it to the release, because that tarball is
|
|
# what install.sh downloads. Without this there is nothing to install.
|
|
#
|
|
# npm (the dependencies' install scripts, the tests, the build) runs only in
|
|
# `tarball`, which can read the repo and nothing else. The job that can write
|
|
# to the repo, `release`, gets just the tarball and its checksum.
|
|
name: Release
|
|
|
|
on:
|
|
push:
|
|
tags: ['v*']
|
|
workflow_dispatch:
|
|
|
|
permissions: {}
|
|
|
|
jobs:
|
|
tarball:
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
persist-credentials: false
|
|
|
|
# The same tarball the develop image is built from (develop-image.yml).
|
|
- uses: ./.github/actions/console-tarball
|
|
|
|
- uses: actions/upload-artifact@v7
|
|
with:
|
|
name: console-tarball
|
|
path: |
|
|
technitium-console.tar.gz
|
|
technitium-console.tar.gz.sha256
|
|
if-no-files-found: error
|
|
# A day: "Re-run failed jobs" of `release` after that fails at the
|
|
# download; "Re-run all jobs" is the way.
|
|
retention-days: 1
|
|
|
|
release:
|
|
needs: tarball
|
|
# Tags only: a manual run from a branch must not publish a release named
|
|
# after it. The image job below has the same guard.
|
|
if: startsWith(github.ref, 'refs/tags/v')
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: write
|
|
steps:
|
|
# For CHANGELOG.md and the tags; no npm here. The token is not left in
|
|
# .git/config: only the release step below gets it, as an input.
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
persist-credentials: false
|
|
|
|
# Outside the workspace: the artifact comes from the job that runs npm,
|
|
# and nothing in it may land over the checkout whose script and
|
|
# CHANGELOG.md the steps below use. Same place as develop-image.yml.
|
|
- uses: actions/download-artifact@v8
|
|
with:
|
|
name: console-tarball
|
|
path: ${{ runner.temp }}/tarball
|
|
|
|
# Exactly the two files the tarball job packs, and the bytes checked
|
|
# against the checksum, before anything is published.
|
|
- name: The tarball, checked against its checksum
|
|
working-directory: ${{ runner.temp }}/tarball
|
|
run: |
|
|
set -eu
|
|
found="$(find . -mindepth 1 | LC_ALL=C sort | tr '\n' ' ')"
|
|
expected="./technitium-console.tar.gz ./technitium-console.tar.gz.sha256 "
|
|
if [ "$found" != "$expected" ] || [ -n "$(find . -mindepth 1 ! -type f)" ]; then
|
|
echo "The artifact holds something other than the tarball and its checksum: $found" >&2
|
|
exit 1
|
|
fi
|
|
sha256sum -c technitium-console.tar.gz.sha256
|
|
|
|
# Docker's floating tags only ever move forward (latest to the highest
|
|
# release, X.Y to the highest of its line; prereleases move neither), as
|
|
# .github/actions/init-image/floating-tags.sh decides. The notes below
|
|
# need to know whether latest will be this release; the image job does not
|
|
# take it from here, it decides again right before moving the tags.
|
|
- name: Which floating tags this release moves
|
|
id: floating
|
|
shell: bash
|
|
run: |
|
|
# Anonymous: the repo is public and checkout kept no token. If it ever
|
|
# cannot read the tags, pipefail or the script's guard fails the release.
|
|
floating="$(git ls-remote --tags --refs origin 'v*' | sh .github/actions/init-image/floating-tags.sh "$GITHUB_REF_NAME")"
|
|
latest=false
|
|
case " $floating " in *" latest "*) latest=true ;; esac
|
|
echo "latest=$latest" >> "$GITHUB_OUTPUT"
|
|
|
|
# The release page is what people read, so it carries this version's own
|
|
# section of CHANGELOG.md. A tag with no section there fails here instead of
|
|
# publishing a release that says nothing.
|
|
- name: Release notes
|
|
id: notes
|
|
shell: bash
|
|
env:
|
|
LATEST: ${{ steps.floating.outputs.latest }}
|
|
run: |
|
|
tag="${GITHUB_REF_NAME}"
|
|
# A prerelease (vX.Y.Z-rc.N) reads the section of the version it previews.
|
|
base="${tag%%-*}"
|
|
awk -v head="## ${base} " 'index($0, head) == 1 { on = 1; next } on && /^## v/ { exit } on' CHANGELOG.md \
|
|
| sed '/^---$/d' > section.md
|
|
# Release pages keep every newline, so the wrapped paragraphs of
|
|
# CHANGELOG.md are joined back into one line each.
|
|
python3 - <<'PY'
|
|
out = []
|
|
for line in open('section.md').read().split('\n'):
|
|
cont = line.startswith(' ') and not line.lstrip().startswith(('- ', '|', '#'))
|
|
plain = line and not line.startswith(('- ', '#', '|', '```')) and not line.startswith(' ')
|
|
if out and out[-1] and not out[-1].startswith(('#', '|')) and (cont or plain):
|
|
out[-1] += ' ' + line.strip()
|
|
else:
|
|
out.append(line)
|
|
open('notes.md', 'w').write('\n'.join(out))
|
|
PY
|
|
[ -s notes.md ] || { echo "CHANGELOG.md has no section for ${base}"; exit 1; }
|
|
# The installer's default is the latest release, which a prerelease
|
|
# never is: it is installed by naming it.
|
|
# shellcheck disable=SC2016 # the backticks are Markdown, not a command
|
|
if [ "$base" != "$tag" ]; then
|
|
printf '\n**A prerelease, for testing:** the one-line installer from the [README](https://github.com/byGarcia/technitium-console#installing) installs it with `sh -s -- --version %s`, and goes back with `--version` and the release you had. Which console goes with which server: [CHANGELOG](https://github.com/byGarcia/technitium-console/blob/main/CHANGELOG.md#which-version-for-which-server).\n' "$tag"
|
|
else
|
|
printf '\n**Install or update:** run the one-line installer from the [README](https://github.com/byGarcia/technitium-console#installing) again. Which console goes with which server: [CHANGELOG](https://github.com/byGarcia/technitium-console/blob/main/CHANGELOG.md#which-version-for-which-server).\n'
|
|
fi >> notes.md
|
|
echo "prerelease=$([ "$base" != "$tag" ] && echo true || echo false)" >> "$GITHUB_OUTPUT"
|
|
# The image job below publishes this same release for Docker. Pulling
|
|
# only brings it when it is the one latest points at.
|
|
# shellcheck disable=SC2016 # the backticks are Markdown, not a command
|
|
if [ "$LATEST" = true ]; then
|
|
printf '\n**On Docker:** `docker compose pull technitium-console && docker compose up -d technitium-console`, or pin `ghcr.io/bygarcia/technitium-console:%s`. See [Docker](https://github.com/byGarcia/technitium-console#docker).\n' "${tag#v}"
|
|
else
|
|
printf '\n**On Docker:** pin `ghcr.io/bygarcia/technitium-console:%s`. See [Docker](https://github.com/byGarcia/technitium-console#docker).\n' "${tag#v}"
|
|
fi >> notes.md
|
|
# The title is the tag and the section's opening bold sentence.
|
|
lead="$({ grep -m1 -o '^\*\*[^*]*\*\*' notes.md || true; } | sed 's/^\*\*//; s/\*\*$//; s/\.$//')"
|
|
echo "title=${tag}${lead:+: ${lead}}" >> "$GITHUB_OUTPUT"
|
|
cat notes.md
|
|
|
|
- uses: softprops/action-gh-release@v2
|
|
with:
|
|
token: ${{ github.token }}
|
|
files: |
|
|
${{ runner.temp }}/tarball/technitium-console.tar.gz
|
|
${{ runner.temp }}/tarball/technitium-console.tar.gz.sha256
|
|
name: ${{ steps.notes.outputs.title }}
|
|
body_path: notes.md
|
|
generate_release_notes: true
|
|
# A prerelease is never the one releases/latest, and so install.sh's
|
|
# default, points at. A release leaves it unset, as before: an explicit
|
|
# true would also move latest back when an older tag is re-run.
|
|
prerelease: ${{ steps.notes.outputs.prerelease }}
|
|
make_latest: ${{ steps.notes.outputs.prerelease == 'true' && 'false' || '' }}
|
|
|
|
# The init image for Docker (README, "Docker"), from the tarball the job
|
|
# above has just published: X.Y.Z is pushed and checked in every platform
|
|
# (contract D4), and only then do X.Y and latest move, decided in that same
|
|
# step from the tags as they are then, so a re-run of this job alone never
|
|
# moves them back. The steps live in .github/actions/init-image, shared with
|
|
# the develop image. GITHUB_TOKEN is the only credential. A package's first
|
|
# publication is private: it is made public by hand, once.
|
|
image:
|
|
needs: release
|
|
if: startsWith(github.ref, 'refs/tags/v')
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
packages: write
|
|
# Two runs of one tag never push over each other.
|
|
concurrency:
|
|
group: image-${{ github.ref }}
|
|
cancel-in-progress: false
|
|
# bash -eo pipefail: a failing command in a pipe fails the step.
|
|
defaults:
|
|
run:
|
|
shell: bash
|
|
steps:
|
|
# For install.sh, docker/Dockerfile and the image action; no npm here.
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
persist-credentials: false
|
|
|
|
# The bytes people download, not a second build of them.
|
|
- name: The release's own tarball
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
run: |
|
|
gh release download "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" --dir "$RUNNER_TEMP/release" \
|
|
--pattern technitium-console.tar.gz --pattern technitium-console.tar.gz.sha256
|
|
|
|
# vX.Y.Z is pushed as X.Y.Z alone; a prerelease as its own version only.
|
|
- uses: ./.github/actions/init-image
|
|
with:
|
|
image: ghcr.io/bygarcia/technitium-console
|
|
tarball-dir: ${{ runner.temp }}/release
|
|
tags: type=semver,pattern={{version}}
|
|
release-tag: ${{ github.ref_name }}
|