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
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

<!-- loosely based on https://keepachangelog.com/en/1.0.0/ -->

## 0.2.2 - Unreleased
## 0.2.2 - 2026-05-19

### Added

### Changed

- `searchDependicusIssues` (in `@dependicus/github-issues`) now skips every pull request returned by GitHub's issues endpoint — drafts and ready-to-review alike — and also skips anything flagged as a draft. Only real, non-draft issues are returned, so notification bots and reports built on this helper stop counting pull requests as open Dependicus items.

### Fixed

- Fix version numbers without `.` failing to match open tickets, resulting in duplicates
Expand Down
8 changes: 8 additions & 0 deletions src/core/utils/versionUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,14 @@ describe('extractDependencyNameFromTitle', () => {
).toBe('sudachidict-core');
});

it('extracts name from legacy arrow FYI title', () => {
expect(
extractDependencyNameFromTitle(
'[Dependicus] FYI: test-pkg 1.0.0 → 2.0.0 (latest: 2.0.0)',
),
).toBe('test-pkg');
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ecosystem branch of legacy arrow pattern is untested

Low Severity

The new legacyFyiMatch regex accepts an optional ecosystem tag via (?:\[(\w+)\]\s+)?, and the code branches on whether ecosystem is defined to return either ${ecosystem}::${dependencyName} or just dependencyName. Only the no-ecosystem path is tested. Every other pattern in extractDependencyNameFromTitle that handles an ecosystem tag (e.g., ecoUpdateMatch, ecoFyiMatch) has a dedicated test for the ecosystem path. A regression in the ecosystem capture group (e.g., accidentally making it non-capturing) would go undetected.

Additional Locations (1)
Fix in Cursor Fix in Web

Triggered by team rule: tests

Reviewed by Cursor Bugbot for commit 4f468a2. Configure here.


it('returns undefined for non-Dependicus titles', () => {
expect(extractDependencyNameFromTitle('Update react to 19.0.0')).toBeUndefined();
expect(extractDependencyNameFromTitle('Fix bug in react')).toBeUndefined();
Expand Down
10 changes: 10 additions & 0 deletions src/core/utils/versionUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,16 @@ export function extractDependencyNameFromTitle(title: string): string | undefine
return `${ecoFyiMatch[1]}::${ecoFyiMatch[2]}`;
}

// Backward compat: older FYI titles used an arrow instead of "is available".
const legacyFyiMatch = title.match(
/^\[Dependicus\]\s+(?:\[(\w+)\]\s+)?FYI:\s+(.+?)\s+\S+\s+→\s+\S+/,
);
if (legacyFyiMatch) {
const ecosystem = legacyFyiMatch[1];
const dependencyName = legacyFyiMatch[2];
return ecosystem ? `${ecosystem}::${dependencyName}` : dependencyName;
}

// Backward compat: standard "Update X from..." format (no ecosystem tag)
const updateMatch = title.match(/^\[Dependicus\]\s+Update\s+(.+?)\s+from\s+/);
if (updateMatch) {
Expand Down
30 changes: 28 additions & 2 deletions src/github-issues/GitHubIssueService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ describe('GitHubIssueService', () => {
});
});

it('skips pull requests', async () => {
it('skips pull requests regardless of draft state', async () => {
mockOctokit.issues.getLabel.mockResolvedValue({ data: { name: 'dependicus' } });

mockOctokit.issues.listForRepo.mockResolvedValue({
Expand All @@ -111,7 +111,33 @@ describe('GitHubIssueService', () => {
number: 42,
title: '[Dependicus] Update react from 18.2.0 to 19.0.0',
updated_at: '2025-01-15T00:00:00Z',
pull_request: { url: 'https://...' },
pull_request: { url: 'https://draft-pr...' },
draft: true,
},
{
number: 43,
title: '[Dependicus] Update react from 18.2.0 to 19.0.0',
updated_at: '2025-01-15T00:00:00Z',
pull_request: { url: 'https://ready-pr...' },
draft: false,
},
],
});

const issues = await service.searchDependicusIssues('owner', 'repo');
expect(issues).toHaveLength(0);
});

it('skips items flagged as draft', async () => {
mockOctokit.issues.getLabel.mockResolvedValue({ data: { name: 'dependicus' } });

mockOctokit.issues.listForRepo.mockResolvedValue({
data: [
{
number: 44,
title: '[Dependicus] Update react from 18.2.0 to 19.0.0',
updated_at: '2025-01-15T00:00:00Z',
draft: true,
},
],
});
Expand Down
12 changes: 10 additions & 2 deletions src/github-issues/GitHubIssueService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ export class GitHubIssueService {
* Search for all open Dependicus issues in a repo.
* Filters by the "dependicus" label and state=open.
* Handles pagination to ensure ALL issues are fetched.
*
* GitHub's issues endpoint returns pull requests alongside issues when
* filtered by label. Pull requests are always skipped (regardless of
* draft state) so that callers only see real issues, and any item with
* a draft flag is skipped defensively so downstream consumers (such as
* the bot that yells about the open count) never see in-progress work.
*/
async searchDependicusIssues(
owner: string,
Expand All @@ -103,8 +109,10 @@ export class GitHubIssueService {
});

for (const issue of response.data) {
// Skip pull requests (GitHub API returns PRs in issues endpoint)
if (issue.pull_request) continue;
// GitHub returns PRs in the issues endpoint — skip every PR
// (draft or not). Also skip anything explicitly flagged as
// a draft so non-PR draft items can't slip through either.
if (issue.pull_request || issue.draft) continue;

const groupName = extractGroupNameFromTitle(issue.title);
const dependencyName = groupName ?? extractDependencyNameFromTitle(issue.title);
Expand Down
11 changes: 10 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2655,7 +2655,16 @@ __metadata:
languageName: node
linkType: hard

"semver@npm:^7.3.5, semver@npm:^7.7.3, semver@npm:^7.7.4":
"semver@npm:^7.3.5":
version: 7.8.0
resolution: "semver@npm:7.8.0"
bin:
semver: bin/semver.js
checksum: 10c0/8f096ca9b80ffd47b308d03f9ce8c873e27e2983f36023c559cdc92c51e8433fc23ebbfe57ec9623fc155636a6961ee989501099841ae4bb1babc8d2b3f048cd
languageName: node
linkType: hard

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unintended semver version split in lockfile

Low Severity

The semver resolution was previously unified — ^7.3.5, ^7.7.3, and ^7.7.4 all resolved to 7.7.4. This diff splits it so ^7.3.5 (from node-gyp) now resolves to 7.8.0 while the others stay on 7.7.4, installing two copies of semver needlessly. No package.json change justifies this; it looks like unintended lockfile churn, possibly from running a tool that re-resolved that range independently.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 4f468a2. Configure here.


"semver@npm:^7.7.3, semver@npm:^7.7.4":
version: 7.7.4
resolution: "semver@npm:7.7.4"
bin:
Expand Down
Loading