App identity for both editions: the three-lane glyph
(rectangle.split.3x1.fill) over a gentle gradient - teal for base
Lanework, dark graphite for Lanework Pro - rendered as 1024 masters and
packaged down the full macOS ladder into each target's own iconset,
replacing the borrowed pathfinder icon.
The About window arrives via IndieAbout (0.2.x): icon, copyright,
version/build/date read from the Info.plist that update_build_info.sh
already stamps on every build (CFBundleVersion 160 = git commit count,
BuildDate, BuildHash - verified in the built product), the version line
opening the bundled CHANGELOG.md, and the new ISC LICENSE.md one
document link away. Both files are authored to the Apple
inline-Markdown subset (no # headings, single-line paragraphs) and
bundle into both editions.
CHANGELOG.md replaces its placeholder with the real 2.0 first-release
notes - one sentence per user-facing feature.
The About box is also an edition seam: base's EditionAbout carries the
one-line Pro signpost 12-editions.md allots ("Lanework Pro adds
git-backed board history and sync."), and the Pro target compiles its
own signpost-less twin instead of that file - the no-#if file-level
doctrine applied to a string. README gains the identity bullet.
1649 green on both schemes; verify-editions.sh 26/26.
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
256 lines
9.8 KiB
YAML
256 lines
9.8 KiB
YAML
name: Kanban
|
|
options:
|
|
bundleIdPrefix: dev.rzen.indie
|
|
deploymentTarget:
|
|
macOS: "26.0"
|
|
xcodeVersion: "26.0"
|
|
defaultConfig: Debug
|
|
|
|
packages:
|
|
Yams:
|
|
url: https://github.com/jpsim/Yams.git
|
|
from: 6.0.0
|
|
# apple/swift-markdown — the card window's Preview parser (05-card-window.md ▸ Preview).
|
|
# Pinned to the next *minor* rather than the next major because the package is pre-1.0: a
|
|
# `from:` range here would silently accept 0.9's breaking changes, which is not what `from:`
|
|
# means for Yams at 6.x.
|
|
swift-markdown:
|
|
url: https://github.com/apple/swift-markdown.git
|
|
minorVersion: 0.8.0
|
|
# The About window (both editions): app icon, version/build from the stamped Info.plist, and
|
|
# the bundled LICENSE/CHANGELOG documents. Pre-1.0 like swift-markdown, same pinning logic.
|
|
IndieAbout:
|
|
url: https://git.rzen.dev/rzen/indie-about.git
|
|
minorVersion: 0.2.2
|
|
|
|
settings:
|
|
base:
|
|
SWIFT_VERSION: "6.0"
|
|
MACOSX_DEPLOYMENT_TARGET: "26.0"
|
|
DEVELOPMENT_TEAM: ${APPLE_TEAM_ID}
|
|
ENABLE_USER_SCRIPT_SANDBOXING: NO
|
|
|
|
# The edition split (12-editions.md ▸ Targets). Two app targets compiled from one source tree:
|
|
# base builds `Kanban/` alone, Pro builds `Kanban/` *plus* `KanbanPro/`. There is no build flag
|
|
# and no `#if` in shared code — "why a real split and not feature flags" (12) is answered by the
|
|
# file list, so an edition difference is always a file one target compiles and the other does not.
|
|
# libgit2 arrives on the Pro target with pro-m1; the target, its entitlements and its source root
|
|
# exist now so that milestone lands without re-splitting anything.
|
|
#
|
|
# YAML anchors (`&name` / `*name`) carry the genuinely identical parts across the two apps and the
|
|
# two unit-test bundles. They are resolved by the YAML parser before XcodeGen sees the file, so
|
|
# they cost nothing at generate time and cannot drift the way copy-paste does.
|
|
targets:
|
|
# MARK: - Lanework (base)
|
|
|
|
Kanban:
|
|
type: application
|
|
platform: macOS
|
|
sources:
|
|
- Kanban
|
|
# The bundled template store (09-templates.md ▸ Definition format): real board folders,
|
|
# copied into `Contents/Resources/Templates/` verbatim as a folder reference — the same
|
|
# arrangement `Fixtures/` uses below, and for the same reason. A template is a board, so it
|
|
# must reach the bundle as directories on disk, not as flattened resource files.
|
|
- path: Templates
|
|
type: folder
|
|
buildPhase: resources
|
|
# The About window's documents (LICENSE, CHANGELOG) — bundled so IndieAbout can render
|
|
# them in-app. Apple-inline-Markdown subset only: no `#` headings, no hard-wrapped
|
|
# paragraphs (every newline renders literally).
|
|
- path: LICENSE.md
|
|
type: file
|
|
buildPhase: resources
|
|
- path: CHANGELOG.md
|
|
type: file
|
|
buildPhase: resources
|
|
dependencies: &appDependencies
|
|
- package: Yams
|
|
- package: swift-markdown
|
|
product: Markdown
|
|
- package: IndieAbout
|
|
postBuildScripts: &updateBuildInfo
|
|
- script: '"${SRCROOT}/../indie-skills/skills/app-versioning/scripts/update_build_info.sh"'
|
|
name: Update Build Info
|
|
shell: /bin/sh
|
|
basedOnDependencyAnalysis: false
|
|
inputFiles:
|
|
- $(TARGET_BUILD_DIR)/$(INFOPLIST_PATH)
|
|
- $(DWARF_DSYM_FOLDER_PATH)/$(DWARF_DSYM_FILE_NAME)/Contents/Info.plist
|
|
settings:
|
|
base:
|
|
# Base keeps the current identifier — it is the app that ships first, so nothing
|
|
# re-wires (12 ▸ Targets, ruled 2026-07-27).
|
|
PRODUCT_BUNDLE_IDENTIFIER: dev.rzen.indie.Kanban
|
|
MARKETING_VERSION: "2.0"
|
|
INFOPLIST_FILE: Kanban/Info.plist
|
|
CODE_SIGN_ENTITLEMENTS: Kanban/Kanban.entitlements
|
|
GENERATE_INFOPLIST_FILE: false
|
|
SWIFT_STRICT_CONCURRENCY: complete
|
|
ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon
|
|
|
|
# MARK: - Lanework Pro
|
|
|
|
KanbanPro:
|
|
type: application
|
|
platform: macOS
|
|
sources:
|
|
# The shared tree, minus the three files that are base's *identity* rather than its code.
|
|
# (XcodeGen already keeps `Info.plist` and `.entitlements` out of build phases; excluding
|
|
# them here keeps them out of the Pro target's file list too, so there is exactly one
|
|
# plist and one entitlements file visible per app.)
|
|
- path: Kanban
|
|
excludes:
|
|
- Info.plist
|
|
- Kanban.entitlements
|
|
- Assets.xcassets
|
|
- Assets.xcassets/**
|
|
# Base's About-box configuration carries the one-line Pro signpost (12-editions.md ▸
|
|
# Quiet signposts); Pro compiles its own `KanbanPro/Edition/EditionAbout.swift` twin
|
|
# without it — the edition split's file-level doctrine, applied to a string.
|
|
- App/EditionAbout.swift
|
|
# Pro's own source root — reserved now, filled by pro-m1. See KanbanPro/Edition/ProEdition.swift.
|
|
- path: KanbanPro
|
|
excludes:
|
|
- Info.plist
|
|
- KanbanPro.entitlements
|
|
# The same bundled template store — the inventory is the app's, not an edition's.
|
|
- path: Templates
|
|
type: folder
|
|
buildPhase: resources
|
|
# The About documents, same files as base — one license, one changelog, two bundles.
|
|
- path: LICENSE.md
|
|
type: file
|
|
buildPhase: resources
|
|
- path: CHANGELOG.md
|
|
type: file
|
|
buildPhase: resources
|
|
dependencies: *appDependencies
|
|
postBuildScripts: *updateBuildInfo
|
|
settings:
|
|
base:
|
|
PRODUCT_BUNDLE_IDENTIFIER: dev.rzen.indie.KanbanPro
|
|
MARKETING_VERSION: "2.0"
|
|
INFOPLIST_FILE: KanbanPro/Info.plist
|
|
CODE_SIGN_ENTITLEMENTS: KanbanPro/KanbanPro.entitlements
|
|
GENERATE_INFOPLIST_FILE: false
|
|
SWIFT_STRICT_CONCURRENCY: complete
|
|
ASSETCATALOG_COMPILER_APPICON_NAME: AppIconPro
|
|
# Spelled out because the whole shared-test-sources arrangement below hangs on it: the two
|
|
# apps must have *different* Swift module names, since both emit `<module>.swiftmodule`
|
|
# into the same `Build/Products/<config>/` and equal names would have one app silently
|
|
# overwrite the other's testable interface.
|
|
PRODUCT_MODULE_NAME: KanbanPro
|
|
|
|
# MARK: - Unit tests
|
|
#
|
|
# One suite, run twice — once hosted by each app. Every test in `KanbanTests/` is
|
|
# edition-agnostic (it exercises the storage format, the live store and the UI model, none of
|
|
# which differ between editions), so duplicating the *sources* would be duplicating the thing
|
|
# that is identical; what is worth running twice is the suite against each *binary*, which is
|
|
# what these two targets do. The Pro bundle compiles the very same files — it is the same
|
|
# `sources` list, by anchor — against `KanbanPro`.
|
|
|
|
KanbanTests:
|
|
type: bundle.unit-test
|
|
platform: macOS
|
|
sources: &unitTestSources
|
|
- KanbanTests
|
|
- path: Fixtures
|
|
type: folder
|
|
buildPhase: resources
|
|
dependencies:
|
|
- target: Kanban
|
|
settings:
|
|
base:
|
|
PRODUCT_BUNDLE_IDENTIFIER: dev.rzen.indie.KanbanTests
|
|
GENERATE_INFOPLIST_FILE: true
|
|
SWIFT_STRICT_CONCURRENCY: complete
|
|
|
|
KanbanProTests:
|
|
type: bundle.unit-test
|
|
platform: macOS
|
|
sources: *unitTestSources
|
|
dependencies:
|
|
- target: KanbanPro
|
|
settings:
|
|
base:
|
|
PRODUCT_BUNDLE_IDENTIFIER: dev.rzen.indie.KanbanProTests
|
|
GENERATE_INFOPLIST_FILE: true
|
|
SWIFT_STRICT_CONCURRENCY: complete
|
|
# The shared sources say `@testable import Kanban`, and they should: they are testing the
|
|
# app, not an edition. `-module-alias` (Swift 5.7+) resolves that import to the Pro
|
|
# module for this bundle only — the supported way to bind one source name to a different
|
|
# module, and it keeps the 56 test files edition-blind instead of littering them with
|
|
# conditional imports.
|
|
OTHER_SWIFT_FLAGS: -module-alias Kanban=KanbanPro
|
|
|
|
# MARK: - UI tests
|
|
#
|
|
# Base-only, deliberately: these tests launch the real app and drive its menu bar, which is the
|
|
# slowest, most environment-dependent part of the suite, and a second copy would double it to
|
|
# re-assert something the Pro unit bundle already proves (it launches the Pro app as its test host
|
|
# on every run). The accessibility audits (10-accessibility.md ▸ Verification) are edition-blind —
|
|
# every surface they walk is built from the shared tree.
|
|
|
|
KanbanUITests:
|
|
type: bundle.ui-testing
|
|
platform: macOS
|
|
sources:
|
|
# The manual verification document lives with the tests it belongs to (10-accessibility.md
|
|
# ▸ Verification: "A manual VoiceOver smoke script lives with the test plan"), so it is listed
|
|
# in the project — visible where the suite is — but with no build phase: it is documentation,
|
|
# not a resource the bundle should carry.
|
|
- path: KanbanUITests
|
|
excludes:
|
|
- "**/*.md"
|
|
- path: KanbanUITests/AccessibilityVerification.md
|
|
buildPhase: none
|
|
dependencies:
|
|
- target: Kanban
|
|
settings:
|
|
base:
|
|
PRODUCT_BUNDLE_IDENTIFIER: dev.rzen.indie.KanbanUITests
|
|
GENERATE_INFOPLIST_FILE: true
|
|
SWIFT_STRICT_CONCURRENCY: complete
|
|
|
|
schemes:
|
|
# `Kanban` is unchanged, on purpose: `xcodebuild … -scheme Kanban` is the established command
|
|
# for this repo and base is the app it has always meant.
|
|
Kanban:
|
|
build:
|
|
targets:
|
|
Kanban: all
|
|
run:
|
|
config: Debug
|
|
test:
|
|
config: Debug
|
|
gatherCoverageData: false
|
|
targets:
|
|
- KanbanTests
|
|
- KanbanUITests
|
|
profile:
|
|
config: Release
|
|
analyze:
|
|
config: Debug
|
|
archive:
|
|
config: Release
|
|
|
|
LaneworkPro:
|
|
build:
|
|
targets:
|
|
KanbanPro: all
|
|
run:
|
|
config: Debug
|
|
test:
|
|
config: Debug
|
|
gatherCoverageData: false
|
|
targets:
|
|
- KanbanProTests
|
|
profile:
|
|
config: Release
|
|
analyze:
|
|
config: Debug
|
|
archive:
|
|
config: Release
|