-
Notifications
You must be signed in to change notification settings - Fork 8
CLI-715 better support for git worktrees during integration #547
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,11 +20,9 @@ | |
|
|
||
| // Auth and project-key resolution for SQAA commands. | ||
|
|
||
| import { resolve } from 'node:path'; | ||
|
|
||
| import type { ResolvedAuth } from '../../../lib/auth-resolver'; | ||
| import logger from '../../../lib/logger'; | ||
| import { spawnProcess } from '../../../lib/process'; | ||
| import { resolveWorktreeRootCandidates } from '../../../lib/project-workspace/git-worktree'; | ||
| import { loadState } from '../../../lib/repository/state-repository'; | ||
| import { canonicalProjectRoot } from '../../../lib/state-manager'; | ||
| import { blank, confirmPrompt, text, warn } from '../../../ui'; | ||
|
|
@@ -110,28 +108,30 @@ export function resolveCloudAuth( | |
| * Look up the project key for the current project from the declarative | ||
| * integration state (`integrations.installed`). | ||
| * | ||
| * The SQAA hook feature is recorded per install target root (the directory | ||
| * passed to `sonar integrate claude`), so when the user runs SQAA from a | ||
| * subdirectory we resolve the git repository top-level first — otherwise | ||
| * `process.cwd()` is a non-match against the recorded root and we incorrectly | ||
| * skip with "no project configured". | ||
| * | ||
| * Falls back to `process.cwd()` when not inside a git repository so the | ||
| * single-file path still works outside git. | ||
| * The SQAA hook feature is recorded per install target root, so | ||
| * `resolveWorktreeRootCandidates` maps the current directory to its working-tree | ||
| * root(s) — the current tree, then the main tree — via a single `git worktree | ||
| * list` call. This lets SQAA resolve the key from a subdirectory and from any | ||
| * linked worktree, matching state recorded in the main checkout. Falls back to | ||
| * `process.cwd()` when not inside a git repository so the single-file path still | ||
| * works outside git. | ||
| */ | ||
| export async function resolveSqaaProjectKey(projectRoot?: string): Promise<string | null> { | ||
| try { | ||
| const root = canonicalProjectRoot(projectRoot ?? (await tryResolveRepoRoot(process.cwd()))); | ||
| const state = loadState(); | ||
|
|
||
| const claude = state.integrations.installed.find( | ||
| (integration) => integration.integrationId === CLAUDE_INTEGRATION_ID, | ||
| ); | ||
| // Try the current working tree's root, then the main working tree, so a | ||
| // linked worktree still resolves state recorded in the main checkout. | ||
| const candidates = new Set( | ||
| (await resolveWorktreeRootCandidates(projectRoot ?? process.cwd())).map(canonicalProjectRoot), | ||
| ); | ||
| const sqaaFeature = claude?.features.find( | ||
| (feature) => | ||
| feature.featureId === SQAA_HOOK_FEATURE_ID && | ||
| feature.scope === 'project' && | ||
| canonicalProjectRoot(feature.targetRoot) === root, | ||
| candidates.has(canonicalProjectRoot(feature.targetRoot)), | ||
| ); | ||
|
Comment on lines
+127
to
135
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Edge Case: Ambiguous match when multiple worktrees register SQAA features
Impact is low: the common case is a single project-scoped SQAA feature recorded against the main checkout, and the tests cover that path. But if you want deterministic behavior favoring the current working tree over the main tree, consider preserving the candidate ordering and selecting the feature matching the earliest candidate rather than treating all candidates as an unordered Set. Resolve the project key deterministically by preferring the current worktree root before falling back to the main tree.:
Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎 |
||
|
|
||
| const projectKey = sqaaFeature?.attrs?.projectKey; | ||
|
|
@@ -147,22 +147,6 @@ export async function resolveSqaaProjectKey(projectRoot?: string): Promise<strin | |
| } | ||
| } | ||
|
|
||
| /** | ||
| * Resolve the git repository top-level for `cwd`, falling back to `cwd` itself | ||
| * when not inside a git repository (so non-git workflows still work). | ||
| */ | ||
| async function tryResolveRepoRoot(cwd: string): Promise<string> { | ||
| try { | ||
| const result = await spawnProcess('git', ['rev-parse', '--show-toplevel'], { cwd }); | ||
| if (result.exitCode === 0) { | ||
| return resolve(result.stdout.trim()); | ||
| } | ||
| } catch { | ||
| // git not installed or otherwise unavailable — fall through to cwd. | ||
| } | ||
| return cwd; | ||
| } | ||
|
|
||
| /** | ||
| * Warn about a large change set and ask the user to confirm. | ||
| * In non-interactive contexts (no stdin TTY — e.g. CI/agent runs), prints a | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.