ci: tag and release from GitHub, drop Gitea CI
Since quire took over mirroring, tags pushed by Gitea CI never reached GitHub, so nothing has released since 2026-06-26.
Assisted-by: Claude Opus 5.5 via Claude Code
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml
deleted file mode 100644
index 91c066b..0000000
--- a/.gitea/workflows/ci.yml
+++ /dev/null
@@ -1,86 +0,0 @@
-name: CI
-
-on:
- push:
- branches: [main]
- pull_request:
-
-permissions: {}
-
-jobs:
- ci:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- with:
- persist-credentials: false
-
- # Can't use facebook/install-dotslash action because it queries the
- # GitHub API using $GITHUB_TOKEN, which is a Gitea token on this runner.
- - run: |
- curl -sL https://github.com/facebook/dotslash/releases/download/v0.5.9/dotslash-linux-musl.x86_64.tar.gz |
- tar xz -C /usr/local/bin
- - run: |
- curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
- echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
- echo "$PWD/bin" >> "$GITHUB_PATH"
-
- - uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4
- with:
- path: ~/.rustup/
- # Bump suffix to force cache bust after upgrading rustup.
- key: rustup-${{ runner.os }}-v1
-
- - run: rustup component add clippy rustfmt llvm-tools
- - run: cargo fmt --check
- - run: just clippy coverage
-
- zizmor:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- with:
- persist-credentials: false
-
- - run: |
- curl -sL https://github.com/facebook/dotslash/releases/download/v0.5.9/dotslash-linux-musl.x86_64.tar.gz |
- tar xz -C /usr/local/bin
- - run: echo "$PWD/bin" >> "$GITHUB_PATH"
-
- # Can't use zizmorcore/zizmor-action because it doesn't support
- # auditing .gitea/workflows/ — it rejects them as invalid inputs.
- - run: zizmor .gitea/workflows/* .github
-
- tag:
- if: github.ref == 'refs/heads/main' && github.event_name == 'push'
- needs: [ci]
- runs-on: ubuntu-latest
- permissions:
- contents: write
- steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 # zizmor: ignore[artipacked] -- needs credentials to push tag
- with:
- fetch-depth: 0
-
- - name: Calculate version
- id: version
- run: |
- CALVER=$(date -u +"%Y-%m-%d")
- SHORT_SHA=$(git rev-parse --short HEAD)
- VERSION="${CALVER}+${SHORT_SHA}"
- echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
-
- - name: Push tag
- env:
- VERSION: ${{ steps.version.outputs.version }}
- run: |
- TAG="v${VERSION}"
-
- # Skip if this tag already exists
- if git tag -l "$TAG" | grep -q .; then
- echo "Tag ${TAG} already exists, skipping"
- exit 0
- fi
-
- git tag "$TAG"
- git push origin "$TAG"
diff --git a/.github/workflows/release.yml b/.github/workflows/ci.yml
similarity index 50%
rename from .github/workflows/release.yml
rename to .github/workflows/ci.yml
index ff2ddcc..090f16a 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/ci.yml
@@ -1,14 +1,68 @@
-name: Release
+name: CI
-on: # zizmor: ignore[dangerous-triggers] -- only triggers on tag pushes from Gitea mirror; no fork PR risk.
+on: # zizmor: ignore[dangerous-triggers] -- only triggers on main pushes from the quire mirror; no fork PR risk.
push:
- tags:
- - 'v*'
+ branches: [main]
permissions: {}
jobs:
+ ci:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ with:
+ persist-credentials: false
+
+ - run: |
+ curl -sL https://github.com/facebook/dotslash/releases/download/v0.5.9/dotslash-linux-musl.x86_64.tar.gz |
+ tar xz -C /usr/local/bin
+ - run: echo "$PWD/bin" >> "$GITHUB_PATH"
+
+ - run: rustup component add clippy rustfmt llvm-tools
+ - run: cargo fmt --check
+ - run: just clippy coverage
+
+ zizmor:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ with:
+ persist-credentials: false
+
+ - run: |
+ curl -sL https://github.com/facebook/dotslash/releases/download/v0.5.9/dotslash-linux-musl.x86_64.tar.gz |
+ tar xz -C /usr/local/bin
+ - run: echo "$PWD/bin" >> "$GITHUB_PATH"
+
+ - run: zizmor .github
+
+ version:
+ needs: [ci, zizmor]
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read # look up existing releases.
+ outputs:
+ tag: ${{ steps.version.outputs.tag }}
+ exists: ${{ steps.version.outputs.exists }}
+ steps:
+ - name: Calculate version
+ id: version
+ env:
+ GH_TOKEN: ${{ github.token }}
+ run: |
+ TAG="v$(date -u +%Y-%m-%d)+${GITHUB_SHA::7}"
+ echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
+ if gh release view "$TAG" -R "$GITHUB_REPOSITORY" > /dev/null 2>&1; then
+ echo "Release ${TAG} already exists, skipping"
+ echo "exists=true" >> "$GITHUB_OUTPUT"
+ else
+ echo "exists=false" >> "$GITHUB_OUTPUT"
+ fi
+
build-macos:
+ needs: version
+ if: needs.version.outputs.exists == 'false'
runs-on: macos-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
@@ -26,6 +80,8 @@ jobs:
path: ranger-aarch64-apple-darwin.tar.gz
build-linux:
+ needs: version
+ if: needs.version.outputs.exists == 'false'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
@@ -44,7 +100,7 @@ jobs:
path: ranger-aarch64-unknown-linux-gnu.tar.gz
publish:
- needs: [build-macos, build-linux]
+ needs: [version, build-macos, build-linux]
runs-on: ubuntu-latest
permissions:
contents: write
@@ -59,17 +115,18 @@ jobs:
- name: Publish
run: |
- VERSION="${GITHUB_REF_NAME#v}"
- gh release create "${GITHUB_REF_NAME}" \
- --title "${GITHUB_REF_NAME}" \
+ gh release create "$TAG" \
+ --target "$GITHUB_SHA" \
+ --title "$TAG" \
--generate-notes \
ranger-aarch64-apple-darwin.tar.gz \
ranger-aarch64-unknown-linux-gnu.tar.gz
env:
GH_TOKEN: ${{ github.token }}
+ TAG: ${{ needs.version.outputs.tag }}
dotslash:
- needs: publish
+ needs: [version, publish]
runs-on: ubuntu-latest
permissions:
contents: write
@@ -80,4 +137,4 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
config: .github/workflows/dotslash-config.json
- tag: ${{ github.ref_name }}
+ tag: ${{ needs.version.outputs.tag }}
diff --git a/AGENTS.md b/AGENTS.md
index 5ad8534..e13b671 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -77,17 +77,14 @@ When installing system packages (`apt-get`), adding Rust components (`rustup com
## CI and Releases
-Two-forge setup:
-
-- **Gitea** (`origin`) is the source of truth. CI runs on Forgejo Actions (`.gitea/workflows/`). On push to `main` and PRs.
-- **GitHub** (`github` remote) is a mirror. Receives tags from Gitea and builds release artifacts.
+- **quire** (`origin`) is the source of truth. It mirrors to Gitea and GitHub (`.quire/config.fnl`).
+- **Gitea** (`gitea` remote) is a plain mirror.
+- **GitHub** (`github` remote) is a mirror. Runs CI and builds release artifacts.
Release flow:
-1. Gitea CI passes on `main`.
-2. Gitea release workflow creates a `vYYYY-MM-DD+<short-sha>` tag and pushes it.
-3. Tag mirrors to GitHub.
-4. GitHub release workflow (`.github/workflows/release.yml`) triggers on tag push, builds macOS and Linux binaries, creates a GitHub release, and publishes Dotslash configuration.
+1. quire mirrors `main` to GitHub.
+2. GitHub CI workflow (`.github/workflows/ci.yml`) triggers on the push, runs CI, and once it passes creates a `vYYYY-MM-DD+<short-sha>` tag and GitHub release, builds macOS and Linux binaries, and publishes Dotslash configuration. It skips a SHA that already has a release that day.
## VCS
diff --git a/README.md b/README.md
index 1c20cc5..b27f7d3 100644
--- a/README.md
+++ b/README.md
@@ -88,10 +88,7 @@ The CLI exists primarily so AI agents can manage tasks programmatically. The web
## Releases
-Ranger uses a two-forge release pipeline:
-
-1. **Gitea** (`git.kejadlen.dev`) is the source of truth. CI runs on every push to `main` (and on PRs). When CI passes, a `vYYYY-MM-DD+<short-sha>` tag is created automatically.
-2. Tags mirror to **GitHub** (`github.com/kejadlen/ranger`). A tag push triggers the release workflow, which builds macOS and Linux binaries, creates a GitHub release, and publishes Dotslash configuration.
+Ranger's source of truth is a quire repository, which mirrors to Gitea (`git.kejadlen.dev`) and **GitHub** (`github.com/kejadlen/ranger`). Each push to `main` on GitHub triggers the CI workflow, which runs checks and, once it passes, tags the commit `vYYYY-MM-DD+<short-sha>`, builds macOS and Linux binaries, creates a GitHub release, and publishes Dotslash configuration.
The version format is calver: the date of the commit plus its short SHA (e.g., `v2026-04-21+abc1234`).