Add support for naming repo explicitly for Bitbucket Cloud (#61536)

This aligns the configuration for Bitbucket Cloud with most other code hosts where we allow to name repos explicitly. This makes it easier to test the connection for a single repo first, instead of having to sync potentially thousands of repos right away.

## Test plan

Added a test using real-world data with VCR and verified manually on my local instance that I can successfully sync single repos.
This commit is contained in:
Erik Seliger 2024-04-08 19:03:53 +02:00 committed by GitHub
parent 0986dd370b
commit 20ef9619cc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 165 additions and 1 deletions

View File

@ -32,6 +32,7 @@ All notable changes to Sourcegraph are documented in this file.
- The frontend Grafana dashboard has a new Prometheus metric that tracks the rate of requests that Sourcegraph issues to external services. [#61348](https://github.com/sourcegraph/sourcegraph/pull/61348)
- Added support for the `gitURLType` setting for Gerrit, Sourcegraph now supports cloning from Gerrit via SSH. Note: Not on Cloud yet, like for all code hosts. [#61537](https://github.com/sourcegraph/sourcegraph/pull/61537)
- Support for OpenAI chat models for enterprise customers. [#61539](https://github.com/sourcegraph/sourcegraph/pull/61539)
- Added support for explicitly enumerating repositories to sync from Bitbucket Cloud. Previously, Sourcegraph would automatically sync all repositories from a Bitbucket Cloud workspace. [#61536](https://github.com/sourcegraph/sourcegraph/pull/61536)
### Changed

View File

@ -4,12 +4,14 @@ import (
"context"
"fmt"
"net/url"
"strings"
"sync"
"github.com/sourcegraph/log"
"github.com/sourcegraph/sourcegraph/internal/api"
"github.com/sourcegraph/sourcegraph/internal/conf/reposource"
"github.com/sourcegraph/sourcegraph/internal/errcode"
"github.com/sourcegraph/sourcegraph/internal/extsvc"
"github.com/sourcegraph/sourcegraph/internal/extsvc/auth"
"github.com/sourcegraph/sourcegraph/internal/extsvc/bitbucketcloud"
@ -175,11 +177,11 @@ func (s *BitbucketCloudSource) listAllRepos(ctx context.Context, results chan So
var wg sync.WaitGroup
// List all repositories of teams selected that the account has access to
wg.Add(1)
go func() {
defer wg.Done()
// List all repositories of teams selected that the account has access to
for _, t := range s.config.Teams {
page := &bitbucketcloud.PageToken{Pagelen: 100}
var err error
@ -193,6 +195,35 @@ func (s *BitbucketCloudSource) listAllRepos(ctx context.Context, results chan So
ch <- batch{repos: repos}
}
}
// List repositories that are explicitly named.
// Admins normally add to end of lists, so end of list most likely has new repos
// => stream them first.
for i := len(s.config.Repos) - 1; i >= 0; i-- {
if err := ctx.Err(); err != nil {
ch <- batch{err: err}
break
}
name := s.config.Repos[i]
ps := strings.SplitN(name, "/", 2)
if len(ps) != 2 {
ch <- batch{err: errors.Errorf("invalid repo name, expected format <workspace>/<repo_slug>, got %q", name)}
continue
}
workspace, repoSlug := ps[0], ps[1]
repo, err := s.client.Repo(ctx, workspace, repoSlug)
if err != nil {
if errcode.IsNotFound(err) {
s.logger.Warn("skipping missing bitbucketcloud.repos entry", log.String("name", name), log.Error(err))
continue
}
ch <- batch{err: errors.Wrapf(err, "failed to fetch repo %q", name)}
} else {
ch <- batch{repos: []*bitbucketcloud.Repo{repo}}
}
}
}()
go func() {

View File

@ -79,6 +79,20 @@ func TestBitbucketCloudSource_ListRepos(t *testing.T) {
},
err: "<nil>",
},
{
name: "with repos",
assert: assertAllReposListed([]string{
"/sourcegraph-testing/src-cli",
}),
conf: &schema.BitbucketCloudConnection{
Username: bbtest.GetenvTestBitbucketCloudUsername(),
AppPassword: os.Getenv("BITBUCKET_CLOUD_APP_PASSWORD"),
Repos: []string{
"sourcegraph-testing/src-cli",
},
},
err: "<nil>",
},
{
name: "with access token",
assert: assertAllReposListed([]string{

View File

@ -0,0 +1,107 @@
---
version: 1
interactions:
- request:
body: ""
form: {}
headers: {}
url: https://api.bitbucket.org/2.0/repositories/sourcegraph-testing/src-cli
method: GET
response:
body: '{"type": "repository", "full_name": "sourcegraph-testing/src-cli", "links":
{"self": {"href": "https://api.bitbucket.org/2.0/repositories/sourcegraph-testing/src-cli"},
"html": {"href": "https://bitbucket.org/sourcegraph-testing/src-cli"}, "avatar":
{"href": "https://bytebucket.org/ravatar/%7Bb090a669-ac7b-44cd-9610-02d027cb39f3%7D?ts=default"},
"pullrequests": {"href": "https://api.bitbucket.org/2.0/repositories/sourcegraph-testing/src-cli/pullrequests"},
"commits": {"href": "https://api.bitbucket.org/2.0/repositories/sourcegraph-testing/src-cli/commits"},
"forks": {"href": "https://api.bitbucket.org/2.0/repositories/sourcegraph-testing/src-cli/forks"},
"watchers": {"href": "https://api.bitbucket.org/2.0/repositories/sourcegraph-testing/src-cli/watchers"},
"branches": {"href": "https://api.bitbucket.org/2.0/repositories/sourcegraph-testing/src-cli/refs/branches"},
"tags": {"href": "https://api.bitbucket.org/2.0/repositories/sourcegraph-testing/src-cli/refs/tags"},
"downloads": {"href": "https://api.bitbucket.org/2.0/repositories/sourcegraph-testing/src-cli/downloads"},
"source": {"href": "https://api.bitbucket.org/2.0/repositories/sourcegraph-testing/src-cli/src"},
"clone": [{"name": "https", "href": "https://sourcegraph-testing@bitbucket.org/sourcegraph-testing/src-cli.git"},
{"name": "ssh", "href": "git@bitbucket.org:sourcegraph-testing/src-cli.git"}],
"hooks": {"href": "https://api.bitbucket.org/2.0/repositories/sourcegraph-testing/src-cli/hooks"}},
"name": "src-cli", "slug": "src-cli", "description": "", "scm": "git", "website":
null, "owner": {"display_name": "Sourcegraph Testing", "links": {"self": {"href":
"https://api.bitbucket.org/2.0/users/%7B4b85b785-1433-4092-8512-20302f4a03be%7D"},
"avatar": {"href": "https://secure.gravatar.com/avatar/f964dc31564db8243e952bdaeabbe884?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FST-2.png"},
"html": {"href": "https://bitbucket.org/%7B4b85b785-1433-4092-8512-20302f4a03be%7D/"}},
"type": "user", "uuid": "{4b85b785-1433-4092-8512-20302f4a03be}", "account_id":
"623316f53fbb880068413f6b", "nickname": "Sourcegraph Testing"}, "workspace":
{"type": "workspace", "uuid": "{4b85b785-1433-4092-8512-20302f4a03be}", "name":
"Sourcegraph Testing", "slug": "sourcegraph-testing", "links": {"avatar": {"href":
"https://bitbucket.org/workspaces/sourcegraph-testing/avatar/?ts=1647515473"},
"html": {"href": "https://bitbucket.org/sourcegraph-testing/"}, "self": {"href":
"https://api.bitbucket.org/2.0/workspaces/sourcegraph-testing"}}}, "is_private":
true, "project": {"type": "project", "key": "SOUR", "uuid": "{a862a17c-1726-47a2-bcd1-d9b37313b350}",
"name": "sourcegraph-testing", "links": {"self": {"href": "https://api.bitbucket.org/2.0/workspaces/sourcegraph-testing/projects/SOUR"},
"html": {"href": "https://bitbucket.org/sourcegraph-testing/workspace/projects/SOUR"},
"avatar": {"href": "https://bitbucket.org/account/user/sourcegraph-testing/projects/SOUR/avatar/32?ts=1647515868"}}},
"fork_policy": "no_public_forks", "created_on": "2022-03-17T11:17:48.581867+00:00",
"updated_on": "2022-04-14T20:49:52.967015+00:00", "size": 3566870, "language":
"", "uuid": "{b090a669-ac7b-44cd-9610-02d027cb39f3}", "mainbranch": {"name":
"master", "type": "branch"}, "override_settings": {"default_merge_strategy":
true, "branching_model": true}, "parent": null, "has_issues": false, "has_wiki":
false}'
headers:
Cache-Control:
- private
Content-Type:
- application/json; charset=utf-8
Date:
- Wed, 03 Apr 2024 00:29:31 GMT
Etag:
- '"a0a3ff29cb18a5af66fa6ab09c0d9c3f"'
Server:
- envoy
Strict-Transport-Security:
- max-age=31536000; includeSubDomains; preload
Vary:
- Authorization, Origin, cookie, user-context
X-B3-Spanid:
- fef36b6ccad0b2d4
X-B3-Traceid:
- 6a2473a1b92c2c31
X-Content-Type-Options:
- nosniff
X-Credential-Type:
- apppassword
X-Dc-Location:
- Micros-3
X-Envoy-Upstream-Service-Time:
- "184"
X-Frame-Options:
- SAMEORIGIN
X-Render-Time:
- "0.16698527336120605"
X-Request-Count:
- "2419"
X-Request-Id:
- 6a2473a1b92c2c31
X-Served-By:
- 03b017e4a0d3
X-Static-Version:
- bcd2fa8cae08
X-Trace-Id:
- 6a2473a1b92c2c31
X-Usage-Input-Ops:
- "0"
X-Usage-Output-Ops:
- "0"
X-Usage-System-Time:
- "0.011698"
X-Usage-User-Time:
- "0.090983"
X-Used-Mesh:
- "False"
X-Version:
- bcd2fa8cae08
X-View-Name:
- bitbucket.apps.repo2.api.v20.repo.RepositoryHandler
X-Xss-Protection:
- 1; mode=block
status: 200 OK
code: 200
duration: ""

View File

@ -113,6 +113,15 @@
"items": { "type": "string", "pattern": "^[\\w-]+$" },
"examples": [["name"], ["kubernetes", "golang", "facebook"]]
},
"repos": {
"description": "An array of repository \"projectKey/repositorySlug\" strings specifying repositories to mirror on Sourcegraph.",
"type": "array",
"items": {
"type": "string",
"pattern": "^~?[\\w-]+/[\\w.-]+$"
},
"examples": [["myproject/myrepo", "myproject/myotherrepo"]]
},
"exclude": {
"description": "A list of repositories to never mirror from Bitbucket Cloud. Takes precedence over \"teams\" configuration.\n\nSupports excluding by name ({\"name\": \"myorg/myrepo\"}) or by UUID ({\"uuid\": \"{fceb73c7-cef6-4abe-956d-e471281126bd}\"}).",
"type": "array",

View File

@ -369,6 +369,8 @@ type BitbucketCloudConnection struct {
GitURLType string `json:"gitURLType,omitempty"`
// RateLimit description: Rate limit applied when making background API requests to Bitbucket Cloud.
RateLimit *BitbucketCloudRateLimit `json:"rateLimit,omitempty"`
// Repos description: An array of repository "projectKey/repositorySlug" strings specifying repositories to mirror on Sourcegraph.
Repos []string `json:"repos,omitempty"`
// RepositoryPathPattern description: The pattern used to generate the corresponding Sourcegraph repository name for a Bitbucket Cloud repository.
//
// - "{host}" is replaced with the Bitbucket Cloud URL's host (such as bitbucket.org), and "{nameWithOwner}" is replaced with the Bitbucket Cloud repository's "owner/path" (such as "myorg/myrepo").