Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
634dc9f688
|
||
|
|
da5779f872 | ||
|
|
874971aa47 | ||
|
|
756943f2b5 | ||
|
|
c675f1817f | ||
|
|
c2be713446 | ||
|
|
dc40fa43bc | ||
|
|
2ae7ded357 | ||
|
|
dd15f22031 |
No files matched your search
@@ -0,0 +1,31 @@
|
||||
# Gitea CI on the shared KofTwentyTwo/ci-workflows macOS workflow (grogu). The .github workflows keep
|
||||
# running on the GitHub mirror (release, notarization, appcast); this one is build only and unsigned.
|
||||
#
|
||||
# Guard B the de-paywall marker and the if-false wrap are still in computeState() (docs/PLAN-maintained-fork.md §4.4)
|
||||
# Guard C no unresolved merge conflict markers in the tree
|
||||
# build the Release scheme, unsigned (a compile check at macOS 12.0: grogu has only Xcode 27)
|
||||
# Guard A the Test scheme is compiled (build-for-testing) but not run: the grogu runner has no GUI session for
|
||||
# testmanagerd. Run scripts/run_tests.sh locally before merging (docs/contributing.md).
|
||||
name: build
|
||||
on:
|
||||
push:
|
||||
branches: ['**']
|
||||
jobs:
|
||||
macos:
|
||||
uses: self:KofTwentyTwo/ci-workflows/.gitea/workflows/macos.yaml@v1
|
||||
with:
|
||||
commands: |
|
||||
F=src/pro/license/LicenseManager.swift
|
||||
[ -f "$F" ] || { echo "::error::Guard B: $F not found; chokepoint moved? Refresh the de-paywall patch (§6.2)."; exit 1; }
|
||||
grep -q 'depaywall' "$F" || { echo "::error::PAYWALL RELOCKED: 'depaywall' marker missing from $F (§6.2)."; exit 1; }
|
||||
grep -Eq 'guard[[:space:]]+false[[:space:]]+else' "$F" || { echo "::error::PAYWALL RELOCKED: 'if false { … }' wrap missing from $F (§6.2)."; exit 1; }
|
||||
echo "Guard B OK"
|
||||
if git -c grep.lineNumber=false grep -nE '^(<<<<<<<|=======|>>>>>>>)' -- . ':(exclude)docs/'; then
|
||||
echo "::error::UNRESOLVED CONFLICT MARKERS present; resolve before merge (§4.4 Guard C)."; exit 1
|
||||
fi
|
||||
echo "Guard C OK"
|
||||
# grogu has only Xcode 27.2, which rejects the app's 10.13 deployment target (the shipping build is the GitHub
|
||||
# mirror's, on Xcode 26.0.1). This compile check builds at 12.0 with the same deprecation downgrade as
|
||||
# config/test-base.xcconfig; every other Swift warning stays an error.
|
||||
xcodebuild -quiet -project alt-tab-macos.xcodeproj -scheme Release -derivedDataPath DerivedData CODE_SIGN_IDENTITY=- CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO MACOSX_DEPLOYMENT_TARGET=12.0 SWIFT_TREAT_WARNINGS_AS_ERRORS=NO 'OTHER_SWIFT_FLAGS=$(inherited) -warnings-as-errors -Wwarning DeprecatedDeclaration' build
|
||||
xcodebuild -quiet -project alt-tab-macos.xcodeproj -scheme Test -configuration Release -derivedDataPath DerivedData build-for-testing
|
||||
@@ -134,12 +134,30 @@ jobs:
|
||||
# meaningless and can mis-bump, so gate to push (PLAN §4.2).
|
||||
- run: scripts/determine_next_version.sh
|
||||
if: github.event_name == 'push'
|
||||
- run: scripts/replace_environment_variables_in_app.sh
|
||||
# alt-tab-free [depaywall]: decouple the release apparatus from "every signing-ready push".
|
||||
# determine_next_version.sh writes an EMPTY VERSION.txt when no commit since the last tag is
|
||||
# release-worthy (semantic-release dry-run finds no bump). Gate the sign/notarize/release steps
|
||||
# on this so a docs/ci/chore push still runs guards + commitlint + run_tests (Release-config
|
||||
# compile check) but does NOT sign-build, notarize, or cut a release — no [skip ci] needed (§4.3).
|
||||
- name: release-decision — did semantic-release compute a version?
|
||||
id: release-decision
|
||||
if: github.event_name == 'push'
|
||||
run: |
|
||||
if [ -n "$(tr -d '[:space:]' < "$VERSION_FILE" 2>/dev/null)" ]; then
|
||||
echo "will-release=true" >> "$GITHUB_OUTPUT"
|
||||
echo "Release-worthy: semantic-release will cut v$(cat "$VERSION_FILE")."
|
||||
else
|
||||
echo "will-release=false" >> "$GITHUB_OUTPUT"
|
||||
echo "::notice::No release-worthy commit — build/test only; notarize+release tail skipped."
|
||||
fi
|
||||
# Inject the release version only when releasing; an empty CURRENT_PROJECT_VERSION would crash
|
||||
# App.version (see config/local.xcconfig). Non-release builds use the committed 0.0.0 default.
|
||||
- run: scripts/replace_environment_variables_in_app.sh
|
||||
if: github.event_name == 'push' && steps.release-decision.outputs.will-release == 'true'
|
||||
# codesign needs APPLE_P12_CERTIFICATE — gated on signing-ready so a not-yet-provisioned fork
|
||||
# does not RED on the missing-cert import (PLAN §3.3/§4.3).
|
||||
- run: scripts/codesign/setup_ci_master.sh
|
||||
if: github.event_name == 'push' && steps.release-gate.outputs.signing-ready == 'true'
|
||||
if: github.event_name == 'push' && steps.release-gate.outputs.signing-ready == 'true' && steps.release-decision.outputs.will-release == 'true'
|
||||
# Guard A — the anti-relock unit test (appended to LicenseManagerTests.swift). Runs on both
|
||||
# push and PR (no secrets needed); on the push path it sits before the sign/tag steps below
|
||||
# so a relock fails BEFORE any irreversible side-effect (PLAN §4.4). This is what keeps push
|
||||
@@ -152,7 +170,7 @@ jobs:
|
||||
# prove the tree compiles without a cert. When the owner adds the secrets AND sets the fork's
|
||||
# Developer ID in config/local.xcconfig, this builds signed for the release tail (PLAN §3.3/§4.3).
|
||||
- name: build app (signed — owner cert provisioned)
|
||||
if: github.event_name == 'push' && steps.release-gate.outputs.signing-ready == 'true'
|
||||
if: github.event_name == 'push' && steps.release-gate.outputs.signing-ready == 'true' && steps.release-decision.outputs.will-release == 'true'
|
||||
run: scripts/build_app.sh
|
||||
- name: build app (ad-hoc — until signing-provisioned)
|
||||
if: github.event_name == 'push' && steps.release-gate.outputs.signing-ready != 'true'
|
||||
@@ -160,24 +178,24 @@ jobs:
|
||||
# --- Release tail: requires the owner's Apple Developer ID + Sparkle secrets. Skipped cleanly
|
||||
# (NOT failed) when they are absent, so push CI stays GREEN until the owner provisions them. ---
|
||||
- run: scripts/package_and_notarize_release.sh
|
||||
if: github.event_name == 'push' && steps.release-gate.outputs.signing-ready == 'true'
|
||||
if: github.event_name == 'push' && steps.release-gate.outputs.signing-ready == 'true' && steps.release-decision.outputs.will-release == 'true'
|
||||
# alt-tab-free [depaywall]: upload_symbols_to_appcenter.sh REMOVED — telemetry is off (PLAN §3.4).
|
||||
- run: scripts/update_appcast.sh
|
||||
if: github.event_name == 'push' && steps.release-gate.outputs.signing-ready == 'true'
|
||||
if: github.event_name == 'push' && steps.release-gate.outputs.signing-ready == 'true' && steps.release-decision.outputs.will-release == 'true'
|
||||
# alt-tab-free [depaywall]: update_readme_and_website.sh REMOVED — it queried the UPSTREAM
|
||||
# lwouis/alt-tab-macos GitHub API for stars/downloads and rewrote docs/contributors.md from the
|
||||
# UPSTREAM contributor graph (semantic mismatch for the fork) and dispatched the lwouis website.
|
||||
# Cosmetic only; dropped per PLAN §4.0/§4.3 (alongside update_website.sh, already removed).
|
||||
- run: npx semantic-release
|
||||
if: github.event_name == 'push' && steps.release-gate.outputs.signing-ready == 'true'
|
||||
if: github.event_name == 'push' && steps.release-gate.outputs.signing-ready == 'true' && steps.release-decision.outputs.will-release == 'true'
|
||||
- id: set_release_info
|
||||
run: scripts/extract_latest_changelog.sh
|
||||
if: github.event_name == 'push' && steps.release-gate.outputs.signing-ready == 'true'
|
||||
if: github.event_name == 'push' && steps.release-gate.outputs.signing-ready == 'true' && steps.release-decision.outputs.will-release == 'true'
|
||||
# alt-tab-free [depaywall]: belt-and-suspenders copy of Guard B + Guard C immediately before the
|
||||
# release is created. The load-bearing copy is at the top of the job (pre-tag-push); this second
|
||||
# copy guards the gh-release object itself (PLAN §4.4).
|
||||
- name: anti-relock + anti-conflict re-check (belt-and-suspenders)
|
||||
if: github.event_name == 'push' && steps.release-gate.outputs.signing-ready == 'true'
|
||||
if: github.event_name == 'push' && steps.release-gate.outputs.signing-ready == 'true' && steps.release-decision.outputs.will-release == 'true'
|
||||
run: |
|
||||
grep -q 'depaywall' src/pro/license/LicenseManager.swift \
|
||||
|| { echo "PAYWALL RELOCKED: depaywall marker missing from computeState()"; exit 1; }
|
||||
@@ -190,7 +208,7 @@ jobs:
|
||||
# (release.config.js has no @semantic-release/github plugin, so softprops is the sole release
|
||||
# creator — PLAN §4.3). repository defaults to ${{ github.repository }} = the fork.
|
||||
- uses: softprops/action-gh-release@v3
|
||||
if: github.event_name == 'push' && steps.release-gate.outputs.signing-ready == 'true'
|
||||
if: github.event_name == 'push' && steps.release-gate.outputs.signing-ready == 'true' && steps.release-decision.outputs.will-release == 'true'
|
||||
with:
|
||||
repository: ${{ github.repository }}
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
## [100.2.1](https://github.com/KofTwentyTwo/CommandTabFree/compare/v100.2.0...v100.2.1) (2026-06-16)
|
||||
|
||||
# [100.2.0](https://github.com/KofTwentyTwo/CommandTabFree/compare/v100.1.0...v100.2.0) (2026-06-16)
|
||||
|
||||
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
// docs: https://help.apple.com/xcode/mac/11.4/#/itcaec37c2a6
|
||||
|
||||
SWIFT_VERSION = 5.8
|
||||
SWIFT_TREAT_WARNINGS_AS_ERRORS = YES
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.13
|
||||
SWIFT_TREAT_WARNINGS_AS_ERRORS = NO // replaced by the explicit flags below so the deprecation group can be downgraded after them
|
||||
// Raising the unit-test target to 12.0 turns uses of APIs deprecated in macOS 11/12 (kept for the 10.13 app) into warnings; only that
|
||||
// group is downgraded here (after -warnings-as-errors, which would otherwise win); every other warning stays an error.
|
||||
OTHER_SWIFT_FLAGS = $(inherited) -warnings-as-errors -Wwarning DeprecatedDeclaration
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.0 // unit-tests only: Xcode 27 supports 12.0+; the shipping app keeps 10.13 in base.xcconfig
|
||||
CODE_SIGNING_REQUIRED = NO // no need for codesign
|
||||
CODE_SIGNING_ALLOWED = NO // no need for codesign
|
||||
ONLY_ACTIVE_ARCH = YES // only need to run on the host machine
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
# CI/CD readiness — CommandTabFree (fork of lwouis/alt-tab-macos)
|
||||
|
||||
**Date:** 2026-06-16 **Branch:** `master` **Repo:** `KofTwentyTwo/CommandTabFree` (public)
|
||||
**Status:** full release pipeline **proven** on the real runner — signed + notarized **v100.1.0** released (run `27643432063`, Developer ID `James Maes (2X834TJ5MA)`, `spctl`-accepted + stapled). Non-release pushes stay green via the ad-hoc build path (run `27634828800`).
|
||||
**Status:** publishing pipeline + Sparkle auto-update **LIVE** — signed + notarized **v100.2.0** released (Developer ID `James Maes (2X834TJ5MA)`, `spctl`-accepted + stapled), feed served on GitHub Pages (`koftwentytwo.github.io/CommandTabFree/appcast.xml`). The release apparatus (cert-import → sign-build → notarize → appcast → semantic-release → gh-release) is gated on a `will-release` signal (empty `VERSION.txt` ⇒ no release), so docs/ci pushes build+test without cutting a release or needing `[skip ci]`.
|
||||
**Authoritative design:** `docs/PLAN-maintained-fork.md` §4; owner checklist `docs/EXECUTION-STATUS.md` §3.4/§3.5.
|
||||
|
||||
This is the state after the CI-fix pass. The pass applied only **safe, owner-secret-independent**
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# SESSION-STATE — CommandTabFree (de-paywalled AltTab fork)
|
||||
|
||||
_Updated 2026-06-16. `master` carries the fork; the **full CI/CD publishing pipeline is LIVE** — signed + notarized **v100.1.0** released and Gatekeeper-accepted. Homebrew tap live._
|
||||
_Updated 2026-06-16. `master` carries the fork; the **full CI/CD publishing pipeline + auto-update are LIVE** — signed + notarized **v100.2.0** released (Gatekeeper-accepted), Sparkle feed served on GitHub Pages. Homebrew tap live._
|
||||
|
||||
## ✅ SIGNED + NOTARIZED RELEASE LIVE
|
||||
|
||||
@@ -8,12 +8,13 @@ The complete release pipeline ran green end-to-end (run `27643432063`, commit `2
|
||||
|
||||
**How signing is wired:** `config/local.xcconfig` sets `CODE_SIGN_IDENTITY` + `CODE_SIGN_STYLE = Manual` + `TEAM_ID 2X834TJ5MA`; the vendored Sparkle helpers (`vendor/Sparkle/Helpers/*`) are committed **re-signed** under the same Developer ID; `setup_ci_master.sh` imports the cert with an optional `APPLE_P12_PASSWORD`. The release secrets (`APPLE_P12_CERTIFICATE`/`APPLE_P12_PASSWORD`/`APPLE_ID`/`APPLE_PASSWORD`/`APPLE_TEAM_ID` + `SPARKLE_ED_PRIVATE_KEY`) are set in the `production` env. Getting here also required two CI fixes earlier this session: `d1e1b296` (regenerate base `Localizable.strings` to clear the genstrings gate) and `6070f0cb` (ad-hoc build until the cert existed).
|
||||
|
||||
**Remaining (NOT yet done):**
|
||||
- **Auto-update** (deferred by choice): `appcast.xml` is published to gh-pages, but the app's feed URL is still `fork.invalid` and `SUEnableAutomaticChecks=false`. To enable N→N+1 updates: set a real `DOMAIN` (kof22.com), serve gh-pages at `https://<DOMAIN>/appcast.xml`, flip checks on.
|
||||
- **Homebrew cask**: now notarized — drop the quarantine-strip postflight and bump the cask to v100.1.0.
|
||||
- **Upstream-sync**: `.fork-sync-state` reset to `v11.3.0` (the release tail no longer clobbers it — see ci_cd.yml). Before enabling upstream-sync, advance the cursor from the sync-merge flow (recording the UPSTREAM tag), and provision `SYNC_BOT_TOKEN` + an external cron. The 3 sync labels exist.
|
||||
**Auto-update is LIVE (shipped in v100.2.0):** `DOMAIN = koftwentytwo.github.io/CommandTabFree`, `SUEnableAutomaticChecks = true`, the in-tree `appcast.xml` skeleton removed + gitignored. GitHub Pages serves `https://koftwentytwo.github.io/CommandTabFree/appcast.xml` (gh-pages branch, published by `update_appcast.sh`); the feed carries v100.1.0 + v100.2.0 enclosures. A kof22.com custom domain can be added later (GitHub redirects the github.io URL — no broken builds). **Homebrew cask** bumped to v100.2.0 + quarantine-strip postflight dropped (`KofTwentyTwo/homebrew-tap`). **Release-gate decoupled:** the sign/notarize/release apparatus is gated on a `will-release` signal (empty `VERSION.txt` ⇒ no release), so docs/ci pushes build+test without cutting a release or needing `[skip ci]` (ci_cd.yml).
|
||||
|
||||
**Repo facts:** GitHub = `KofTwentyTwo/CommandTabFree` (local dir `~/Git.Local/kof22/alt-tab-free`, SSH remote). Latest release **v100.1.0** (signed + notarized zip). ⌘⇥ icon FINAL. Owner-gated checklist: `docs/TODO.md`.
|
||||
**Remaining (owner-gated, NOT automatable):**
|
||||
- **Upstream-sync**: provision `SYNC_BOT_TOKEN` + an external `repository_dispatch` cron; re-wire the `.fork-sync-state` cursor advance into the sync-merge flow (recording the UPSTREAM tag). `.fork-sync-state` = `v11.3.0`; the 3 sync labels exist.
|
||||
- **(Optional)** kof22.com custom domain for the appcast (one DNS CNAME → `koftwentytwo.github.io`).
|
||||
|
||||
**Repo facts:** GitHub = `KofTwentyTwo/CommandTabFree` (local dir `~/Git.Local/kof22/alt-tab-free`, SSH remote). Latest release **v100.2.0** (signed + notarized + auto-updating). ⌘⇥ icon FINAL. Owner-gated checklist: `docs/TODO.md`.
|
||||
|
||||
|
||||
## What this is
|
||||
|
||||
+14
-25
@@ -1,34 +1,23 @@
|
||||
# TODO — CommandTabFree
|
||||
|
||||
_Updated 2026-06-16. The **signed + notarized publishing pipeline is LIVE** — **v100.1.0** is released (Gatekeeper-accepted). Remaining items are auto-update, the Homebrew cask, and upstream-sync. Full detail: `docs/CICD-STATUS.md`, `docs/EXECUTION-STATUS.md` §3._
|
||||
_Updated 2026-06-16. The **publishing pipeline + auto-update are LIVE** — **v100.2.0** released (signed, notarized, Gatekeeper-accepted, auto-updating). The only substantial remaining work is upstream-sync automation. Full detail: `docs/CICD-STATUS.md`, `docs/EXECUTION-STATUS.md` §3._
|
||||
|
||||
## ✅ Signed + notarized releases — DONE (2026-06-16)
|
||||
- [x] Apple Developer ID `Developer ID Application: James Maes (2X834TJ5MA)` provisioned; cert + app-specific password in `production` secrets (`APPLE_P12_CERTIFICATE`/`APPLE_P12_PASSWORD`/`APPLE_ID`/`APPLE_PASSWORD`/`APPLE_TEAM_ID`).
|
||||
- [x] `CODE_SIGN_IDENTITY` + Manual style + `TEAM_ID` set in `config/local.xcconfig`.
|
||||
- [x] Vendored `vendor/Sparkle/Helpers/*` committed re-signed under the fork Developer ID.
|
||||
- [x] Full release tail proven on CI (run `27643432063`): signed → notarized → stapled → released. **v100.1.0** published.
|
||||
## ✅ Done this session (2026-06-16)
|
||||
- [x] **Signed + notarized releases** — Developer ID `James Maes (2X834TJ5MA)`; cert + creds in `production` secrets; `CODE_SIGN_IDENTITY`/Manual/`TEAM_ID` in `config/local.xcconfig`; vendored Sparkle helpers re-signed. Full tail proven (runs `27643432063` v100.1.0, `27647918163` v100.2.0).
|
||||
- [x] **Auto-update** — `DOMAIN = koftwentytwo.github.io/CommandTabFree`, `SUEnableAutomaticChecks = true`, in-tree `appcast.xml` removed + gitignored. GitHub Pages serves the gh-pages feed; v100.2.0 ships auto-updating.
|
||||
- [x] **Homebrew cask** — bumped to v100.2.0 + quarantine-strip postflight dropped (`KofTwentyTwo/homebrew-tap`).
|
||||
- [x] **Release-gate decouple** — sign/notarize/release apparatus gated on a `will-release` signal (empty `VERSION.txt` ⇒ no release); non-release pushes build+test without cutting a release or needing `[skip ci]`.
|
||||
- [x] genstrings gate fixed (`d1e1b296`); ad-hoc-until-cert build (`6070f0cb`); `.fork-sync-state` reset to `v11.3.0` + release tail no longer clobbers it; 3 sync labels created.
|
||||
|
||||
## Auto-update (deferred by choice — appcast already publishes to gh-pages)
|
||||
- [ ] **Real `DOMAIN`** — replace `fork.invalid` in `config/local.xcconfig` with the fork host (kof22.com).
|
||||
- [ ] Serve the gh-pages `appcast.xml` at `https://<DOMAIN>/appcast.xml` (CNAME the gh-pages site).
|
||||
- [ ] `git rm` the in-tree `appcast.xml` skeleton + gitignore it (feed is published out-of-tree to gh-pages); flip `SUEnableAutomaticChecks` back on (PLAN §3.2).
|
||||
|
||||
## Homebrew cask (now that builds are notarized)
|
||||
- [ ] Drop the quarantine-strip postflight (`xattr`) from `KofTwentyTwo/homebrew-tap` `Casks/commandtabfree.rb` — no longer needed for a notarized app.
|
||||
- [ ] Bump the cask to v100.1.0.
|
||||
|
||||
## Upstream-sync automation
|
||||
- [x] `.fork-sync-state` reset to `v11.3.0`; release tail no longer clobbers the cursor with the fork tag (`ci_cd.yml`).
|
||||
- [ ] **Re-wire the cursor advance** into the upstream-sync merge flow so it records the synced **UPSTREAM** tag (not the fork release tag) — `upstream_sync.yml` (PLAN §4.2).
|
||||
## Remaining — Upstream-sync automation (owner-gated)
|
||||
- [ ] **`SYNC_BOT_TOKEN`** — GitHub App installation token (or fork PAT with contents + pull-requests write). Default `GITHUB_TOKEN` does NOT re-trigger PR checks, so guards never run on the sync PR.
|
||||
- [ ] **External cron** — hit `repository_dispatch` (type `upstream-sync`) from an external scheduler (immune to GitHub's 60-day in-repo `schedule:` auto-disable).
|
||||
- [x] Sync PR labels `sync` / `conflict` / `chokepoint-refresh` created.
|
||||
- [ ] **Re-wire the `.fork-sync-state` cursor advance** into the upstream-sync merge flow so it records the synced **UPSTREAM** tag (not the fork release tag) — `upstream_sync.yml` (PLAN §4.2).
|
||||
|
||||
## Bootstrap acceptance tests (after the above)
|
||||
## Optional
|
||||
- [ ] kof22.com custom domain for the appcast (one DNS CNAME → `koftwentytwo.github.io`; GitHub redirects the github.io URL, so existing builds keep updating).
|
||||
|
||||
## Bootstrap acceptance tests (after upstream-sync is wired)
|
||||
- [ ] Sync PR through the bot shows guard checks running.
|
||||
- [ ] A deliberately-relocked branch goes RED on `guard.yml`.
|
||||
- [ ] Fork build N→N+1 auto-updates via Sparkle (needs DOMAIN/appcast live).
|
||||
|
||||
## Done earlier this session (2026-06-16)
|
||||
- [x] genstrings consistency gate fixed — regenerated base `Localizable.strings` from source (`d1e1b296`).
|
||||
- [x] `build_app.sh` builds ad-hoc until cert provisioned; was failing on upstream's Developer ID (`6070f0cb`). Push CI green (run `27634828800`).
|
||||
- [x] Fork build N→N+1 auto-updates via Sparkle — infra live (feed served + v100.2.0 auto-update-enabled); end-to-end N→N+1 confirmed on the next release.
|
||||
@@ -11,6 +11,12 @@ This project has minimal dependency on Xcode-only features (e.g. InterfaceBuilde
|
||||
* `scripts/codesign/setup_local.sh` to generate a local self-signed certificate, to avoid having to re-check the `System Preferences > Security & Privacy` permissions on every build
|
||||
* Either open `alt-tab-macos.xcodeproj` with Xcode, or use the CLI: `xcodebuild -project alt-tab-macos.xcodeproj -scheme Debug` to build the .app with the `Debug` build configuration
|
||||
|
||||
### Tests (run locally before merging)
|
||||
|
||||
The Gitea CI (`.gitea/workflows/build.yaml`) runs Guards B and C (the de-paywall markers and conflict markers), builds the `Release` scheme unsigned and compiles the `Test` scheme (`build-for-testing`), but does not run the tests: its macOS runner has no GUI session, so `xcodebuild test` cannot reach `testmanagerd`. Run them, including the anti-relock tests in `src/pro/license/LicenseManagerTests.swift` (Guard A, `docs/PLAN-maintained-fork.md` §4.4), locally before merging, especially an upstream sync:
|
||||
|
||||
* `scripts/run_tests.sh` (the `Test` scheme, `-configuration Release`)
|
||||
|
||||
## Mac development
|
||||
|
||||
Mac development ecosystem is pretty terrible in general. They keep piling on the tech stacks on top of each other, so you have C APIs, ObjC APIs, Swift APIs, Interface builder, Playgrounds, Swift UI, Mac Catalyst. All these are bridging with each other with a bunch of macros, SDKs glue, compiler flags, compatibility mode, XCode legacy build system, etc. For alt-tab, we are on Swift 5.0. Note that swift just recently started being stable, but overall any change of version breaks a lot of stuff. Swift itself is the mainstream language with the worst governance I’ve seen in modern times.
|
||||
|
||||
@@ -291,7 +291,7 @@ class ExceptionEditorView: NSView {
|
||||
}
|
||||
|
||||
private func resolveHeaderAsync(for bundleId: String) {
|
||||
DispatchQueue.global(qos: .userInitiated).async {
|
||||
DispatchQueue.global(qos: .userInitiated).async { [weak self] in
|
||||
let info = AppDisplayInfo.resolve(bundleId: bundleId)
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let self, self.entry.bundleIdentifier == bundleId else { return }
|
||||
|
||||
@@ -319,7 +319,7 @@ class ExceptionsTab {
|
||||
// BundleId changed (or first paint): show a synchronous placeholder, then resolve async.
|
||||
row.setIcon(AppDisplayInfo.genericIcon, size: iconSize)
|
||||
row.setContent(bundleId, summary)
|
||||
DispatchQueue.global(qos: .userInitiated).async {
|
||||
DispatchQueue.global(qos: .userInitiated).async { [weak row] in
|
||||
let info = AppDisplayInfo.resolve(bundleId: bundleId)
|
||||
DispatchQueue.main.async { [weak row] in
|
||||
guard let row else { return }
|
||||
|
||||
Reference in new issue
Block a user