-
Notifications
You must be signed in to change notification settings - Fork 3
Addressing PR comments #131
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
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 | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -1021,3 +1021,82 @@ func putBitbucketScopes(client *devlake.Client, connID int, repos []*devlake.Bit | |||||||
| } | ||||||||
| return client.PutScopes("bitbucket", connID, &devlake.ScopeBatchRequest{Data: data}) | ||||||||
| } | ||||||||
|
|
||||||||
| // scopeSonarQubeHandler is the ScopeHandler for the sonarqube plugin. | ||||||||
| func scopeSonarQubeHandler(client *devlake.Client, connID int, org, enterprise string, opts *ScopeOpts) (*devlake.BlueprintConnection, error) { | ||||||||
| fmt.Println("\n📋 Fetching SonarQube projects...") | ||||||||
|
|
||||||||
| // Aggregate all pages of remote scopes | ||||||||
| var allChildren []devlake.RemoteScopeChild | ||||||||
| pageToken := "" | ||||||||
| for { | ||||||||
| remoteScopes, err := client.ListRemoteScopes("sonarqube", connID, "", pageToken) | ||||||||
| if err != nil { | ||||||||
| return nil, fmt.Errorf("failed to list SonarQube projects: %w", err) | ||||||||
| } | ||||||||
| allChildren = append(allChildren, remoteScopes.Children...) | ||||||||
| pageToken = remoteScopes.NextPageToken | ||||||||
| if pageToken == "" { | ||||||||
| break | ||||||||
| } | ||||||||
| } | ||||||||
|
|
||||||||
| // Extract projects from remote-scope response | ||||||||
| var projectOptions []string | ||||||||
| projectMap := make(map[string]*devlake.RemoteScopeChild) | ||||||||
| for i := range allChildren { | ||||||||
| child := &allChildren[i] | ||||||||
| if child.Type == "scope" { | ||||||||
| // Skip projects without a valid project key (child.ID) | ||||||||
| if child.ID == "" { | ||||||||
| continue | ||||||||
| } | ||||||||
| label := fmt.Sprintf("%s (key: %s)", child.Name, child.ID) | ||||||||
| projectOptions = append(projectOptions, label) | ||||||||
| projectMap[label] = child | ||||||||
| } | ||||||||
| } | ||||||||
|
|
||||||||
| if len(projectOptions) == 0 { | ||||||||
| return nil, fmt.Errorf("no SonarQube projects found for connection %d", connID) | ||||||||
| } | ||||||||
|
|
||||||||
| fmt.Println() | ||||||||
| selectedLabels := prompt.SelectMulti("Select SonarQube projects to track", projectOptions) | ||||||||
| if len(selectedLabels) == 0 { | ||||||||
| return nil, fmt.Errorf("at least one SonarQube project must be selected") | ||||||||
| } | ||||||||
|
|
||||||||
| // Build scope data for PUT | ||||||||
| fmt.Println("\n📝 Adding SonarQube project scopes...") | ||||||||
| var scopeData []any | ||||||||
| var blueprintScopes []devlake.BlueprintScope | ||||||||
| for _, label := range selectedLabels { | ||||||||
| child := projectMap[label] | ||||||||
| scopeData = append(scopeData, devlake.SonarQubeProjectScope{ | ||||||||
| ConnectionID: connID, | ||||||||
| ProjectKey: child.ID, | ||||||||
| Name: child.Name, | ||||||||
| }) | ||||||||
| blueprintScopes = append(blueprintScopes, devlake.BlueprintScope{ | ||||||||
| ScopeID: child.ID, | ||||||||
| ScopeName: child.Name, | ||||||||
| }) | ||||||||
| } | ||||||||
|
|
||||||||
| if len(scopeData) == 0 { | ||||||||
| return nil, fmt.Errorf("no valid projects to add") | ||||||||
| } | ||||||||
|
|
||||||||
|
Comment on lines
+1087
to
+1090
|
||||||||
| if len(scopeData) == 0 { | |
| return nil, fmt.Errorf("no valid projects to add") | |
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -324,6 +324,24 @@ var connectionRegistry = []*ConnectionDef{ | |
| ScopeIDField: "boardId", | ||
| HasRepoScopes: false, | ||
| }, | ||
| { | ||
| Plugin: "sonarqube", | ||
| DisplayName: "SonarQube", | ||
| Available: true, | ||
| Endpoint: "", // user must provide (e.g., https://sonar.example.com/) | ||
| SupportsTest: true, | ||
| AuthMethod: "AccessToken", | ||
| RateLimitPerHour: 0, // uses default 4500 | ||
|
||
| // SonarQube uses API tokens; permissions come from the user account. | ||
| RequiredScopes: []string{}, | ||
| ScopeHint: "", | ||
| TokenPrompt: "SonarQube token", | ||
| EnvVarNames: []string{"SONARQUBE_TOKEN", "SONAR_TOKEN"}, | ||
| EnvFileKeys: []string{"SONARQUBE_TOKEN", "SONAR_TOKEN"}, | ||
| ScopeFunc: scopeSonarQubeHandler, | ||
| ScopeIDField: "projectKey", | ||
| HasRepoScopes: false, | ||
| }, | ||
| } | ||
|
|
||
| // AvailableConnections returns only available (non-coming-soon) connection defs. | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -664,4 +664,69 @@ func TestConnectionRegistry_Jenkins(t *testing.T) { | |||||
| if !foundJobs { | ||||||
| t.Errorf("jenkins ScopeFlags should include jobs flag") | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
|
||||||
| } | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The selection list includes projects even when
child.ID(theprojectKey) is empty, but those selections are later skipped. This can lead to a confusing UX where a user selects items and then hitsno valid projects to add. Consider filtering outchild.ID == ""projects when buildingprojectOptions(and not inserting them intoprojectMap), or fail early with a clear message that the server returned projects without keys.