Skip to content

GROW-213 Provision SonarQube project in sonar import command#560

Open
kevinmlsilva wants to merge 1 commit into
masterfrom
kevinmlsilva/sonar-import-create-project-v1
Open

GROW-213 Provision SonarQube project in sonar import command#560
kevinmlsilva wants to merge 1 commit into
masterfrom
kevinmlsilva/sonar-import-create-project-v1

Conversation

@kevinmlsilva

Copy link
Copy Markdown
Contributor

Summary

  • Wires up the final step of sonar import: after org/repo selection, creates the bound SonarQube project via the provision_projects API and prints its project key.
  • Resolves the org's connected DevOps platform to format the installationKeys param correctly (<slug>|<id> for GitHub, plain id otherwise).
  • Enforces the org's public/private project visibility rules (onlyPrivateProjects + billing entitlement) before provisioning, rejecting mismatched repos.
  • Already-imported repos are filtered out of the interactive picker instead of just labeled; fails clearly if none remain to import.
  • Command remains hidden while in development.

Continuation of GROW-212.

Test plan

  • bun run typecheck
  • bun run lint
  • bun test tests/integration/specs/import/import.test.ts (29 pass, including new provisioning/visibility test cases)

JIRA: GROW-213

@netlify

netlify Bot commented Jul 7, 2026

Copy link
Copy Markdown

Deploy Preview for sonarqube-cli canceled.

Name Link
🔨 Latest commit f5e4482
🔍 Latest deploy log https://app.netlify.com/projects/sonarqube-cli/deploys/6a50c8372fb9ab0008643862

@hashicorp-vault-sonar-prod

hashicorp-vault-sonar-prod Bot commented Jul 7, 2026

Copy link
Copy Markdown

GROW-213

Comment thread src/cli/commands/import/_common/resolve-options.ts
Comment thread src/cli/commands/import/index.ts Outdated
@kevinmlsilva kevinmlsilva force-pushed the kevinmlsilva/sonar-import-create-project-v1 branch from d7316be to 8e830a7 Compare July 7, 2026 12:25
@kevinmlsilva kevinmlsilva requested a review from nquinquenel July 7, 2026 12:42

@nquinquenel nquinquenel left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks ok, one comment about org and private project is important to tackle I think

}

if (opts.org) return opts.org;
if (opts.org) return { key: opts.org };

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

When org is passed, it only returns key. Later we do:

  const onlyPrivateProjects: OnlyPrivateProjects = {
    enabled: onlyPrivateProjectsEnabled ?? false,
    available: await client.hasPrivateProjectsEntitlement(orgKey),
  };

So it means when org is passed it never loads the org's private projects. Is it expected?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch, that wasn't expected. Fixed: added SonarQubeClient.fetchOrganizationByKey(), a targeted /api/organizations/search?organizations=<key> lookup (same pattern as checkOrganization), and resolveOrg's --org branch now uses it to populate both almKey and onlyPrivateProjectsEnabled instead of leaving them undefined. This also means onlyPrivateProjects.enabled is now correctly enforced when using --org directly, not just in the interactive flow. Added a regression test for it.

