docs: add Gitea workflows, issue/PR templates, README and licence notice
CI / ci (pull_request) Has been cancelled
CI / android (pull_request) Has been cancelled

ci.yml calls `scripts/ci.sh` rather than restating the checks: a workflow that
reimplements them becomes a second definition of "done", and the two drift.

Android runs as a separate job. It fails when the SDK is absent while ci.sh
skips it — a developer should not be blocked by a missing toolchain, but a
silently skipped Android build in CI means regressions ship unnoticed. Every
action is pinned to an exact version.

LICENSE.md records that no licence is chosen yet, and why it is not a formality:
the choice is upstream of the UI toolkit decision, since Slint is GPL-3.0.

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
2026-10-01 15:56:13 +03:00
parent 5073c7321d
commit af8b28f6c6
8 changed files with 784 additions and 0 deletions
+125
View File
@@ -0,0 +1,125 @@
name: CI
# Section 10.4 requires every PR to pass these checks. This workflow does not
# reimplement them: it runs `scripts/ci.sh`, which is the single source of truth
# for what must pass. Reimplementing the steps here is how CI and local checks
# drift apart, and then one of them is lying to you.
on:
push:
branches: [main]
pull_request:
# Superseded PR runs are cancelled rather than left to finish and report on a
# commit that no longer exists.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
ci:
# Matches the act_runner label in .gitea/workflows/README.md. Change both
# together if the runner is registered under a different label.
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Check out
uses: actions/checkout@v4.1.7
# Pinned to an exact version, never a floating tag. A floating tag lets
# upstream change what runs in your CI without review, which is a supply
# chain problem, not a convenience.
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
# rust-toolchain.toml pins the channel and components, so this action
# installs exactly what the project asks for and CI matches local.
- name: Cache cargo
uses: Swatinem/rust-cache@v2.7.5
- name: Cache cargo registry
uses: actions/cache@v4.1.2
with:
path: |
~/.cargo/registry/index
~/.cargo/registry/cache
~/.cargo/git/db
key: ${{ runner.os }}-cargo-${{ hashFiles('Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-
- name: Run all checks
# scripts/ci.sh runs: fmt --check, clippy -D warnings, cargo test, the 5 MB
# size gate, Android lint (skipped loudly without an SDK), and gitleaks.
#
# A skip inside ci.sh prints SKIP with the reason and is listed in the
# summary as "NOT a pass", so an unverified Android build can never be
# mistaken for a verified one.
run: bash scripts/ci.sh
- name: Upload the release daemon
# Section 10.5 requires releases to carry SHA-256 checksums. Producing
# the checksum here means the release pipeline never has to trust an
# artifact it did not build itself.
if: always()
run: |
set -euo pipefail
BIN="${CARGO_TARGET_DIR:-$HOME/.blocker-target}/release/blocker-daemon"
mkdir -p dist
if [ -f "$BIN" ]; then
cp "$BIN" dist/blocker-daemon
sha256sum dist/blocker-daemon > dist/blocker-daemon.sha256
else
echo "release daemon not built; nothing to upload"
fi
- uses: actions/upload-artifact@v4.4.3
if: always()
with:
name: blocker-daemon-linux
path: dist/
if-no-files-found: warn
# A separate job, rather than a step, for two reasons: it needs a different
# runner label (a runner with the Android SDK), and its failure should be
# legible on its own rather than buried in the middle of the CI output.
#
# Note the asymmetry with ci.sh, which is deliberate. ci.sh SKIPS Android when
# no SDK is present, because a developer running checks locally should not be
# blocked by a missing toolchain. This job FAILS when the SDK is absent,
# because a silently skipped Android build in CI means Android regressions ship
# unnoticed. Same check, opposite defaults, for opposite contexts.
android:
runs-on: android-build
timeout-minutes: 60
if: github.event_name == 'pull_request' || github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4.1.7
- uses: actions/setup-java@v4.4.0
with:
distribution: temurin
java-version: '17'
- uses: android-actions/setup-android@v3.2.2
- name: Accept SDK licences
run: yes | sdkmanager --licenses > /dev/null 2>&1 || true
- name: Cache Gradle
uses: actions/cache@v4.1.2
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('android/**/*.gradle.kts') }}
restore-keys: ${{ runner.os }}-gradle-
# Sideload flavour only. There is deliberately no Play Store signing path
# in CI: sections 6.8 and 4.1 record that the strongest friction
# (Stubborn level, Device Admin uninstall block) is hostile to Play Store
# policy and is intended for sideload or F-Droid distribution.
- name: Lint and assemble release
working-directory: android
run: ./gradlew lint assembleRelease