native macOS codings agent orchestrator
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 391 lines 19 kB view raw
1# Sensible defaults 2.ONESHELL: 3SHELL := bash 4.SHELLFLAGS := -e -u -c -o pipefail 5.DELETE_ON_ERROR: 6MAKEFLAGS += --warn-undefined-variables 7MAKEFLAGS += --no-builtin-rules 8 9# Derived values (DO NOT TOUCH). 10CURRENT_MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) 11CURRENT_MAKEFILE_DIR := $(patsubst %/,%,$(dir $(CURRENT_MAKEFILE_PATH))) 12GHOSTTY_XCFRAMEWORK_PATH := $(CURRENT_MAKEFILE_DIR)/Frameworks/GhosttyKit.xcframework 13GHOSTTY_RESOURCE_PATH := $(CURRENT_MAKEFILE_DIR)/Resources/ghostty 14GHOSTTY_TERMINFO_PATH := $(CURRENT_MAKEFILE_DIR)/Resources/terminfo 15GHOSTTY_BUILD_OUTPUTS := $(GHOSTTY_XCFRAMEWORK_PATH) $(GHOSTTY_RESOURCE_PATH) $(GHOSTTY_TERMINFO_PATH) 16GHOSTTY_BUILD_STAMP := $(CURRENT_MAKEFILE_DIR)/.ghostty_build_stamp 17GHOSTTY_HASH_FILE := $(CURRENT_MAKEFILE_DIR)/.ghostty_hash 18SPM_CACHE_DIR := /tmp/supacode-spm-cache/SourcePackages 19VERSION ?= 20BUILD ?= 21XCODEBUILD_FLAGS ?= 22FORMAT_BASE_REF ?= origin/main 23 24# Release-only analytics/crash credentials. Included from Config/Secrets.env if present, 25# or overridable from the environment (e.g. CI). Debug builds skip SDK init regardless. 26-include Config/Secrets.env 27PROWL_SENTRY_DSN ?= 28PROWL_POSTHOG_API_KEY ?= 29PROWL_POSTHOG_HOST ?= 30 31.DEFAULT_GOAL := help 32.PHONY: build-ghostty-xcframework ensure-ghostty sync-ghostty _check-ghostty-hash _record-ghostty-hash build-app build-cli build-cli-release embed-cli-debug embed-cli run-app install-dev-build install-release archive export-archive format format-changed format-lint lint check test test-cli-smoke test-cli-integration bump-version bump-and-release log-stream 33 34help: # Display this help. 35 @-+echo "Run make with one of the following targets:" 36 @-+echo 37 @-+grep -Eh "^[a-z-]+:.*#" $(CURRENT_MAKEFILE_PATH) | sed -E 's/^(.*:)(.*#+)(.*)/ \1 @@@ \3 /' | column -t -s "@@@" 38 39build-ghostty-xcframework: $(GHOSTTY_BUILD_STAMP) # Build ghostty framework 40 @$(MAKE) _record-ghostty-hash 41 42# Internal: actually rebuild ghostty. 43$(GHOSTTY_BUILD_STAMP): 44 @cd $(CURRENT_MAKEFILE_DIR)/ThirdParty/ghostty && mise exec -- zig build -Doptimize=ReleaseFast -Demit-xcframework=true -Dsentry=false 45 rsync -a ThirdParty/ghostty/macos/GhosttyKit.xcframework Frameworks 46 @src="$(CURRENT_MAKEFILE_DIR)/ThirdParty/ghostty/zig-out/share/ghostty"; \ 47 dst="$(GHOSTTY_RESOURCE_PATH)"; \ 48 terminfo_src="$(CURRENT_MAKEFILE_DIR)/ThirdParty/ghostty/zig-out/share/terminfo"; \ 49 terminfo_dst="$(GHOSTTY_TERMINFO_PATH)"; \ 50 mkdir -p "$$dst"; \ 51 rsync -a --delete "$$src/" "$$dst/"; \ 52 mkdir -p "$$terminfo_dst"; \ 53 rsync -a --delete "$$terminfo_src/" "$$terminfo_dst/" 54 touch "$(GHOSTTY_BUILD_STAMP)" 55 56# Public entry point: only rebuilds ghostty if submodule SHA changed (or outputs are missing). 57ensure-ghostty: _check-ghostty-hash # Ensure GhosttyKit is up-to-date (fast path when unchanged) 58 59# Internal: compare current submodule SHA against the recorded one. 60_check-ghostty-hash: 61 @current_sha="$$(git -C $(CURRENT_MAKEFILE_DIR)/ThirdParty/ghostty rev-parse HEAD)"; \ 62 last_sha=""; \ 63 if [ -f "$(GHOSTTY_HASH_FILE)" ]; then \ 64 last_sha="$$(cat "$(GHOSTTY_HASH_FILE)")"; \ 65 fi; \ 66 artifacts_ok=1; \ 67 for path in "$(GHOSTTY_XCFRAMEWORK_PATH)" "$(GHOSTTY_RESOURCE_PATH)" "$(GHOSTTY_TERMINFO_PATH)"; do \ 68 if [ ! -e "$$path" ]; then \ 69 artifacts_ok=0; \ 70 fi; \ 71 done; \ 72 if [ "$$current_sha" != "$$last_sha" ] || [ "$$artifacts_ok" -ne 1 ]; then \ 73 echo "Syncing GhosttyKit for submodule $$current_sha"; \ 74 $(MAKE) -B build-ghostty-xcframework; \ 75 if [ "$$current_sha" != "$$last_sha" ]; then \ 76 rm -rf ~/Library/Developer/Xcode/DerivedData/supacode-*; \ 77 echo "Cleared Xcode DerivedData for ghostty header/module changes"; \ 78 fi; \ 79 else \ 80 echo "GhosttyKit up-to-date (SHA unchanged)"; \ 81 fi 82 83# Internal: record the current submodule SHA after a successful build. 84_record-ghostty-hash: 85 @git -C $(CURRENT_MAKEFILE_DIR)/ThirdParty/ghostty rev-parse HEAD > "$(GHOSTTY_HASH_FILE)" 86 87# Force a clean rebuild of GhosttyKit (ignores cached SHA, useful after submodule updates). 88sync-ghostty: # Force sync GhosttyKit to current submodule HEAD (always rebuilds) 89 @echo "Forcing GhosttyKit rebuild..." 90 $(MAKE) -B build-ghostty-xcframework 91 rm -rf ~/Library/Developer/Xcode/DerivedData/supacode-* 92 @echo "Done. Xcode module cache cleared for fresh compilation." 93 94build-app: ensure-ghostty embed-cli-debug # Build the macOS app (Debug) 95 bash -o pipefail -c 'xcodebuild -project supacode.xcodeproj -scheme supacode -configuration Debug build -skipMacroValidation -clonedSourcePackagesDirPath $(SPM_CACHE_DIR) 2>&1 | mise exec -- xcsift -qw --format toon' 96 97sync-cli-version: # Sync app MARKETING_VERSION into ProwlCLIShared/ProwlVersion.swift 98 @version="$$(/usr/bin/awk -F' = ' '/MARKETING_VERSION = [0-9.]*;/{gsub(/;/,"",$$2);print $$2; exit}' \ 99 "$(CURRENT_MAKEFILE_DIR)/supacode.xcodeproj/project.pbxproj")"; \ 100 dst="$(CURRENT_MAKEFILE_DIR)/supacode/CLIService/Shared/ProwlVersion.swift"; \ 101 printf '// Auto-generated by Makefile (sync-cli-version). Do not edit.\n\npublic enum ProwlVersion {\n public static let current = "%s"\n}\n' "$$version" > "$$dst" 102 103build-cli: sync-cli-version # Build Swift CLI binary (SPM) 104 swift build --product prowl 105 106build-cli-release: sync-cli-version # Build universal CLI binary in release mode 107 swift build -c release --arch arm64 --arch x86_64 --product prowl 108 109embed-cli-debug: build-cli # Build debug CLI and copy into Resources for dev builds 110 @set -euo pipefail; \ 111 bin="$$(swift build --show-bin-path)/prowl"; \ 112 dst="$(CURRENT_MAKEFILE_DIR)/Resources/prowl-cli"; \ 113 mkdir -p "$$dst"; \ 114 cp "$$bin" "$$dst/prowl"; \ 115 chmod +x "$$dst/prowl"; \ 116 echo "embedded CLI binary at $$dst/prowl" 117 118embed-cli: build-cli-release # Build release CLI and copy into Resources for distribution 119 @set -euo pipefail; \ 120 bin="$$(swift build -c release --arch arm64 --arch x86_64 --show-bin-path)/prowl"; \ 121 dst="$(CURRENT_MAKEFILE_DIR)/Resources/prowl-cli"; \ 122 mkdir -p "$$dst"; \ 123 cp "$$bin" "$$dst/prowl"; \ 124 chmod +x "$$dst/prowl"; \ 125 echo "embedded CLI binary at $$dst/prowl" 126 127run-app: build-app # Build then launch (Debug) with log streaming 128 @set -euo pipefail; \ 129 settings="$$(xcodebuild -project supacode.xcodeproj -scheme supacode -configuration Debug -showBuildSettings -json 2>/dev/null)"; \ 130 build_dir="$$(echo "$$settings" | jq -er '.[0].buildSettings.BUILT_PRODUCTS_DIR')"; \ 131 product="$$(echo "$$settings" | jq -er '.[0].buildSettings.FULL_PRODUCT_NAME')"; \ 132 exec_name="$$(echo "$$settings" | jq -r '.[0].buildSettings.EXECUTABLE_NAME')"; \ 133 if [ -z "$$build_dir" ] || [ -z "$$product" ] || [ "$$build_dir" = "null" ] || [ "$$product" = "null" ] || [ -z "$$exec_name" ] || [ "$$exec_name" = "null" ]; then \ 134 echo "error: failed to resolve app path from build settings"; \ 135 exit 1; \ 136 fi; \ 137 "$$build_dir/$$product/Contents/MacOS/$$exec_name" 138 139install-dev-build: build-app # install dev build to /Applications 140 @set -euo pipefail; \ 141 settings="$$(xcodebuild -project supacode.xcodeproj -scheme supacode -configuration Debug -showBuildSettings -json 2>/dev/null)"; \ 142 build_dir="$$(echo "$$settings" | jq -er '.[0].buildSettings.BUILT_PRODUCTS_DIR')"; \ 143 product="$$(echo "$$settings" | jq -er '.[0].buildSettings.FULL_PRODUCT_NAME')"; \ 144 if [ -z "$$build_dir" ] || [ -z "$$product" ] || [ "$$build_dir" = "null" ] || [ "$$product" = "null" ]; then \ 145 echo "error: failed to resolve app path from build settings"; \ 146 exit 1; \ 147 fi; \ 148 if [ "$$product" != "$$(basename "$$product")" ]; then \ 149 echo "error: invalid product name (contains path separators): $$product"; \ 150 exit 1; \ 151 fi; \ 152 if [[ "$$product" != *.app ]]; then \ 153 echo "error: unexpected product name: $$product"; \ 154 exit 1; \ 155 fi; \ 156 src="$$build_dir/$$product"; \ 157 dst="/Applications/$$product"; \ 158 dst_parent="$$(cd "$$(dirname "$$dst")" && pwd -P)"; \ 159 if [ "$$dst_parent" != "/Applications" ]; then \ 160 echo "error: refusing to install outside /Applications: $$dst"; \ 161 exit 1; \ 162 fi; \ 163 if [ "$$src" = "/" ] || [ "$$dst" = "/Applications" ] || [ "$$dst" = "/Applications/" ]; then \ 164 echo "error: unsafe install path (src=$$src, dst=$$dst)"; \ 165 exit 1; \ 166 fi; \ 167 case "$$dst" in \ 168 /Applications/*.app) ;; \ 169 *) \ 170 echo "error: refusing to install outside /Applications/*.app: $$dst"; \ 171 exit 1; \ 172 ;; \ 173 esac; \ 174 if [ ! -d "$$src" ]; then \ 175 echo "app not found: $$src"; \ 176 exit 1; \ 177 fi; \ 178 if [ ! -d "$$src/Contents" ]; then \ 179 echo "error: source is not an app bundle: $$src"; \ 180 exit 1; \ 181 fi; \ 182 echo "copying $$src -> $$dst"; \ 183 if [ -e "$$dst" ]; then \ 184 if ! command -v trash >/dev/null 2>&1; then \ 185 echo "error: trash command not found; refusing to remove $$dst"; \ 186 exit 1; \ 187 fi; \ 188 echo "moving existing app to Trash: $$dst"; \ 189 trash "$$dst"; \ 190 fi; \ 191 ditto "$$src" "$$dst"; \ 192 echo "installed $$dst" 193 194install-release: build-ghostty-xcframework # Build Release, sign locally, install to /Applications 195 @set -euo pipefail; \ 196 SIGNING_IDENTITY="$$(security find-identity -v -p codesigning 2>/dev/null | awk -F'"' '/Developer ID Application/ {print $$2; exit}')"; \ 197 if [ -z "$$SIGNING_IDENTITY" ]; then \ 198 echo "error: no Developer ID Application identity found"; \ 199 exit 1; \ 200 fi; \ 201 IDENTITY_SHA="$$(security find-identity -v -p codesigning 2>/dev/null | grep "$$SIGNING_IDENTITY" | head -1 | awk '{print $$2}')"; \ 202 TEAM_ID="$$(echo "$$SIGNING_IDENTITY" | grep -oE '\([A-Z0-9]{10}\)$$' | tr -d '()')"; \ 203 echo "identity: $$SIGNING_IDENTITY"; \ 204 echo "team: $$TEAM_ID"; \ 205 APPLE_TEAM_ID="$$TEAM_ID" DEVELOPER_ID_IDENTITY_SHA="$$IDENTITY_SHA" $(MAKE) archive; \ 206 mkdir -p build; \ 207 printf '%s\n' \ 208 '<?xml version="1.0" encoding="UTF-8"?>' \ 209 '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">' \ 210 '<plist version="1.0">' \ 211 '<dict>' \ 212 ' <key>method</key>' \ 213 ' <string>developer-id</string>' \ 214 ' <key>signingStyle</key>' \ 215 ' <string>manual</string>' \ 216 ' <key>signingCertificate</key>' \ 217 " <string>$$SIGNING_IDENTITY</string>" \ 218 ' <key>teamID</key>' \ 219 " <string>$$TEAM_ID</string>" \ 220 '</dict>' \ 221 '</plist>' > build/ExportOptions.plist; \ 222 $(MAKE) export-archive; \ 223 APP_PATH="$$(find build/export -name '*.app' -maxdepth 3 -print -quit)"; \ 224 if [ ! -d "$$APP_PATH" ]; then \ 225 echo "error: exported app not found"; \ 226 exit 1; \ 227 fi; \ 228 SPARKLE="$$APP_PATH/Contents/Frameworks/Sparkle.framework/Versions/B"; \ 229 if [ -d "$$SPARKLE" ]; then \ 230 codesign -f -s "$$IDENTITY_SHA" -o runtime --timestamp -v "$$SPARKLE/XPCServices/Installer.xpc"; \ 231 codesign -f -s "$$IDENTITY_SHA" -o runtime --timestamp --preserve-metadata=entitlements -v "$$SPARKLE/XPCServices/Downloader.xpc"; \ 232 codesign -f -s "$$IDENTITY_SHA" -o runtime --timestamp -v "$$SPARKLE/Updater.app"; \ 233 codesign -f -s "$$IDENTITY_SHA" -o runtime --timestamp -v "$$SPARKLE/Autoupdate"; \ 234 codesign -f -s "$$IDENTITY_SHA" -o runtime --timestamp -v "$$SPARKLE/Sparkle"; \ 235 codesign -f -s "$$IDENTITY_SHA" -o runtime --timestamp -v "$$APP_PATH/Contents/Frameworks/Sparkle.framework"; \ 236 fi; \ 237 SENTRY="$$APP_PATH/Contents/Frameworks/Sentry.framework"; \ 238 if [ -d "$$SENTRY" ]; then \ 239 codesign -f -s "$$IDENTITY_SHA" -o runtime --timestamp -v "$$SENTRY/Versions/A/Sentry"; \ 240 codesign -f -s "$$IDENTITY_SHA" -o runtime --timestamp -v "$$SENTRY"; \ 241 fi; \ 242 codesign -f -s "$$IDENTITY_SHA" -o runtime --timestamp --preserve-metadata=entitlements,requirements,flags -v "$$APP_PATH"; \ 243 codesign -vvv --deep --strict "$$APP_PATH"; \ 244 PRODUCT="$$(basename "$$APP_PATH")"; \ 245 if [ -z "$$PRODUCT" ] || [ "$$PRODUCT" = "." ] || [[ "$$PRODUCT" != *.app ]]; then \ 246 echo "error: unexpected release product name: $$PRODUCT"; \ 247 exit 1; \ 248 fi; \ 249 DST="/Applications/$$PRODUCT"; \ 250 if [ "$$DST" = "/Applications" ] || [ "$$DST" = "/Applications/" ]; then \ 251 echo "error: unsafe install destination: $$DST"; \ 252 exit 1; \ 253 fi; \ 254 case "$$DST" in \ 255 /Applications/*.app) ;; \ 256 *) \ 257 echo "error: refusing to install outside /Applications/*.app: $$DST"; \ 258 exit 1; \ 259 ;; \ 260 esac; \ 261 echo "copying $$APP_PATH -> $$DST"; \ 262 if [ -e "$$DST" ]; then \ 263 if ! command -v trash >/dev/null 2>&1; then \ 264 echo "error: trash command not found; refusing to remove $$DST"; \ 265 exit 1; \ 266 fi; \ 267 echo "moving existing app to Trash: $$DST"; \ 268 trash "$$DST"; \ 269 fi; \ 270 ditto "$$APP_PATH" "$$DST"; \ 271 echo "installed $$DST (Release build, locally signed)" 272 273archive: build-ghostty-xcframework embed-cli # Archive Release build for distribution 274 bash -o pipefail -c 'xcodebuild -project supacode.xcodeproj -scheme supacode -configuration Release -archivePath build/supacode.xcarchive archive CODE_SIGN_STYLE=Manual DEVELOPMENT_TEAM="$$APPLE_TEAM_ID" CODE_SIGN_IDENTITY="$$DEVELOPER_ID_IDENTITY_SHA" OTHER_CODE_SIGN_FLAGS="--timestamp" PROWL_SENTRY_DSN="$(PROWL_SENTRY_DSN)" PROWL_POSTHOG_API_KEY="$(PROWL_POSTHOG_API_KEY)" PROWL_POSTHOG_HOST="$(PROWL_POSTHOG_HOST)" -skipMacroValidation -clonedSourcePackagesDirPath $(SPM_CACHE_DIR) $(XCODEBUILD_FLAGS) 2>&1 | mise exec -- xcsift -qw --format toon' 275 276export-archive: # Export xarchive 277 bash -o pipefail -c 'xcodebuild -exportArchive -archivePath build/supacode.xcarchive -exportPath build/export -exportOptionsPlist build/ExportOptions.plist 2>&1 | mise exec -- xcsift -qw --format toon' 278 279test: ensure-ghostty 280 @set -euo pipefail; \ 281 result_bundle="$(CURRENT_MAKEFILE_DIR)/build/test-results/supacode-tests.xcresult"; \ 282 mkdir -p "$$(dirname "$$result_bundle")"; \ 283 rm -rf "$$result_bundle"; \ 284 set +e; \ 285 xcodebuild test -project supacode.xcodeproj -scheme supacode -destination "platform=macOS" -resultBundlePath "$$result_bundle" CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY="" -skipMacroValidation -clonedSourcePackagesDirPath $(SPM_CACHE_DIR) 2>&1 | mise exec -- xcsift -w --format toon; \ 286 xcodebuild_status=$${PIPESTATUS[0]}; \ 287 set -e; \ 288 if [ "$$xcodebuild_status" -ne 0 ]; then \ 289 bash "$(CURRENT_MAKEFILE_DIR)/scripts/print-xcresult-failures.sh" "$$result_bundle" || true; \ 290 fi; \ 291 exit "$$xcodebuild_status" 292 293test-cli-smoke: build-cli # Smoke test CLI executable 294 @set -euo pipefail; \ 295 bin="$$(swift build --show-bin-path)/prowl"; \ 296 help_output="$$("$$bin" --help)"; \ 297 version_output="$$("$$bin" --version)"; \ 298 echo "$$help_output" | grep -q "USAGE:"; \ 299 echo "$$version_output" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+(-[A-Za-z0-9.]+)?$$'; \ 300 socket="/tmp/prowl-cli-smoke-$$RANDOM.sock"; \ 301 PROWL_CLI_SOCKET="$$socket" "$$bin" list --json >/tmp/prowl-cli-smoke.json || true; \ 302 jq -e '.error.code == "APP_NOT_RUNNING"' /tmp/prowl-cli-smoke.json >/dev/null 303 304test-cli-integration: # Run CLI integration tests via SwiftPM 305 swift test --filter ProwlCLIIntegrationTests 306 307format: # Format all Swift code with swift-format (full-tree cleanup) 308 swift-format -p --in-place --recursive --configuration ./.swift-format.json supacode supacodeTests 309 310format-changed: # Format Swift files changed from FORMAT_BASE_REF (default: origin/main) 311 @base="$$(git merge-base HEAD "$(FORMAT_BASE_REF)" 2>/dev/null || git rev-parse HEAD)"; \ 312 mapfile -t files < <( \ 313 { \ 314 git diff --name-only --diff-filter=ACMR "$$base" -- supacode supacodeTests; \ 315 git ls-files --others --exclude-standard -- supacode supacodeTests; \ 316 } | awk '/\.swift$$/' | sort -u \ 317 ); \ 318 if [ "$${#files[@]}" -eq 0 ]; then \ 319 echo "No changed Swift files to format."; \ 320 else \ 321 printf 'Formatting %s changed Swift file(s) from %s\n' "$${#files[@]}" "$$base"; \ 322 swift-format -p --in-place --configuration ./.swift-format.json "$${files[@]}"; \ 323 fi 324 325format-lint: # Check Swift formatting without rewriting files 326 swift-format lint --strict --recursive --configuration ./.swift-format.json supacode supacodeTests 327 328lint: # Lint code with swiftlint 329 mise exec -- swiftlint lint --quiet --config .swiftlint.yml 330 331check: format-changed format-lint lint # Format changed Swift files, then run swift-format lint and SwiftLint 332 333log-stream: # Stream logs from the app via log stream 334 log stream --predicate 'subsystem == "com.onevcat.prowl"' --style compact --color always 335 336bump-version: # Bump app version (usage: make bump-version [VERSION=YYYY.M.DD] [BUILD=YYYYMMDD]) 337 @if [ -z "$(VERSION)" ]; then \ 338 version="$$(date +%Y.%-m.%-d)"; \ 339 suffix=1; \ 340 while git rev-parse "v$$version" >/dev/null 2>&1; do \ 341 suffix=$$((suffix + 1)); \ 342 version="$$(date +%Y.%-m.%-d).$$suffix"; \ 343 done; \ 344 else \ 345 if ! echo "$(VERSION)" | grep -qE '^[0-9]{4}\.[0-9]{1,2}\.[0-9]{1,2}(\.[0-9]+)?$$'; then \ 346 echo "error: VERSION must be in YYYY.M.DD or YYYY.M.DD.N format"; \ 347 exit 1; \ 348 fi; \ 349 version="$(VERSION)"; \ 350 fi; \ 351 if [ -z "$(BUILD)" ]; then \ 352 base_build="$$(date +%Y%m%d)"; \ 353 current_build="$$(/usr/bin/awk -F' = ' '/CURRENT_PROJECT_VERSION = [0-9]+;/{gsub(/;/,"",$$2);print $$2; exit}' "$(CURRENT_MAKEFILE_DIR)/supacode.xcodeproj/project.pbxproj")"; \ 354 if [ "$$current_build" -ge "$$base_build" ] 2>/dev/null; then \ 355 build="$$((current_build + 1))"; \ 356 else \ 357 build="$$base_build"; \ 358 fi; \ 359 else \ 360 if ! echo "$(BUILD)" | grep -qE '^[0-9]+$$'; then \ 361 echo "error: BUILD must be an integer"; \ 362 exit 1; \ 363 fi; \ 364 build="$(BUILD)"; \ 365 fi; \ 366 sed -i '' "s/MARKETING_VERSION = [0-9.]*;/MARKETING_VERSION = $$version;/g" \ 367 "$(CURRENT_MAKEFILE_DIR)/supacode.xcodeproj/project.pbxproj"; \ 368 sed -i '' "s/CURRENT_PROJECT_VERSION = [0-9]*;/CURRENT_PROJECT_VERSION = $$build;/g" \ 369 "$(CURRENT_MAKEFILE_DIR)/supacode.xcodeproj/project.pbxproj"; \ 370 printf '// Auto-generated by Makefile (sync-cli-version). Do not edit.\n\npublic enum ProwlVersion {\n public static let current = "%s"\n}\n' "$$version" > \ 371 "$(CURRENT_MAKEFILE_DIR)/supacode/CLIService/Shared/ProwlVersion.swift"; \ 372 git add "$(CURRENT_MAKEFILE_DIR)/supacode.xcodeproj/project.pbxproj" \ 373 "$(CURRENT_MAKEFILE_DIR)/supacode/CLIService/Shared/ProwlVersion.swift"; \ 374 git commit -m "bump v$$version"; \ 375 git tag -s "v$$version" -m "v$$version"; \ 376 echo "version bumped to $$version (build $$build), tagged v$$version" 377 378bump-and-release: bump-version # Bump version and push tags to trigger release 379 git push --follow-tags 380 @tag="$$(git describe --tags --abbrev=0)"; \ 381 repo="$$(gh repo view --json nameWithOwner -q .nameWithOwner)"; \ 382 prev="$$(gh release view --json tagName -q .tagName 2>/dev/null || echo '')"; \ 383 tmp=$$(mktemp); \ 384 if [ -n "$$prev" ]; then \ 385 gh api "repos/$$repo/releases/generate-notes" -f tag_name="$$tag" -f previous_tag_name="$$prev" --jq '.body' > "$$tmp"; \ 386 else \ 387 gh api "repos/$$repo/releases/generate-notes" -f tag_name="$$tag" --jq '.body' > "$$tmp"; \ 388 fi; \ 389 $${EDITOR:-vim} "$$tmp"; \ 390 gh release create "$$tag" --notes-file "$$tmp"; \ 391 rm -f "$$tmp"