diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml
deleted file mode 100644
index 53e9068..0000000
--- a/.gitea/workflows/ci.yml
+++ /dev/null
@@ -1,21 +0,0 @@
-name: CI
-
-on:
- push:
- branches: [main]
- pull_request:
- workflow_dispatch:
-
-jobs:
- check:
- runs-on: pixi-build-rust
- env:
- CARGO_TARGET_DIR: /opt/cargo-target/${{ gitea.repository }}
- steps:
- - uses: actions/checkout@v4
-
- - name: Install the pinned toolchain
- run: pixi install
-
- - name: Verify (formatting, lint, tests, docs)
- run: pixi run check
diff --git a/.gitea/workflows/docs.yml b/.gitea/workflows/docs.yml
deleted file mode 100644
index 1f39848..0000000
--- a/.gitea/workflows/docs.yml
+++ /dev/null
@@ -1,41 +0,0 @@
-name: Deploy docs
-
-on:
- push:
- branches: [main]
- tags: ['*.*.*']
- workflow_dispatch:
-
-env:
- SITE_SLUG: coursebank
- CRATE: coursebank
-
-jobs:
- deploy:
- runs-on: pixi-build-rust
- env:
- CARGO_TARGET_DIR: /opt/cargo-target/${{ gitea.repository }}
- steps:
- - uses: actions/checkout@v4
-
- - name: Build the API docs
- env:
- RUSTDOCFLAGS: "--html-before-content ${{ gitea.workspace }}/scripts/docs-banner.html"
- run: |
- pixi install --locked
- pixi run doc-build
-
- - name: Redirect the channel root to the crate page
- run: |
- printf '%s\n' "" > target/doc/index.html
-
- - name: Publish the channel to /srv/www
- run: |
- case "${{ gitea.ref }}" in
- refs/tags/*) channel=release ;;
- *) channel=nightly ;;
- esac
- bash scripts/publish-docs.sh "$channel"
-
- - name: Point the site root at the latest release, else nightly
- run: bash scripts/redirect-docs.sh
diff --git a/.gitea/workflows/nightly.yml b/.gitea/workflows/nightly.yml
deleted file mode 100644
index 09af897..0000000
--- a/.gitea/workflows/nightly.yml
+++ /dev/null
@@ -1,73 +0,0 @@
-name: Nightly
-
-on:
- push:
- branches: [main]
- schedule:
- - cron: '0 6 * * *'
- workflow_dispatch:
-
-jobs:
- nightly:
- runs-on: pixi-build-rust
- permissions:
- contents: write
- env:
- CARGO_TARGET_DIR: /opt/cargo-target/${{ gitea.repository }}
- API: ${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}
- TOKEN: ${{ secrets.GITEA_TOKEN }}
- TAG: nightly
- ASSET: coursebank-nightly-linux-x64.tar.gz
- steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0
- fetch-tags: true
-
- - name: Install the pinned toolchain
- run: pixi install
-
- - name: Build the release binary
- run: pixi run build
-
- - name: Package
- run: |
- set -euo pipefail
- tar -czf "$ASSET" \
- -C target/release coursebank \
- -C "${{ gitea.workspace }}" LICENSE.md
- sha256sum "$ASSET" > "$ASSET.sha256"
-
- - name: Publish the rolling nightly prerelease
- run: |
- set -euo pipefail
- auth="Authorization: token ${TOKEN}"
- # jq is fetched on demand; no toolchain change needed for it.
- jq() { pixi exec --spec jq -- jq "$@"; }
-
- sha="${{ gitea.sha }}"
- version=$(grep -m1 '^version' Cargo.toml | sed -E 's/.*"([^"]+)".*/\1/')
- body="Nightly build of ${version} at $(date -u +%Y-%m-%d) (commit ${sha:0:8}). Not a stable release."
-
- # Drop the previous nightly release and its moving tag, if present, so
- # the new one points at the current commit.
- existing=$(curl -fsSL -H "$auth" "${API}/releases/tags/${TAG}" 2>/dev/null || true)
- if [ -n "$existing" ]; then
- id=$(printf '%s' "$existing" | jq -r '.id // empty')
- [ -n "$id" ] && curl -fsSL -X DELETE -H "$auth" "${API}/releases/${id}"
- fi
- curl -fsSL -X DELETE -H "$auth" "${API}/tags/${TAG}" 2>/dev/null || true
-
- # Create the release at the current commit.
- rid=$(curl -fsSL -X POST -H "$auth" -H "Content-Type: application/json" \
- "${API}/releases" \
- -d "$(jq -n --arg tag "$TAG" --arg sha "$sha" --arg body "$body" \
- '{tag_name:$tag, target_commitish:$sha, name:"Nightly", body:$body, draft:false, prerelease:true}')" \
- | jq -r '.id')
-
- # Attach the tarball and its checksum.
- for f in "$ASSET" "$ASSET.sha256"; do
- curl -fsSL -X POST -H "$auth" \
- -F "attachment=@${f}" \
- "${API}/releases/${rid}/assets?name=${f}"
- done
diff --git a/.gitea/workflows/pipeline.yml b/.gitea/workflows/pipeline.yml
new file mode 100644
index 0000000..4202a46
--- /dev/null
+++ b/.gitea/workflows/pipeline.yml
@@ -0,0 +1,140 @@
+name: Pipeline
+
+on:
+ push:
+ branches: [main]
+ tags: ['*.*.*']
+ pull_request:
+ schedule:
+ - cron: '0 7 * * *'
+ workflow_dispatch:
+
+env:
+ SITE_SLUG: coursebank
+ CRATE: coursebank
+
+jobs:
+ check:
+ runs-on: pixi-build-rust
+ env:
+ CARGO_TARGET_DIR: /opt/cargo-target/${{ gitea.repository }}
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Install the pinned toolchain
+ run: pixi install
+
+ - name: Verify (formatting, lint, tests, docs)
+ run: pixi run check
+
+ nightly:
+ needs: check
+ if: ${{ (gitea.event_name == 'push' && gitea.ref == 'refs/heads/main') || gitea.event_name == 'schedule' || gitea.event_name == 'workflow_dispatch' }}
+ runs-on: pixi-build-rust
+ permissions:
+ contents: write
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ fetch-tags: true
+
+ - name: Install the pinned toolchain
+ run: pixi install
+
+ - name: Build the release binary
+ run: |
+ COURSEBANK_VERSION="$(bash scripts/nightly-version.sh)"
+ export COURSEBANK_VERSION
+ echo "nightly version: ${COURSEBANK_VERSION}"
+ pixi run build
+
+ - name: Package
+ run: |
+ mkdir -p stage
+ cp target/release/coursebank LICENSE.md stage/
+ bash scripts/package.sh coursebank-nightly-linux-x64.tar.gz stage
+
+ - name: Publish the rolling nightly prerelease
+ env:
+ GITEA_API: ${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}
+ GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
+ JQ: pixi exec --spec jq -- jq
+ TAG: nightly
+ PRERELEASE: "true"
+ REPLACE: "true"
+ TARGET_COMMITISH: ${{ gitea.sha }}
+ ASSETS: coursebank-nightly-linux-x64.tar.gz coursebank-nightly-linux-x64.tar.gz.sha256
+ run: |
+ ver="$(bash scripts/nightly-version.sh)"
+ export RELEASE_NAME="Nightly ${ver}"
+ export BODY="Nightly build ${ver}, built $(date -u +%Y-%m-%d). Not a stable release."
+ bash scripts/gitea-release.sh
+
+ release:
+ needs: check
+ if: ${{ gitea.event_name == 'push' && startsWith(gitea.ref, 'refs/tags/') }}
+ runs-on: pixi-build-rust
+ permissions:
+ contents: write
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Check the tag matches the crate version
+ env:
+ TAG: ${{ gitea.ref_name }}
+ run: bash scripts/check-tag-version.sh
+
+ - name: Install the pinned toolchain
+ run: pixi install
+
+ - name: Build the full bundle (binary and license notices)
+ run: |
+ pixi run setup-tools
+ pixi run dist
+
+ - name: Package
+ run: bash scripts/package.sh "coursebank-$(bash scripts/version.sh)-linux-x64.tar.gz" dist
+
+ - name: Publish the release
+ env:
+ GITEA_API: ${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}
+ GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
+ JQ: pixi exec --spec jq -- jq
+ TAG: ${{ gitea.ref_name }}
+ BODY: See CHANGELOG.md.
+ run: |
+ asset="coursebank-$(bash scripts/version.sh)-linux-x64.tar.gz"
+ export ASSETS="$asset $asset.sha256"
+ bash scripts/gitea-release.sh
+
+ docs:
+ needs: check
+ if: ${{ (gitea.event_name == 'push' && (gitea.ref == 'refs/heads/main' || startsWith(gitea.ref, 'refs/tags/'))) || gitea.event_name == 'workflow_dispatch' }}
+ runs-on: pixi-build-rust
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Build the API docs
+ env:
+ RUSTDOCFLAGS: "--html-before-content ${{ gitea.workspace }}/scripts/docs-banner.html"
+ run: |
+ pixi install --locked
+ pixi run doc-build
+
+ - name: Redirect the channel root to the crate page
+ run: |
+ printf '%s\n' "" > target/doc/index.html
+
+ - name: Publish the channel to /srv/www
+ run: |
+ case "${{ gitea.ref }}" in
+ refs/tags/*) channel=release ;;
+ *) channel=nightly ;;
+ esac
+ bash scripts/publish-docs.sh "$channel"
+
+ - name: Point the site root at the latest release, else nightly
+ run: bash scripts/docs-default-redirect.sh
diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml
deleted file mode 100644
index 9a8d1e1..0000000
--- a/.gitea/workflows/release.yml
+++ /dev/null
@@ -1,62 +0,0 @@
-name: Release
-
-on:
- push:
- tags:
- - '*.*.*'
-
-jobs:
- release:
- runs-on: pixi-build-rust
- permissions:
- contents: write
- env:
- CARGO_TARGET_DIR: /opt/cargo-target/${{ gitea.repository }}
- API: ${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}
- TOKEN: ${{ secrets.GITEA_TOKEN }}
- TAG: ${{ gitea.ref_name }}
- steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0
-
- - name: Check the tag matches the crate version
- run: |
- set -euo pipefail
- version=$(grep -m1 '^version' Cargo.toml | sed -E 's/.*"([^"]+)".*/\1/')
- tag="${TAG#v}"
- if [ "$tag" != "$version" ]; then
- echo "tag ${TAG} does not match Cargo.toml version ${version}" >&2
- exit 1
- fi
-
- - name: Install the pinned toolchain
- run: pixi install
-
- - name: Build the full bundle (binary and license notices)
- run: |
- pixi run setup-tools
- pixi run dist
-
- - name: Package and publish the release
- run: |
- set -euo pipefail
- auth="Authorization: token ${TOKEN}"
- jq() { pixi exec --spec jq -- jq "$@"; }
-
- version=$(grep -m1 '^version' Cargo.toml | sed -E 's/.*"([^"]+)".*/\1/')
- asset="coursebank-${version}-linux-x64.tar.gz"
- tar -czf "$asset" -C dist coursebank LICENSE.md THIRD-PARTY-LICENSES.txt
- sha256sum "$asset" > "$asset.sha256"
-
- rid=$(curl -fsSL -X POST -H "$auth" -H "Content-Type: application/json" \
- "${API}/releases" \
- -d "$(jq -n --arg tag "$TAG" \
- '{tag_name:$tag, name:$tag, body:"See CHANGELOG.md.", draft:false, prerelease:false}')" \
- | jq -r '.id')
-
- for f in "$asset" "$asset.sha256"; do
- curl -fsSL -X POST -H "$auth" \
- -F "attachment=@${f}" \
- "${API}/releases/${rid}/assets?name=${f}"
- done