Some checks failed
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.
199 lines
6.8 KiB
YAML
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'"
|