Comment thread tests/integration/specs/import/import.test.ts Outdated
Comment thread src/sonarqube/client.ts Outdated
Comment thread src/sonarqube/client.ts Outdated
@kevinmlsilva kevinmlsilva force-pushed the kevinmlsilva/sonar-import-create-project-v1 branch from 8e830a7 to aa7012b Compare July 10, 2026 09:26
Comment on lines +95 to +102
if (opts.org) {
const org = await client.fetchOrganizationByKey(opts.org);
return {
key: opts.org,
almKey: org?.alm?.key,
onlyPrivateProjectsEnabled: org?.onlyPrivateProjects?.enabled,
};
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Edge Case: --org visibility rule silently disabled on lookup failure

In the --org fast path, resolveOrg derives onlyPrivateProjectsEnabled from client.fetchOrganizationByKey(opts.org). fetchOrganizationByKey swallows any error (transient network/API failure) and returns undefined, which callers default to false (no restriction). The result is that a transient failure fetching the org record silently disables the organization's private-only project visibility enforcement — the very policy this PR is meant to enforce. A public repo could then be provisioned into an org that requires private-only projects.

This degradation is documented as intentional in the ResolvedOrg doc comment, and the server may re-enforce during provisioning, so impact is limited. But consider distinguishing 'org not found' / 'lookup failed' from 'onlyPrivateProjects genuinely disabled' — e.g. fail fast (or surface a warning) when the org lookup errors under --org, rather than silently falling back to the permissive default. Note the interactive path (lines 137-144) gets these values reliably from the already-fetched org list, so only the --org path is affected.

Was this helpful? React with 👍 / 👎

Wires up the final step of sonar import: after org/repo selection,
create the bound SonarQube project via provision_projects, resolving
the org's DevOps platform to format the installation key and
enforcing the org's public/private project visibility rules.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@kevinmlsilva kevinmlsilva force-pushed the kevinmlsilva/sonar-import-create-project-v1 branch from aa7012b to f5e4482 Compare July 10, 2026 10:23
@gitar-bot

gitar-bot Bot commented Jul 10, 2026

Copy link
Copy Markdown
Code Review 👍 Approved with suggestions 2 resolved / 3 findings

Wires up SonarQube project provisioning and visibility enforcement in the import command, resolving previous picker and API lookup issues. Address the minor bug where visibility rules are silently disabled during --org lookups.

💡 Edge Case: --org visibility rule silently disabled on lookup failure

📄 src/cli/commands/import/_common/resolve-options.ts:95-102 📄 src/sonarqube/client.ts:808-819

In the --org fast path, resolveOrg derives onlyPrivateProjectsEnabled from client.fetchOrganizationByKey(opts.org). fetchOrganizationByKey swallows any error (transient network/API failure) and returns undefined, which callers default to false (no restriction). The result is that a transient failure fetching the org record silently disables the organization's private-only project visibility enforcement — the very policy this PR is meant to enforce. A public repo could then be provisioned into an org that requires private-only projects.

This degradation is documented as intentional in the ResolvedOrg doc comment, and the server may re-enforce during provisioning, so impact is limited. But consider distinguishing 'org not found' / 'lookup failed' from 'onlyPrivateProjects genuinely disabled' — e.g. fail fast (or surface a warning) when the org lookup errors under --org, rather than silently falling back to the permissive default. Note the interactive path (lines 137-144) gets these values reliably from the already-fetched org list, so only the --org path is affected.

✅ 2 resolved
Bug: Interactive repo picker ignores visibility rules (disabled flag no-op)

📄 src/cli/commands/import/_common/resolve-options.ts:237-251
In resolveRepo's interactive path, each option is built with disabled: !isRepoSelectable(repo, onlyPrivateProjects). However, selectPrompt/SelectOption (src/ui/components/prompts.ts) has no disabled field and no logic that skips or blocks disabled entries — the property is silently dropped. As a result the onlyPrivateProjects visibility rule is NOT enforced in interactive mode: a user can navigate to and select a repo whose visibility is disallowed (e.g. a public repo in a private-only org, or vice-versa). This contradicts the explicit --repo fast path (lines 189-193), which throws CommandFailedError for the same mismatch. The selected repo then proceeds straight to provisionProject, relying on a server-side rejection rather than the intended client-side guard.

Either the prompt needs real disabled-option support, or resolveRepo should re-validate the chosen repo (or filter non-selectable repos out and error when none remain), mirroring the --repo behavior.

Quality: resolveOrg's almKey is fetched but never used; refetched via API

📄 src/cli/commands/import/index.ts:35 📄 src/cli/commands/import/index.ts:39 📄 src/cli/commands/import/_common/resolve-options.ts:129-137
resolveOrg populates ResolvedOrg.almKey from org.alm?.key for the interactive path, but importHandler destructures only { key, onlyPrivateProjectsEnabled } and always calls client.getOrganizationAlmKey(orgKey) — an extra getOrganizationLegacyId + organization-bindings round trip — even when the ALM key was already known from the org listing. This is a redundant network call and leaves the almKey field effectively dead in this code path. Consider using the already-resolved almKey when present and only falling back to getOrganizationAlmKey for the --org path where it is undefined.

🤖 Prompt for agents
Code Review: Wires up SonarQube project provisioning and visibility enforcement in the import command, resolving previous picker and API lookup issues. Address the minor bug where visibility rules are silently disabled during `--org` lookups.

1. 💡 Edge Case: --org visibility rule silently disabled on lookup failure
   Files: src/cli/commands/import/_common/resolve-options.ts:95-102, src/sonarqube/client.ts:808-819

   In the `--org` fast path, `resolveOrg` derives `onlyPrivateProjectsEnabled` from `client.fetchOrganizationByKey(opts.org)`. `fetchOrganizationByKey` swallows any error (transient network/API failure) and returns `undefined`, which callers default to `false` (no restriction). The result is that a transient failure fetching the org record silently *disables* the organization's private-only project visibility enforcement — the very policy this PR is meant to enforce. A public repo could then be provisioned into an org that requires private-only projects.
   
   This degradation is documented as intentional in the `ResolvedOrg` doc comment, and the server may re-enforce during provisioning, so impact is limited. But consider distinguishing 'org not found' / 'lookup failed' from 'onlyPrivateProjects genuinely disabled' — e.g. fail fast (or surface a warning) when the org lookup errors under `--org`, rather than silently falling back to the permissive default. Note the interactive path (lines 137-144) gets these values reliably from the already-fetched org list, so only the `--org` path is affected.

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing less information.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants