Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f7f6a8bd87 | ||
|
|
ed91ebf807 | ||
|
|
77c065f433 |
@@ -93,6 +93,53 @@ codesign -dvv <sidecar>
|
|||||||
```
|
```
|
||||||
Universal (`ARCHS='arm64 x86_64' ONLY_ACTIVE_ARCH=NO`) is still required for release verification / packaging.
|
Universal (`ARCHS='arm64 x86_64' ONLY_ACTIVE_ARCH=NO`) is still required for release verification / packaging.
|
||||||
|
|
||||||
|
## Remote test builds (runner host)
|
||||||
|
Test builds done as part of change implementations run on the CI runner
|
||||||
|
host, not the dev machine — the runner is a macOS 12.7.6 **x86_64** VM
|
||||||
|
with Xcode 14.2, and CI failures there are often environmental and do not
|
||||||
|
reproduce locally.
|
||||||
|
|
||||||
|
- Host: `localadmin@192.168.0.172` (SSH, LAN). Runner daemon:
|
||||||
|
`gitea-runner daemon -c /opt/gitea-runner/config.yaml`.
|
||||||
|
- Credentials: `~/Projects/build-host.env` defines `BUILD_HOST_USER` /
|
||||||
|
`BUILD_HOST_PASSWORD`. **Never read or print this file** — load it with
|
||||||
|
`set -a; source ~/Projects/build-host.env; set +a` so values stay in the
|
||||||
|
environment.
|
||||||
|
- `sshpass` is installed (`/usr/local/bin/sshpass`). Feed the password via
|
||||||
|
the `SSHPASS` env var — never on the command line:
|
||||||
|
```sh
|
||||||
|
SSHPASS="$BUILD_HOST_PASSWORD" sshpass -e ssh localadmin@192.168.0.172 '<cmd>'
|
||||||
|
SSHPASS="$BUILD_HOST_PASSWORD" sshpass -e scp <local> localadmin@192.168.0.172:<remote>
|
||||||
|
```
|
||||||
|
First connection needs `-o StrictHostKeyChecking=accept-new`.
|
||||||
|
- Remote checkout: `~/Projects/iccery-v2-mac` (anonymous HTTPS clone works;
|
||||||
|
full history needed by `scripts/version.sh`). Before testing, sync it to
|
||||||
|
the same base commit as the local work:
|
||||||
|
`git fetch origin && git checkout <local base sha>`, then `scp` each
|
||||||
|
locally-changed file over its remote counterpart (uncommitted work
|
||||||
|
transfers this way — there is no push).
|
||||||
|
- `xcodegen` is **not** on PATH: prepend
|
||||||
|
`$HOME/.local/xcodegen/2.38.0/xcodegen/bin` (prebuilt 2.38.0 installed
|
||||||
|
by `scripts/ensure-host-tools.sh`; brew's formula needs Xcode 15.3,
|
||||||
|
impossible on macOS 12 — #109).
|
||||||
|
- Mirror `.gitea/workflows/macos.yml` exactly, from the repo root with
|
||||||
|
`DERIVED=build/DerivedData-test`:
|
||||||
|
`scripts/ensure-host-tools.sh` → `xcodegen generate --spec project.yml`
|
||||||
|
→ `eval "$(scripts/version.sh)"` → `xcodebuild build-for-testing
|
||||||
|
-scheme ICCery -destination 'platform=macOS' -derivedDataPath "$DERIVED"
|
||||||
|
-configuration Debug ARCHS="$(uname -m)" ONLY_ACTIVE_ARCH=NO
|
||||||
|
CODE_SIGNING_ALLOWED=YES CODE_SIGN_IDENTITY='-' MARKETING_VERSION=…
|
||||||
|
CURRENT_PROJECT_VERSION=… ICCERY_RELEASE_TAG=…` → codesign every
|
||||||
|
`*_PackageProduct.framework` under `$DERIVED/Build/Products/Debug`
|
||||||
|
(#119) → `xcodebuild test-without-building -xctestrun <ICCery*.xctestrun>
|
||||||
|
-only-testing:ICCeryCoreTests -destination 'platform=macOS'
|
||||||
|
-derivedDataPath "$DERIVED"`.
|
||||||
|
- Run **unit tests only** (`ICCeryCoreTests`). UI tests need a logged-in
|
||||||
|
GUI session and fail environmentally on the VM (runs 29700, 29804,
|
||||||
|
42183) — do not use them for verification unless asked.
|
||||||
|
- xcodebuild takes minutes — run the ssh command in a background shell
|
||||||
|
and poll rather than blocking.
|
||||||
|
|
||||||
## Private ColorSync SPI
|
## Private ColorSync SPI
|
||||||
2-arg `(PMPrintSession, CFStringRef) -> OSStatus`. Never pass integer `1`.
|
2-arg `(PMPrintSession, CFStringRef) -> OSStatus`. Never pass integer `1`.
|
||||||
Modes: `AP_ApplicationColorMatching` then `ApplicationColorMatching`.
|
Modes: `AP_ApplicationColorMatching` then `ApplicationColorMatching`.
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ as AGPLv3 child processes. The GUI never `dlopen`s or links Argyll.
|
|||||||
|---|---|
|
|---|---|
|
||||||
| Product | ICCery v2 for macOS |
|
| Product | ICCery v2 for macOS |
|
||||||
| Bundle | `com.gronod.iccery2` |
|
| Bundle | `com.gronod.iccery2` |
|
||||||
| Version | 2.0.0 |
|
| Version | 2.0.3 |
|
||||||
| Floor | macOS 12.0 Monterey, universal `arm64` + `x86_64` |
|
| Floor | macOS 12.0 Monterey, universal `arm64` + `x86_64` |
|
||||||
| Toolchain | Xcode 14.2 / Swift 5.7 (project `SWIFT_VERSION` is 5.0) |
|
| Toolchain | Xcode 14.2 / Swift 5.7 (project `SWIFT_VERSION` is 5.0) |
|
||||||
| CI | Gitea Actions `macos-12` runner |
|
| CI | Gitea Actions `macos-12` runner |
|
||||||
|
|||||||
@@ -114,18 +114,18 @@ final class Milestone3UITests: XCTestCase {
|
|||||||
return recordedSpoolLog()
|
return recordedSpoolLog()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Drags `#galleryPage-0`'s TIFF upward so `identifier`'s button
|
/// Scrolls `stage-2` with the synthesized scroll wheel so
|
||||||
/// moves up, clear of the Dock collision zone at the window's
|
/// `identifier`'s button moves up, clear of the Dock collision
|
||||||
/// bottom edge (#132).
|
/// zone at the window's bottom edge (#132).
|
||||||
///
|
///
|
||||||
/// macOS overlay scrollbars are not in the AX tree — never use
|
/// macOS overlay scrollbars are not in the AX tree — never use
|
||||||
/// `app.scrollBars` — and a synthesized scroll wheel is inert on
|
/// `app.scrollBars` — and a click-drag does not scroll a macOS
|
||||||
/// this LazyVGrid, so the scroll is a real drag on the gallery
|
/// ScrollView (content-drag scrolling is iOS-only); the scroll
|
||||||
/// cell's content. A stale/off-screen AX frame resolves to a screen
|
/// wheel is the mechanism the platform supports (#215). A
|
||||||
/// point that can be a Dock icon — a coordinate click there once
|
/// stale/off-screen AX frame resolves to a screen point that can
|
||||||
/// opened Calendar instead of Print. Callers must click only when
|
/// be a Dock icon — a coordinate click there once opened Calendar
|
||||||
/// the returned element `isHittable`; never coordinate-click a
|
/// instead of Print. Callers must click only when the returned
|
||||||
/// stale frame.
|
/// element `isHittable`; never coordinate-click a stale frame.
|
||||||
@discardableResult
|
@discardableResult
|
||||||
private func scrollStage2UntilHittable(
|
private func scrollStage2UntilHittable(
|
||||||
_ identifier: String,
|
_ identifier: String,
|
||||||
@@ -134,6 +134,8 @@ final class Milestone3UITests: XCTestCase {
|
|||||||
var button = app.buttons[identifier]
|
var button = app.buttons[identifier]
|
||||||
let cell = app.descendants(matching: .any)["galleryPage-0"].firstMatch
|
let cell = app.descendants(matching: .any)["galleryPage-0"].firstMatch
|
||||||
XCTAssertTrue(cell.waitForExistence(timeout: 10), "galleryPage-0")
|
XCTAssertTrue(cell.waitForExistence(timeout: 10), "galleryPage-0")
|
||||||
|
let scrollView = app.scrollViews["stage-2"]
|
||||||
|
XCTAssertTrue(scrollView.waitForExistence(timeout: 10), "stage-2")
|
||||||
|
|
||||||
let deadline = Date().addingTimeInterval(timeout)
|
let deadline = Date().addingTimeInterval(timeout)
|
||||||
while Date() < deadline {
|
while Date() < deadline {
|
||||||
@@ -142,25 +144,12 @@ final class Milestone3UITests: XCTestCase {
|
|||||||
button.frame.maxY < windowBottom - 80 {
|
button.frame.maxY < windowBottom - 80 {
|
||||||
return button
|
return button
|
||||||
}
|
}
|
||||||
// Grab the upper half of the cell (the TIFF, not the Print
|
// Wheel-down inside the stage-2 viewport: content moves
|
||||||
// button / Dock) and drag toward the top of the window.
|
// UP ⇒ Print leaves the Dock zone. Negative deltaY scrolls
|
||||||
// Mouse moves UP ⇒ gallery content moves UP ⇒ Print leaves
|
// toward the document bottom (#215).
|
||||||
// the Dock zone.
|
|
||||||
if cell.isHittable {
|
|
||||||
let start = cell.coordinate(withNormalizedOffset:
|
|
||||||
CGVector(dx: 0.5, dy: 0.25))
|
|
||||||
let end = start.withOffset(CGVector(dx: 0, dy: -280))
|
|
||||||
start.press(forDuration: 0.15, thenDragTo: end)
|
|
||||||
} else {
|
|
||||||
// Cell not hit-testable: drag the stage-2 content
|
|
||||||
// directly — still content, still never scrollBars.
|
|
||||||
let scrollView = app.scrollViews["stage-2"]
|
|
||||||
scrollView.coordinate(withNormalizedOffset:
|
scrollView.coordinate(withNormalizedOffset:
|
||||||
CGVector(dx: 0.5, dy: 0.55))
|
CGVector(dx: 0.5, dy: 0.5))
|
||||||
.press(forDuration: 0.15, thenDragTo:
|
.scroll(byDeltaX: 0, deltaY: -60)
|
||||||
scrollView.coordinate(withNormalizedOffset:
|
|
||||||
CGVector(dx: 0.5, dy: 0.15)))
|
|
||||||
}
|
|
||||||
RunLoop.current.run(until: Date().addingTimeInterval(0.4))
|
RunLoop.current.run(until: Date().addingTimeInterval(0.4))
|
||||||
button = app.buttons[identifier]
|
button = app.buttons[identifier]
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -61,7 +61,7 @@ targets:
|
|||||||
INFOPLIST_KEY_LSMinimumSystemVersion: "12.0"
|
INFOPLIST_KEY_LSMinimumSystemVersion: "12.0"
|
||||||
INFOPLIST_KEY_NSPrincipalClass: NSApplication
|
INFOPLIST_KEY_NSPrincipalClass: NSApplication
|
||||||
INFOPLIST_KEY_NSHumanReadableCopyright: "Copyright © 2026 Gronod. AGPLv3."
|
INFOPLIST_KEY_NSHumanReadableCopyright: "Copyright © 2026 Gronod. AGPLv3."
|
||||||
MARKETING_VERSION: "2.0.2"
|
MARKETING_VERSION: "2.0.3"
|
||||||
CURRENT_PROJECT_VERSION: "1"
|
CURRENT_PROJECT_VERSION: "1"
|
||||||
# Stamped by scripts/version.sh at packaging/CI time (release tag or
|
# Stamped by scripts/version.sh at packaging/CI time (release tag or
|
||||||
# `git describe` string); About shows it next to the marketing version.
|
# `git describe` string); About shows it next to the marketing version.
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ if [ ! -f "$DMG_BACKGROUND" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo "==> Building DMG"
|
echo "==> Building DMG"
|
||||||
VERSION="$(plutil -extract CFBundleShortVersionString raw "$APP/Contents/Info.plist" 2>/dev/null || printf '2.0.0')"
|
VERSION="$(plutil -extract CFBundleShortVersionString raw "$APP/Contents/Info.plist" 2>/dev/null || printf '2.0.3')"
|
||||||
BUILD_NUM="$(plutil -extract CFBundleVersion raw "$APP/Contents/Info.plist" 2>/dev/null || printf '1')"
|
BUILD_NUM="$(plutil -extract CFBundleVersion raw "$APP/Contents/Info.plist" 2>/dev/null || printf '1')"
|
||||||
# Tagged/described builds carry the tag in the DMG name so prerelease
|
# Tagged/described builds carry the tag in the DMG name so prerelease
|
||||||
# artefacts are self-describing (ICCery-2.0.0-pre2-grok-236.dmg); a plain
|
# artefacts are self-describing (ICCery-2.0.0-pre2-grok-236.dmg); a plain
|
||||||
|
|||||||
Reference in New Issue
Block a user