ci: Refactor timelord action to use git-warp-time fallback

Updates the timelord action to fall back to git-warp-time when the cache
is completely empty, enabling timestamp restoration even on fresh builds.
When git-warp-time is used, performs an unshallow fetch to get full history,
while subsequent runs use normal fetches. Simplifies the interface by making
inputs optional with sensible defaults.

Adds binary caching for timelord-cli and git-warp-time tools to avoid
repeated installations, and updates paths to use /usr/share/rust/.cargo/bin/
for the catthehacker runner image used by the dind profile (may need updating
if/when switching to standard image).

The main timelord restore now happens inside the Dockerfile itself, as Docker
intentionally wipes all file mtimes on COPY/ADD operations.
This commit is contained in:
Tom Foster 2025-09-08 04:32:23 +01:00
commit 7950e2cc7f
3 changed files with 106 additions and 34 deletions

View file

@ -1,46 +1,99 @@
name: timelord name: timelord
description: | description: |
Use timelord to set file timestamps Use timelord to set file timestamps with git-warp-time fallback for cache misses
inputs: inputs:
key: key:
description: | description: |
The key to use for caching the timelord data. The key to use for caching the timelord data.
This should be unique to the repository and the runner. required: false
required: true default: ''
default: timelord-v0
path: path:
description: | description: |
The path to the directory to be timestamped. The path to the directory to be timestamped.
This should be the root of the repository. required: false
required: true default: ''
default: .
outputs:
database-path:
description: Path to timelord database
value: '${{ env.TIMELORD_CACHE_PATH }}'
runs: runs:
using: composite using: composite
steps: steps:
- name: Cache timelord-cli installation - name: Set defaults
id: cache-timelord-bin
uses: actions/cache@v3
with:
path: ~/.cargo/bin/timelord
key: timelord-cli-v3.0.1
- name: Install timelord-cli
uses: https://github.com/cargo-bins/cargo-binstall@main
if: steps.cache-timelord-bin.outputs.cache-hit != 'true'
- run: cargo binstall timelord-cli@3.0.1
shell: bash shell: bash
if: steps.cache-timelord-bin.outputs.cache-hit != 'true' run: |
echo "TIMELORD_KEY=${{ inputs.key || format('timelord-v1-{0}-{1}', github.repository, hashFiles('**/*.rs', '**/Cargo.toml', '**/Cargo.lock')) }}" >> $GITHUB_ENV
echo "TIMELORD_PATH=${{ inputs.path || '.' }}" >> $GITHUB_ENV
echo "TIMELORD_CACHE_PATH=$HOME/.cache/timelord" >> $GITHUB_ENV
- name: Load timelord files - name: Restore binary cache
uses: actions/cache/restore@v3 id: binary-cache
uses: actions/cache/restore@v4
with: with:
path: /timelord/ path: /usr/share/rust/.cargo/bin
key: ${{ inputs.key }} key: timelord-binaries-v1
- name: Run timelord to set timestamps
- name: Check if binaries need installation
shell: bash shell: bash
run: timelord sync --source-dir ${{ inputs.path }} --cache-dir /timelord/ id: check-binaries
- name: Save timelord run: |
uses: actions/cache/save@v3 NEED_INSTALL=false
if [ ! -e /usr/share/rust/.cargo/bin/timelord ]; then
echo "timelord-cli not found at /usr/share/rust/.cargo/bin/timelord, needs installation"
NEED_INSTALL=true
fi
if [ ! -e /usr/share/rust/.cargo/bin/git-warp-time ]; then
echo "git-warp-time not found at /usr/share/rust/.cargo/bin/git-warp-time, needs installation"
NEED_INSTALL=true
fi
echo "need-install=$NEED_INSTALL" >> $GITHUB_OUTPUT
- name: Install timelord-cli and git-warp-time
if: steps.check-binaries.outputs.need-install == 'true'
uses: https://github.com/taiki-e/install-action@v2
with: with:
path: /timelord/ tool: git-warp-time,timelord-cli@3.0.1
key: ${{ inputs.key }}
- name: Save binary cache
if: steps.check-binaries.outputs.need-install == 'true'
uses: actions/cache/save@v4
with:
path: /usr/share/rust/.cargo/bin
key: timelord-binaries-v1
- name: Restore timelord cache with fallbacks
id: timelord-restore
uses: actions/cache/restore@v4
with:
path: ${{ env.TIMELORD_CACHE_PATH }}
key: ${{ env.TIMELORD_KEY }}
restore-keys: |
timelord-v1-${{ github.repository }}-
- name: Initialize timestamps on complete cache miss
if: steps.timelord-restore.outputs.cache-hit != 'true'
shell: bash
run: |
echo "Complete timelord cache miss - running git-warp-time"
git fetch --unshallow
if [ "${{ env.TIMELORD_PATH }}" = "." ]; then
/usr/share/rust/.cargo/bin/git-warp-time --quiet
else
/usr/share/rust/.cargo/bin/git-warp-time --quiet ${{ env.TIMELORD_PATH }}
fi
echo "Git timestamps restored"
- name: Run timelord sync
shell: bash
run: |
mkdir -p ${{ env.TIMELORD_CACHE_PATH }}
/usr/share/rust/.cargo/bin/timelord sync --source-dir ${{ env.TIMELORD_PATH }} --cache-dir ${{ env.TIMELORD_CACHE_PATH }}
- name: Save updated timelord cache immediately
uses: actions/cache/save@v4
with:
path: ${{ env.TIMELORD_CACHE_PATH }}
key: ${{ env.TIMELORD_KEY }}

