Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: CI

on:
pull_request:
push:
branches:
- master
Comment thread
sozercan marked this conversation as resolved.

permissions:
contents: read

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

jobs:
test-and-package:
runs-on: macos-26
timeout-minutes: 30

steps:
- name: Checkout code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7

- name: Select Xcode
run: sudo xcode-select -s /Applications/Xcode_26.2.app/Contents/Developer

- name: Run focused tests
run: ./scripts/test.sh

- name: Build universal app
env:
ARCHES: "arm64 x86_64"
run: ./scripts/build-app.sh release

- name: Verify packaged app
run: |
set -euo pipefail

APP_PATH="$PWD/.build/app/Open in Code.app"
EXECUTABLE_PATH="$APP_PATH/Contents/MacOS/Open in Code"

test -d "$APP_PATH"
test -f "$APP_PATH/Contents/Resources/Assets.car"
test -f "$APP_PATH/Contents/Resources/vscode.icns"
plutil -lint "$APP_PATH/Contents/Info.plist"

ARCHITECTURES=$(lipo -archs "$EXECUTABLE_PATH")
echo "Architectures: $ARCHITECTURES"
[[ "$ARCHITECTURES" == *arm64* ]]
[[ "$ARCHITECTURES" == *x86_64* ]]

codesign --verify --deep --strict --verbose=2 "$APP_PATH"
ENTITLEMENTS=$(codesign -d --entitlements :- "$APP_PATH" 2>/dev/null)
grep -F 'com.apple.security.automation.apple-events' <<< "$ENTITLEMENTS" >/dev/null
29 changes: 11 additions & 18 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -177,33 +177,26 @@ jobs:
- name: Build and sign release app
id: app
env:
VERSION: ${{ steps.version.outputs.version }}
BUNDLE_VERSION: ${{ steps.version.outputs.bundle_version }}
MARKETING_VERSION: ${{ steps.version.outputs.bundle_version }}
BUILD_NUMBER: ${{ github.run_number }}
ARCHES: "arm64 x86_64"
OPEN_IN_CODE_SIGNING: unsigned
SIGNING_IDENTITY: ${{ steps.signing.outputs.identity }}
SIGNING_MODE: ${{ steps.signing.outputs.mode }}
run: |
set -euo pipefail

DERIVED_DATA="$RUNNER_TEMP/OpenInCodeDerivedData"
xcodebuild \
-project "Open in Code.xcodeproj" \
-scheme "Open in Code" \
-configuration Release \
-destination "generic/platform=macOS" \
-derivedDataPath "$DERIVED_DATA" \
ARCHS="arm64 x86_64" \
ONLY_ACTIVE_ARCH=NO \
CODE_SIGNING_ALLOWED=NO \
CODE_SIGNING_REQUIRED=NO \
clean build

APP_PATH="$DERIVED_DATA/Build/Products/Release/Open in Code.app"
./scripts/build-app.sh release

APP_PATH="$PWD/.build/app/Open in Code.app"
PLIST_PATH="$APP_PATH/Contents/Info.plist"
EXECUTABLE_PATH="$APP_PATH/Contents/MacOS/Open in Code"

test -d "$APP_PATH"
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $BUNDLE_VERSION" "$PLIST_PATH"
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $GITHUB_RUN_NUMBER" "$PLIST_PATH"
test -f "$APP_PATH/Contents/Resources/Assets.car"
test -f "$APP_PATH/Contents/Resources/vscode.icns"
test "$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$PLIST_PATH")" = "$MARKETING_VERSION"
test "$(/usr/libexec/PlistBuddy -c 'Print :CFBundleVersion' "$PLIST_PATH")" = "$BUILD_NUMBER"

ARCHITECTURES=$(lipo -archs "$EXECUTABLE_PATH")
echo "Architectures: $ARCHITECTURES"
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

## Build generated
build/
.build/
DerivedData/

## Various settings
Expand Down
41 changes: 18 additions & 23 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,32 @@

## Project at a glance

OpenInCode is a small macOS Finder toolbar utility written in Objective-C. It reads the selected Finder item, or the front Finder window when nothing is selected, and opens the corresponding folder in Visual Studio Code.
OpenInCode is a small macOS Finder toolbar utility written in Swift. It reads the selected Finder item, or the front Finder window when nothing is selected, and opens the corresponding folder in Visual Studio Code.

- Deployment target: macOS 12 or newer.
- Build system: `Open in Code.xcodeproj`; Xcode 26 or newer is required for the current Icon Composer asset.
- Memory model: manual reference counting; ARC is disabled.
- Dependencies: Apple frameworks only; there is no package manager or dependency-install step.
- Build system: Swift Package Manager via `Package.swift`; Xcode 26 or newer is required only for `actool` to compile the current Icon Composer asset when packaging the app.
- Swift language mode: Swift 6.
- Dependencies: Apple frameworks only; SwiftPM resolves no external packages.

