diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e5e1b7f..0b33d4c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,7 +3,23 @@ name: CI on: push: branches: [develop] + paths: + - 'Sources/**' + - 'Tests/**' + - 'Entitlements/**' + - 'project.yml' + - 'build.sh' + - 'test.sh' + - '.github/workflows/ci.yml' pull_request: + paths: + - 'Sources/**' + - 'Tests/**' + - 'Entitlements/**' + - 'project.yml' + - 'build.sh' + - 'test.sh' + - '.github/workflows/ci.yml' concurrency: group: ci-${{ github.ref }} diff --git a/README.md b/README.md index 146c4d6..fdedac0 100644 --- a/README.md +++ b/README.md @@ -1,48 +1,74 @@ -# GitHub Project Menu Bar +

+ GitHub Project Menu Bar icon +

-English / [日本語](docs/README.ja.md) +

GitHub Project Menu Bar

-A native macOS **menu bar app + WidgetKit widget** to browse and edit your -private **GitHub Projects (v2)** boards. Built with **SwiftUI**. +

+ Browse and edit your private GitHub Projects (v2) boards from the macOS + menu bar — with a Notification Center / desktop widget. +

-- **Menu bar panel**: kanban board — drag cards between columns to change Status, - right-click to change Status, "+" to add a task, click a card to open it on - GitHub. Sorted to match the project view's configured sort. -- **Widget** (Notification Center / desktop): status buttons across the top; tap - one to show that status's tasks. Read-only, refreshes on a timeline. +

English / 日本語

+ +## Screenshots + +**Menu bar panel** — a kanban board. Drag cards between columns to change Status, +right-click to change Status, "+" to add a task, click a card to open it on GitHub. + +

+ Menu bar kanban panel +

+ +**Widget** — status buttons across the top; tap one to show that status's tasks. + +

+ Notification Center widget +

+ +## Features + +- **Kanban board** in the menu bar: view, drag-and-drop Status changes, add tasks (draft issues), open items on GitHub. +- **Sorted like GitHub**: cards follow the project view's configured sort. +- **Status colors**: each card shows its Status color dot. +- **Interactive widget**: pick a status, see its tasks — read-only, auto-refreshing. +- **Menu-bar-only**: no Dock icon; the panel drops down from the menu bar. ## Stack | Layer | Choice | |---|---| -| App | SwiftUI `MenuBarExtra` (menu-bar-only, no Dock icon) | +| App | SwiftUI `MenuBarExtra` (no Dock icon) | | Widget | WidgetKit + interactive AppIntents | | GitHub API | Projects v2 **GraphQL** (URLSession) | | Token / shared state | OS **Keychain** (shared between app & widget) | | Project generation | [XcodeGen](https://github.com/yonaskolb/XcodeGen) (`project.yml`) | +No third-party runtime dependencies (Foundation / SwiftUI / WidgetKit / AppIntents / Security only). + ## Layout ``` -project.yml XcodeGen spec (app + widget targets, one team) +project.yml XcodeGen spec (app + widget + tests, one team) build.sh CLI build → sign → install to /Applications → launch -Entitlements/ App.entitlements / Widget.entitlements (sandbox, keychain, network) +test.sh CLI unit tests +Entitlements/ App.entitlements / Widget.entitlements Sources/ Shared/ compiled into BOTH targets AppConfig / TokenStore(+SharedStore, BoardCache) / Models - GitHubAPI (GraphQL + view-sort replication) / StatusColor - SelectStatusIntent (widget button intent — must be in the app too) - App/ MenuBarExtra app: App / BoardViewModel / MenuContent / BoardView / SettingsView - Widget/ WidgetKit: BoardProvider / BoardWidgetView + GitHubAPI (GraphQL + view-sort replication) / StatusColor / SelectStatusIntent + App/ MenuBarExtra app + Assets.xcassets (AppIcon) + Widget/ WidgetKit: provider + views +Tests/ Shared-logic unit tests ``` -The `.xcodeproj` and `Generated/` are produced by XcodeGen and are git-ignored; +The `.xcodeproj` and `Generated/` are produced by XcodeGen and git-ignored; `project.yml` is the source of truth. ## Prerequisites -- Full **Xcode** installed -- **XcodeGen** (`brew install xcodegen`) +- Full **Xcode** +- **XcodeGen** — `brew install xcodegen` ## Build & install (no need to open Xcode) @@ -50,7 +76,7 @@ The `.xcodeproj` and `Generated/` are produced by XcodeGen and are git-ignored; ./build.sh ``` -This regenerates the project, builds a signed Release, installs it to +Regenerates the project, builds a signed Release, installs it to `/Applications/GitHubProjectMenuBar.app`, and launches it. > Signed with a **free personal team** (`DEVELOPMENT_TEAM` in `project.yml`). @@ -58,21 +84,33 @@ This regenerates the project, builds a signed Release, installs it to ## Setup -1. Click the menu bar icon → **⚙ Settings** → paste a GitHub **classic PAT** - with the `project` scope (and `repo` if your board draws from private repos). +1. Click the menu bar icon → **⚙ Settings** → paste a GitHub **classic PAT** with + the `project` scope (and `repo` if your board draws from private repos). 2. Pick a project → the board loads. 3. Add the widget from **Edit Widgets** (Notification Center / desktop). -## Tests +The token is stored in the OS **Keychain** and shared with the widget via a +keychain access group (works on a free Apple ID; no App Group needed). -Unit tests cover the Shared logic (view-sort replication, models): +## Tests ```bash ./test.sh ``` +Unit tests cover the Shared logic (view-sort replication, models). + ## Open in Xcode (optional) ```bash xcodegen generate && open GitHubProjectMenuBar.xcodeproj ``` + +## Notes & limitations + +- **Manual drag order** (no configured sort) can't be reproduced — the GitHub API + doesn't expose it. Only **field-based sorts** match. +- The widget is **read-only** (WidgetKit); it refreshes on a timeline, and status + switching renders instantly from a cache. +- Built for **personal use on your own Mac** with a free team — not for + distribution. Others must build with their own Apple ID / Team ID. diff --git a/docs/README.ja.md b/docs/README.ja.md index a6145b7..151ab65 100644 --- a/docs/README.ja.md +++ b/docs/README.ja.md @@ -1,44 +1,71 @@ -# GitHub Project Menu Bar +