View file

@ -150,10 +150,18 @@ jobs:
echo "Commit timestamp: $timestamp" echo "Commit timestamp: $timestamp"
- uses: ./.forgejo/actions/timelord - uses: ./.forgejo/actions/timelord
if: ${{ env.BUILDKIT_ENDPOINT == '' }} id: timelord
with:
key: timelord-v0 - name: Copy timelord cache to workspace
path: . shell: bash
run: |
mkdir -p ./timelord
if [ -d "${{ steps.timelord.outputs.database-path }}" ]; then
cp -r "${{ steps.timelord.outputs.database-path }}"/* ./timelord/
echo "Copied timelord cache to workspace"
else
echo "No timelord cache to copy"
fi
- name: Cache Rust registry - name: Cache Rust registry
if: ${{ env.BUILDKIT_ENDPOINT == '' }} if: ${{ env.BUILDKIT_ENDPOINT == '' }}
@ -217,6 +225,7 @@ jobs:
GIT_COMMIT_HASH_SHORT=${{ env.COMMIT_SHORT_SHA }} GIT_COMMIT_HASH_SHORT=${{ env.COMMIT_SHORT_SHA }}
GIT_REMOTE_URL=${{github.event.repository.html_url }} GIT_REMOTE_URL=${{github.event.repository.html_url }}
GIT_REMOTE_COMMIT_URL=${{github.event.head_commit.url }} GIT_REMOTE_COMMIT_URL=${{github.event.head_commit.url }}
CARGO_INCREMENTAL=${{ env.BUILDKIT_ENDPOINT != '' && '1' || '0' }}
platforms: ${{ matrix.platform }} platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
annotations: ${{ steps.meta.outputs.annotations }} annotations: ${{ steps.meta.outputs.annotations }}

View file

@ -60,6 +60,7 @@ RUN <<EOF
curl --retry 5 -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash curl --retry 5 -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash
cargo binstall --no-confirm cargo-sbom --version $CARGO_SBOM_VERSION cargo binstall --no-confirm cargo-sbom --version $CARGO_SBOM_VERSION
cargo binstall --no-confirm lddtree --version $LDDTREE_VERSION cargo binstall --no-confirm lddtree --version $LDDTREE_VERSION
cargo binstall --no-confirm timelord-cli@3.0.1
EOF EOF
# Set up xx (cross-compilation scripts) # Set up xx (cross-compilation scripts)
@ -81,8 +82,9 @@ RUN rustc --version \
&& xx-cargo --setup-target-triple && xx-cargo --setup-target-triple
# Build binary # Build binary
# We disable incremental compilation to save disk space, as it only produces a minimal speedup for this case. # Configure incremental compilation based on build context
RUN echo "CARGO_INCREMENTAL=0" >> /etc/environment ARG CARGO_INCREMENTAL=0
RUN echo "CARGO_INCREMENTAL=${CARGO_INCREMENTAL}" >> /etc/environment
# Configure pkg-config # Configure pkg-config
RUN <<EOF RUN <<EOF
@ -133,6 +135,14 @@ FROM toolchain AS builder
# Get source # Get source
COPY . . COPY . .
# Restore timestamps from timelord cache if available
RUN if [ -f /app/timelord/timelord.db ]; then \
echo "Restoring timestamps from timelord cache"; \
timelord sync --source-dir /app --cache-dir /app/timelord; \
else \
echo "No timelord cache found, timestamps will be build time"; \
fi
ARG TARGETPLATFORM ARG TARGETPLATFORM
# Verify environment configuration # Verify environment configuration