Merge branch 'master' into f/badge-subscriptions

This commit is contained in:
spaced4ndy committed 2026-10-27 12:08:14 +04:00
commit d3e2157dca
26 files changed
+528 -169

No files matched your search

+149 -3
View File
@@ -1,14 +1,158 @@
# App tests on GitHub's runners
# CI on GitHub's runners
Three workflows build the apps from a branch's own code and test them, only when asked: `ios-sim` (the iOS app in a simulator on a macOS runner), `desktop-linux` (the desktop app on a Linux runner) and `android-emu` (the Android app in an emulator on a Linux runner). Each runs a scripted smoke test and, on request, a Claude session that follows a test plan, and a test backend (relay, directory, names server, peers). Details: [iOS](ios-sim/README.md), [desktop](desktop-linux/README.md), [Android](android/README.md).
## Reduced build
GitHub runs the reduced build of `build.yml` on a dispatch (workflow_dispatch), on each push to a draft pull request and on a push to master or stable in a fork. Once the pull request is marked ready for review, GitHub runs the full matrix, as on a push to master or stable in simplex-chat/simplex-chat.
On a push to master or stable in a fork, the release steps and tests are skipped; build-linux saves the -O0 build caches, and on master the Docker image cache, that the fork's dispatches restore.
On a draft pull request, the tests are selected by a fenced block with the info string `ci-tests` in the description, one hspec match pattern per line; the block is read at each push. `/` runs the whole suite; without a block, the reduced build runs no tests.
### Dispatch
```sh
curl -fsS -X POST \
-H "Authorization: Bearer $GH_TOKEN" \
-H "Accept: application/vnd.github+json" \
https://api.github.com/repos/<owner>/simplex-chat/actions/workflows/build.yml/dispatches \
-d '{"ref": "<branch>", "inputs": {"tests": "/SimpleX chat client/group tests/\n/Message batching/"}}'
```
Endpoint: https://docs.github.com/en/rest/actions/workflows#create-a-workflow-dispatch-event. Inputs:
| Input | Default | Value |
|---|---|---|
| `tests` | empty | hspec match patterns, one per line (`\n` in JSON); `/` runs the whole suite, and an empty value builds without tests |
| `base` | `master` | the branch that the changes are compared with:<br>`stable` for a branch cut from stable<br>the parent branch for a stacked branch |
When a newer dispatch on the same branch starts build-linux or build-ios, GitHub cancels the unfinished job of the older one (`cancel-in-progress`).
Results:
- Run and jobs: `GET /repos/<owner>/simplex-chat/actions/runs?head_sha=<commit>&event=workflow_dispatch` returns the run id; `GET /repos/<owner>/simplex-chat/actions/runs/<run id>/jobs` returns each step with its start, end and conclusion.
- Job log: `GET /repos/<owner>/simplex-chat/actions/jobs/<job id>/logs` returns a redirect to a text file, valid for 1 minute (https://docs.github.com/en/rest/actions/workflow-jobs#download-job-logs-for-a-workflow-run). The test summary is printed as "Finished in N seconds" and "N examples, N failures".
### Scopes
The reduced build runs one Linux job, build-linux (ubuntu-22.04 x86_64), for every scope except ios, and one macOS job, build-ios (macos-latest), for ios.
#### core
- Globs: `BUILD_CHANGES["haskell"]` in packages_release.py.
- CI, in build-linux:
- Docker image (step "Build and cache Docker image");
- caches (the steps "Restore ... from cache");
- `cabal build -j --enable-tests --ghc-options=-O0` (step "Build CLI");
- simplex-chat-test with the selected tests (step "Run tests").
- Local:
```sh
cp scripts/cabal.project.local.linux cabal.project.local
cabal build --enable-tests --ghc-options=-O0
mkdir -p tests/tmp
cabal test simplex-chat-test --ghc-options=-O0 --test-option=-m --test-option='/SimpleX chat client/group tests/'
```
The selection runs as in CI with scripts/ci/run-tests.sh, which appends the patterns of `TESTS` to the test binary:
```sh
TESTS='/SimpleX chat client/group tests/' scripts/ci/run-tests.sh "$(cabal list-bin simplex-chat-test --ghc-options=-O0)"
```
`--ghc-options=-O0` matches the reduced build; the library and test-suite stanzas of simplex-chat.cabal set -O2. Test directories are created under tests/tmp (`tmpBracket` in tests/Test.hs).
#### kotlin
- Globs: `BUILD_CHANGES["kotlin"]` in packages_release.py.
- CI: Gradle in the Docker container of build-linux (step "Build and test Kotlin apps", matrix field `kotlin`).
- Local:
```sh
cd apps/multiplatform
./gradlew --no-daemon --max-workers=1 :common:desktopTest :desktop:compileKotlinJvm -x :desktop:cmakeBuildAndCopy :android:compileGoogleDebugKotlin :android:testFossDebugUnitTest
```
JDK 17 and an Android SDK in ANDROID_HOME are required, as installed by Dockerfile.build.
#### ios
- Globs:
- apps/ios/**
- scripts/ci/ios-stub-libs.sh
- CI: build-ios: stub libraries, then xcodebuild for the iOS Simulator without signing.
- Local, on macOS: `scripts/ci/ios-stub-libs.sh`, then the xcodebuild command of the step "Build iOS app" of build-ios.
#### packages
- Globs:
- packages/simplex-chat-nodejs/**
- packages/simplex-chat-client/types/typescript/**
- packages/simplex-chat-python/**
- scripts/ci/package-tests.sh
- CI, in build-linux:
- Node 22 and Python 3.12 (steps "Setup Node.js" and "Setup Python");
- libsimplex, when `CORE_SOURCES` of packages_release.py also changed (step "Build library");
- `package-tests.sh build linux-x86_64` and `package-tests.sh test` (step "Package tests (pull request)").
- With libsimplex built, SIMPLEX_LIBS_DIR is set to it for the nodejs tests; the python tests run with it unset (package-tests.sh). Without SIMPLEX_LIBS_DIR, the pinned release libraries are downloaded (packages/simplex-chat-nodejs/src/libs.ts).
- Local:
```sh
scripts/ci/package-tests.sh build linux-x86_64
scripts/ci/package-tests.sh test
```
#### badge-web
- Globs: apps/simplex-badge-service/web/**. These paths are also in the core globs (apps/simplex-badge-service/**), and web/src/catalog.ts is read by core tests (tests/Bots/BadgeService/CatalogTests.hs, WebTests.hs).
- CI, in build-linux: core build and tests, then `scope-tests.sh badge-web` (step "Test changed scopes").
- Selected core tests: `/SimpleX badge service/` and `/SimpleX badge service e2e/`.
- Local:
```sh
cd apps/simplex-badge-service/web
npm ci
npm test
```
#### ci-scripts
- Globs:
- scripts/ci/packages_release.py
- scripts/ci/test_packages_release.py
- These paths are also in the core globs (scripts/ci/**).
- CI, in build-linux: `scope-tests.sh ci-scripts` (step "Test changed scopes").
- Local: `python3 scripts/ci/test_packages_release.py`; Python 3.11 or newer is required for tomllib (packages_release.py).
#### Scopes lacking CI tests
| Scope | Paths | CI |
|---|---|---|
| ios | apps/ios/** | compile only |
| types package | packages/simplex-chat-client/types/typescript/** | compile only |
| website | website/**<br>images/**<br>blog/**<br>docs/**<br>PRIVACY.md | build and deploy on master pushes (web.yml) |
| ts-client | packages/simplex-chat-client/typescript/** | - |
| webrtc | packages/simplex-chat-webrtc/** | - |
| mcp | packages/simplex-chat-mcp/** | - |
| calculator-bot | apps/simplex-calculator-bot/** | - |
| support-bot | apps/simplex-support-bot/** | - |
| support-bot-light | apps/simplex-support-bot-light/** | - |
| prices | scripts/prices/** | - |
| nft | eth/nft/** | - |
CI coverage of such a scope is added in the pull request that changes it (Adding CI coverage).
### Adding CI coverage
For a scope lacking CI tests, in the pull request that changes it:
1. scripts/ci/packages_release.py: an entry `"<scope>": ["<glob>", ...]` in SCOPE_CHANGES.
2. build.yml, `on.pull_request.paths`: the same globs; the two are compared in `test_build_yml_runs_for_the_paths_of_its_builds` of test_packages_release.py.
3. scripts/ci/scope-tests.sh: a `<scope>)` case with the build and test commands, and the scope name in the usage line.
4. scripts/ci/test_packages_release.py, ChangesTest: a case asserting that the scope is printed in `scopes` for a change to one of its files.
5. This file, "Scopes": a subsection for the scope, in place of its row in "Scopes lacking CI tests".
6. Checks: `python3 scripts/ci/test_packages_release.py`, the new case of scope-tests.sh locally, then a dispatch of the reduced build.
The scope commands run in build-linux after the core tests, with Node 22 and Python 3.12 (steps "Setup Node.js" and "Setup Python"). For a scope that needs other versions, a setup step is added before "Test changed scopes", conditioned on the scope name in `needs.maybe-release.outputs.scopes`. A scope that needs macOS is a BUILD_CHANGES entry with a separate maybe-release output, as ios is, and a step in build-ios; the `if` of build-ios includes that output.
## Starting a run
Pushes start nothing: a run is started by hand, on any branch, with inputs that are off by default and combine.
Pushes start none of the app workflows: a run is started by hand, on any branch, with inputs that are off by default and combine.
| Input | iOS | Desktop | Android |
|---|---|---|---|
| no input | scripted test | scripted test | scripted test |
| no input | scripted test, the app uploaded | scripted test, the app uploaded | scripted test, the app uploaded |
| `claude` | scripted test, then Claude | scripted test, then Claude | scripted test, then Claude |
| `backend` | also the test backend | also the test backend | also the test backend |
| `release` | — | also the latest release's onboarding, to tell a branch's failure from the runner's | also the latest release's onboarding, to tell a branch's failure from the runner's |
@@ -24,6 +168,8 @@ gh workflow run android-emu.yml --ref <branch> -f claude=true
A newer run of a workflow on the same branch cancels the older one.
Each run uploads the app it built, for manual tests, as an artifact kept 14 days: `ios-sim-app` (SimpleX.app.tar.gz, for the iOS simulator on an Apple-silicon Mac), `desktop-app` (desktop-app.tar.gz, for Linux x86-64) and `android-app` (the debug APK, arm64-v8a only). The run's page lists it under Artifacts; `gh run download <run id> -n <artifact>` downloads it.
## How long a run takes
| Run | iOS | Desktop | Android |
+2 -2
View File
@@ -4,7 +4,7 @@
## Running it
The workflow runs only when started by hand, on any branch: in the Actions tab, `android-emu` → Run workflow, or `gh workflow run android-emu.yml --ref <branch>` with `-f claude=true`, `-f backend=true` or `-f release=true`. [App tests on GitHub's runners](../README.md) lists the inputs. A newer run on the same branch cancels the older one.
The workflow runs only when started by hand, on any branch: in the Actions tab, `android-emu` → Run workflow, or `gh workflow run android-emu.yml --ref <branch>` with `-f claude=true`, `-f backend=true` or `-f release=true`. [CI on GitHub's runners](../README.md) lists the inputs. A newer run on the same branch cancels the older one.
Every run builds the core library, and the backend when it's asked for, from the branch's own Haskell code. It reuses an earlier build only when the sources are unchanged, as an artifact of the same branch named after a hash of its sources (30 days): for the core `src/**`, `cabal.project`, `simplex-chat.cabal`, `PRIVACY.md`, the Nix files (`flake.nix`, `flake.lock`, `scripts/nix/**`) and `build-core.sh`; the backend is desktop-linux's, under its name and hash, so a backend either workflow built is reused by both. The workflow saves no Actions caches, which this repository evicts within hours and shares with `build.yml`.
@@ -19,7 +19,7 @@ Every run builds the core library, and the backend when it's asked for, from the
| `backend` (opt-in) | desktop-linux's `build-backend.sh` | about 30 min, skipped when reused |
| `release` (opt-in) | the latest release's arm64 APK, its signer checked against SimpleX's key, onboarding only | about 4 min |
Results are artifacts: `android-smoke-test` (numbered screenshots, the accessibility tree and the text of each, `steps.log`, `checks.txt`, logcat as `app.log`, `emulator.log`), `android-release-smoke-test`, `android-claude-test`, and the backend's logs; `android-app`, the APK for the Claude job, is kept a day. The job summaries list the checks and the Claude usage.
Results are artifacts: `android-smoke-test` (numbered screenshots, the accessibility tree and the text of each, `steps.log`, `checks.txt`, logcat as `app.log`, `emulator.log`), `android-release-smoke-test`, `android-claude-test`, and the backend's logs; `android-app`, the APK for manual tests and the Claude job, is kept 14 days. The job summaries list the checks and the Claude usage.
## The emulator
+2 -2
View File
@@ -4,7 +4,7 @@
## Running it
The workflow runs only when started by hand, on any branch, from the Actions tab or with `gh workflow run`: [App tests on GitHub's runners](../README.md) says how and lists the inputs.
The workflow runs only when started by hand, on any branch, from the Actions tab or with `gh workflow run`: [CI on GitHub's runners](../README.md) says how and lists the inputs.
Every run builds the core library, and the backend when it's asked for, from the branch's own Haskell code. It reuses an earlier build only when the sources are unchanged, as an artifact of the same branch named after a hash of its sources (30 days): for the core `src/**`, `cabal.project`, `simplex-chat.cabal`, `PRIVACY.md` and the build scripts, for the backend `src/**`, the CLI's and the directory's sources, `cabal.project`, `simplex-chat.cabal` and its build script. So a branch that changes core and app code together tests both. The workflow saves no Actions caches, which this repository evicts within hours and shares with `build.yml`.
@@ -19,7 +19,7 @@ Every run builds the core library, and the backend when it's asked for, from the
| `backend` (opt-in) | `build-backend.sh`: `simplex-chat`, `simplex-directory-service`, and `smp-server` from the simplexmq commit `cabal.project` pins | about 30 min, skipped when reused |
| `release` (opt-in) | the latest release's .deb for this Ubuntu, onboarding only, to tell a branch's failure from the runner's | 1.5 min |
Queueing for a runner adds from under a minute to 20 minutes. Results are artifacts: `desktop-smoke-test` (numbered screenshots, the text OCR read from each, `steps.log`, `checks.txt`, `app.log`), `desktop-test-report`, `desktop-claude-test`, and the backend's logs; `desktop-app`, the distributable for the Claude job, is kept a day. The job summaries list the checks, the desktopTest results and the Claude usage.
Queueing for a runner adds from under a minute to 20 minutes. Results are artifacts: `desktop-smoke-test` (numbered screenshots, the text OCR read from each, `steps.log`, `checks.txt`, `app.log`), `desktop-test-report`, `desktop-claude-test`, and the backend's logs; `desktop-app`, the distributable for manual tests and the Claude job, is kept 14 days. The job summaries list the checks, the desktopTest results and the Claude usage.
## Scripts
+2 -2
View File
@@ -4,7 +4,7 @@
## Running it
The workflow runs only when started by hand, on any branch, from the Actions tab or with `gh workflow run`: [App tests on GitHub's runners](../README.md) says how and lists the inputs.
The workflow runs only when started by hand, on any branch, from the Actions tab or with `gh workflow run`: [CI on GitHub's runners](../README.md) says how and lists the inputs.
Results: the job logs, the Claude job's summary (Claude's usage) and the artifacts `ios-sim-smoke-test` (a screenshot, a 1000-px view and an accessibility tree per step, the app log), `ios-sim-backend-logs` and `ios-sim-claude-test` (the Claude job's smoke test in `smoke-test/`, and per session: `prompt.md`, `report.md`, `shots/`, `transcript.jsonl`, `usage.json`). Read them with `gh run view <id> --log` and `gh run download <id> -n <artifact>`.
@@ -22,7 +22,7 @@ The macOS jobs run on `macos-26`, the image with Xcode 26 and the iPhone 17 simu
## The Claude session
It runs in its own job, `claude`, once the app job has passed: the job installs that job's build (the artifact `ios-sim-app`, kept a day) in a new simulator, runs the smoke test to reach the sessions' starting state, then one session per layout listed in `claude-scope`, with Claude Code installed from npm at the version the desktop workflow pins too. Only this job references the environment `app-sim-claude`, which holds the secret `CLAUDE_CODE_OAUTH_TOKEN` (a Claude subscription token) and admits the branches its rule allows; one runs per branch at a time. Only the Claude step gets the token, and `claude-test.sh` passes it to the `claude` processes alone. The job checks out without persisting its GitHub token and installs a pinned AXe (`install-axe.sh`), since it holds the Claude token. It starts the test backend when `claude-scope` says `backend: yes`; a run that asks for Claude must then ask for the backend too, or the plan job fails. On master it says `no`, since the smoke plan doesn't use the backend.
It runs in its own job, `claude`, once the app job has passed: the job installs that job's build (the artifact `ios-sim-app`, kept 14 days) in a new simulator, runs the smoke test to reach the sessions' starting state, then one session per layout listed in `claude-scope`, with Claude Code installed from npm at the version the desktop workflow pins too. Only this job references the environment `app-sim-claude`, which holds the secret `CLAUDE_CODE_OAUTH_TOKEN` (a Claude subscription token) and admits the branches its rule allows; one runs per branch at a time. Only the Claude step gets the token, and `claude-test.sh` passes it to the `claude` processes alone. The job checks out without persisting its GitHub token and installs a pinned AXe (`install-axe.sh`), since it holds the Claude token. It starts the test backend when `claude-scope` says `backend: yes`; a run that asks for Claude must then ask for the backend too, or the plan job fails. On master it says `no`, since the smoke plan doesn't use the backend.
Each session's final message ends with `CLAUDE-TEST: PASS`, or `CLAUDE-TEST: FAIL` and the failed cases; the step fails unless every session passes.
+19 -4
View File
@@ -10,7 +10,8 @@ publish-release publish a draft release that has every asset
check-pins check the pins of the packages against the published releases
download download a release asset and check its digest
download-pinned download a pinned asset and check its pin
changes print whether the changes since a commit touch the chat core, the add-on and each build of build.yml
changes print whether the changes since a commit touch the chat core, the add-on, each build of build.yml and each scope of scope-tests.sh
scopes print every scope of scope-tests.sh
build-plan print the platforms to test the packages on, none when build.yml builds the core for the pull request
prepare update pins and versions of the packages
publish-plan print the package versions that are not published yet
@@ -47,7 +48,7 @@ RELEASE_FILE = f"{NODEJS_DIR}/src/release.ts"
PYTHON_VERSION_FILE = f"{PYTHON_DIR}/src/simplex_chat/_version.py"
ADDON_SOURCES = [f"{NODEJS_DIR}/binding.gyp", f"{NODEJS_DIR}/cpp"]
CORE_SOURCES = ["src", "simplex-chat.cabal", "cabal.project"]
# The pull_request paths of build.yml are the union of these globs; ":!" excludes a path from its build.
# The pull_request paths of build.yml are the union of the globs of BUILD_CHANGES and SCOPE_CHANGES; ":!" excludes a path from its build.
BUILD_CHANGES = {
"haskell": [
"src/**",
@@ -68,7 +69,17 @@ BUILD_CHANGES = {
".github/**",
],
"kotlin": ["apps/multiplatform/**", "Dockerfile*", ".github/**"],
"ios": ["apps/ios/**", "scripts/ci/ios-stub-libs.sh", ".github/**"],
"ios": ["apps/ios/**", "scripts/ci/ios-stub-libs.sh"],
"packages": [
"packages/simplex-chat-nodejs/**",
"packages/simplex-chat-client/types/typescript/**",
"packages/simplex-chat-python/**",
"scripts/ci/package-tests.sh",
],
}
SCOPE_CHANGES = {
"badge-web": ["apps/simplex-badge-service/web/**"],
"ci-scripts": ["scripts/ci/packages_release.py", "scripts/ci/test_packages_release.py"],
}
CABAL_FILE = "simplex-chat.cabal"
CABAL_VERSION = re.compile(r"^(version:\s*)(\S+)", re.M)
@@ -496,7 +507,7 @@ def changed_since(base: str, sources: list[str]) -> bool:
def build_pathspecs(build: str) -> list[str]:
return [path if path.startswith(":") else f":(glob){path}" for path in BUILD_CHANGES[build]]
return [path if path.startswith(":") else f":(glob){path}" for path in (BUILD_CHANGES | SCOPE_CHANGES)[build]]
def changes(base: str) -> None:
@@ -504,6 +515,7 @@ def changes(base: str) -> None:
print(f"addon={'true' if changed_since(base, ADDON_SOURCES) else ''}")
for build in BUILD_CHANGES:
print(f"{build}={'true' if changed_since(base, build_pathspecs(build)) else ''}")
print(f"scopes={' '.join(scope for scope in SCOPE_CHANGES if changed_since(base, build_pathspecs(scope)))}")
def print_build_plan(args: argparse.Namespace) -> None:
@@ -959,6 +971,7 @@ def main(argv: list[str]) -> None:
download_pinned_parser.add_argument("directory")
changes_parser = commands.add_parser("changes")
changes_parser.add_argument("base", help="the commit to compare with")
commands.add_parser("scopes")
build_parser = commands.add_parser("build-plan")
build_parser.add_argument("--base", required=True, help="the base commit of the pull request")
prepare_parser = commands.add_parser("prepare")
@@ -996,6 +1009,8 @@ def main(argv: list[str]) -> None:
download_pinned(args.asset, args.directory)
elif args.command == "changes":
changes(args.base)
elif args.command == "scopes":
print(f"scopes={' '.join(SCOPE_CHANGES)}")
elif args.command == "build-plan":
print_build_plan(args)
elif args.command == "prepare":
+38
View File
@@ -0,0 +1,38 @@
#!/bin/bash
set -euo pipefail
if [ "$#" -eq 0 ]; then
echo "usage: $0 <test command>" >&2
exit 1
fi
if [ -n "${PR_BODY:-}" ]; then
TESTS=$(printf '%s\n' "$PR_BODY" | tr -d '\r' | awk '/^```ci-tests[ \t]*$/ {f = 1; next} /^```[ \t]*$/ {f = 0} f')
fi
args=()
while read -r p; do
if [ -n "$p" ]; then args+=(-m "$p"); fi
done <<< "${TESTS:-}"
if [ "${#args[@]}" -gt 0 ]; then
args+=(--fail-on=empty)
elif [ "${REDUCED:-}" = true ]; then
echo "No tests selected"
exit 0
fi
i=1
attempts=${ATTEMPTS:-1}
while [ "$i" -le "$attempts" ]; do
if "$@" "${args[@]}"; then
break
elif [ "$i" -lt "$attempts" ]; then
echo "Attempt $i failed, retrying..."
sleep 1
fi
i=$((i + 1))
done
if [ "$i" -gt "$attempts" ]; then
echo "Attempt $attempts failed."
exit 1
fi
+18
View File
@@ -0,0 +1,18 @@
#!/bin/bash
set -euo pipefail
cd "$(dirname "$0")/../.."
case "${1:-}" in
badge-web)
(cd apps/simplex-badge-service/web && npm ci && npm test)
;;
ci-scripts)
python3 scripts/ci/test_packages_release.py
;;
*)
echo "usage: $0 badge-web | ci-scripts" >&2
exit 1
;;
esac
+17 -5
View File
@@ -27,6 +27,7 @@ from packages_release import (
TYPES_README,
ADDON_PLATFORMS,
BUILD_CHANGES,
SCOPE_CHANGES,
LIBS_ASSETS,
Package,
Pins,
@@ -245,7 +246,7 @@ class BuildPlanTest(unittest.TestCase):
found = re.search(r'^ pull_request:\n paths:\n((?: - ".*"\n)+)', workflow, re.M)
self.assertIsNotNone(found, "no pull_request paths in build.yml")
paths = re.findall(r'^ - "(.*)"$', found[1], re.M)
globs = {path for build in BUILD_CHANGES.values() for path in build if not path.startswith(":")}
globs = {path for build in (BUILD_CHANGES | SCOPE_CHANGES).values() for path in build if not path.startswith(":")}
self.assertEqual(sorted(paths), sorted(globs))
self.assertEqual(len(paths), len(set(paths)), "duplicate pull_request paths in build.yml")
@@ -463,8 +464,8 @@ class ChangesTest(GitRepoTest):
output = io.StringIO()
with mock.patch.object(packages_release, "ROOT", self.repo), contextlib.redirect_stdout(output):
changes(self.base)
values = dict(line.split("=", 1) for line in output.getvalue().splitlines())
return {build for build in BUILD_CHANGES if values[build] == "true"}
self.values = dict(line.split("=", 1) for line in output.getvalue().splitlines())
return {build for build in BUILD_CHANGES if self.values[build] == "true"}
def test_ios_change_builds_only_ios(self):
self.assertEqual(self.builds("apps/ios/Shared/View.swift"), {"ios"})
@@ -487,12 +488,23 @@ class ChangesTest(GitRepoTest):
def test_build_image_change_builds_the_core_and_kotlin(self):
self.assertEqual(self.builds("Dockerfile.build"), {"haskell", "kotlin"})
def test_workflow_change_builds_everything(self):
self.assertEqual(self.builds(".github/workflows/build.yml"), {"haskell", "kotlin", "ios"})
def test_workflow_change_builds_the_core_and_kotlin(self):
self.assertEqual(self.builds(".github/workflows/build.yml"), {"haskell", "kotlin"})
def test_unrelated_change_builds_nothing(self):
self.assertEqual(self.builds("docs/guide.md", "packages/pkg/src.txt"), set())
def test_package_change_builds_only_packages(self):
self.assertEqual(self.builds("packages/simplex-chat-python/src/simplex_chat/client.py"), {"packages"})
def test_badge_web_change_builds_the_core_and_tests_its_scope(self):
self.assertEqual(self.builds("apps/simplex-badge-service/web/src/catalog.ts"), {"haskell"})
self.assertEqual(self.values["scopes"], "badge-web")
def test_release_script_change_tests_the_ci_scripts(self):
self.assertEqual(self.builds("scripts/ci/packages_release.py"), {"haskell"})
self.assertEqual(self.values["scopes"], "ci-scripts")
class PackageStateTest(GitRepoTest):
def setUp(self):