Files
vibe-kanban/.gitea/workflows/host-release.yml
rob thijssen ce825d9c93
Some checks failed
host-release / build (push) Failing after 19m50s
host-release / package (43) (push) Has been skipped
host-release / package (44) (push) Has been skipped
host-release / publish (43) (push) Has been skipped
host-release / publish (44) (push) Has been skipped
host: build and publish the local server as a signed RPM
The banner on a host comes from `npx vibe-kanban` fetching upstream's
published 0.1.44, which embeds upstream's frontend. Our fork already fixes
that UI -- the revert restored LocalProjectKanban and showCloudShutdownBanner
is pinned false in SharedAppLayout, which local-web uses -- it just was not
in the binary anyone was running.

npx cannot be pointed at us. npx-cli resolves its download from R2_BASE_URL,
a placeholder substituted at npm-publish time to BloopAI's bucket, with no
runtime override. That bucket serves the sunset binary and dies with them.

So build our own. crates/server embeds packages/local-web/dist via rust-embed
and crates/server/build.rs reads VK_SHARED_API_BASE at compile time, so one
build yields the fixed UI and our endpoints as defaults, with no environment
on the command line -- std::env::var still wins at runtime for overrides.

Packaged as an RPM to rpm.lair.cafe, mirroring lair/claude-desktop-package:
package and publish on the `rpm` runner, sign, rsync to oolon, createrepo
under the shared flock. The compile runs first on a podman runner instead, so
this never depends on the rpm host's toolchain matching the nightly pinned in
rust-toolchain.toml.

Built on bookworm although the target is Fedora 43/44: glibc compatibility is
forward-only, so one binary covers both. The build fails closed if the sunset
strings reappear or the baked endpoint is missing.

Needs RPM_SIGNING_KEY, RPM_SIGNING_KEY_ID and RSYNC_SSH_KEY on this repo;
they currently exist only on lair/claude-desktop-package.
2026-07-21 19:34:06 +03:00

199 lines
6.8 KiB
YAML

