1 Commits

Author SHA1 Message Date
pi 4744f05232 ci: CI-resolve mempalace-toolkit to a pinned SHA
mempalace-toolkit is the only companion cloned in Dockerfile.base (all
others live in Dockerfile.variant), so it bypassed the resolve-versions ->
build-arg plumbing and its ref stayed a literal `main`. Because the base
only rebuilds on a content hash of Dockerfile.base + rootfs/* + entrypoints,
a toolkit-only fix would silently fail to land unless Dockerfile.base itself
changed (as it incidentally did in v1.1.1).

Changes:
- resolve-versions: new mempalace_toolkit_ref output (gitea commits API,
  mirrors pi-toolkit resolution; jq '.[0].sha // "main"' fallback).
- base-decide: needs resolve-versions; fold the resolved SHA into the
  base-tag hash so a moved toolkit forces a base rebuild automatically.
- build-base: needs resolve-versions; pass --build-arg MEMPALACE_TOOLKIT_REF.
- Dockerfile.base: switch clone from `git clone --branch` to a SHA-capable
  `git fetch <ref> + checkout FETCH_HEAD` (the --branch <SHA> footgun
  already fixed in Dockerfile.variant, run 374).

base_tag now reflects a live gitea lookup; on API blip it falls back to
`main`, triggering one extra rebuild, never a missed one.

No new tag — lands on the next v* release or workflow_dispatch.
2026-06-14 15:11:22 +02:00
3 changed files with 64 additions and 3 deletions
+20 -1
View File
@@ -47,6 +47,7 @@ env:
jobs:
# ── Phase 1: decide whether base needs rebuilding ──────────────────
base-decide:
needs: [resolve-versions]
runs-on: ubuntu-latest
container:
image: catthehacker/ubuntu:act-latest
@@ -75,6 +76,10 @@ jobs:
! -name '._*' \
-print0 2>/dev/null | sort -z | xargs -0 cat 2>/dev/null
cat entrypoint.sh entrypoint-user.sh
# mempalace-toolkit is cloned in Dockerfile.base at a ref CI
# resolves to a SHA; fold it in so base_tag changes when the
# toolkit moves (otherwise a toolkit-only fix never lands).
echo "${{ needs.resolve-versions.outputs.mempalace_toolkit_ref }}"
} | sha256sum | cut -c1-12
)
BASE_TAG="base-${HASH}"
@@ -117,6 +122,7 @@ jobs:
toolkit_ref: ${{ steps.resolve.outputs.toolkit_ref }}
extensions_ref: ${{ steps.resolve.outputs.extensions_ref }}
studio_ref: ${{ steps.resolve.outputs.studio_ref }}
mempalace_toolkit_ref: ${{ steps.resolve.outputs.mempalace_toolkit_ref }}
steps:
- name: Resolve pi version + companion refs
id: resolve
@@ -151,6 +157,16 @@ jobs:
[ -n "$EXTENSIONS_REF" ] || EXTENSIONS_REF=main
echo "toolkit_ref=${TOOLKIT_REF}" >> "$GITHUB_OUTPUT"
echo "extensions_ref=${EXTENSIONS_REF}" >> "$GITHUB_OUTPUT"
# Resolve mempalace-toolkit main HEAD to a SHA. UNLIKE the others,
# mempalace-toolkit is cloned in Dockerfile.base, so this SHA is
# ALSO folded into the base-decide hash to force a base rebuild
# when the toolkit moves (without it, a toolkit-only fix silently
# fails to land unless Dockerfile.base itself changes).
MEMPALACE_TOOLKIT_REF=$(curl -sf -H "Authorization: token ${GITEA_BUILD_TOKEN:-${GITHUB_TOKEN:-}}" \
"https://gitea.jordbo.se/api/v1/repos/joakimp/mempalace-toolkit/commits?limit=1&sha=main" \
| jq -r '.[0].sha // "main"' 2>/dev/null || echo "main")
[ -n "$MEMPALACE_TOOLKIT_REF" ] || MEMPALACE_TOOLKIT_REF=main
echo "mempalace_toolkit_ref=${MEMPALACE_TOOLKIT_REF}" >> "$GITHUB_OUTPUT"
# Resolve pi-studio (omaclaren/pi-studio) main HEAD to a SHA for
# the :latest-studio variant — same cache-busting rationale.
STUDIO_REF=$(curl -sf -H "Accept: application/vnd.github.sha" \
@@ -161,10 +177,11 @@ jobs:
echo "Resolved PI_FORK_REF=${FORK_REF}, PI_OBSMEM_REF=${OBSMEM_REF}"
echo "Resolved PI_TOOLKIT_REF=${TOOLKIT_REF}, PI_EXTENSIONS_REF=${EXTENSIONS_REF}"
echo "Resolved PI_STUDIO_REF=${STUDIO_REF}"
echo "Resolved MEMPALACE_TOOLKIT_REF=${MEMPALACE_TOOLKIT_REF}"
# ── Phase 2: build & push base (multi-arch), only when needed ──────
build-base:
needs: [base-decide]
needs: [base-decide, resolve-versions]
if: needs.base-decide.outputs.need_build == 'true'
runs-on: ubuntu-latest
container:
@@ -206,6 +223,7 @@ jobs:
shell: bash
env:
BASE_TAG_FULL: ${{ env.IMAGE }}:${{ needs.base-decide.outputs.base_tag }}
MEMPALACE_TOOLKIT_REF: ${{ needs.resolve-versions.outputs.mempalace_toolkit_ref }}
run: |
set -euo pipefail
# 3-attempt retry around `docker buildx build --push` for transient
@@ -219,6 +237,7 @@ jobs:
if docker buildx build \
--platform linux/amd64,linux/arm64 \
--file Dockerfile.base \
--build-arg MEMPALACE_TOOLKIT_REF="${MEMPALACE_TOOLKIT_REF}" \
--push \
--tag "${BASE_TAG_FULL}" \
.; then
+28
View File
@@ -11,6 +11,34 @@ Pre-v1.0.0 tags followed the pi npm version (`v{pi_version}[letter]`).
---
## Unreleased
### Changed
- **`mempalace-toolkit` is now CI-resolved to a commit SHA**, closing a
silent-staleness footgun. It is the only companion cloned in
`Dockerfile.base` (all others are cloned in `Dockerfile.variant`), so it
was never run through the `resolve-versions` → build-arg plumbing. Its
ref stayed a literal `main`, and because the base only rebuilds when the
hash of `Dockerfile.base + rootfs/* + entrypoints` changes, a
toolkit-only fix would *not* land in the image unless `Dockerfile.base`
itself happened to change (as it did, incidentally, in v1.1.1).
Now `resolve-versions` resolves `mempalace-toolkit` `main` HEAD to a SHA
(new `mempalace_toolkit_ref` output), `base-decide` folds that SHA into
the base-tag hash (so a moved toolkit forces a base rebuild), and
`build-base` passes it as `--build-arg MEMPALACE_TOOLKIT_REF`. The base
clone switched from `git clone --branch` to a SHA-capable
`git fetch <ref> + checkout FETCH_HEAD` (the `--branch <40-char-SHA>`
footgun previously fixed in `Dockerfile.variant`, run 374).
Note: `base-decide` now depends on `resolve-versions`, so the base tag
reflects a live gitea API lookup. On an API blip it falls back to `main`
— which hashes differently than a SHA and triggers one *extra* rebuild,
never a *missed* one (fail-toward-rebuild).
---
## v1.1.1 — 2026-06-13
Patch release: pi `0.79.1``0.79.3` (auto-resolved at build) plus the
+16 -2
View File
@@ -336,9 +336,23 @@ RUN if [ "${INSTALL_MEMPALACE}" = "true" ]; then \
# ── mempalace-toolkit — bash wrappers for session/docs mining ────────
ARG INSTALL_MEMPALACE_TOOLKIT=true
ARG MEMPALACE_TOOLKIT_REF=main
# MEMPALACE_TOOLKIT_REF accepts EITHER a branch name OR a commit SHA. CI
# resolves it to a SHA (resolve-versions job) and folds that SHA into the
# base-decide hash so the base rebuilds when the toolkit moves. `git clone
# --branch <40-char-SHA>` fails ("Remote branch not found") — the same
# footgun fixed in Dockerfile.variant (v1.0.0-rerun, run 374) — so use
# `git fetch <ref> + checkout FETCH_HEAD`, which works for name and SHA.
RUN if [ "${INSTALL_MEMPALACE}" = "true" ] && [ "${INSTALL_MEMPALACE_TOOLKIT}" = "true" ]; then \
git clone --depth 1 --branch "${MEMPALACE_TOOLKIT_REF}" \
https://gitea.jordbo.se/joakimp/mempalace-toolkit.git /opt/mempalace-toolkit && \
rm -rf /opt/mempalace-toolkit && mkdir -p /opt/mempalace-toolkit && \
git -C /opt/mempalace-toolkit init -q && \
git -C /opt/mempalace-toolkit remote add origin https://gitea.jordbo.se/joakimp/mempalace-toolkit.git && \
ok=0; for i in 1 2 3 4 5; do \
if git -C /opt/mempalace-toolkit fetch --depth 1 origin "${MEMPALACE_TOOLKIT_REF}" && \
git -C /opt/mempalace-toolkit checkout -q FETCH_HEAD; then ok=1; break; fi; \
echo "git fetch mempalace-toolkit@${MEMPALACE_TOOLKIT_REF} failed (attempt $i/5), retrying in $((i*5))s..."; \
sleep $((i*5)); \
done; \
[ "$ok" = "1" ] && \
ln -sf /opt/mempalace-toolkit/bin/mempalace-session /usr/local/bin/mempalace-session && \
ln -sf /opt/mempalace-toolkit/bin/mempalace-docs /usr/local/bin/mempalace-docs && \
chmod +x /opt/mempalace-toolkit/bin/mempalace-session /opt/mempalace-toolkit/bin/mempalace-docs && \