## Repository map

- `main.m`: Finder automation, user-facing errors, application lookup, and launch flow.
- `OpenInCodeCore.h` / `OpenInCodeCore.m`: testable editor-priority and Finder-path logic.
- `Tests/OpenInCodeCoreTests.m`: standalone Foundation test executable used by the test script.
- `scripts/test.sh`: canonical focused test command; also validates Homebrew cask rendering.
- `Package.swift`: SwiftPM executable and test target definitions.
- `Sources/OpenInCode/OpenInCodeApplication.swift`: Finder automation, user-facing errors, application lookup, and launch flow.
- `Sources/OpenInCode/OpenInCodeCore.swift`: testable editor-priority and Finder-path logic.
- `Tests/OpenInCodeTests/OpenInCodeCoreTests.swift`: XCTest coverage for editor priority and Finder paths.
- `scripts/test.sh`: canonical focused test command; runs `swift test` and validates Homebrew cask rendering.
- `scripts/build-app.sh`: builds thin SwiftPM executables, creates a universal binary when requested, compiles the icon, assembles the app bundle, and optionally ad-hoc signs it.
- `scripts/render-homebrew-cask.sh`: release cask template generator.
- `Info.plist` and `Open in Code.entitlements`: app metadata and Finder Apple Events permission.
- `Open in Code.xcodeproj`: target membership, build settings, signing, and the build rule that generates `Finder.h` from Finder's scripting definition.
- `.github/workflows/release.yml`: tag-driven universal build, signing, notarization, GitHub release, and Homebrew cask update.

## Working rules

1. Check `git status --short` before editing and preserve unrelated user changes.
2. Inspect only the files relevant to the task; do not search generated `build/` or `DerivedData/` content.
2. Inspect only the files relevant to the task; do not search generated `.build/`, `build/`, or `DerivedData/` content.
3. Keep changes focused. Avoid adding dependencies, new abstractions, or project files unless the task requires them.
4. Put deterministic, UI-independent behavior in `OpenInCodeCore.*` and cover it in `Tests/OpenInCodeCoreTests.m`.
5. When adding or removing source or resource files, keep the Xcode project references and target membership in sync.
6. Do not add a generated `Finder.h` to the repository; Xcode creates it during the build.
4. Put deterministic, UI-independent behavior in `Sources/OpenInCode/OpenInCodeCore.swift` and cover it in `Tests/OpenInCodeTests/OpenInCodeCoreTests.swift`.
5. Keep SwiftPM target definitions, source layout, and packaging inputs in sync when adding or removing source or resource files.

## Behavioral invariants

Expand All @@ -40,10 +40,10 @@ Preserve these unless the requested change explicitly replaces them:
- Present actionable errors for Finder permission failures and missing or failed VS Code launches.
- Keep compatibility with macOS 12; guard any newer API before use.

## Objective-C conventions
## Swift conventions

- Match the existing Objective-C style and naming (`OIC` prefix for shared symbols).
- ARC is disabled. Balance ownership with `retain`, `release`, `autorelease`, or `copy`, and keep `dealloc` implementations correct.
- Match the existing Swift style and naming (`OIC` prefix for shared symbols).
- Keep the application compatible with Swift 6 language mode and macOS 12.
- Treat compiler warnings as errors in testable core code.
- Prefer small functions with explicit failure handling over silent fallback behavior.

Expand All @@ -58,15 +58,10 @@ Run the smallest relevant checks:
./scripts/test.sh
```

- Application code, plist, entitlements, icon, or Xcode project changes: run the focused tests, then an unsigned Release build:
- Application code, package manifest, plist, entitlements, icon, or packaging changes: run the focused tests, then assemble an unsigned Release app:

```sh
xcodebuild \
-project "Open in Code.xcodeproj" \
-scheme "Open in Code" \
-configuration Release \
CODE_SIGNING_ALLOWED=NO \
clean build
OPEN_IN_CODE_SIGNING=unsigned ./scripts/build-app.sh release
```

Do not create tags, publish releases, notarize artifacts, update the Homebrew tap, or alter signing identities, team IDs, bundle identifiers, or release secrets unless explicitly requested.
Expand Down
4 changes: 3 additions & 1 deletion Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<key>CFBundleIconFile</key>
<string>vscode</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<string>com.sertacozercan.openincode</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
Expand All @@ -32,5 +32,7 @@
<string>Open in Code uses Finder to determine which folder or selected item to open in Visual Studio Code.</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>CFBundleIconName</key>
<string>vscode</string>
</dict>
</plist>
Loading