fix(worker): include project key in Bitbucket repo identifiers#904
Conversation
For Bitbucket Server, repo names now include the project key (PROJECT/repo) instead of just the repo name, preventing collisions across projects. For Bitbucket Cloud, repo names now include the project key (workspace/PROJECT/repo) instead of just workspace/repo. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
WalkthroughBitbucket repository identifiers and displayName construction now include project keys: Server repos use "PROJECT_KEY/repoSlug"; Cloud repos use "workspace/PROJECT_KEY/repoSlug". Documentation, schemas, tests, and a changelog entry were updated accordingly. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…format Update cloudShouldExcludeRepo to match against workspace/PROJECT_KEY/repo instead of full_name (workspace/repo), consistent with the new displayName format. Also update schema examples to reflect the correct formats. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
packages/backend/src/repoCompileUtils.ts (1)
457-461: Eliminate redundantfull_namesplit by extracting both parts at once
full_name!.split('/')is called twice to extract workspace and repo slug. A single split with destructuring is cleaner and more efficient. This pattern is already used correctly inbitbucket.ts:Suggested fix
- `${(repo as BitbucketCloudRepository).full_name!.split('/')[0]}/${(repo as BitbucketCloudRepository).project?.key}/${(repo as BitbucketCloudRepository).full_name!.split('/')[1]}`; + (() => { + const [workspace, repoSlug] = (repo as BitbucketCloudRepository).full_name!.split('/'); + return `${workspace}/${(repo as BitbucketCloudRepository).project?.key}/${repoSlug}`; + })();Or extract the variables before the ternary for clarity.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/backend/src/repoCompileUtils.ts` around lines 457 - 461, The displayName construction redundantly calls (repo as BitbucketCloudRepository).full_name!.split('/') twice; modify the logic so you split full_name once (e.g., const [workspace, repoSlug] = (repo as BitbucketCloudRepository).full_name!.split('/')) and use those variables in the ternary that builds displayName (the branch that handles BitbucketCloudRepository), keeping the existing BitbucketServerRepository branch unchanged; you can perform the split immediately before the ternary or extract workspace/repoSlug above the displayName assignment, similar to the pattern used in bitbucket.ts.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/backend/src/repoCompileUtils.ts`:
- Line 461: The template literal that constructs displayName currently uses
(repo as BitbucketCloudRepository).project?.key which serializes undefined into
the string "undefined" and corrupts repo identifiers (propagating to repoName,
zoekt.name, and zoekt.display-name); update the code that builds displayName
(and any upstream uses) to explicitly validate that (repo as
BitbucketCloudRepository).project?.key is present and non-empty, and fail loudly
(throw an Error or return early) with a clear message referencing the missing
project key instead of interpolating undefined; ensure the same validation logic
mirrors the server branch behavior (project!.key) semantics so missing project
keys are detected rather than embedded.
---
Nitpick comments:
In `@packages/backend/src/repoCompileUtils.ts`:
- Around line 457-461: The displayName construction redundantly calls (repo as
BitbucketCloudRepository).full_name!.split('/') twice; modify the logic so you
split full_name once (e.g., const [workspace, repoSlug] = (repo as
BitbucketCloudRepository).full_name!.split('/')) and use those variables in the
ternary that builds displayName (the branch that handles
BitbucketCloudRepository), keeping the existing BitbucketServerRepository branch
unchanged; you can perform the split immediately before the ternary or extract
workspace/repoSlug above the displayName assignment, similar to the pattern used
in bitbucket.ts.
…format Update cloudShouldExcludeRepo to match against workspace/PROJECT_KEY/repo instead of full_name (workspace/repo), consistent with the new displayName format. Also update schema examples to reflect the correct formats. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…displayName Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
packages/schemas/src/v3/bitbucket.schema.ts (1)
106-107: Optional: align placeholder casing for the Cloud workspace segment.
cloud_workspaceuses lowercase snake_case, making it look like a real workspace slug rather than a placeholder — unlikePROJECT_KEY/SERVER_PROJECT_KEYwhich are clearly uppercase tokens. Capitalizing it improves clarity for users reading the examples.✨ Suggested clarification
- "cloud_workspace/PROJECT_KEY/repo1", - "SERVER_PROJECT_KEY/repo2" + "WORKSPACE/PROJECT_KEY/repo1", + "SERVER_PROJECT_KEY/repo2"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/schemas/src/v3/bitbucket.schema.ts` around lines 106 - 107, Update the example placeholder in the Bitbucket schema so the Cloud workspace segment uses an uppercase token to match the style of PROJECT_KEY/SERVER_PROJECT_KEY: replace the string "cloud_workspace/PROJECT_KEY/repo1" with a tokenized placeholder like "CLOUD_WORKSPACE/PROJECT_KEY/repo1" in the bitbucket.schema (the example array that currently contains "cloud_workspace/PROJECT_KEY/repo1", "SERVER_PROJECT_KEY/repo2") so the workspace placeholder is clearly a token rather than a real slug.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/backend/src/bitbucket.ts`:
- Around line 351-352: The code builds repoName using cloudRepo.project?.key
which yields "undefined" when project is missing; make this consistent with
other code that assumes a project exists or provide a safe fallback: either
assert the project key is present (use cloudRepo.project?.key! when you have
validated project earlier) or replace the expression with a fallback such as
const projectKey = cloudRepo.project?.key ?? '<no-project>' and then construct
repoName = `${workspace}/${projectKey}/${repoSlug}`; ensure the chosen approach
matches the assumption in functions like repoCompileUtils
(cloudRepo.project?.key!) and avoid emitting the literal "undefined".
---
Nitpick comments:
In `@packages/schemas/src/v3/bitbucket.schema.ts`:
- Around line 106-107: Update the example placeholder in the Bitbucket schema so
the Cloud workspace segment uses an uppercase token to match the style of
PROJECT_KEY/SERVER_PROJECT_KEY: replace the string
"cloud_workspace/PROJECT_KEY/repo1" with a tokenized placeholder like
"CLOUD_WORKSPACE/PROJECT_KEY/repo1" in the bitbucket.schema (the example array
that currently contains "cloud_workspace/PROJECT_KEY/repo1",
"SERVER_PROJECT_KEY/repo2") so the workspace placeholder is clearly a token
rather than a real slug.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/backend/src/bitbucket.test.ts (1)
7-13:makeCloudRepoalways suppliesproject; no test exercises theundefinedproject pathEvery
cloudShouldExcludeRepotest usesproject: { type: 'project', key: 'PROJ' }. There is no test covering the case wherecloudRepo.projectis absent, which is the exact edge case that causes the silent"workspace/undefined/repo"naming bug inbitbucket.ts. Adding such a test now would either document the current broken behaviour or catch a fix:test('returns false (or throws) when project is undefined', () => { const repoWithoutProject = makeCloudRepo({ project: undefined }); // Currently produces repoName "myworkspace/undefined/my-repo" – should not silently match patterns expect(cloudShouldExcludeRepo(repoWithoutProject, { ...baseConfig, exclude: { repos: ['myworkspace/PROJ/my-repo'] }, })).toBe(false); });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/backend/src/bitbucket.test.ts` around lines 7 - 13, The factory makeCloudRepo currently always injects project into the returned CloudRepository, so tests never exercise the code path where project is undefined; update makeCloudRepo to allow omitting project by not providing a default project property (i.e., accept overrides and only spread project when provided) and then add a unit test that calls makeCloudRepo({ project: undefined }) and asserts cloudShouldExcludeRepo(repoWithoutProject, { ...baseConfig, exclude: { repos: ['myworkspace/PROJ/my-repo'] } }) behaves correctly; reference makeCloudRepo, CloudRepository/BitbucketRepository and cloudShouldExcludeRepo when locating the factory and the test to modify.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@packages/backend/src/bitbucket.ts`:
- Around line 351-352: The repoName construction silently embeds the string
"undefined" because `${cloudRepo.project?.key}` coerces undefined; change the
logic that builds repoName (where cloudRepo.full_name is split into workspace
and repoSlug and repoName is set) to explicitly check cloudRepo.project?.key: if
project.key exists use `${workspace}/${cloudRepo.project.key}/${repoSlug}`,
otherwise fall back to `${workspace}/${repoSlug}` (or another explicit sentinel)
so you never interpolate an undefined into the identifier; alternatively, if you
want failures surfaced, consistently use a non-null assertion
(`cloudRepo.project!.key`) across code (e.g., match repoCompileUtils.ts) so a
missing project throws early—pick one approach and apply it to the repoName
assignment and any related debug/log outputs.
---
Nitpick comments:
In `@packages/backend/src/bitbucket.test.ts`:
- Around line 7-13: The factory makeCloudRepo currently always injects project
into the returned CloudRepository, so tests never exercise the code path where
project is undefined; update makeCloudRepo to allow omitting project by not
providing a default project property (i.e., accept overrides and only spread
project when provided) and then add a unit test that calls makeCloudRepo({
project: undefined }) and asserts cloudShouldExcludeRepo(repoWithoutProject, {
...baseConfig, exclude: { repos: ['myworkspace/PROJ/my-repo'] } }) behaves
correctly; reference makeCloudRepo, CloudRepository/BitbucketRepository and
cloudShouldExcludeRepo when locating the factory and the test to modify.
Summary
PROJECT/repo) instead of just the bare repo name, preventing collisions when multiple projects have repos with the same slugworkspace/PROJECT/repo) instead ofworkspace/repoBreaking Changes
Bitbucket Cloud users with
exclude.repospatterns will need to update them to include the project key:Bitbucket Server users are unaffected —
exclude.reposwas already usingPROJECT_KEY/repoformat.🤖 Generated with Claude Code
Summary by CodeRabbit
Bug Fixes
Documentation
workspace/PROJECT_KEY/repo).Migration Note
workspace/repotoworkspace/PROJECT_KEY/repoformat.