name: host-release
# Build the LOCAL vibe-kanban server and publish it as a signed RPM to
# rpm.lair.cafe, so a host installs it with dnf instead of `npx vibe-kanban`.
#
# npx is not an option here: npx-cli resolves its download from R2_BASE_URL, a
# placeholder substituted at npm-publish time to BloopAI's bucket, with no
# runtime override (npx-cli/src/download.ts). That serves upstream's binary --
# which still carries the product sunset -- from infrastructure that disappears
# when they do.
#
# Convention mirrors lair/claude-desktop-package: package and publish on the
# `rpm` runner, sign with RPM_SIGNING_KEY, rsync to oolon, createrepo under
# flock. The compile happens first on a podman runner rather than on the rpm
# runner, so this never depends on a host toolchain matching the pinned
# nightly in rust-toolchain.toml.
on:
push:
branches: [main]
paths:
- "crates/**"
- "packages/local-web/**"
- "packages/web-core/**"
- "packages/ui/**"
- "shared/**"
- "Cargo.toml"
- "Cargo.lock"
- "rust-toolchain.toml"
- "rpm/**"
- ".gitea/workflows/host-release.yml"
workflow_dispatch:
concurrency:
group: host-release
cancel-in-progress: false
jobs:
build:
runs-on:
- metal
- podman
timeout-minutes: 120
steps:
- uses: actions/checkout@v4
- name: derive version
id: meta
run: |
set -euo pipefail
echo "version=$(jq -r .version package.json)" >> "$GITHUB_OUTPUT"
echo "commit=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT"
- name: build the host binary
run: |
set -euo pipefail
# --target export writes the binary straight out of the scratch stage,
# so nothing has to be extracted from an image afterwards.
mkdir -p out
podman build --pull=newer \
-f rpm/Containerfile \
--target export \
--output type=local,dest=out \
.
test -s out/vibe-kanban
chmod 0755 out/vibe-kanban
file out/vibe-kanban || true
- name: sanity-check the binary
run: |
set -euo pipefail
# The whole point of building our own: upstream's carries the sunset.
if grep -qa "Project functionality has been retired" out/vibe-kanban; then
echo "ERROR: the sunset page is embedded in the host binary."
echo "The revert of #3387 has been lost -- refusing to publish."
exit 1
fi
if grep -qa "Cloud is shutting down" out/vibe-kanban; then
echo "ERROR: the cloud-shutdown banner is embedded in the host binary."
exit 1
fi
# And it must point at us, not at api.vibekanban.com.
grep -qa "kanban.internal" out/vibe-kanban \
|| { echo "ERROR: baked API base missing from the binary"; exit 1; }
echo "ok: no sunset UI, lair endpoints baked in"
- uses: actions/upload-artifact@v3
with:
name: host-binary
path: out/vibe-kanban
retention-days: 7
outputs:
version: ${{ steps.meta.outputs.version }}
commit: ${{ steps.meta.outputs.commit }}
package:
needs: build
runs-on: rpm
strategy:
fail-fast: false
matrix:
fedora_version: ["43", "44"]
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v3
with:
name: host-binary
path: bin/
- name: rpmbuild
run: |
set -euo pipefail
find bin/ -name vibe-kanban -exec mv --target-directory=bin/ {} + 2>/dev/null || true
mkdir -p ~/rpmbuild/SOURCES
install -m 0755 bin/vibe-kanban ~/rpmbuild/SOURCES/vibe-kanban
rpmbuild -bb rpm/vibe-kanban.spec \
--define "vk_version ${{ needs.build.outputs.version }}" \
--define "vk_commit ${{ needs.build.outputs.commit }}" \
--define "dist .fc${{ matrix.fedora_version }}"
ls -l ~/rpmbuild/RPMS/x86_64/
- uses: actions/upload-artifact@v3
with:
name: rpm-fc${{ matrix.fedora_version }}
path: ~/rpmbuild/RPMS/x86_64/*.rpm
retention-days: 7
publish:
needs: package
runs-on: rpm
env:
RPM_REPO_HOST: oolon.kosherinata.internal
strategy:
fail-fast: false
matrix:
fedora_version: ["43", "44"]
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v3
with:
name: rpm-fc${{ matrix.fedora_version }}
path: rpms/
- name: Flatten RPM artifacts
run: |
find rpms/ -name '*.rpm' -exec mv --target-directory=rpms/ {} +
find rpms/ -mindepth 1 -type d -empty -delete
- name: Import signing key
run: |
echo "${{ secrets.RPM_SIGNING_KEY }}" | gpg --batch --import
fpr=$(gpg --batch --with-colons --list-keys "${{ secrets.RPM_SIGNING_KEY_ID }}" | awk -F: '/^fpr:/ { print $10; exit }')
echo "${fpr}:6:" | gpg --batch --import-ownertrust
sed "s/@GPG_NAME@/${{ secrets.RPM_SIGNING_KEY_ID }}/" rpm/rpmmacros > ~/.rpmmacros
- name: Sign RPMs
run: |
for rpm in rpms/*.rpm; do
echo "signing ${rpm}..."
rpm --addsign "${rpm}"
done
- name: Set up SSH
run: |
install --directory --mode 700 ~/.ssh
echo "${RSYNC_SSH_KEY}" | install --mode 600 /dev/stdin ~/.ssh/id_ed25519
env:
RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
- name: Test SSH connectivity
run: |
ssh -o StrictHostKeyChecking=accept-new "gitea_ci@${RPM_REPO_HOST}" exit
- name: Sync RPMs to repo
run: |
rsync \
--archive \
--verbose \
--chmod D755,F644 \
rpms/*.rpm \
"gitea_ci@${RPM_REPO_HOST}:/var/www/rpm/fedora/${{ matrix.fedora_version }}/x86_64/"
- name: Update repo metadata
run: |
# flock guards createrepo against concurrent publishes into the
# shared repo tree (other package repos publish here too).
ssh "gitea_ci@${RPM_REPO_HOST}" \
"flock /var/www/rpm/.publish.lock -c 'cd /var/www/rpm/fedora/${{ matrix.fedora_version }}/x86_64 && createrepo_c --update .'"
- name: Generate packages.json
run: |
scp rpm/generate-packages-json.py "gitea_ci@${RPM_REPO_HOST}:/tmp/"
ssh "gitea_ci@${RPM_REPO_HOST}" \
"flock /var/www/rpm/.publish.lock -c 'python3 /tmp/generate-packages-json.py \
--repodata-dir /var/www/rpm/fedora/${{ matrix.fedora_version }}/x86_64/repodata \
--output /var/www/rpm/fedora/${{ matrix.fedora_version }}/x86_64/packages.json \
--base-url https://rpm.lair.cafe/fedora/${{ matrix.fedora_version }}/x86_64'"