refactor: change how hashes work

This commit is contained in:
zk
2026-05-16 13:42:22 +00:00
parent 9f2ca87665
commit 0dcd5325b6
14 changed files with 113 additions and 36 deletions
+17 -3
View File
@@ -20,13 +20,24 @@ jobs:
permissions:
contents: read
packages: write
outputs:
image_tag: ${{ steps.revision.outputs.image_tag }}
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- name: Revision tag (YYYYMMDD-shortsha + full SHA aliases)
id: revision
run: |
set -eu
short=$(git rev-parse --short=7 HEAD)
d=$(TZ=UTC0 git log -1 --format=%cd --date=format:%Y%m%d HEAD)
echo "image_tag=${d}-${short}" >> "$GITHUB_OUTPUT"
- name: Log in to GHCR
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
with:
registry: ghcr.io
@@ -49,11 +60,12 @@ jobs:
provenance: true
sbom: true
tags: |
ghcr.io/zkldi/tachi-bot:${{ steps.revision.outputs.image_tag }}
ghcr.io/zkldi/tachi-bot:${{ github.sha }}
ghcr.io/zkldi/tachi-bot:main
ghcr.io/zkldi/tachi-bot:latest
build-args: |
COMMIT_HASH=${{ github.sha }}
GIT_REVISION=${{ github.sha }}
BUILD_TIME=${{ steps.build_time.outputs.value }}
cache-from: type=gha,scope=${{ github.ref_name }}-bot
cache-to: type=gha,mode=max,scope=${{ github.ref_name }}-bot
@@ -73,10 +85,12 @@ jobs:
GH_TOKEN: ${{ secrets.DEPLOY_DISPATCH_TOKEN }}
DEST: ${{ matrix.destination }}
SHA: ${{ github.sha }}
IMAGE_TAG: ${{ needs.docker-push.outputs.image_tag }}
run: |
gh api repos/zkldi/tachi-deploy/dispatches \
-f event_type=deploy \
-F "client_payload[app]=bot" \
-F "client_payload[dest]=${DEST}" \
-F "client_payload[sha]=${SHA}"
echo "::notice::Dispatched bot@${DEST} ${SHA} — logs: https://github.com/zkldi/tachi-deploy/actions/workflows/deploy.yml"
-F "client_payload[sha]=${SHA}" \
-F "client_payload[image_tag]=${IMAGE_TAG}"
echo "::notice::Dispatched bot@${DEST} ${IMAGE_TAG} (${SHA}) — logs: https://github.com/zkldi/tachi-deploy/actions/workflows/deploy.yml"
+9
View File
@@ -34,6 +34,14 @@ jobs:
with:
persist-credentials: false
- name: Revision tag (YYYYMMDD-shortsha + full SHA aliases)
id: revision
run: |
set -eu
short=$(git rev-parse --short=7 HEAD)
d=$(TZ=UTC0 git log -1 --format=%cd --date=format:%Y%m%d HEAD)
echo "image_tag=${d}-${short}" >> "$GITHUB_OUTPUT"
- name: Log in to GHCR
if: ${{ github.event_name != 'pull_request' }}
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
@@ -54,6 +62,7 @@ jobs:
tags: |
ghcr.io/zkldi/tachi-dev:main
ghcr.io/zkldi/tachi-dev:latest
ghcr.io/zkldi/tachi-dev:${{ steps.revision.outputs.image_tag }}
ghcr.io/zkldi/tachi-dev:${{ github.sha }}
cache-from: type=gha,scope=dev-image
cache-to: type=gha,mode=max,scope=dev-image
+17 -3
View File
@@ -19,13 +19,24 @@ jobs:
permissions:
contents: read
packages: write
outputs:
image_tag: ${{ steps.revision.outputs.image_tag }}
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- name: Revision tag (YYYYMMDD-shortsha + full SHA aliases)
id: revision
run: |
set -eu
short=$(git rev-parse --short=7 HEAD)
d=$(TZ=UTC0 git log -1 --format=%cd --date=format:%Y%m%d HEAD)
echo "image_tag=${d}-${short}" >> "$GITHUB_OUTPUT"
- name: Log in to GHCR
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
with:
registry: ghcr.io
@@ -48,11 +59,12 @@ jobs:
provenance: true
sbom: true
tags: |
ghcr.io/zkldi/tachi-ghbot:${{ steps.revision.outputs.image_tag }}
ghcr.io/zkldi/tachi-ghbot:${{ github.sha }}
ghcr.io/zkldi/tachi-ghbot:main
ghcr.io/zkldi/tachi-ghbot:latest
build-args: |
COMMIT_HASH=${{ github.sha }}
GIT_REVISION=${{ github.sha }}
BUILD_TIME=${{ steps.build_time.outputs.value }}
cache-from: type=gha,scope=${{ github.ref_name }}-github-bot
cache-to: type=gha,mode=max,scope=${{ github.ref_name }}-github-bot
@@ -67,10 +79,12 @@ jobs:
env:
GH_TOKEN: ${{ secrets.DEPLOY_DISPATCH_TOKEN }}
SHA: ${{ github.sha }}
IMAGE_TAG: ${{ needs.docker-push.outputs.image_tag }}
run: |
gh api repos/zkldi/tachi-deploy/dispatches \
-f event_type=deploy \
-F "client_payload[app]=ghbot" \
-F "client_payload[dest]=-" \
-F "client_payload[sha]=${SHA}"
echo "::notice::Dispatched ghbot ${SHA} — logs: https://github.com/zkldi/tachi-deploy/actions/workflows/deploy.yml"
-F "client_payload[sha]=${SHA}" \
-F "client_payload[image_tag]=${IMAGE_TAG}"
echo "::notice::Dispatched ghbot ${IMAGE_TAG} (${SHA}) — logs: https://github.com/zkldi/tachi-deploy/actions/workflows/deploy.yml"
+17 -3
View File
@@ -105,12 +105,22 @@ jobs:
permissions:
contents: read
packages: write
outputs:
image_tag: ${{ steps.revision.outputs.image_tag }}
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- name: Revision tag (YYYYMMDD-shortsha + full SHA aliases)
id: revision
run: |
set -eu
short=$(git rev-parse --short=7 HEAD)
d=$(TZ=UTC0 git log -1 --format=%cd --date=format:%Y%m%d HEAD)
echo "image_tag=${d}-${short}" >> "$GITHUB_OUTPUT"
- name: Log in to GHCR
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
with:
@@ -140,12 +150,14 @@ jobs:
provenance: true
sbom: true
tags: |
ghcr.io/zkldi/tachi:${{ steps.revision.outputs.image_tag }}
ghcr.io/zkldi/tachi:${{ github.sha }}
ghcr.io/zkldi/tachi:main
ghcr.io/zkldi/tachi:latest
build-args: |
VERSION=${{ steps.server_version.outputs.version }}
COMMIT_HASH=${{ github.sha }}
VERSION_DETAIL=${{ steps.revision.outputs.image_tag }}
GIT_REVISION=${{ github.sha }}
BUILD_TIME=${{ steps.build_time.outputs.value }}
cache-from: type=gha,scope=server-${{ github.ref_name }}
cache-to: type=gha,mode=max,scope=server-${{ github.ref_name }}
@@ -170,10 +182,12 @@ jobs:
GH_TOKEN: ${{ secrets.DEPLOY_DISPATCH_TOKEN }}
DEST: ${{ matrix.destination }}
SHA: ${{ github.sha }}
IMAGE_TAG: ${{ needs.docker-push.outputs.image_tag }}
run: |
gh api repos/zkldi/tachi-deploy/dispatches \
-f event_type=deploy \
-F "client_payload[app]=server" \
-F "client_payload[dest]=${DEST}" \
-F "client_payload[sha]=${SHA}"
echo "::notice::Dispatched server@${DEST} ${SHA} — logs: https://github.com/zkldi/tachi-deploy/actions/workflows/deploy.yml"
-F "client_payload[sha]=${SHA}" \
-F "client_payload[image_tag]=${IMAGE_TAG}"
echo "::notice::Dispatched server@${DEST} ${IMAGE_TAG} (${SHA}) — logs: https://github.com/zkldi/tachi-deploy/actions/workflows/deploy.yml"
+2 -2
View File
@@ -18,8 +18,8 @@ server:
set -euo pipefail
cd typescript/server
VERSION="${VERSION:-"$(jq -r .version package.json)"}"
COMMIT_HASH="${COMMIT_HASH:-"$(git rev-parse --short HEAD)"}"
export VERSION COMMIT_HASH
VERSION_DETAIL="${VERSION_DETAIL:-$(TZ=UTC0 git log -1 --format=%cd --date=format:%Y%m%d HEAD)-$(git rev-parse --short=7 HEAD)}"
export VERSION VERSION_DETAIL
sidecar_pids=()
# Crons: Postgres-backed scheduler. Jobs: `job_queue` (SKIP LOCKED; run multiple for load).
if [[ -z "${TACHI_SERVER_NO_SIDECARS:-}" ]]; then
+15 -4
View File
@@ -12,16 +12,27 @@ check-all-docker-builds: assert-docker-host
#!/usr/bin/env bash
set -euo pipefail
root="$(git rev-parse --show-toplevel)"
sha="$(git -C "$root" rev-parse --short HEAD)"
server_ver="$(jq -r .version "$root/typescript/server/package.json")"
detail="$(TZ=UTC0 git -C "$root" log -1 --format=%cd --date=format:%Y%m%d HEAD)-$(git -C "$root" rev-parse --short=7 HEAD)"
full="$(git -C "$root" rev-parse HEAD)"
bt="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
echo "==> server (prod)"
docker build -f "$root/docker/Dockerfile.server" --target prod \
--build-arg "VERSION=$server_ver" \
--build-arg "COMMIT_HASH=$sha" -t tachi-server:check "$root"
--build-arg "VERSION_DETAIL=$detail" \
--build-arg "GIT_REVISION=$full" \
--build-arg "BUILD_TIME=$bt" \
-t tachi-server:check "$root"
echo "==> bot"
docker build -f "$root/docker/Dockerfile.bot" -t tachi-bot:check "$root"
docker build -f "$root/docker/Dockerfile.bot" \
--build-arg "GIT_REVISION=$full" \
--build-arg "BUILD_TIME=$bt" \
-t tachi-bot:check "$root"
echo "==> github-bot"
docker build -f "$root/docker/Dockerfile.ghbot" -t tachi-ghbot:check "$root"
docker build -f "$root/docker/Dockerfile.ghbot" \
--build-arg "GIT_REVISION=$full" \
--build-arg "BUILD_TIME=$bt" \
-t tachi-ghbot:check "$root"
echo "==> dev image"
docker build -f "$root/Dockerfile.dev" -t tachi-dev:check "$root"
echo "All Docker builds succeeded."
+4 -4
View File
@@ -1,6 +1,6 @@
# Build context must be the repo root. Full tree + .dockerignore (see repo root).
# docker build -f docker/Dockerfile.bot \
# --build-arg COMMIT_HASH="$(git rev-parse --short HEAD)" \
# --build-arg GIT_REVISION="$(git rev-parse HEAD)" \
# --build-arg BUILD_TIME="$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
# .
@@ -28,11 +28,11 @@ RUN bun build \
# --- prod: nothing but the binary ---
FROM alpine:3.21 AS prod
ARG COMMIT_HASH
ARG GIT_REVISION
ARG BUILD_TIME
# Fail the build if any arg is omitted (Docker has no required-ARG syntax).
RUN set -eu; \
: "${COMMIT_HASH:?Dockerfile.bot: COMMIT_HASH build-arg is required}"; \
: "${GIT_REVISION:?Dockerfile.bot: GIT_REVISION build-arg is required}"; \
: "${BUILD_TIME:?Dockerfile.bot: BUILD_TIME build-arg is required}";
RUN apk add --no-cache curl libstdc++ libgcc
@@ -41,7 +41,7 @@ COPY --from=build /bot /bot
LABEL service="tachi-bot" \
org.opencontainers.image.source="https://github.com/zkldi/Tachi3" \
org.opencontainers.image.revision="${COMMIT_HASH}" \
org.opencontainers.image.revision="${GIT_REVISION}" \
org.opencontainers.image.created="${BUILD_TIME}"
HEALTHCHECK --interval=15s --timeout=5s \
+4 -4
View File
@@ -1,6 +1,6 @@
# Build context must be the repo root. Full tree + .dockerignore (see repo root).
# docker build -f docker/Dockerfile.ghbot \
# --build-arg COMMIT_HASH="$(git rev-parse --short HEAD)" \
# --build-arg GIT_REVISION="$(git rev-parse HEAD)" \
# --build-arg BUILD_TIME="$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
# .
@@ -28,11 +28,11 @@ RUN bun build \
# --- prod: nothing but the binary ---
FROM alpine:3.21 AS prod
ARG COMMIT_HASH
ARG GIT_REVISION
ARG BUILD_TIME
# Fail the build if any arg is omitted (Docker has no required-ARG syntax).
RUN set -eu; \
: "${COMMIT_HASH:?Dockerfile.ghbot: COMMIT_HASH build-arg is required}"; \
: "${GIT_REVISION:?Dockerfile.ghbot: GIT_REVISION build-arg is required}"; \
: "${BUILD_TIME:?Dockerfile.ghbot: BUILD_TIME build-arg is required}";
RUN apk add --no-cache curl libstdc++ libgcc
@@ -41,7 +41,7 @@ COPY --from=build /ghbot /ghbot
LABEL service="tachi-ghbot" \
org.opencontainers.image.source="https://github.com/zkldi/Tachi3" \
org.opencontainers.image.revision="${COMMIT_HASH}" \
org.opencontainers.image.revision="${GIT_REVISION}" \
org.opencontainers.image.created="${BUILD_TIME}"
HEALTHCHECK --interval=15s --timeout=5s \
+8 -5
View File
@@ -2,7 +2,8 @@
# Respects .dockerignore (see repo root). Full tree copy keeps workspace installs correct.
# docker build -f docker/Dockerfile.server \
# --build-arg VERSION="$(jq -r .version typescript/server/package.json)" \
# --build-arg COMMIT_HASH="$(git rev-parse --short HEAD)" \
# --build-arg VERSION_DETAIL="$(TZ=UTC0 git log -1 --format=%cd --date=format:%Y%m%d HEAD)-$(git rev-parse --short=7 HEAD)" \
# --build-arg GIT_REVISION="$(git rev-parse HEAD)" \
# --build-arg BUILD_TIME="$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
# -t tachi-server:local .
#
@@ -24,16 +25,18 @@ RUN bun install --frozen-lockfile
FROM oven/bun:alpine AS prod
ARG VERSION
ARG COMMIT_HASH
ARG VERSION_DETAIL
ARG GIT_REVISION
ARG BUILD_TIME
# Fail the build if any arg is omitted (Docker has no required-ARG syntax).
RUN set -eu; \
: "${VERSION:?Dockerfile.server: VERSION build-arg is required}"; \
: "${COMMIT_HASH:?Dockerfile.server: COMMIT_HASH build-arg is required}"; \
: "${VERSION_DETAIL:?Dockerfile.server: VERSION_DETAIL build-arg is required}"; \
: "${GIT_REVISION:?Dockerfile.server: GIT_REVISION build-arg is required}"; \
: "${BUILD_TIME:?Dockerfile.server: BUILD_TIME build-arg is required}";
ENV VERSION=${VERSION}
ENV COMMIT_HASH=${COMMIT_HASH}
ENV VERSION_DETAIL=${VERSION_DETAIL}
ENV MIGRATIONS_DIR=/app/db/migrations
ENV PORT=8080
@@ -45,7 +48,7 @@ COPY --from=deps /app .
LABEL service="tachi-server" \
org.opencontainers.image.source="https://github.com/zkldi/Tachi3" \
org.opencontainers.image.revision="${COMMIT_HASH}" \
org.opencontainers.image.revision="${GIT_REVISION}" \
org.opencontainers.image.version="${VERSION}" \
org.opencontainers.image.created="${BUILD_TIME}"
+2
View File
@@ -5,6 +5,8 @@ REDIS_URL=
POSTGRES_URL=
MIGRATIONS_DIR=
VERSION=
# YYYYMMDD-shortsha from commit date (UTC) + abbreviated SHA; COMMIT_HASH is still read as fallback
VERSION_DETAIL=
COMMIT_HASH=
LOG_LEVEL=
+1 -1
View File
@@ -5,7 +5,7 @@ PORT=8080
MIGRATIONS_DIR=/tachi/db/migrations
LOG_LEVEL=warn
VERSION=test
COMMIT_HASH=test
VERSION_DETAIL=test-detail
TACHI_CAPTCHA_SECRET_KEY=unused
TACHI_SESSION_SECRET=unused
@@ -1,4 +1,4 @@
import { Env } from "#lib/setup/config";
export const VERSION_STR = Env.VERSION;
export const VERSION_PRETTY = `v${Env.VERSION} [${Env.COMMIT_HASH ?? "unknown commit"}]`;
export const VERSION_PRETTY = `v${Env.VERSION} [${Env.VERSION_DETAIL}]`;
+15 -5
View File
@@ -522,11 +522,21 @@ if (!version) {
version = "0.0.0";
}
let commitHash = process.env.COMMIT_HASH;
/** Human-readable build identity: `{commit date UTC YYYYMMDD}-{short sha}`, e.g. `20260516-a1b2c3d`. */
let versionDetail = process.env.VERSION_DETAIL?.trim();
if (!commitHash) {
log.warn(`No COMMIT_HASH specified in environment. defaulting to unknown commit.`);
commitHash = "unknown";
if (!versionDetail) {
const legacy = process.env.COMMIT_HASH?.trim();
if (legacy) {
versionDetail = legacy;
}
}
if (!versionDetail) {
log.warn(
`No VERSION_DETAIL (or COMMIT_HASH) specified in environment. defaulting detail to unknown.`,
);
versionDetail = "unknown";
}
export const Env = {
@@ -535,7 +545,7 @@ export const Env = {
POSTGRES_URL,
MIGRATIONS_DIR,
VERSION: version,
COMMIT_HASH: commitHash,
VERSION_DETAIL: versionDetail,
NODE_ENV: NODE_ENV as "dev" | "production" | "staging" | "test",
LOG_LEVEL: logLevel as "crit" | "debug" | "error" | "info" | "severe" | "verbose" | "warn",
};
+1 -1
View File
@@ -38,7 +38,7 @@ export default defineConfig({
MIGRATIONS_DIR: "/tachi/db/migrations",
LOG_LEVEL: "warn",
VERSION: "test",
COMMIT_HASH: "test",
VERSION_DETAIL: "test-detail",
},
// Parallel test execution - each worker gets its own isolated Postgres database.