+ GitHub Project Menu Bar アイコン +

-[English](../README.md) / 日本語 +

GitHub Project Menu Bar

-自分の **GitHub Projects (v2)** のボードを、macOSの**メニューバー**と**ウィジェット**から閲覧・編集できるネイティブアプリです。**SwiftUI** 製。 +

+ 自分の GitHub Projects (v2) のボードを、macOSのメニューバーウィジェットから閲覧・編集できるネイティブアプリです。 +

-- **メニューバーパネル**: カンバンボード表示。カードを**ドラッグ**して列(Status)を変更、**右クリック**でもStatus変更、**「+」**でタスク追加、カードをクリックでGitHubを開く。GitHub Project のビューで設定した**ソート順**に並びます。 -- **ウィジェット**(通知センター/デスクトップ): 上部に各Statusのボタンが並び、**タップするとそのStatusのタスク**が表示されます。読み取り専用で、一定間隔で更新されます。 +

English / 日本語

+ +## スクリーンショット + +**メニューバーパネル** — カンバンボード。カードを**ドラッグ**して列(Status)を変更、**右クリック**でもStatus変更、**「+」**でタスク追加、カードをクリックでGitHubを開きます。 + +

+ メニューバーのカンバンパネル +

+ +**ウィジェット** — 上部のStatusボタンをタップすると、そのStatusのタスクが表示されます。 + +

+ 通知センターのウィジェット +

