diff --git a/.claude/rules/ci.md b/.claude/rules/ci.md index 9b2f3c0190..1b0df46f78 100644 --- a/.claude/rules/ci.md +++ b/.claude/rules/ci.md @@ -44,7 +44,7 @@ The required check names are in `AGENTS.md` (CI). Reading a red check: `.claude/ - `Changes (macOS)` outputs `run` (detector `macos`) and `plugins` (detector `plugins`). The test job has a 120-minute limit and sets `NSUnbufferedIO=YES`. - Setup, in order: checkout, setup-xcode, prepare-build (setup-xcodegen, `scripts/download-libs.sh`, `generate-project.sh macos`, SPM restore), resolve, SPM save. - One `build-for-testing` with no `-testPlan` builds both plans and writes one `.xctestrun` per plan, with signing, the index store and the compilation cache off. -- `COMPILE_PLUGINS` is true on every push and dispatch, and on a PR when the `plugins` detector is not false. It adds Go, the Dameng and HANA bridge builds, `xcodebuild build -scheme AllPlugins`, then `scripts/ci/verify-plugin-loads.sh`. +- `COMPILE_PLUGINS` is true when the `plugins` detector is not false, on a PR and a push alike; a dispatch has no base, so it always compiles. It adds Go, the Dameng and HANA bridge builds, `xcodebuild build -scheme AllPlugins`, then `scripts/ci/verify-plugin-loads.sh`. - `test-without-building -testPlan Unit`, then `-testPlan UI`. The UI plan runs after a Unit failure too, so one round trip reports both. - No shards, and no parallel, iteration or retry flags: the plans decide. - `scripts/ci/summarize-xcresult.sh` always runs. Evidence uploads only on failure (`.claude/skills/fix-issue/references/verification-apple.md`, Reading CI). @@ -115,7 +115,7 @@ The required check names are in `AGENTS.md` (CI). Reading a red check: `.claude/ - `detect-changed-paths.sh [--base ] macos|plugins|ios|oracle|hana|release` prints `true` or `false`. An unknown suite or flag exits 2. - A PR passes its base SHA, a push `github.event.before`. No base prints true. The all-zero SHA of a new ref diffs against `git merge-base HEAD origin/main`, so a branch cut from main skips what main already ran; with no merge base it prints true. - `macos` watches the app, test, plugin, package, native, config and libs folders, `TestPlans/`, `project.yml`, the app's `Package.resolved`, the build scripts and CI scripts it runs, the setup actions and its workflow. `Packages/` covers TableProMacCore. -- `plugins` watches `Plugins/`, `Packages/TableProCore/`, `Packages/TableProOracle/`, `Native/`, `Libs/`, `Configs/`, `project.yml`, the bridge scripts and `verify-plugin-loads.sh`. +- `plugins` watches `Plugins/`, `Packages/TableProCore/`, `Packages/TableProOracle/`, `Native/`, `Libs/`, `Configs/`, `project.yml`, the app's `Package.resolved`, the project, libs and bridge scripts, `verify-plugin-loads.sh` and the setup actions. - `ios` watches `TableProMobile/`, `Libs/`, `Plugins/TableProPluginKit/` (the package target is a symlink to it), and every `../` path it reads out of `TableProMobile/project.yml`. - `oracle` watches `Packages/TableProOracle/`; `hana` watches `Native/HanaBridge/`. Each suite also watches its own workflow. - `release` watches what the Release build reads: the app, plugin, package, native, config and libs folders, `project.yml`, the app's `Package.resolved`, `.github/plugin-registry.json`, the release scripts it runs (`build.sh`, `package.sh`, `registry.py`, `version.py`, `notes.py`), the build and CI scripts it runs and the setup actions. It skips `Plugins/*Tests/` and `Packages/*/Tests/`. @@ -126,7 +126,7 @@ The required check names are in `AGENTS.md` (CI). Reading a red check: `.claude/ ## What runs where - A pull request: both changes jobs; macOS Tests and iOS and Package Tests unless their detector says false (Oracle only when its detector is not false); SwiftLint; Repo Hygiene; PR title. `AllPlugins` only when the `plugins` detector is not false. -- A push to main or `release/**`: the same minus PR title, plus Release Build; never cancelled, `AllPlugins` always, the SPM cache saved on a miss. Every code push runs both plans in full; a docs-only or changelog-only push skips the suites through the detector. +- A push to main or `release/**`: the same minus PR title, plus Release Build; never cancelled, the SPM cache saved on a miss. Every code push runs both plans in full; a docs-only or changelog-only push skips the suites through the detector. - A `v*` tag runs only `release.yml`, and a `linux-v*` tag only `release-linux.yml`, which calls `linux-packages.yml`. The test workflows never run on a tag. - `workflow_dispatch` exists on every workflow except `pr-title.yml` and `release.yml`. - `build-linux.yml` builds and tests the Linux app (`linux/docs/testing.md`, CI). Its `Changes (Linux)` job skips the rest when nothing under `linux/` or the scripts and workflows it reads changed, and its `Linux` job gates on all of them. diff --git a/.github/workflows/macos-tests.yml b/.github/workflows/macos-tests.yml index 605609279b..857a952303 100644 --- a/.github/workflows/macos-tests.yml +++ b/.github/workflows/macos-tests.yml @@ -48,7 +48,7 @@ jobs: timeout-minutes: 120 env: NSUnbufferedIO: "YES" - COMPILE_PLUGINS: ${{ github.event_name != 'pull_request' || needs.changes.outputs.plugins != 'false' }} + COMPILE_PLUGINS: ${{ needs.changes.outputs.plugins != 'false' }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 @@ -85,7 +85,7 @@ jobs: | xcbeautify --renderer github-actions # The TablePro scheme builds only the bundled plugins. AllPlugins also compiles the - # registry-only drivers, so every push runs it. + # registry-only drivers. - name: Set up Go for the SAP HANA helper if: ${{ !cancelled() && env.COMPILE_PLUGINS == 'true' }} uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 diff --git a/scripts/ci/detect-changed-paths.sh b/scripts/ci/detect-changed-paths.sh index 8bddf3a372..2d7ddec8fa 100755 --- a/scripts/ci/detect-changed-paths.sh +++ b/scripts/ci/detect-changed-paths.sh @@ -31,8 +31,9 @@ case "$SUITE" in PATTERNS=('Plugins/' 'Packages/TableProCore/' 'Packages/TableProOracle/' 'Native/' 'Libs/' 'Configs/' 'project\.yml$' 'TablePro\.xcodeproj/project\.xcworkspace/xcshareddata/swiftpm/Package\.resolved$' - 'scripts/(build-dameng|build-hana)\.sh$' 'scripts/lib/' 'scripts/ci/verify-plugin-loads\.sh$' - '\.github/actions/setup-xcode/' '\.github/workflows/macos-tests\.yml$') ;; + 'scripts/(generate-project|download-libs|create-openssl-dylibs|build-dameng|build-hana)\.sh$' + 'scripts/lib/' 'scripts/ci/verify-plugin-loads\.sh$' + '\.github/actions/(setup-xcode(gen)?|prepare-build)/' '\.github/workflows/macos-tests\.yml$') ;; ios) # The package's TableProPluginKit target is a symlink, so git reports its changes here. PATTERNS=('TableProMobile/' 'Libs/' 'Plugins/TableProPluginKit/' diff --git a/scripts/ci/test_detect_changed_paths.py b/scripts/ci/test_detect_changed_paths.py index d564999549..3e1acec325 100644 --- a/scripts/ci/test_detect_changed_paths.py +++ b/scripts/ci/test_detect_changed_paths.py @@ -155,6 +155,50 @@ def test_macos_runs_on_the_notes_script_its_build_phase_reads(self): self.assertEqual(self.verdict_after("macos", "scripts/release/notes.py"), "true") self.assertEqual(self.verdict_after("macos", "scripts/release/feed.py"), "false") + def test_plugins_runs_on_what_the_plugin_build_reads(self): + for path in [ + "Plugins/OracleDriverPlugin/OraclePlugin.swift", + "Plugins/TableProPluginKit/PluginKit.swift", + "Packages/TableProCore/Sources/Core.swift", + "Packages/TableProOracle/Package.swift", + "Native/HanaBridge/go.mod", + "Native/DamengBridge/src/lib.rs", + "Libs/checksums.sha256", + "Configs/Base.xcconfig", + "project.yml", + "TablePro.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved", + "scripts/generate-project.sh", + "scripts/download-libs.sh", + "scripts/create-openssl-dylibs.sh", + "scripts/build-dameng.sh", + "scripts/build-hana.sh", + "scripts/lib/deployment-target.sh", + "scripts/ci/verify-plugin-loads.sh", + ".github/actions/setup-xcode/action.yml", + ".github/actions/setup-xcodegen/action.yml", + ".github/actions/prepare-build/action.yml", + ".github/workflows/macos-tests.yml", + ]: + with self.subTest(path=path): + self.assertEqual(self.verdict_after("plugins", path), "true") + + def test_plugins_skips_the_app_its_tests_and_other_workflows(self): + for path in [ + "TablePro/App.swift", + "TableProTests/AppTests.swift", + "TableProUITests/AppUITests.swift", + "TestPlans/Unit.xctestplan", + "Packages/TableProMacCore/Sources/MacCore.swift", + "Packages/TableProEditor/Sources/Editor.swift", + "TableProMobile/App.swift", + "scripts/ci/summarize-xcresult.sh", + "scripts/release/build.sh", + ".github/workflows/ios-tests.yml", + ".github/workflows/release-build.yml", + ]: + with self.subTest(path=path): + self.assertEqual(self.verdict_after("plugins", path), "false") + def test_changelog_files_run_no_suite(self): for suite in ["macos", "plugins", "oracle", "hana", "release"]: for path in ["CHANGELOG.md", "changelog.d/3500.added.md", "towncrier.toml", "appcast.xml"]: