diff --git a/CHANGELOG.md b/CHANGELOG.md index ec407e4..c8739f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,22 @@ All notable changes to **Neon Vision Editor** are documented in this file. The format follows *Keep a Changelog*. Versions use semantic versioning with prerelease tags. +## [v0.4.9] - 2026-02-13 + +### Added +- Pre-release CI workflow on `main`/PR with critical runtime checks, docs validation, and icon payload verification. +- Release dry-run workflow and local `scripts/release_dry_run.sh` command for pre-tag validation. +- Release runtime policy test suite (`ReleaseRuntimePolicyTests`) covering settings-tab routing, theme mapping, find-next cursor behavior, and subscription button state logic. + +### Improved +- Unified release automation in `scripts/release_all.sh` to run preflight checks before tagging and to verify uploaded release assets after notarized publish. +- README changelog summary automation now keeps release summaries version-sorted and limited to the latest three entries. +- Notarized workflows now include compatibility fallbacks so older tags without `scripts/ci/*` can still be rebuilt and published. + +### Fixed +- Fixed macOS toolbar Settings (gear) button path to open the Settings scene reliably via SwiftUI `openSettings`. +- Hardened release workflows with post-publish verification and rollback behavior (delete bad asset and mark release draft on verification failure). + ## [v0.4.8] - 2026-02-12 ### Added diff --git a/Neon Vision Editor.xcodeproj/project.pbxproj b/Neon Vision Editor.xcodeproj/project.pbxproj index 2065807..459b429 100644 --- a/Neon Vision Editor.xcodeproj/project.pbxproj +++ b/Neon Vision Editor.xcodeproj/project.pbxproj @@ -358,7 +358,7 @@ CODE_SIGNING_ALLOWED = YES; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 193; + CURRENT_PROJECT_VERSION = 194; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = CS727NF72U; ENABLE_APP_SANDBOX = YES; @@ -438,7 +438,7 @@ CODE_SIGNING_ALLOWED = YES; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 193; + CURRENT_PROJECT_VERSION = 194; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = CS727NF72U; ENABLE_APP_SANDBOX = YES; diff --git a/Neon Vision Editor/UI/NeonSettingsView.swift b/Neon Vision Editor/UI/NeonSettingsView.swift index 1090305..5f40a03 100644 --- a/Neon Vision Editor/UI/NeonSettingsView.swift +++ b/Neon Vision Editor/UI/NeonSettingsView.swift @@ -4,6 +4,7 @@ import AppKit #endif struct NeonSettingsView: View { + private static var cachedEditorFonts: [String] = [] let supportsOpenInTabs: Bool let supportsTranslucency: Bool @EnvironmentObject private var supportPurchaseManager: SupportPurchaseManager @@ -135,7 +136,7 @@ struct NeonSettingsView: View { .preferredColorScheme(preferredColorSchemeOverride) .onAppear { settingsActiveTab = "general" - refreshAvailableEditorFonts() + loadAvailableEditorFontsIfNeeded() if supportPurchaseManager.supportProduct == nil { Task { await supportPurchaseManager.refreshStoreState() } } @@ -211,7 +212,6 @@ struct NeonSettingsView: View { NSApp.appearance = target for window in NSApp.windows { window.appearance = target - window.displayIfNeeded() } } #endif @@ -368,7 +368,23 @@ struct NeonSettingsView: View { ) } - private func refreshAvailableEditorFonts() { + private func loadAvailableEditorFontsIfNeeded() { + if !availableEditorFonts.isEmpty { + selectedFontValue = useSystemFont ? systemFontSentinel : (editorFontName.isEmpty ? systemFontSentinel : editorFontName) + return + } + if !Self.cachedEditorFonts.isEmpty { + availableEditorFonts = Self.cachedEditorFonts + selectedFontValue = useSystemFont ? systemFontSentinel : (editorFontName.isEmpty ? systemFontSentinel : editorFontName) + return + } + // Defer font discovery until after the initial settings view appears. + DispatchQueue.main.async { + populateEditorFonts() + } + } + + private func populateEditorFonts() { #if os(macOS) let names = NSFontManager.shared.availableFonts #else @@ -380,6 +396,7 @@ struct NeonSettingsView: View { if !editorFontName.isEmpty && !merged.contains(editorFontName) { merged.insert(editorFontName, at: 0) } + Self.cachedEditorFonts = merged availableEditorFonts = merged selectedFontValue = useSystemFont ? systemFontSentinel : (editorFontName.isEmpty ? systemFontSentinel : editorFontName) } diff --git a/Neon Vision Editor/UI/PanelsAndHelpers.swift b/Neon Vision Editor/UI/PanelsAndHelpers.swift index 26eabff..7071dee 100644 --- a/Neon Vision Editor/UI/PanelsAndHelpers.swift +++ b/Neon Vision Editor/UI/PanelsAndHelpers.swift @@ -220,12 +220,12 @@ struct WelcomeTourView: View { private let pages: [TourPage] = [ TourPage( title: "What’s New in This Release", - subtitle: "Major changes since v0.4.7:", + subtitle: "Major changes since v0.4.8:", bullets: [ - "Extended release automation coverage for the next tag cycle, including synchronized README/changelog/welcome-tour release content updates.", - "macOS settings parity with iOS by wiring the `Open in Tabs` preference into live window tabbing behavior.", - "Welcome Tour release highlights are now aligned with distribution content for current App Store/TestFlight-facing builds.", - "Release workflow environment compatibility by removing hard `rg` dependency from docs validation steps." + "Pre-release CI workflow on `main`/PR with critical runtime checks, docs validation, and icon payload verification.", + "Release dry-run workflow and local `scripts/release_dry_run.sh` command for pre-tag validation.", + "Release runtime policy test suite (`ReleaseRuntimePolicyTests`) covering settings-tab routing, theme mapping, find-next cursor behavior, and subscription button state logic.", + "Unified release automation in `scripts/release_all.sh` to run preflight checks before tagging and to verify uploaded release assets after notarized publish." ], iconName: "sparkles.rectangle.stack", colors: [Color(red: 0.40, green: 0.28, blue: 0.90), Color(red: 0.96, green: 0.46, blue: 0.55)], diff --git a/README.md b/README.md index 662c69a..296ada9 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@

> Status: **active release** -> Latest release: **v0.4.8** +> Latest release: **v0.4.9** > Platform target: **macOS 26 (Tahoe)** compatible with **macOS Sequoia** > Apple Silicon: tested / Intel: not tested @@ -25,7 +25,7 @@ Prebuilt binaries are available on [GitHub Releases](https://github.com/h3pdesign/Neon-Vision-Editor/releases). -- Latest release: **v0.4.8** +- Latest release: **v0.4.9** - Architecture: Apple Silicon (Intel not tested) - Notarization: *is finally there* @@ -121,6 +121,14 @@ If macOS blocks first launch: ## Changelog +### v0.4.9 (summary) + +- Pre-release CI workflow on `main`/PR with critical runtime checks, docs validation, and icon payload verification. +- Release dry-run workflow and local `scripts/release_dry_run.sh` command for pre-tag validation. +- Release runtime policy test suite (`ReleaseRuntimePolicyTests`) covering settings-tab routing, theme mapping, find-next cursor behavior, and subscription button state logic. +- Unified release automation in `scripts/release_all.sh` to run preflight checks before tagging and to verify uploaded release assets after notarized publish. +- README changelog summary automation now keeps release summaries version-sorted and limited to the latest three entries. + ### v0.4.8 (summary) - Extended release automation coverage for the next tag cycle, including synchronized README/changelog/welcome-tour release content updates. @@ -137,14 +145,6 @@ If macOS blocks first launch: - Visibility of matched bracket tokens and scope guide markers for easier detection on iOS and macOS. - Settings window opening/persistence path now uses the native Settings scene behavior, avoiding custom frame persistence conflicts. -### v0.4.6 (summary) - -- Self-hosted notarized release workflow for macOS (`release-notarized-selfhosted.yml`) targeting macOS runners with Xcode 17+. -- Automated icon payload preflight in notarized release pipelines to block publishing assets with missing AppIcon renditions. -- Release automation wiring so `scripts/release_all.sh --notarized` triggers the self-hosted notarized workflow. -- Release tooling robustness in `release_all.sh` / `release_prep.sh` for optional arguments and end-to-end docs flow. -- Welcome Tour release page automation now derives the first card from the selected changelog section during release prep. - Full release history: [`CHANGELOG.md`](CHANGELOG.md) ## Known Limitations @@ -164,12 +164,12 @@ Full release history: [`CHANGELOG.md`](CHANGELOG.md) ## Release Integrity -- Tag: `v0.4.8` +- Tag: `v0.4.9` - Tagged commit: `TBD` - Verify local tag target: ```bash -git rev-parse --verify v0.4.8 +git rev-parse --verify v0.4.9 ``` - Verify downloaded artifact checksum locally: diff --git a/scripts/ci/release_preflight.sh b/scripts/ci/release_preflight.sh index 7989413..a03326b 100755 --- a/scripts/ci/release_preflight.sh +++ b/scripts/ci/release_preflight.sh @@ -27,21 +27,35 @@ grep -nE "^### ${TAG} \\(summary\\)$" README.md >/dev/null SAFE_TAG="$(echo "$TAG" | tr -c 'A-Za-z0-9_' '_')" WORK_DIR="/tmp/nve_release_preflight_${SAFE_TAG}" -DERIVED="${WORK_DIR}/DerivedData" rm -rf "$WORK_DIR" mkdir -p "$WORK_DIR" echo "Running critical runtime tests..." -xcodebuild \ - -project "Neon Vision Editor.xcodeproj" \ - -scheme "Neon Vision Editor" \ - -destination "platform=macOS" \ - -derivedDataPath "$DERIVED" \ - CODE_SIGNING_ALLOWED=NO \ - CODE_SIGNING_REQUIRED=NO \ - CODE_SIGN_IDENTITY="" \ - -only-testing:"Neon Vision EditorTests/ReleaseRuntimePolicyTests" \ - test >"${WORK_DIR}/test.log" +run_critical_tests() { + local derived_path="$1" + xcodebuild \ + -project "Neon Vision Editor.xcodeproj" \ + -scheme "Neon Vision Editor" \ + -destination "platform=macOS" \ + -derivedDataPath "$derived_path" \ + CODE_SIGNING_ALLOWED=NO \ + CODE_SIGNING_REQUIRED=NO \ + CODE_SIGN_IDENTITY="" \ + -only-testing:"Neon Vision EditorTests/ReleaseRuntimePolicyTests" \ + test >"${WORK_DIR}/test.log" 2>&1 +} + +DERIVED_PRIMARY="${WORK_DIR}/DerivedData" +DERIVED_FALLBACK="/tmp/nve_ci_critical_test2" + +if ! run_critical_tests "$DERIVED_PRIMARY"; then + echo "Primary test pass failed in this environment; retrying with fallback DerivedData path..." + rm -rf "$DERIVED_FALLBACK" + run_critical_tests "$DERIVED_FALLBACK" + DERIVED="$DERIVED_FALLBACK" +else + DERIVED="$DERIVED_PRIMARY" +fi APP="$DERIVED/Build/Products/Debug/Neon Vision Editor.app" scripts/ci/verify_icon_payload.sh "$APP"