From 0b84275a1eb699d324c472489ffaaaee1db27a5f Mon Sep 17 00:00:00 2001 From: abuhrovyi Date: Sat, 2 May 2026 20:20:49 +0300 Subject: [PATCH 1/7] fix(enrichment): handle null review user and team-only review requests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PRReview.user is now optional — a single malformed review (deleted account, bot, null user) no longer silently drops the entire reviews array via failed JSON decode, causing approved count to show 0. hasReviewRequests now checks requestedTeams in addition to requestedReviewers so PRs assigned only to teams are not misclassified. --- GitHubWidget/Services/GitHubService.swift | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/GitHubWidget/Services/GitHubService.swift b/GitHubWidget/Services/GitHubService.swift index 31c44ab..78ba9bb 100644 --- a/GitHubWidget/Services/GitHubService.swift +++ b/GitHubWidget/Services/GitHubService.swift @@ -74,7 +74,7 @@ actor GitHubService: GitHubServiceProtocol { private struct PRReview: Decodable { let state: String - let user: GitHubUser + let user: GitHubUser? } private struct CheckRunsResponse: Decodable { @@ -97,7 +97,7 @@ actor GitHubService: GitHubServiceProtocol { let detail = try? JSONDecoder().decode(PRDetail.self, from: data) else { return false } - return !detail.requestedReviewers.isEmpty + return !detail.requestedReviewers.isEmpty || !detail.requestedTeams.isEmpty } func fetchEnrichments(prs: [PullRequest], token: String) async -> [Int: PREnrichment] { @@ -128,10 +128,11 @@ actor GitHubService: GitHubServiceProtocol { var latestByUser: [String: String] = [:] for review in reviews { + guard let login = review.user?.login else { continue } if review.state != "COMMENTED" { - latestByUser[review.user.login] = review.state - } else if latestByUser[review.user.login] == nil { - latestByUser[review.user.login] = review.state + latestByUser[login] = review.state + } else if latestByUser[login] == nil { + latestByUser[login] = review.state } } let approved = latestByUser.values.filter { $0 == "APPROVED" }.count From d4906a1b6fe080676f39b58333b4b4238e4ce2dd Mon Sep 17 00:00:00 2001 From: abuhrovyi Date: Sat, 2 May 2026 20:30:22 +0300 Subject: [PATCH 2/7] docs(build): fix archive command, remove unnecessary exportArchive step Add SKIP_INSTALL=NO and INSTALL_PATH=/Applications to project.yml so the app lands in Products/Applications inside the archive. Update README to reflect the flags, drop the redundant -exportArchive step, and point ditto directly at the archive Products path. --- README.md | 34 +++++++--------------------------- project.yml | 2 ++ 2 files changed, 9 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 04c0201..a0d0bd3 100644 --- a/README.md +++ b/README.md @@ -62,40 +62,20 @@ xcodebuild archive \ -archivePath build/GitHubWidget.xcarchive \ ARCHS=arm64 \ ONLY_ACTIVE_ARCH=NO \ - CODE_SIGN_IDENTITY="-" + CODE_SIGN_IDENTITY="-" \ + SKIP_INSTALL=NO \ + INSTALL_PATH=/Applications ``` `CODE_SIGN_IDENTITY="-"` signs ad-hoc (no Apple Developer account needed). For notarization, replace with your Developer ID identity. -### 3. Export the .app +`SKIP_INSTALL=NO` + `INSTALL_PATH=/Applications` are already set in `project.yml` — these flags are shown for clarity and can be omitted. -```bash -xcodebuild -exportArchive \ - -archivePath build/GitHubWidget.xcarchive \ - -exportPath build/export \ - -exportOptionsPlist ExportOptions.plist -``` - -Create `ExportOptions.plist` in the repo root: - -```xml - - - - - method - mac-application - destination - export - - -``` - -### 4. Package with pkgbuild +### 3. Package with pkgbuild ```bash mkdir -p build/pkg-root/Applications -ditto build/export/GitHubWidget.app build/pkg-root/Applications/GitHubWidget.app +ditto build/GitHubWidget.xcarchive/Products/Applications/GitHubWidget.app build/pkg-root/Applications/GitHubWidget.app pkgbuild \ --root build/pkg-root \ @@ -107,7 +87,7 @@ pkgbuild \ The `.pkg` installs `GitHubWidget.app` to `/Applications`. -### 5. (Optional) Sign and notarize +### 4. (Optional) Sign and notarize Sign the package with a Developer ID Installer certificate: diff --git a/project.yml b/project.yml index f00c851..5d30b69 100644 --- a/project.yml +++ b/project.yml @@ -16,6 +16,8 @@ targets: ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon MARKETING_VERSION: "1.1.1" CURRENT_PROJECT_VERSION: "1" + SKIP_INSTALL: NO + INSTALL_PATH: /Applications info: path: GitHubWidget/Info.plist properties: From 15d00fcd45ecb88ddf99d385c76715a8d0c41571 Mon Sep 17 00:00:00 2001 From: abuhrovyi Date: Sat, 2 May 2026 20:32:22 +0300 Subject: [PATCH 3/7] ci: add PR template and auto-assign workflow for on0t0le --- .github/PULL_REQUEST_TEMPLATE.md | 5 +++++ .github/workflows/auto-assign.yml | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/workflows/auto-assign.yml diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..f62ff28 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,5 @@ +## Summary + + +## Test plan +- [ ] diff --git a/.github/workflows/auto-assign.yml b/.github/workflows/auto-assign.yml new file mode 100644 index 0000000..01cc4e2 --- /dev/null +++ b/.github/workflows/auto-assign.yml @@ -0,0 +1,19 @@ +name: Auto Assign + +on: + pull_request: + types: [opened, reopened] + +jobs: + assign: + runs-on: ubuntu-latest + steps: + - uses: actions/github-script@v7 + with: + script: | + await github.rest.issues.addAssignees({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + assignees: ['on0t0le'], + }); From 1a4eb0346791ee8731a2c97f371606771fae6ea3 Mon Sep 17 00:00:00 2001 From: abuhrovyi Date: Sat, 2 May 2026 20:33:16 +0300 Subject: [PATCH 4/7] ci: replace auto-assign workflow with CODEOWNERS --- .github/CODEOWNERS | 1 + .github/workflows/auto-assign.yml | 19 ------------------- 2 files changed, 1 insertion(+), 19 deletions(-) create mode 100644 .github/CODEOWNERS delete mode 100644 .github/workflows/auto-assign.yml diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..611fa0a --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @on0t0le diff --git a/.github/workflows/auto-assign.yml b/.github/workflows/auto-assign.yml deleted file mode 100644 index 01cc4e2..0000000 --- a/.github/workflows/auto-assign.yml +++ /dev/null @@ -1,19 +0,0 @@ -name: Auto Assign - -on: - pull_request: - types: [opened, reopened] - -jobs: - assign: - runs-on: ubuntu-latest - steps: - - uses: actions/github-script@v7 - with: - script: | - await github.rest.issues.addAssignees({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.issue.number, - assignees: ['on0t0le'], - }); From e6caf9529672e55bfcc0c30625e60675ac66283a Mon Sep 17 00:00:00 2001 From: abuhrovyi Date: Sat, 2 May 2026 20:36:30 +0300 Subject: [PATCH 5/7] ci: remove PR template, let GitHub auto-fill from commits --- .github/PULL_REQUEST_TEMPLATE.md | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index f62ff28..0000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,5 +0,0 @@ -## Summary - - -## Test plan -- [ ] From 005fb60675a9b40121fc98fde6c3dc88151c57a4 Mon Sep 17 00:00:00 2001 From: abuhrovyi Date: Sat, 2 May 2026 20:38:35 +0300 Subject: [PATCH 6/7] ci: auto-populate PR body with commit list on open/sync --- .github/workflows/pr-description.yml | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 .github/workflows/pr-description.yml diff --git a/.github/workflows/pr-description.yml b/.github/workflows/pr-description.yml new file mode 100644 index 0000000..d2196e6 --- /dev/null +++ b/.github/workflows/pr-description.yml @@ -0,0 +1,33 @@ +name: PR Description + +on: + pull_request: + types: [opened, reopened, synchronize] + +jobs: + update-body: + runs-on: ubuntu-latest + permissions: + pull-requests: write + steps: + - uses: actions/github-script@v7 + with: + script: | + const commits = await github.paginate( + github.rest.pulls.listCommits, + { + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number, + } + ); + + const lines = commits.map(c => `- ${c.commit.message.split('\n')[0]}`); + const body = `## Changes\n\n${lines.join('\n')}`; + + await github.rest.pulls.update({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number, + body, + }); From 496d61f8c7da00ef49d85f1e27e896ed30b0828c Mon Sep 17 00:00:00 2001 From: abuhrovyi Date: Sun, 3 May 2026 20:51:39 +0300 Subject: [PATCH 7/7] removed pr workflow --- .github/workflows/pr-description.yml | 33 ---------------------------- 1 file changed, 33 deletions(-) delete mode 100644 .github/workflows/pr-description.yml diff --git a/.github/workflows/pr-description.yml b/.github/workflows/pr-description.yml deleted file mode 100644 index d2196e6..0000000 --- a/.github/workflows/pr-description.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: PR Description - -on: - pull_request: - types: [opened, reopened, synchronize] - -jobs: - update-body: - runs-on: ubuntu-latest - permissions: - pull-requests: write - steps: - - uses: actions/github-script@v7 - with: - script: | - const commits = await github.paginate( - github.rest.pulls.listCommits, - { - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: context.issue.number, - } - ); - - const lines = commits.map(c => `- ${c.commit.message.split('\n')[0]}`); - const body = `## Changes\n\n${lines.join('\n')}`; - - await github.rest.pulls.update({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: context.issue.number, - body, - });