docs: add Gitea workflows, issue/PR templates, README and licence notice
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:
@@ -0,0 +1,109 @@
|
||||
name: Bug report
|
||||
description: Something behaves differently from how CLAUDE.md section 1 describes it
|
||||
title: ""
|
||||
labels: ["bug"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Two failure modes matter most here, and they need different fixes.
|
||||
|
||||
- **A block that should have fired but did not.**
|
||||
- **A block that fired but should not have.**
|
||||
|
||||
Please pick which one you are reporting in the first question.
|
||||
|
||||
- type: dropdown
|
||||
id: mode
|
||||
attributes:
|
||||
label: Which kind of failure is this?
|
||||
description: The two modes below need completely different investigations.
|
||||
options:
|
||||
- A blocked app was not blocked
|
||||
- A block fired when it should not have
|
||||
- Enforcement stopped working entirely
|
||||
- The app crashed or would not start
|
||||
- Something else
|
||||
|
||||
- type: dropdown
|
||||
id: platform
|
||||
attributes:
|
||||
label: Platform
|
||||
options:
|
||||
- Linux (KDE Plasma / Wayland)
|
||||
- Linux (KDE Plasma / X11)
|
||||
- Linux (other compositor)
|
||||
- Windows
|
||||
- Android
|
||||
- More than one
|
||||
- Not yet implemented on any
|
||||
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: Version or commit
|
||||
description: Output of `blocker-daemon --version`, or the commit SHA for a build from source.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: repro
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: |
|
||||
Concrete steps, starting from a known state. "Open Discord during Focus" is
|
||||
reproducible; "it blocks sometimes" is not.
|
||||
placeholder: |
|
||||
1. Start a schedule named "Focus", 09:00-17:00, targeting Discord
|
||||
2. Focus Discord
|
||||
3. Nothing happens
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: expected
|
||||
attributes:
|
||||
label: Expected behaviour
|
||||
description: What does CLAUDE.md section 1 say should happen? Quote the requirement if you can.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: actual
|
||||
attributes:
|
||||
label: Actual behaviour
|
||||
description: What happened instead, including any error output.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: backend
|
||||
attributes:
|
||||
label: Which enforcement backend is active?
|
||||
description: |
|
||||
The troubleshooting screen shows this. If you cannot find it, say so — that is
|
||||
itself useful information, because it suggests the daemon started with no
|
||||
backend and cannot block anything.
|
||||
placeholder: "kwin: KWin script loaded successfully"
|
||||
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Daemon log output
|
||||
description: |
|
||||
From `journalctl --user -u blocker -n 100`.
|
||||
|
||||
Redact anything private. Do not paste API tokens, keys, or credentials.
|
||||
render: shell
|
||||
|
||||
- type: checkboxes
|
||||
id: checks
|
||||
attributes:
|
||||
label: Before submitting
|
||||
options:
|
||||
- label: I searched existing issues for this.
|
||||
- label: I removed secrets and personal paths from anything I pasted above.
|
||||
- label: I am not asking to block ADB, safe mode, factory reset, or OS recovery.
|
||||
description: |
|
||||
Those are never blocked, by design (CLAUDE.md section 6.7 and ADR-11). Such a
|
||||
request will be closed with a link to the ADR rather than implemented.
|
||||
@@ -0,0 +1,102 @@
|
||||
name: Platform limitation
|
||||
description: A case where the OS will not permit what CLAUDE.md asks for
|
||||
title: ""
|
||||
labels: ["limitation"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
CLAUDE.md section 6 lists the hard limits this project is known to have. This
|
||||
template exists so a newly discovered one is recorded rather than quietly worked
|
||||
around.
|
||||
|
||||
Section 0 rule 2: never fake a feature. If something cannot be enforced on a
|
||||
platform, we implement the closest honest approximation and document the gap.
|
||||
This form is how that documentation starts.
|
||||
|
||||
- type: dropdown
|
||||
id: existing
|
||||
attributes:
|
||||
label: Is this already documented?
|
||||
description: |
|
||||
If it matches a numbered limitation in CLAUDE.md section 6, please comment on
|
||||
that discussion instead of opening a new issue.
|
||||
options:
|
||||
- "No, this is new"
|
||||
- "Yes, but our handling of it is wrong or incomplete"
|
||||
- "Not sure"
|
||||
|
||||
- type: input
|
||||
id: section
|
||||
attributes:
|
||||
label: Which section 6 limitation does this relate to?
|
||||
description: "A number 1-8, or 'new'."
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: platform
|
||||
attributes:
|
||||
label: Platform
|
||||
options:
|
||||
- Linux (KDE Plasma / Wayland)
|
||||
- Linux (KDE Plasma / X11)
|
||||
- Linux (wlroots compositor)
|
||||
- Linux (GNOME)
|
||||
- Windows
|
||||
- Android
|
||||
- More than one
|
||||
|
||||
- type: textarea
|
||||
id: reality
|
||||
attributes:
|
||||
label: What does the OS refuse to do?
|
||||
description: |
|
||||
The OS-level fact. Not "we could not figure it out" — what the platform makes
|
||||
impossible or requires privileges we do not have.
|
||||
placeholder: |
|
||||
Wayland has no portable API for the focused window. Each compositor exposes its
|
||||
own, and none is standard.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: workaround
|
||||
attributes:
|
||||
label: What do we do instead?
|
||||
description: |
|
||||
The closest honest approximation. If the answer is "nothing", say that. An
|
||||
unimplemented limitation is a valid and common answer.
|
||||
placeholder: "Process-based detection, which cannot show a block screen."
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: privileges
|
||||
attributes:
|
||||
label: What privileges would a real fix need?
|
||||
description: |
|
||||
Root, CAP_SYS_ADMIN, an accessibility service, a browser extension, a Windows
|
||||
service install? This determines whether the limitation is permanent or a
|
||||
matter of permission design.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: checkboxes
|
||||
id: docs
|
||||
attributes:
|
||||
label: Documentation
|
||||
options:
|
||||
- label: This gap is documented in docs/LIMITATIONS.md
|
||||
description: |
|
||||
Required. An undocumented limitation is worse than an unimplemented one,
|
||||
because the docs will imply a capability that does not exist.
|
||||
|
||||
- type: checkboxes
|
||||
id: notblocked
|
||||
attributes:
|
||||
label: Confirm
|
||||
options:
|
||||
- label: |
|
||||
This is not a request to block ADB, root access, safe mode, factory reset, or
|
||||
OS recovery. Those are never blocked, by design (section 6.7, ADR-11).
|
||||
@@ -0,0 +1,69 @@
|
||||
name: Question
|
||||
description: An open decision for the project owner, or something blocking work
|
||||
title: ""
|
||||
labels: ["question"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
CLAUDE.md section 10.3: any open question becomes an issue labelled
|
||||
"question" instead of being buried in a chat thread where it gets lost.
|
||||
|
||||
Most questions here are ones the agent cannot answer alone — section 0 rule 3
|
||||
requires stopping to ask before adding an unlisted dependency, changing the
|
||||
architecture, or choosing between two non-obvious OS mechanisms.
|
||||
|
||||
- type: textarea
|
||||
id: question
|
||||
attributes:
|
||||
label: The question
|
||||
description: One question. If there are several, they need separate issues.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: kind
|
||||
attributes:
|
||||
label: What kind of decision is this?
|
||||
options:
|
||||
- Dependency to add (section 0 rule 3)
|
||||
- Architecture change (section 0 rule 3)
|
||||
- Choice between OS mechanisms (section 0 rule 3)
|
||||
- Licensing
|
||||
- Scope or priority
|
||||
- Something else
|
||||
|
||||
- type: input
|
||||
id: blocks
|
||||
attributes:
|
||||
label: What does this block?
|
||||
description: Which milestone, and what specifically cannot proceed.
|
||||
placeholder: "M2-Linux: the KWin backend cannot be written until the block-window approach is chosen."
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: options
|
||||
attributes:
|
||||
label: Options and trade-offs
|
||||
description: |
|
||||
What are the realistic choices, and what does each cost? Include binary size,
|
||||
licence, and maintenance burden where they apply.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: recommendation
|
||||
attributes:
|
||||
label: Recommendation, if you have one
|
||||
description: |
|
||||
Optional. A default the agent has been proceeding with, so it can keep working
|
||||
while you decide. Say here if you would rather it stop and wait.
|
||||
|
||||
- type: textarea
|
||||
id: research
|
||||
attributes:
|
||||
label: Supporting research
|
||||
description: |
|
||||
Measurements, documentation links, or a comparison. Links are more useful than
|
||||
conclusions.
|
||||
@@ -0,0 +1,88 @@
|
||||
<!--
|
||||
Pull request template for Blocker.
|
||||
|
||||
CLAUDE.md section 10.2 requires each PR to state: what changed, which section 1
|
||||
requirement it covers, test evidence, and perf numbers if it touches the hot path.
|
||||
|
||||
Test evidence means pasted output. A claim that tests pass is not evidence; the
|
||||
output is. Section 10.6: if a check fails, say so in the PR — do not weaken a test
|
||||
to make it pass.
|
||||
-->
|
||||
|
||||
## What changed
|
||||
|
||||
<!-- What this PR does, in a paragraph. Not a file list — the diff is the file list. -->
|
||||
|
||||
Refs #
|
||||
|
||||
## Which requirement this covers
|
||||
|
||||
<!--
|
||||
Quote the relevant part of CLAUDE.md section 1. If this covers none, say so plainly
|
||||
and explain why the change exists anyway — refactors and CI changes legitimately
|
||||
cover no user-facing requirement, but that should be visible rather than assumed.
|
||||
-->
|
||||
|
||||
Section 1:
|
||||
|
||||
## Test evidence
|
||||
|
||||
<!--
|
||||
Paste the actual output of `scripts/ci.sh`. Not "all tests pass" — the output.
|
||||
|
||||
Note any check that SKIPPED, and why. A skip is not a pass, and saying so here is
|
||||
part of the evidence.
|
||||
```
|
||||
|
||||
$ scripts/ci.sh
|
||||
...
|
||||
```
|
||||
|
||||
## Performance
|
||||
|
||||
<!--
|
||||
Required if this touches the hot path — the evaluator, the event loop, the block
|
||||
screen, or anything that runs on every focus change (section 9).
|
||||
|
||||
Otherwise write "not affected" and say why.
|
||||
-->
|
||||
|
||||
Measured against section 5:
|
||||
|
||||
| Metric | Target | Before | After |
|
||||
|---|---|---|---|
|
||||
| | | | |
|
||||
|
||||
Command used:
|
||||
|
||||
```
|
||||
|
||||
## Checklist
|
||||
|
||||
- [ ] Each commit builds and passes tests on its own (section 10.2)
|
||||
- [ ] Commits are conventional (`feat:`, `fix:`, `perf:`, `refactor:`, `test:`, `docs:`, `ci:`)
|
||||
- [ ] `scripts/ci.sh` passes, or every skip is explained above
|
||||
- [ ] New golden decision-table cases are **added**, and behaviour changes are
|
||||
matched by a case change in the same commit (the add-before-change rule)
|
||||
- [ ] Every fallible OS or I/O call is handled — no `unwrap()`/`expect()` outside
|
||||
tests (section 0 rule 5)
|
||||
- [ ] Perf budget re-measured if the hot path was touched (section 9)
|
||||
- [ ] Any platform that cannot comply has its gap documented in `docs/LIMITATIONS.md`
|
||||
- [ ] No credentials, keystores, `.env` files, or local databases in the diff
|
||||
- [ ] No secret, API token, SSH key, or private path appears in the diff
|
||||
- [ ] No dependency added without sign-off (section 0 rule 3) and an ADR entry
|
||||
|
||||
## Notes for the reviewer
|
||||
|
||||
<!--
|
||||
Anything you would flag yourself: a place you are unsure about, a shortcut taken, a
|
||||
decision that needs a second opinion.
|
||||
|
||||
If a check fails, say so here. A failing check stated plainly is fine. A failing
|
||||
check hidden by a weakened test is not, and section 10.6 prohibits it.
|
||||
-->
|
||||
|
||||
## Do not merge this yourself
|
||||
|
||||
The agent does not merge its own PR (section 10.2). Squash or rebase merge, keep
|
||||
history linear. Tag the milestone when it lands.
|
||||
@@ -0,0 +1,119 @@
|
||||
# Gitea Actions setup
|
||||
|
||||
**The owner has not yet confirmed whether a runner is registered on this Gitea.**
|
||||
Until one is, `scripts/ci.sh` is the only thing gating merges, and every check must
|
||||
be run locally before opening a PR.
|
||||
|
||||
The workflows in this directory are written for **act_runner**, Gitea's
|
||||
act-compatible runner, which executes jobs in Docker. They are also close enough to
|
||||
GitHub Actions syntax that a GitHub-style runner would work with the labels
|
||||
adjusted.
|
||||
|
||||
---
|
||||
|
||||
## Labels these workflows expect
|
||||
|
||||
| File | `runs-on` | Needs |
|
||||
|---|---|---|
|
||||
| `ci.yml` → `ci` | `ubuntu-latest` | Rust toolchain, no Android SDK |
|
||||
| `ci.yml` → `android` | `android-build` | JDK 17 + Android SDK 35 |
|
||||
|
||||
If your runner is registered under different labels, change `runs-on` here. Both
|
||||
must be changed together — a mismatch shows up as a job that queues forever, with
|
||||
no error message, which is the worst failure mode of a mislabelled runner.
|
||||
|
||||
---
|
||||
|
||||
## Registering act_runner
|
||||
|
||||
On the runner host, with Docker present:
|
||||
|
||||
```sh
|
||||
# 1. Generate a registration token, in Gitea's UI:
|
||||
# Site Administration → Actions → Runners → Create new runner
|
||||
# Copy the token.
|
||||
|
||||
# 2. Register. --instance is the URL Gitea is reachable at *from the runner*.
|
||||
act_runner register \
|
||||
--instance https://git.valiq.vu \
|
||||
--token "<REGISTRATION_TOKEN>" \
|
||||
--name blocker-ci \
|
||||
--labels ubuntu-latest:docker://node:20-bookworm \
|
||||
--labels android-build:docker://ghcr.io/cirruslabs/android-sdk:34
|
||||
|
||||
# 3. Start it.
|
||||
./act_runner run --server http://localhost:8080
|
||||
```
|
||||
|
||||
Each `--labels` entry is `name:docker://image`. The runner runs the job inside that
|
||||
container, so the image must contain everything the job needs:
|
||||
|
||||
- `ubuntu-latest` — needs `bash`, `git`, `curl`, and Rust. The workflow installs
|
||||
Rust via `dtolnay/rust-toolchain`, so a Rust-free base image is fine.
|
||||
- `android-build` — needs JDK 17 and the Android SDK, hence the Cirrus Labs image.
|
||||
|
||||
### Running act_runner as a service
|
||||
|
||||
```ini
|
||||
# /etc/systemd/system/act_runner.service
|
||||
[Unit]
|
||||
Description=Gitea Actions runner
|
||||
After=docker.service
|
||||
Requires=docker.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=git
|
||||
WorkingDirectory=/opt/act_runner
|
||||
ExecStart=/opt/act_runner/act_runner run --server http://localhost:3000 --config /opt/act_runner/config.yml
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## What the runner still needs from the owner
|
||||
|
||||
CLAUDE.md section 10.4 says to ask whether the runner has the Android SDK. **Not
|
||||
yet answered.** The two behaviours are deliberately different until it is:
|
||||
|
||||
- `scripts/ci.sh` **skips** Android when no SDK is found, and prints SKIP with the
|
||||
reason. A developer should not be blocked from running checks by a missing
|
||||
toolchain.
|
||||
- The `android` job in CI **fails** when the SDK is missing. A silently skipped
|
||||
Android build in CI means Android regressions ship unnoticed.
|
||||
|
||||
Same check, opposite defaults, because the contexts are opposite. If you would
|
||||
rather the CI job also skip, say so and it will be changed — but the failure mode
|
||||
of the current setting is "you find out from a user", which is worse.
|
||||
|
||||
---
|
||||
|
||||
## Why the workflow calls scripts/ci.sh
|
||||
|
||||
`ci.yml` runs `bash scripts/ci.sh` rather than repeating the fmt/clippy/test/size
|
||||
steps inline.
|
||||
|
||||
The reason is drift. A workflow that reimplements the checks is a second
|
||||
definition of "done". The two diverge — someone adds a check locally, forgets CI,
|
||||
and green ticks mean nothing. One script, two callers, no drift.
|
||||
|
||||
The workflow keeps separate steps for checkout, toolchain install, caching, and
|
||||
artifact upload, because those are genuinely different between a runner and a
|
||||
laptop.
|
||||
|
||||
---
|
||||
|
||||
## Action pinning
|
||||
|
||||
Every action is pinned to an exact version (`@v4.1.7`, not `@v4`, and never `@main`).
|
||||
|
||||
A floating tag means upstream can change what runs in your CI without a review, a
|
||||
tag can be repointed, and `@main` can change arbitrarily. On a self-hosted runner
|
||||
that is a supply chain problem: the code that decides whether a change is safe to
|
||||
merge is code someone else controls.
|
||||
|
||||
Bumping a pin is its own commit, so the diff shows what changed.
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user