+ +## 特徴 + +- メニューバーの**カンバンボード**: 閲覧・**ドラッグ&ドロップでStatus変更**・タスク追加(ドラフトIssue)・GitHubで開く +- **GitHubと同じ並び**: プロジェクトビューで設定したソート順を再現 +- **Status色**: 各カードにStatusの色ドットを表示 +- **インタラクティブなウィジェット**: Statusを選んでタスク一覧を表示(読み取り専用・自動更新) +- **メニューバー常駐**: Dockアイコンなし。アイコンからパネルが開きます ## 技術スタック | レイヤー | 採用 | |---|---| -| アプリ本体 | SwiftUI `MenuBarExtra`(メニューバー常駐・Dockアイコンなし) | +| アプリ本体 | SwiftUI `MenuBarExtra`(Dockアイコンなし) | | ウィジェット | WidgetKit + インタラクティブ AppIntents | | GitHub API | Projects v2 **GraphQL**(URLSession) | | トークン/共有状態 | OS **Keychain**(本体とウィジェットで共有) | | プロジェクト生成 | [XcodeGen](https://github.com/yonaskolb/XcodeGen)(`project.yml`) | +サードパーティ製の実行時依存はありません(Foundation / SwiftUI / WidgetKit / AppIntents / Security のみ)。 + ## ディレクトリ構成 ``` -project.yml XcodeGen定義(App+Widgetの2ターゲット、Team固定) +project.yml XcodeGen定義(App+Widget+Tests、Team固定) build.sh CLIビルド → 署名 → /Applications へインストール → 起動 -Entitlements/ App.entitlements / Widget.entitlements(サンドボックス・Keychain・ネットワーク) +test.sh CLIユニットテスト +Entitlements/ App.entitlements / Widget.entitlements Sources/ Shared/ App と Widget の両方にコンパイルされる共通コード - AppConfig / TokenStore(+SharedStore, BoardCache)/ Models - GitHubAPI(GraphQL+ビューのソート再現)/ StatusColor - SelectStatusIntent(ウィジェットのボタン用Intent。本体にも必要なのでShared) - App/ MenuBarExtra アプリ: App / BoardViewModel / MenuContent / BoardView / SettingsView - Widget/ WidgetKit: BoardProvider / BoardWidgetView - App/Assets.xcassets アプリアイコン(AppIcon) + AppConfig / TokenStore(+SharedStore, BoardCache) / Models + GitHubAPI(GraphQL+ビューのソート再現)/ StatusColor / SelectStatusIntent + App/ MenuBarExtra アプリ + Assets.xcassets(AppIcon) + Widget/ WidgetKit: プロバイダ+ビュー +Tests/ 共通ロジックのユニットテスト ``` -`.xcodeproj` と `Generated/` は XcodeGen が生成する成果物なので **gitignore** しています。**source of truth は `project.yml`** です。 +`.xcodeproj` と `Generated/` は XcodeGen の生成物で **gitignore** しています。**source of truth は `project.yml`** です。 ## 必要なもの -- **Xcode** 本体(フル版。CommandLine Toolsのみでは不可) -- **XcodeGen**(`brew install xcodegen`) +- **Xcode** 本体(フル版) +- **XcodeGen** — `brew install xcodegen` ## ビルド&インストール(Xcodeを開かずに実行) @@ -46,14 +73,9 @@ Sources/ ./build.sh ``` -`build.sh` は次を自動で行います。 - -1. `xcodegen generate`(プロジェクト再生成) -2. `xcodebuild`(Release・**署名付き**)でアプリ+ウィジェットをビルド -3. `/Applications/GitHubProjectMenuBar.app` に上書きインストール -4. アプリを起動 +プロジェクト再生成 → 署名付きReleaseビルド → `/Applications/GitHubProjectMenuBar.app` にインストール → 起動、までを自動で行います。 -> **無料のPersonal Team**(`project.yml` の `DEVELOPMENT_TEAM`)で署名しています。 +> **無料のPersonal Team**(`project.yml` の `DEVELOPMENT_TEAM`)で署名します。 > 無料Teamのプロビジョニングは**約7日で失効**するので、切れたら `./build.sh` を再実行してください。 ## 使い方 @@ -62,18 +84,16 @@ Sources/ 2. プロジェクトを選択 → ボードが読み込まれます 3. **ウィジェットを編集**(通知センター/デスクトップ)から「GitHub Project」を追加 -### トークンについて -- トークンは **OS Keychain** に保存され、ソースやファイルには平文で残りません。 -- 本体とウィジェットは `keychain-access-groups` で同じ項目を共有します(無料Apple IDでも動作。App Groupは有料が必要なため未使用)。 +トークンは OS **Keychain** に保存され、Keychainアクセスグループで本体↔ウィジェットが共有します(無料Apple IDで動作。App Groupは不要)。 ## テスト -共通ロジック(ビューのソート再現・モデル)のユニットテストがあります。 - ```bash ./test.sh ``` +共通ロジック(ビューのソート再現・モデル)のユニットテストがあります。 + ## Xcodeで開く場合(任意) ```bash @@ -83,5 +103,5 @@ xcodegen generate && open GitHubProjectMenuBar.xcodeproj ## 補足・既知の制約 - **手動ドラッグの並び順**(ソート未設定)はGitHub APIが公開しておらず再現できません。ビューで**フィールドソート**を設定している場合のみ順序が一致します。 -- ウィジェットは WidgetKit の仕様上**読み取り専用**で、更新はタイムライン(数十分間隔)に依存します。Statusボタンの切り替えはキャッシュから即時描画されます。 -- **配布不可・自分のMac専用**(無料Team)。他人が使うには各自の Apple ID / Team ID に置き換えてビルドが必要です。 +- ウィジェットは WidgetKit の仕様上**読み取り専用**で、更新はタイムラインに依存します。Statusボタンの切り替えはキャッシュから即時描画されます。 +- **自分のMac専用**(無料Team)。配布は不可で、他人が使うには各自の Apple ID / Team ID でビルドが必要です。 diff --git a/docs/images/icon.png b/docs/images/icon.png new file mode 100644 index 0000000..9217ed1 Binary files /dev/null and b/docs/images/icon.png differ diff --git a/docs/images/menubar.png b/docs/images/menubar.png new file mode 100644 index 0000000..ac6ee9f Binary files /dev/null and b/docs/images/menubar.png differ diff --git a/docs/images/widget.png b/docs/images/widget.png new file mode 100644 index 0000000..e826a5c Binary files /dev/null and b/docs/images/widget.png differ