From 6025a02aca87a928ae3827861c68fcdaddcc5367 Mon Sep 17 00:00:00 2001 From: Erik Seliger Date: Tue, 16 Aug 2022 00:35:44 +0200 Subject: [PATCH 1/5] Remove src-cli workspace resolution This is available as a faster API from the backend now, so no need to keep this duplicative, slower code. This is a 4.0 deprecation execution. --- cmd/src/batch_common.go | 52 +-- cmd/src/batch_repositories.go | 59 +-- internal/batches/features.go | 22 +- internal/batches/service/build_tasks.go | 7 + internal/batches/service/service.go | 361 --------------- internal/batches/service/service_test.go | 482 -------------------- internal/batches/service/workspaces.go | 214 --------- internal/batches/service/workspaces_test.go | 345 -------------- 8 files changed, 54 insertions(+), 1488 deletions(-) delete mode 100644 internal/batches/service/workspaces.go delete mode 100644 internal/batches/service/workspaces_test.go diff --git a/cmd/src/batch_common.go b/cmd/src/batch_common.go index 58cf4a039a..9875925524 100644 --- a/cmd/src/batch_common.go +++ b/cmd/src/batch_common.go @@ -370,51 +370,23 @@ func executeBatchSpec(ctx context.Context, ui ui.ExecUI, opts executeBatchSpecOp ui.DeterminingWorkspaceCreatorTypeSuccess(typ) } - var ( - repos []*graphql.Repository - workspaces []service.RepoWorkspace - ) - if svc.Features().ServerSideWorkspaceResolution { - ui.ResolvingRepositories() - var err error - workspaces, repos, err = svc.ResolveWorkspacesForBatchSpec(ctx, batchSpec, opts.flags.allowUnsupported, opts.flags.allowIgnored) - if err != nil { - if repoSet, ok := err.(batches.UnsupportedRepoSet); ok { - ui.ResolvingRepositoriesDone(repos, repoSet, nil) - } else if repoSet, ok := err.(batches.IgnoredRepoSet); ok { - ui.ResolvingRepositoriesDone(repos, nil, repoSet) - } else { - return errors.Wrap(err, "resolving repositories server-side") - } + ui.ResolvingRepositories() + workspaces, repos, err := svc.ResolveWorkspacesForBatchSpec(ctx, batchSpec, opts.flags.allowUnsupported, opts.flags.allowIgnored) + if err != nil { + if repoSet, ok := err.(batches.UnsupportedRepoSet); ok { + ui.ResolvingRepositoriesDone(repos, repoSet, nil) + } else if repoSet, ok := err.(batches.IgnoredRepoSet); ok { + ui.ResolvingRepositoriesDone(repos, nil, repoSet) } else { - ui.ResolvingRepositoriesDone(repos, nil, nil) + return errors.Wrap(err, "resolving repositories") } - - ui.DeterminingWorkspaces() - ui.DeterminingWorkspacesSuccess(len(workspaces)) } else { - ui.ResolvingRepositories() - repos, err = svc.ResolveRepositories(ctx, batchSpec, opts.flags.allowUnsupported, opts.flags.allowIgnored) - if err != nil { - if repoSet, ok := err.(batches.UnsupportedRepoSet); ok { - ui.ResolvingRepositoriesDone(repos, repoSet, nil) - } else if repoSet, ok := err.(batches.IgnoredRepoSet); ok { - ui.ResolvingRepositoriesDone(repos, nil, repoSet) - } else { - return errors.Wrap(err, "resolving repositories") - } - } else { - ui.ResolvingRepositoriesDone(repos, nil, nil) - } - - ui.DeterminingWorkspaces() - workspaces, err = svc.DetermineWorkspaces(ctx, repos, batchSpec) - if err != nil { - return err - } - ui.DeterminingWorkspacesSuccess(len(workspaces)) + ui.ResolvingRepositoriesDone(repos, nil, nil) } + ui.DeterminingWorkspaces() + ui.DeterminingWorkspacesSuccess(len(workspaces)) + archiveRegistry := repozip.NewArchiveRegistry(opts.client, opts.flags.cacheDir, opts.flags.cleanArchives) logManager := log.NewDiskManager(opts.flags.tempDir, opts.flags.keepLogs) coord := executor.NewCoordinator( diff --git a/cmd/src/batch_repositories.go b/cmd/src/batch_repositories.go index 02d8979cee..3d92b578bb 100644 --- a/cmd/src/batch_repositories.go +++ b/cmd/src/batch_repositories.go @@ -9,6 +9,7 @@ import ( "github.com/sourcegraph/sourcegraph/lib/output" "github.com/sourcegraph/src-cli/internal/api" + "github.com/sourcegraph/src-cli/internal/batches" "github.com/sourcegraph/src-cli/internal/batches/graphql" "github.com/sourcegraph/src-cli/internal/batches/service" "github.com/sourcegraph/src-cli/internal/batches/ui" @@ -90,31 +91,34 @@ Examples: return err } - repoCount := 0 - for _, on := range spec.On { - repos, _, err := svc.ResolveRepositoriesOn(ctx, &on) - if err != nil { - return errors.Wrapf(err, "Resolving %q", on.String()) + _, repos, err := svc.ResolveWorkspacesForBatchSpec(ctx, spec, allowUnsupported, allowIgnored) + if err != nil { + if _, ok := err.(batches.UnsupportedRepoSet); ok { + // This is fine, we just ignore those in the output. + } else if _, ok := err.(batches.IgnoredRepoSet); ok { + // This is fine, we just ignore those in the output. + } else { + return errors.Wrap(err, "resolving repositories") } + } - max := 0 - for _, repo := range repos { - if len(repo.Name) > max { - max = len(repo.Name) - } - - repoCount++ + repoCount := 0 + max := 0 + for _, repo := range repos { + if len(repo.Name) > max { + max = len(repo.Name) } - if err := execTemplate(queryTmpl, batchRepositoryTemplateInput{ - Max: max, - Query: on.String(), - RepoCount: len(repos), - Repos: repos, - SourcegraphEndpoint: cfg.Endpoint, - }); err != nil { - return err - } + repoCount++ + } + + if err := execTemplate(queryTmpl, batchRepositoryTemplateInput{ + Max: max, + RepoCount: len(repos), + Repos: repos, + SourcegraphEndpoint: cfg.Endpoint, + }); err != nil { + return err } return execTemplate(totalTmpl, batchRepositoryTemplateInput{ @@ -135,19 +139,6 @@ Examples: } const batchRepositoriesTemplate = ` -{{- color "logo" -}}✱{{- color "nc" -}} -{{- " " -}} -{{- if eq .RepoCount 0 -}} - {{- color "warning" -}} -{{- else -}} - {{- color "success" -}} -{{- end -}} -{{- .RepoCount }} workspace{{ if ne .RepoCount 1 }}s{{ end }}{{- color "nc" -}} -{{- if ne (len .Query) 0 -}} - {{- " for " -}}{{- color "search-query"}}"{{.Query}}"{{ color "nc" -}} -{{- end -}} -{{- "\n" -}} - {{- range .Repos -}} {{- " "}}{{ color "success" }}{{ padRight .Name $.Max " " }}{{ color "nc" -}} {{- if ne (len .Branch.Name) 0 -}}{{ " " }}{{- color "search-branch" -}}{{- .Branch.Name -}}{{ color "nc" -}}{{- end -}} diff --git a/internal/batches/features.go b/internal/batches/features.go index a2a285fb47..c27e94596f 100644 --- a/internal/batches/features.go +++ b/internal/batches/features.go @@ -9,17 +9,16 @@ import ( // FeatureFlags represent features that are only available on certain // Sourcegraph versions and we therefore have to detect at runtime. type FeatureFlags struct { - AllowArrayEnvironments bool - IncludeAutoAuthorDetails bool - UseGzipCompression bool - AllowTransformChanges bool - AllowWorkspaces bool - BatchChanges bool - AllowConditionalExec bool - AllowOptionalPublished bool - ServerSideBatchChanges bool - BitbucketCloud bool - ServerSideWorkspaceResolution bool + AllowArrayEnvironments bool + IncludeAutoAuthorDetails bool + UseGzipCompression bool + AllowTransformChanges bool + AllowWorkspaces bool + BatchChanges bool + AllowConditionalExec bool + AllowOptionalPublished bool + ServerSideBatchChanges bool + BitbucketCloud bool } func (ff *FeatureFlags) SetFromVersion(version string) error { @@ -45,7 +44,6 @@ func (ff *FeatureFlags) SetFromVersion(version string) error { {&ff.AllowOptionalPublished, ">= 3.30.0-0", "2021-06-21"}, {&ff.ServerSideBatchChanges, ">= 3.37.0-0", "2022-02-08"}, {&ff.BitbucketCloud, ">= 3.40.0-0", "2022-04-20"}, - {&ff.ServerSideWorkspaceResolution, ">= 3.42.0-0", "2022-07-19"}, } { value, err := api.CheckSourcegraphVersion(version, feature.constraint, feature.minDate) if err != nil { diff --git a/internal/batches/service/build_tasks.go b/internal/batches/service/build_tasks.go index c7898759ff..265b090b06 100644 --- a/internal/batches/service/build_tasks.go +++ b/internal/batches/service/build_tasks.go @@ -5,8 +5,15 @@ import ( "github.com/sourcegraph/sourcegraph/lib/batches/template" "github.com/sourcegraph/src-cli/internal/batches/executor" + "github.com/sourcegraph/src-cli/internal/batches/graphql" ) +type RepoWorkspace struct { + Repo *graphql.Repository + Path string + OnlyFetchWorkspace bool +} + // buildTasks returns *executor.Tasks for all the workspaces determined for the given spec. func buildTasks(attributes *template.BatchChangeAttributes, steps []batcheslib.Step, workspaces []RepoWorkspace) []*executor.Task { tasks := make([]*executor.Task, 0, len(workspaces)) diff --git a/internal/batches/service/service.go b/internal/batches/service/service.go index 44c97843e1..7a8287f031 100644 --- a/internal/batches/service/service.go +++ b/internal/batches/service/service.go @@ -6,16 +6,12 @@ import ( "fmt" "os" "os/exec" - "path" "path/filepath" "strings" "sync" "text/template" - "github.com/grafana/regexp" - batcheslib "github.com/sourcegraph/sourcegraph/lib/batches" - onlib "github.com/sourcegraph/sourcegraph/lib/batches/on" templatelib "github.com/sourcegraph/sourcegraph/lib/batches/template" "github.com/sourcegraph/sourcegraph/lib/errors" @@ -364,10 +360,6 @@ func (svc *Service) EnsureDockerImages( return images, nil } -func (svc *Service) DetermineWorkspaces(ctx context.Context, repos []*graphql.Repository, spec *batcheslib.BatchSpec) ([]RepoWorkspace, error) { - return findWorkspaces(ctx, spec, svc, repos) -} - func (svc *Service) BuildTasks(attributes *templatelib.BatchChangeAttributes, steps []batcheslib.Step, workspaces []RepoWorkspace) []*executor.Task { return buildTasks(attributes, steps, workspaces) } @@ -669,114 +661,6 @@ func (svc *Service) ResolveNamespace(ctx context.Context, namespace string) (Nam return Namespace{}, fmt.Errorf("failed to resolve namespace %q: no user or organization found", namespace) } -func (svc *Service) ResolveRepositories(ctx context.Context, spec *batcheslib.BatchSpec, allowUnsupported, allowIgnored bool) ([]*graphql.Repository, error) { - agg := onlib.NewRepoRevisionAggregator() - unsupported := batches.UnsupportedRepoSet{} - ignored := batches.IgnoredRepoSet{} - - // TODO: this could be trivially parallelised in the future. - for _, on := range spec.On { - repos, ruleType, err := svc.ResolveRepositoriesOn(ctx, &on) - if err != nil { - return nil, errors.Wrapf(err, on.String()) - } - - result := agg.NewRuleRevisions(ruleType) - reposWithBranch := make([]*graphql.Repository, 0, len(repos)) - for _, repo := range repos { - if !repo.HasBranch() { - continue - } - reposWithBranch = append(reposWithBranch, repo) - } - - var repoBatchIgnores map[*graphql.Repository][]string - if !allowIgnored { - repoBatchIgnores, err = svc.FindDirectoriesInRepos(ctx, ".batchignore", reposWithBranch...) - if err != nil { - return nil, err - } - } - - for _, repo := range reposWithBranch { - result.AddRepoRevision(repo.ID, repo) - - switch st := strings.ToLower(repo.ExternalRepository.ServiceType); st { - case "github", "gitlab", "bitbucketserver": - case "bitbucketcloud": - if svc.features.BitbucketCloud { - break - } - fallthrough - default: - if !allowUnsupported { - unsupported.Append(repo) - } - } - - if !allowIgnored { - if locations, ok := repoBatchIgnores[repo]; ok && len(locations) > 0 { - ignored.Append(repo) - } - } - } - } - - final := []*graphql.Repository{} - for _, rev := range agg.Revisions() { - repo := rev.(*graphql.Repository) - if !unsupported.Includes(repo) && !ignored.Includes(repo) { - final = append(final, repo) - } - } - - if unsupported.HasUnsupported() { - return final, unsupported - } - - if ignored.HasIgnored() { - return final, ignored - } - - return final, nil -} - -func (svc *Service) ResolveRepositoriesOn(ctx context.Context, on *batcheslib.OnQueryOrRepository) ([]*graphql.Repository, onlib.RepositoryRuleType, error) { - if on.RepositoriesMatchingQuery != "" { - repo, err := svc.resolveRepositorySearch(ctx, on.RepositoriesMatchingQuery) - return repo, onlib.RepositoryRuleTypeQuery, err - } else if on.Repository != "" { - branches, err := on.GetBranches() - if err != nil { - return nil, onlib.RepositoryRuleTypeExplicit, err - } - - if len(branches) > 0 { - repos := make([]*graphql.Repository, len(branches)) - for i, branch := range branches { - repo, err := svc.resolveRepositoryNameAndBranch(ctx, on.Repository, branch) - if err != nil { - return nil, onlib.RepositoryRuleTypeExplicit, err - } - - repos[i] = repo - } - - return repos, onlib.RepositoryRuleTypeExplicit, nil - } else { - repo, err := svc.resolveRepositoryName(ctx, on.Repository) - if err != nil { - return nil, onlib.RepositoryRuleTypeExplicit, err - } - return []*graphql.Repository{repo}, onlib.RepositoryRuleTypeExplicit, nil - } - } - - // This shouldn't happen on any batch spec that has passed validation, but, - // alas, software. - return nil, onlib.RepositoryRuleTypeExplicit, ErrMalformedOnQueryOrRepository -} - const repositoryNameQuery = ` query Repository($name: String!, $queryCommit: Boolean!, $rev: String!) { repository(name: $name) { @@ -800,251 +684,6 @@ func (svc *Service) resolveRepositoryName(ctx context.Context, name string) (*gr return result.Repository, nil } -func (svc *Service) resolveRepositoryNameAndBranch(ctx context.Context, name, branch string) (*graphql.Repository, error) { - var result struct{ Repository *graphql.Repository } - if ok, err := svc.client.NewRequest(repositoryNameQuery, map[string]interface{}{ - "name": name, - "queryCommit": true, - "rev": branch, - }).Do(ctx, &result); err != nil || !ok { - return nil, err - } - if result.Repository == nil { - return nil, errors.New("no repository found") - } - if result.Repository.Commit.OID == "" { - return nil, fmt.Errorf("no branch matching %q found for repository %s", branch, name) - } - - result.Repository.Branch = graphql.Branch{ - Name: branch, - Target: result.Repository.Commit, - } - - return result.Repository, nil -} - -// TODO: search result alerts. -const repositorySearchQuery = ` -query ChangesetRepos( - $query: String!, - $queryCommit: Boolean!, - $rev: String!, -) { - search(query: $query, version: V2) { - results { - results { - __typename - ... on Repository { - ...repositoryFields - } - ... on FileMatch { - file { path } - repository { - ...repositoryFields - } - } - } - } - } -} -` + graphql.RepositoryFieldsFragment - -func (svc *Service) resolveRepositorySearch(ctx context.Context, query string) ([]*graphql.Repository, error) { - var result struct { - Search struct { - Results struct { - Results []searchResult - } - } - } - - if ok, err := svc.client.NewRequest(repositorySearchQuery, map[string]interface{}{ - "query": setDefaultQueryCount(query), - "queryCommit": false, - "rev": "", - }).Do(ctx, &result); err != nil || !ok { - return nil, err - } - - ids := map[string]*graphql.Repository{} - var repos []*graphql.Repository - for _, r := range result.Search.Results.Results { - existing, ok := ids[r.ID] - if !ok { - repo := r.Repository - repos = append(repos, &repo) - ids[r.ID] = &repo - } else { - for file := range r.FileMatches { - existing.FileMatches[file] = true - } - } - } - return repos, nil -} - -// findDirectoriesResult maps the name of the GraphQL query to its results. The -// name is the repository's ID. -type findDirectoriesResult map[string]struct { - Results struct{ Results []searchResult } -} - -const searchQueryTmpl = `%s: search(query: %q, version: V2) { - results { - results { - __typename - ... on FileMatch { - file { path } - } - } - } -} -` - -const findDirectoriesInReposBatchSize = 50 - -// FindDirectoriesInRepos returns a map of repositories and the locations of -// files matching the given file name in the repository. -// The locations are paths relative to the root of the directory. -// No "/" at the beginning. -// A dot (".") represents the root directory. -func (svc *Service) FindDirectoriesInRepos(ctx context.Context, fileName string, repos ...*graphql.Repository) (map[*graphql.Repository][]string, error) { - // Build up unique identifiers that are safe to use as GraphQL query aliases. - reposByQueryID := map[string]*graphql.Repository{} - queryIDByRepo := map[*graphql.Repository]string{} - for i, repo := range repos { - queryID := fmt.Sprintf("repo_%d", i) - reposByQueryID[queryID] = repo - queryIDByRepo[repo] = queryID - } - - findInBatch := func(batch []*graphql.Repository, results map[*graphql.Repository][]string) error { - var a strings.Builder - a.WriteString("query DirectoriesContainingFile {\n") - - for _, repo := range batch { - query := fmt.Sprintf(`file:(^|/)%s$ repo:^%s$@%s type:path count:99999`, regexp.QuoteMeta(fileName), regexp.QuoteMeta(repo.Name), repo.Rev()) - - a.WriteString(fmt.Sprintf(searchQueryTmpl, queryIDByRepo[repo], query)) - } - - a.WriteString("}") - - var result findDirectoriesResult - if ok, err := svc.client.NewQuery(a.String()).Do(ctx, &result); err != nil || !ok { - return err - } - - for queryID, search := range result { - repo, ok := reposByQueryID[queryID] - if !ok { - return fmt.Errorf("result for query %q did not match any repository", queryID) - } - - files := map[string]struct{}{} - - for _, r := range search.Results.Results { - for file := range r.FileMatches { - files[file] = struct{}{} - } - } - - var dirs []string - for f := range files { - dir := path.Dir(f) - // "." means the path is root, but in the executor we use "" to signify root. - if dir == "." { - dir = "" - } - // We use path.Dir and not filepath.Dir here, because while - // src-cli might be executed on Windows, we need the paths to - // be Unix paths, since they will be used inside Docker - // containers. - dirs = append(dirs, dir) - } - - results[repo] = dirs - } - - return nil - } - - results := make(map[*graphql.Repository][]string) - - for start := 0; start < len(repos); start += findDirectoriesInReposBatchSize { - if err := ctx.Err(); err != nil { - return nil, err - } - - end := start + findDirectoriesInReposBatchSize - if end > len(repos) { - end = len(repos) - } - - batch := repos[start:end] - - err := findInBatch(batch, results) - if err != nil { - return results, err - } - } - - return results, nil -} - -var defaultQueryCountRegex = regexp.MustCompile(`\bcount:(\d+|all)\b`) - -const hardCodedCount = " count:999999" - -func setDefaultQueryCount(query string) string { - if defaultQueryCountRegex.MatchString(query) { - return query - } - - return query + hardCodedCount -} - -type searchResult struct { - graphql.Repository -} - -func (sr *searchResult) UnmarshalJSON(data []byte) error { - var tn struct { - Typename string `json:"__typename"` - } - if err := json.Unmarshal(data, &tn); err != nil { - return err - } - - switch tn.Typename { - case "FileMatch": - var result struct { - Repository graphql.Repository - File struct { - Path string - } - } - if err := json.Unmarshal(data, &result); err != nil { - return err - } - - sr.Repository = result.Repository - sr.Repository.FileMatches = map[string]bool{result.File.Path: true} - return nil - - case "Repository": - if err := json.Unmarshal(data, &sr.Repository); err != nil { - return err - } - sr.Repository.FileMatches = map[string]bool{} - return nil - - default: - return errors.Errorf("unknown GraphQL type %q", tn.Typename) - } -} - func getGitConfig(attribute string) (string, error) { cmd := exec.Command("git", "config", "--get", attribute) out, err := cmd.CombinedOutput() diff --git a/internal/batches/service/service_test.go b/internal/batches/service/service_test.go index 8d2f1b604e..70bde9fff8 100644 --- a/internal/batches/service/service_test.go +++ b/internal/batches/service/service_test.go @@ -1,19 +1,14 @@ package service import ( - "bytes" "context" "fmt" - "net/http" - "net/http/httptest" "os" "path/filepath" "strconv" "strings" "testing" - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -21,488 +16,11 @@ import ( batcheslib "github.com/sourcegraph/sourcegraph/lib/batches" - "github.com/sourcegraph/src-cli/internal/api" - "github.com/sourcegraph/src-cli/internal/batches" "github.com/sourcegraph/src-cli/internal/batches/docker" "github.com/sourcegraph/src-cli/internal/batches/graphql" "github.com/sourcegraph/src-cli/internal/batches/mock" ) -func TestSetDefaultQueryCount(t *testing.T) { - for in, want := range map[string]string{ - "": hardCodedCount, - "count:10": "count:10", - "count:all": "count:all", - "r:foo": "r:foo" + hardCodedCount, - "r:foo count:10": "r:foo count:10", - "r:foo count:10 f:bar": "r:foo count:10 f:bar", - "r:foo count:": "r:foo count:" + hardCodedCount, - "r:foo count:xyz": "r:foo count:xyz" + hardCodedCount, - } { - t.Run(in, func(t *testing.T) { - have := setDefaultQueryCount(in) - if have != want { - t.Errorf("unexpected query: have %q; want %q", have, want) - } - }) - } -} - -func TestResolveRepositorySearch(t *testing.T) { - client, done := mockGraphQLClient(testResolveRepositorySearchResult) - defer done() - - svc := &Service{client: client} - - repos, err := svc.resolveRepositorySearch(context.Background(), "sourcegraph reconciler or src-cli") - if err != nil { - t.Fatalf("unexpected error: %s", err) - } - - // We want multiple FileMatches in the same repository to result in one repository - // and Repository and FileMatches should be folded into the same repository. - if have, want := len(repos), 3; have != want { - t.Fatalf("wrong number of repos. want=%d, have=%d", want, have) - } -} - -const testResolveRepositorySearchResult = `{ - "data": { - "search": { - "results": { - "results": [ - { - "__typename": "FileMatch", - "file": { "path": "website/src/components/PricingTable.tsx" }, - "repository": { - "id": "UmVwb3NpdG9yeTo0MDc=", - "name": "github.com/sd9/about", - "url": "/github.com/sd9/about", - "externalRepository": { "serviceType": "github" }, - "defaultBranch": { "name": "refs/heads/master", "target": { "oid": "1576f235209fbbfc918129db35f3d108347b74cb" } } - } - }, - { - "__typename": "Repository", - "id": "UmVwb3NpdG9yeToxOTM=", - "name": "github.com/sd9/src-cli", - "url": "/github.com/sd9/src-cli", - "externalRepository": { "serviceType": "github" }, - "defaultBranch": { "name": "refs/heads/master", "target": { "oid": "21dd58b08d64620942401b5543f5b0d33498bacb" } } - }, - { - "__typename": "FileMatch", - "file": { "path": "cmd/src/api.go" }, - "repository": { - "id": "UmVwb3NpdG9yeToxOTM=", - "name": "github.com/sd9/src-cli", - "url": "/github.com/sd9/src-cli", - "externalRepository": { "serviceType": "github" }, - "defaultBranch": { "name": "refs/heads/master", "target": { "oid": "21dd58b08d64620942401b5543f5b0d33498bacb" } } - } - }, - { - "__typename": "FileMatch", - "file": { "path": "client/web/src/components/externalServices/externalServices.tsx" }, - "repository": { - "id": "UmVwb3NpdG9yeTo2", - "name": "github.com/sourcegraph/sourcegraph", - "url": "/github.com/sourcegraph/sourcegraph", - "externalRepository": { "serviceType": "github" }, - "defaultBranch": { "name": "refs/heads/main", "target": { "oid": "e612c34f2e27005928ff3dfdd8e5ead5a0cb1526" } } - } - }, - { - "__typename": "FileMatch", - "file": { "path": "cmd/frontend/internal/httpapi/src_cli.go" }, - "repository": { - "id": "UmVwb3NpdG9yeTo2", - "name": "github.com/sourcegraph/sourcegraph", - "url": "/github.com/sourcegraph/sourcegraph", - "externalRepository": { "serviceType": "github" }, - "defaultBranch": { "name": "refs/heads/main", "target": { "oid": "e612c34f2e27005928ff3dfdd8e5ead5a0cb1526" } } - } - } - ] - } - } - } -} -` - -func mockGraphQLClient(responses ...string) (client api.Client, done func()) { - mux := http.NewServeMux() - - var count int - mux.HandleFunc("/.api/graphql", func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - - _, _ = w.Write([]byte(responses[count])) - - if count < len(responses)-1 { - count += 1 - } - }) - - ts := httptest.NewServer(mux) - - var clientBuffer bytes.Buffer - client = api.NewClient(api.ClientOpts{Endpoint: ts.URL, Out: &clientBuffer}) - - return client, ts.Close -} - -func TestResolveRepositories_Unsupported(t *testing.T) { - client, done := mockGraphQLClient(testResolveRepositoriesUnsupported) - defer done() - - spec := &batcheslib.BatchSpec{ - On: []batcheslib.OnQueryOrRepository{ - {RepositoriesMatchingQuery: "testquery"}, - }, - } - - t.Run("allowUnsupported:true", func(t *testing.T) { - svc := &Service{client: client} - - repos, err := svc.ResolveRepositories(context.Background(), spec, true, true) - if err != nil { - t.Fatalf("unexpected error: %s", err) - } - if len(repos) != 4 { - t.Fatalf("wrong number of repos. want=%d, have=%d", 4, len(repos)) - } - }) - - t.Run("allowUnsupported:false", func(t *testing.T) { - svc := &Service{client: client} - - repos, err := svc.ResolveRepositories(context.Background(), spec, false, true) - repoSet, ok := err.(batches.UnsupportedRepoSet) - if !ok { - t.Fatalf("err is not UnsupportedRepoSet") - } - if len(repoSet) != 1 { - t.Fatalf("wrong number of repos. want=%d, have=%d", 1, len(repoSet)) - } - if len(repos) != 3 { - t.Fatalf("wrong number of repos. want=%d, have=%d", 3, len(repos)) - } - }) -} - -const testResolveRepositoriesUnsupported = `{ - "data": { - "search": { - "results": { - "results": [ - { - "__typename": "Repository", - "id": "UmVwb3NpdG9yeToxMw==", - "name": "bitbucket.sgdev.org/SOUR/automation-testing", - "url": "/bitbucket.sgdev.org/SOUR/automation-testing", - "externalRepository": { "serviceType": "bitbucketserver" }, - "defaultBranch": { "name": "refs/heads/master", "target": { "oid": "b978d56de5578a935ca0bf07b56528acc99d5a61" } } - }, - { - "__typename": "Repository", - "id": "UmVwb3NpdG9yeTo0", - "name": "github.com/sourcegraph/automation-testing", - "url": "/github.com/sourcegraph/automation-testing", - "externalRepository": { "serviceType": "github" }, - "defaultBranch": { "name": "refs/heads/master", "target": { "oid": "6ac8a32ecaf6c4dc5ce050b9af51bce3db8efd63" } } - }, - { - "__typename": "Repository", - "id": "UmVwb3NpdG9yeTo2MQ==", - "name": "gitlab.sgdev.org/sourcegraph/automation-testing", - "url": "/gitlab.sgdev.org/sourcegraph/automation-testing", - "externalRepository": { "serviceType": "gitlab" }, - "defaultBranch": { "name": "refs/heads/master", "target": { "oid": "3b79a5d479d2af9cfe91e0aad4e9dddca7278150" } } - }, - { - "__typename": "Repository", - "id": "UmVwb3NpdG9yeToxNDg=", - "name": "git-codecommit.us-est-1.amazonaws.com/stripe-go", - "url": "/git-codecommit.us-est-1.amazonaws.com/stripe-go", - "externalRepository": { "serviceType": "awscodecommit" }, - "defaultBranch": { "name": "refs/heads/master", "target": { "oid": "3b79a5d479d2af9cfe91e0aad4e9dddca7278150" } } - } - ] - } - } - } -} -` - -func TestResolveRepositories_Ignored(t *testing.T) { - spec := &batcheslib.BatchSpec{ - On: []batcheslib.OnQueryOrRepository{ - {RepositoriesMatchingQuery: "testquery"}, - }, - } - - t.Run("allowIgnored:true", func(t *testing.T) { - client, done := mockGraphQLClient(testResolveRepositories, testBatchIgnoreInRepos) - defer done() - - svc := &Service{client: client} - - repos, err := svc.ResolveRepositories(context.Background(), spec, false, true) - if err != nil { - t.Fatalf("unexpected error: %s", err) - } - if len(repos) != 3 { - t.Fatalf("wrong number of repos. want=%d, have=%d", 3, len(repos)) - } - }) - - t.Run("allowIgnored:false", func(t *testing.T) { - client, done := mockGraphQLClient(testResolveRepositories, testBatchIgnoreInRepos) - defer done() - - svc := &Service{client: client} - - repos, err := svc.ResolveRepositories(context.Background(), spec, false, false) - ignored, ok := err.(batches.IgnoredRepoSet) - if !ok { - t.Fatalf("err is not IgnoredRepoSet: %s", err) - } - if len(ignored) != 1 { - t.Fatalf("wrong number of ignored repos. want=%d, have=%d", 1, len(ignored)) - } - if len(repos) != 2 { - t.Fatalf("wrong number of repos. want=%d, have=%d", 2, len(repos)) - } - }) -} - -const testResolveRepositories = `{ - "data": { - "search": { - "results": { - "results": [ - { - "__typename": "Repository", - "id": "UmVwb3NpdG9yeToxMw==", - "name": "bitbucket.sgdev.org/SOUR/automation-testing", - "url": "/bitbucket.sgdev.org/SOUR/automation-testing", - "externalRepository": { "serviceType": "bitbucketserver" }, - "defaultBranch": { "name": "refs/heads/master", "target": { "oid": "b978d56de5578a935ca0bf07b56528acc99d5a61" } } - }, - { - "__typename": "Repository", - "id": "UmVwb3NpdG9yeTo0", - "name": "github.com/sourcegraph/automation-testing", - "url": "/github.com/sourcegraph/automation-testing", - "externalRepository": { "serviceType": "github" }, - "defaultBranch": { "name": "refs/heads/master", "target": { "oid": "6ac8a32ecaf6c4dc5ce050b9af51bce3db8efd63" } } - }, - { - "__typename": "Repository", - "id": "UmVwb3NpdG9yeTo2MQ==", - "name": "gitlab.sgdev.org/sourcegraph/automation-testing", - "url": "/gitlab.sgdev.org/sourcegraph/automation-testing", - "externalRepository": { "serviceType": "gitlab" }, - "defaultBranch": { "name": "refs/heads/master", "target": { "oid": "3b79a5d479d2af9cfe91e0aad4e9dddca7278150" } } - } - ] - } - } - } -} -` - -const testBatchIgnoreInRepos = `{ - "data": { - "repo_0": { - "results": { - "results": [ - { - "__typename": "FileMatch", - "file": { - "path": ".batchignore" - } - } - ] - } - }, - "repo_1": { "results": { "results": [] } }, - "repo_2": { "results": { "results": [] } } - } -} -` - -func TestResolveRepositories_RepoWithoutBranch(t *testing.T) { - spec := &batcheslib.BatchSpec{ - On: []batcheslib.OnQueryOrRepository{ - {RepositoriesMatchingQuery: "testquery"}, - }, - } - - client, done := mockGraphQLClient(testResolveRepositoriesNoBranch, testBatchIgnoreInReposNoBranch) - defer done() - - svc := &Service{client: client} - - repos, err := svc.ResolveRepositories(context.Background(), spec, false, false) - if err != nil { - t.Fatalf("unexpected error: %s", err) - } - if len(repos) != 1 { - t.Fatalf("wrong number of repos. want=%d, have=%d", 2, len(repos)) - } -} - -const testResolveRepositoriesNoBranch = `{ - "data": { - "search": { - "results": { - "results": [ - { - "__typename": "Repository", - "id": "UmVwb3NpdG9yeToxMw==", - "name": "bitbucket.sgdev.org/SOUR/automation-testing", - "url": "/bitbucket.sgdev.org/SOUR/automation-testing", - "externalRepository": { "serviceType": "bitbucketserver" }, - "defaultBranch": null - }, - { - "__typename": "Repository", - "id": "UmVwb3NpdG9yeTo0", - "name": "github.com/sourcegraph/automation-testing", - "url": "/github.com/sourcegraph/automation-testing", - "externalRepository": { "serviceType": "github" }, - "defaultBranch": null - }, - { - "__typename": "Repository", - "id": "UmVwb3NpdG9yeTo2MQ==", - "name": "gitlab.sgdev.org/sourcegraph/automation-testing", - "url": "/gitlab.sgdev.org/sourcegraph/automation-testing", - "externalRepository": { "serviceType": "gitlab" }, - "defaultBranch": { "name": "refs/heads/master", "target": { "oid": "3b79a5d479d2af9cfe91e0aad4e9dddca7278150" } } - } - ] - } - } - } -} -` - -const testBatchIgnoreInReposNoBranch = `{ - "data": { - "repo_0": { "results": { "results": [] } } - } -} -` - -func TestService_FindDirectoriesInRepos(t *testing.T) { - client, done := mockGraphQLClient(testFindDirectoriesInRepos) - defer done() - - fileName := "package.json" - repos := []*graphql.Repository{ - { - ID: "repo-id-0", - Name: "github.com/sourcegraph/automation-testing", - Branch: graphql.Branch{Name: "dev"}, - DefaultBranch: &graphql.Branch{ - Name: "main", - Target: graphql.Target{ - OID: "d34db33f", - }, - }, - }, - { - ID: "repo-id-1", - Name: "github.com/sourcegraph/sourcegraph", - Branch: graphql.Branch{Name: "dev"}, - DefaultBranch: &graphql.Branch{ - Name: "main", - Target: graphql.Target{ - OID: "d34db33f", - }, - }, - }, - } - - svc := &Service{client: client} - - results, err := svc.FindDirectoriesInRepos(context.Background(), fileName, repos...) - if err != nil { - t.Fatalf("unexpected error: %s", err) - } - if len(results) != len(repos) { - t.Fatalf("wrong number of repos. want=%d, have=%d", 4, len(repos)) - } - - want := map[*graphql.Repository][]string{ - repos[0]: {"examples/project3", "project1", "project2"}, - repos[1]: {"docs/client1", "", "docs/client2/examples"}, - } - - if !cmp.Equal(want, results, cmpopts.SortSlices(sortStrings)) { - t.Errorf("wrong tasks built (-want +got):\n%s", cmp.Diff(want, results)) - } -} - -func sortStrings(a, b string) bool { return a < b } - -const testFindDirectoriesInRepos = `{ - "data": { - "repo_0": { - "results": { - "results": [ - { - "__typename": "FileMatch", - "file": { - "path": "examples/project3/package.json" - } - }, - { - "__typename": "FileMatch", - "file": { - "path": "project1/package.json" - } - }, - { - "__typename": "FileMatch", - "file": { - "path": "project2/package.json" - } - } - ] - } - }, - "repo_1": { - "results": { - "results": [ - { - "__typename": "FileMatch", - "file": { - "path": "docs/client1/package.json" - } - }, - { - "__typename": "FileMatch", - "file": { - "path": "package.json" - } - }, - { - "__typename": "FileMatch", - "file": { - "path": "docs/client2/examples/package.json" - } - } - ] - } - } - } -} -` - func TestService_ValidateChangesetSpecs(t *testing.T) { repo1 := &graphql.Repository{ID: "repo-graphql-id-1", Name: "github.com/sourcegraph/src-cli"} repo2 := &graphql.Repository{ID: "repo-graphql-id-2", Name: "github.com/sourcegraph/sourcegraph"} diff --git a/internal/batches/service/workspaces.go b/internal/batches/service/workspaces.go deleted file mode 100644 index c5df1005ac..0000000000 --- a/internal/batches/service/workspaces.go +++ /dev/null @@ -1,214 +0,0 @@ -package service - -import ( - "context" - "sort" - "strings" - - "github.com/gobwas/glob" - batcheslib "github.com/sourcegraph/sourcegraph/lib/batches" - "github.com/sourcegraph/sourcegraph/lib/batches/template" - "github.com/sourcegraph/sourcegraph/lib/errors" - - "github.com/sourcegraph/src-cli/internal/batches/graphql" - "github.com/sourcegraph/src-cli/internal/batches/util" -) - -type RepoWorkspace struct { - Repo *graphql.Repository - Path string - OnlyFetchWorkspace bool -} - -type directoryFinder interface { - FindDirectoriesInRepos(ctx context.Context, fileName string, repos ...*graphql.Repository) (map[*graphql.Repository][]string, error) -} - -// findWorkspaces matches the given repos to the workspace configs and -// searches, via the Sourcegraph instance, the locations of the workspaces in -// each repository. -// The repositories that were matched by a workspace config and all repos that didn't -// match a config are returned as workspaces. -func findWorkspaces( - ctx context.Context, - spec *batcheslib.BatchSpec, - finder directoryFinder, - repos []*graphql.Repository, -) ([]RepoWorkspace, error) { - // Pre-compile all globs. - workspaceMatchers := make(map[batcheslib.WorkspaceConfiguration]glob.Glob) - for _, conf := range spec.Workspaces { - in := conf.In - // Empty `in` should fall back to matching all, instead of nothing. - if in == "" { - in = "*" - } - g, err := glob.Compile(in) - if err != nil { - return nil, batcheslib.NewValidationError(errors.Errorf("failed to compile glob %q: %v", in, err)) - } - workspaceMatchers[conf] = g - } - - root := []*graphql.Repository{} - - // Maps workspace config indexes to repositories matching them. - matched := map[int][]*graphql.Repository{} - - for _, repo := range repos { - found := false - - // Try to find a workspace configuration matching this repo. - for idx, conf := range spec.Workspaces { - if !workspaceMatchers[conf].Match(repo.Name) { - continue - } - - // Don't allow duplicate matches. - if found { - return nil, batcheslib.NewValidationError(errors.Errorf("repository %s matches multiple workspaces.in globs in the batch spec. glob: %q", repo.Name, conf.In)) - } - - matched[idx] = append(matched[idx], repo) - found = true - } - - if !found { - root = append(root, repo) - } - } - - type repoWorkspaces struct { - Repo *graphql.Repository - Paths []string - OnlyFetchWorkspace bool - } - type workspaceKey struct { - repo string - branch string - } - workspacesByKey := map[workspaceKey]repoWorkspaces{} - for idx, repos := range matched { - conf := spec.Workspaces[idx] - repoDirs, err := finder.FindDirectoriesInRepos(ctx, conf.RootAtLocationOf, repos...) - if err != nil { - return nil, err - } - - for repo, dirs := range repoDirs { - // Don't add repos that don't have any matched workspaces. - if len(dirs) == 0 { - continue - } - key := workspaceKey{ - repo: repo.ID, - branch: repo.Branch.Name, - } - workspacesByKey[key] = repoWorkspaces{ - Repo: repo, - Paths: dirs, - OnlyFetchWorkspace: conf.OnlyFetchWorkspace, - } - } - } - - // And add the root for repos. - for _, repo := range root { - key := workspaceKey{ - repo: repo.ID, - branch: repo.Branch.Name, - } - conf, ok := workspacesByKey[key] - if !ok { - workspacesByKey[key] = repoWorkspaces{ - Repo: repo, - Paths: []string{""}, - OnlyFetchWorkspace: false, - } - continue - } - conf.Paths = append(workspacesByKey[key].Paths, "") - } - - workspaces := make([]RepoWorkspace, 0, len(workspacesByKey)) - for _, workspace := range workspacesByKey { - for _, path := range workspace.Paths { - fetchWorkspace := workspace.OnlyFetchWorkspace - if path == "" { - fetchWorkspace = false - } - - // Filter file matches by workspace. Only include paths that are - // _within_ the directory. - paths := map[string]bool{} - for probe := range workspace.Repo.FileMatches { - if strings.HasPrefix(probe, path) { - paths[probe] = true - } - } - - repo := *workspace.Repo - repo.FileMatches = paths - - steps, err := stepsForRepo(spec, util.NewTemplatingRepo(repo.Name, repo.FileMatches)) - if err != nil { - return nil, err - } - - // If the workspace doesn't have any steps we don't need to include it. - if len(steps) == 0 { - continue - } - - workspaces = append(workspaces, RepoWorkspace{ - Repo: &repo, - Path: path, - OnlyFetchWorkspace: fetchWorkspace, - }) - } - } - - // Stable sorting. - sort.Slice(workspaces, func(i, j int) bool { - if workspaces[i].Repo.Name == workspaces[j].Repo.Name { - return workspaces[i].Path < workspaces[j].Path - } - return workspaces[i].Repo.Name < workspaces[j].Repo.Name - }) - - return workspaces, nil -} - -// stepsForRepo calculates the steps required to run on the given repo. -func stepsForRepo(spec *batcheslib.BatchSpec, repo template.Repository) ([]batcheslib.Step, error) { - taskSteps := []batcheslib.Step{} - for _, step := range spec.Steps { - // If no if condition is given, just go ahead and add the step to the list. - if step.IfCondition() == "" { - taskSteps = append(taskSteps, step) - continue - } - - batchChange := template.BatchChangeAttributes{ - Name: spec.Name, - Description: spec.Description, - } - stepCtx := &template.StepContext{ - Repository: repo, - BatchChange: batchChange, - } - static, boolVal, err := template.IsStaticBool(step.IfCondition(), stepCtx) - if err != nil { - return nil, err - } - - // If we could evaluate the condition statically and the resulting - // boolean is false, we don't add that step. - if !static { - taskSteps = append(taskSteps, step) - } else if boolVal { - taskSteps = append(taskSteps, step) - } - } - return taskSteps, nil -} diff --git a/internal/batches/service/workspaces_test.go b/internal/batches/service/workspaces_test.go deleted file mode 100644 index 06b9be3193..0000000000 --- a/internal/batches/service/workspaces_test.go +++ /dev/null @@ -1,345 +0,0 @@ -package service - -import ( - "context" - "sort" - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" - batcheslib "github.com/sourcegraph/sourcegraph/lib/batches" - - "github.com/sourcegraph/src-cli/internal/batches/graphql" - "github.com/sourcegraph/src-cli/internal/batches/util" -) - -func TestFindWorkspaces(t *testing.T) { - repos := []*graphql.Repository{ - {ID: "repo-id-0", Name: "github.com/sourcegraph/automation-testing", FileMatches: map[string]bool{}}, - {ID: "repo-id-1", Name: "github.com/sourcegraph/sourcegraph", FileMatches: map[string]bool{}}, - {ID: "repo-id-2", Name: "bitbucket.sgdev.org/SOUR/automation-testing", FileMatches: map[string]bool{}}, - {ID: "repo-id-3", Name: "github.com/sourcegraph/src-cli", FileMatches: map[string]bool{"a/b": true, "a/b/c": true, "d/e/f": true}}, - } - steps := []batcheslib.Step{{Run: "echo 1"}} - - type finderResults map[*graphql.Repository][]string - - tests := map[string]struct { - spec *batcheslib.BatchSpec - finderResults map[*graphql.Repository][]string - - // workspaces in which repo/path they are executed - wantWorkspaces []RepoWorkspace - }{ - "no workspace configuration": { - spec: &batcheslib.BatchSpec{Steps: steps}, - finderResults: finderResults{}, - wantWorkspaces: []RepoWorkspace{ - {Repo: repos[0], Path: ""}, - {Repo: repos[1], Path: ""}, - {Repo: repos[2], Path: ""}, - {Repo: repos[3], Path: ""}, - }, - }, - - "workspace configuration matching no repos": { - spec: &batcheslib.BatchSpec{ - Steps: steps, - Workspaces: []batcheslib.WorkspaceConfiguration{ - {In: "this-does-not-match", RootAtLocationOf: "package.json"}, - }, - }, - finderResults: finderResults{}, - wantWorkspaces: []RepoWorkspace{ - {Repo: repos[0], Path: ""}, - {Repo: repos[1], Path: ""}, - {Repo: repos[2], Path: ""}, - {Repo: repos[3], Path: ""}, - }, - }, - - "workspace configuration matching 3 repos with no results": { - spec: &batcheslib.BatchSpec{ - Steps: steps, - Workspaces: []batcheslib.WorkspaceConfiguration{ - {In: "*automation-testing", RootAtLocationOf: "package.json"}, - }, - }, - finderResults: finderResults{ - repos[0]: []string{}, - repos[2]: []string{}, - }, - wantWorkspaces: []RepoWorkspace{ - {Repo: repos[1], Path: ""}, - {Repo: repos[3], Path: ""}, - }, - }, - - "workspace configuration matching 2 repos with 3 results each": { - spec: &batcheslib.BatchSpec{ - Steps: steps, - Workspaces: []batcheslib.WorkspaceConfiguration{ - {In: "*automation-testing", RootAtLocationOf: "package.json"}, - }, - }, - finderResults: finderResults{ - repos[0]: {"a/b", "a/b/c", "d/e/f"}, - repos[2]: {"a/b", "a/b/c", "d/e/f"}, - }, - wantWorkspaces: []RepoWorkspace{ - {Repo: repos[0], Path: "a/b"}, - {Repo: repos[0], Path: "a/b/c"}, - {Repo: repos[0], Path: "d/e/f"}, - {Repo: repos[1], Path: ""}, - {Repo: repos[2], Path: "a/b"}, - {Repo: repos[2], Path: "a/b/c"}, - {Repo: repos[2], Path: "d/e/f"}, - {Repo: repos[3], Path: ""}, - }, - }, - - "workspace configuration matches repo with OnlyFetchWorkspace": { - spec: &batcheslib.BatchSpec{ - Steps: steps, - Workspaces: []batcheslib.WorkspaceConfiguration{ - { - OnlyFetchWorkspace: true, - In: "*automation-testing", - RootAtLocationOf: "package.json", - }, - }, - }, - finderResults: finderResults{ - repos[0]: {"a/b", "a/b/c", "d/e/f"}, - repos[2]: {"a/b", "a/b/c", "d/e/f"}, - }, - wantWorkspaces: []RepoWorkspace{ - {Repo: repos[0], Path: "a/b", OnlyFetchWorkspace: true}, - {Repo: repos[0], Path: "a/b/c", OnlyFetchWorkspace: true}, - {Repo: repos[0], Path: "d/e/f", OnlyFetchWorkspace: true}, - {Repo: repos[1], Path: ""}, - {Repo: repos[2], Path: "a/b", OnlyFetchWorkspace: true}, - {Repo: repos[2], Path: "a/b/c", OnlyFetchWorkspace: true}, - {Repo: repos[2], Path: "d/e/f", OnlyFetchWorkspace: true}, - {Repo: repos[3], Path: ""}, - }, - }, - "workspace configuration without 'in' matches all": { - spec: &batcheslib.BatchSpec{ - Steps: steps, - Workspaces: []batcheslib.WorkspaceConfiguration{ - { - RootAtLocationOf: "package.json", - }, - }, - }, - finderResults: finderResults{ - repos[0]: {"a/b"}, - repos[2]: {"a/b"}, - }, - wantWorkspaces: []RepoWorkspace{ - {Repo: repos[0], Path: "a/b"}, - {Repo: repos[2], Path: "a/b"}, - }, - }, - "workspace gets subset of search_result_paths": { - spec: &batcheslib.BatchSpec{ - Steps: steps, - Workspaces: []batcheslib.WorkspaceConfiguration{ - { - In: "*src-cli", - RootAtLocationOf: "package.json", - }, - }, - }, - finderResults: finderResults{ - repos[3]: {"a/b", "d"}, - }, - wantWorkspaces: []RepoWorkspace{ - {Repo: repos[0], Path: ""}, - {Repo: repos[1], Path: ""}, - {Repo: repos[2], Path: ""}, - { - Repo: &graphql.Repository{ - ID: repos[3].ID, - Name: repos[3].Name, - URL: repos[3].URL, - ExternalRepository: repos[3].ExternalRepository, - DefaultBranch: repos[3].DefaultBranch, - Branch: repos[3].Branch, - Commit: repos[3].Commit, - // Only expect the file matches that are children of a/b. - FileMatches: map[string]bool{"a/b": true, "a/b/c": true}, - }, - Path: "a/b", - }, - { - Repo: &graphql.Repository{ - ID: repos[3].ID, - Name: repos[3].Name, - URL: repos[3].URL, - ExternalRepository: repos[3].ExternalRepository, - DefaultBranch: repos[3].DefaultBranch, - Branch: repos[3].Branch, - Commit: repos[3].Commit, - // Only expect the file matches that are children of d. - FileMatches: map[string]bool{"d/e/f": true}, - }, - Path: "d", - }, - }, - }, - } - - for name, tt := range tests { - t.Run(name, func(t *testing.T) { - finder := &mockDirectoryFinder{results: tt.finderResults} - workspaces, err := findWorkspaces(context.Background(), tt.spec, finder, repos) - if err != nil { - t.Fatalf("unexpected err: %s", err) - } - - // Sort by ID, easier than by name for tests. - sort.Slice(workspaces, func(i, j int) bool { - if workspaces[i].Repo.ID == workspaces[j].Repo.ID { - return workspaces[i].Path < workspaces[j].Path - } - return workspaces[i].Repo.ID < workspaces[j].Repo.ID - }) - - if diff := cmp.Diff(tt.wantWorkspaces, workspaces); diff != "" { - t.Errorf("mismatch (-want +got):\n%s", diff) - } - }) - } -} - -type mockDirectoryFinder struct { - results map[*graphql.Repository][]string -} - -func (m *mockDirectoryFinder) FindDirectoriesInRepos(ctx context.Context, fileName string, repos ...*graphql.Repository) (map[*graphql.Repository][]string, error) { - return m.results, nil -} - -func TestStepsForRepo(t *testing.T) { - tests := map[string]struct { - spec *batcheslib.BatchSpec - - wantSteps []batcheslib.Step - }{ - "no if": { - spec: &batcheslib.BatchSpec{ - Steps: []batcheslib.Step{ - {Run: "echo 1"}, - }, - }, - wantSteps: []batcheslib.Step{ - {Run: "echo 1"}, - }, - }, - - "if has static true value": { - spec: &batcheslib.BatchSpec{ - Steps: []batcheslib.Step{ - {Run: "echo 1", If: "true"}, - }, - }, - wantSteps: []batcheslib.Step{ - {Run: "echo 1", If: "true"}, - }, - }, - - "one of many steps has if with static true value": { - spec: &batcheslib.BatchSpec{ - Steps: []batcheslib.Step{ - {Run: "echo 1"}, - {Run: "echo 2", If: "true"}, - {Run: "echo 3"}, - }, - }, - wantSteps: []batcheslib.Step{ - {Run: "echo 1"}, - {Run: "echo 2", If: "true"}, - {Run: "echo 3"}, - }, - }, - - "if has static non-true value": { - spec: &batcheslib.BatchSpec{ - Steps: []batcheslib.Step{ - {Run: "echo 1", If: "this is not true"}, - }, - }, - wantSteps: []batcheslib.Step{}, - }, - - "one of many steps has if with static non-true value": { - spec: &batcheslib.BatchSpec{ - Steps: []batcheslib.Step{ - {Run: "echo 1"}, - {Run: "echo 2", If: "every type system needs generics"}, - {Run: "echo 3"}, - }, - }, - wantSteps: []batcheslib.Step{ - {Run: "echo 1"}, - {Run: "echo 3"}, - }, - }, - - "if expression that can be partially evaluated to true": { - spec: &batcheslib.BatchSpec{ - Steps: []batcheslib.Step{ - {Run: "echo 1", If: `${{ matches repository.name "github.com/sourcegraph/src*" }}`}, - }, - }, - wantSteps: []batcheslib.Step{ - {Run: "echo 1", If: `${{ matches repository.name "github.com/sourcegraph/src*" }}`}, - }, - }, - - "if expression that can be partially evaluated to false": { - spec: &batcheslib.BatchSpec{ - Steps: []batcheslib.Step{ - {Run: "echo 1", If: `${{ matches repository.name "horse" }}`}, - }, - }, - wantSteps: []batcheslib.Step{}, - }, - - "one of many steps has if expression that can be evaluated to true": { - spec: &batcheslib.BatchSpec{ - Steps: []batcheslib.Step{ - {Run: "echo 1", If: `${{ matches repository.name "horse" }}`}, - }, - }, - wantSteps: []batcheslib.Step{}, - }, - - "if expression that can NOT be partially evaluated": { - spec: &batcheslib.BatchSpec{ - Steps: []batcheslib.Step{ - {Run: "echo 1", If: `${{ eq outputs.value "foobar" }}`}, - }, - }, - wantSteps: []batcheslib.Step{ - {Run: "echo 1", If: `${{ eq outputs.value "foobar" }}`}, - }, - }, - } - - for name, tt := range tests { - t.Run(name, func(t *testing.T) { - haveSteps, err := stepsForRepo(tt.spec, util.NewTemplatingRepo(testRepo1.Name, testRepo1.FileMatches)) - if err != nil { - t.Fatalf("unexpected err: %s", err) - } - - opts := cmpopts.IgnoreUnexported(batcheslib.Step{}) - if diff := cmp.Diff(tt.wantSteps, haveSteps, opts); diff != "" { - t.Errorf("mismatch (-want +got):\n%s", diff) - } - }) - } -} From 34f8f9fe4d2b30064b30578a50d25e23c5c2dceb Mon Sep 17 00:00:00 2001 From: Erik Seliger Date: Tue, 16 Aug 2022 13:51:22 +0200 Subject: [PATCH 2/5] Cleanup --- internal/batches/service/main_test.go | 13 ------------- internal/batches/ui/tui.go | 4 ++-- 2 files changed, 2 insertions(+), 15 deletions(-) delete mode 100644 internal/batches/service/main_test.go diff --git a/internal/batches/service/main_test.go b/internal/batches/service/main_test.go deleted file mode 100644 index 07883000b4..0000000000 --- a/internal/batches/service/main_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package service - -import "github.com/sourcegraph/src-cli/internal/batches/graphql" - -var testRepo1 = &graphql.Repository{ - ID: "src-cli", - Name: "github.com/sourcegraph/src-cli", - DefaultBranch: &graphql.Branch{Name: "main", Target: graphql.Target{OID: "d34db33f"}}, - FileMatches: map[string]bool{ - "README.md": true, - "main.go": true, - }, -} diff --git a/internal/batches/ui/tui.go b/internal/batches/ui/tui.go index f146ab77fc..16b5f735b1 100644 --- a/internal/batches/ui/tui.go +++ b/internal/batches/ui/tui.go @@ -99,13 +99,13 @@ func (ui *TUI) ResolvingRepositories() { func (ui *TUI) ResolvingRepositoriesDone(repos []*graphql.Repository, unsupported batches.UnsupportedRepoSet, ignored batches.IgnoredRepoSet) { batchCompletePending(ui.pending, fmt.Sprintf("Resolved %d repositories", len(repos))) - if unsupported != nil && len(unsupported) != 0 { + if len(unsupported) != 0 { block := ui.Out.Block(output.Line(" ", output.StyleWarning, "Some repositories are hosted on unsupported code hosts and will be skipped. Use the -allow-unsupported flag to avoid skipping them.")) for repo := range unsupported { block.Write(repo.Name) } block.Close() - } else if ignored != nil && len(ignored) != 0 { + } else if len(ignored) != 0 { block := ui.Out.Block(output.Line(" ", output.StyleWarning, "The repositories listed below contain .batchignore files and will be skipped. Use the -force-override-ignore flag to avoid skipping them.")) for repo := range ignored { block.Write(repo.Name) From 486b2352c878dc7d2c165e672a2e41b7ae384208 Mon Sep 17 00:00:00 2001 From: Erik Seliger Date: Tue, 16 Aug 2022 16:57:03 +0200 Subject: [PATCH 3/5] Finish --- cmd/src/batch_common.go | 11 ++++------- go.mod | 12 ++++++------ go.sum | 22 ++++++++++++---------- internal/batches/ui/exec_ui.go | 5 +---- internal/batches/ui/json_lines.go | 20 +++++++------------- internal/batches/ui/tui.go | 16 ++++------------ 6 files changed, 34 insertions(+), 52 deletions(-) diff --git a/cmd/src/batch_common.go b/cmd/src/batch_common.go index 9875925524..cbd58b4e72 100644 --- a/cmd/src/batch_common.go +++ b/cmd/src/batch_common.go @@ -370,23 +370,20 @@ func executeBatchSpec(ctx context.Context, ui ui.ExecUI, opts executeBatchSpecOp ui.DeterminingWorkspaceCreatorTypeSuccess(typ) } - ui.ResolvingRepositories() + ui.DeterminingWorkspaces() workspaces, repos, err := svc.ResolveWorkspacesForBatchSpec(ctx, batchSpec, opts.flags.allowUnsupported, opts.flags.allowIgnored) if err != nil { if repoSet, ok := err.(batches.UnsupportedRepoSet); ok { - ui.ResolvingRepositoriesDone(repos, repoSet, nil) + ui.DeterminingWorkspacesSuccess(len(workspaces), len(repos), repoSet, nil) } else if repoSet, ok := err.(batches.IgnoredRepoSet); ok { - ui.ResolvingRepositoriesDone(repos, nil, repoSet) + ui.DeterminingWorkspacesSuccess(len(workspaces), len(repos), nil, repoSet) } else { return errors.Wrap(err, "resolving repositories") } } else { - ui.ResolvingRepositoriesDone(repos, nil, nil) + ui.DeterminingWorkspacesSuccess(len(workspaces), len(repos), nil, nil) } - ui.DeterminingWorkspaces() - ui.DeterminingWorkspacesSuccess(len(workspaces)) - archiveRegistry := repozip.NewArchiveRegistry(opts.client, opts.flags.cacheDir, opts.flags.cleanArchives) logManager := log.NewDiskManager(opts.flags.tempDir, opts.flags.keepLogs) coord := executor.NewCoordinator( diff --git a/go.mod b/go.mod index fa2c21900a..07e1305860 100644 --- a/go.mod +++ b/go.mod @@ -21,10 +21,10 @@ require ( github.com/sourcegraph/go-diff v0.6.1 github.com/sourcegraph/jsonx v0.0.0-20200629203448-1a936bd500cf github.com/sourcegraph/scip v0.2.0 - github.com/sourcegraph/sourcegraph/lib v0.0.0-20220816103048-5fb36f9b800c + github.com/sourcegraph/sourcegraph/lib v0.0.0-20220816145032-2e96fa544bee github.com/stretchr/testify v1.7.2 - golang.org/x/net v0.0.0-20220526153639-5463443f8c37 - golang.org/x/sync v0.0.0-20210220032951-036812b2e83c + golang.org/x/net v0.0.0-20220722155237-a158d28d115b + golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 google.golang.org/protobuf v1.28.0 gopkg.in/yaml.v3 v3.0.1 jaytaylor.com/html2text v0.0.0-20200412013138-3577fbdbcff7 @@ -95,7 +95,7 @@ require ( github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect - github.com/yuin/goldmark v1.4.4 // indirect + github.com/yuin/goldmark v1.4.13 // indirect github.com/yuin/goldmark-emoji v1.0.1 // indirect go.opencensus.io v0.23.0 // indirect go.uber.org/atomic v1.9.0 // indirect @@ -103,10 +103,10 @@ require ( go.uber.org/zap v1.21.0 // indirect golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect - golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e // indirect + golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect golang.org/x/term v0.0.0-20220411215600-e5f449aeb171 // indirect golang.org/x/text v0.3.7 // indirect - golang.org/x/tools v0.1.11 // indirect + golang.org/x/tools v0.1.12 // indirect golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4 // indirect google.golang.org/grpc v1.45.0 // indirect diff --git a/go.sum b/go.sum index 4b56d5fbef..757a3cc5c2 100644 --- a/go.sum +++ b/go.sum @@ -370,8 +370,8 @@ github.com/sourcegraph/log v0.0.0-20220707160925-6a936691c838 h1:8wknDSCUVYbaRT6 github.com/sourcegraph/log v0.0.0-20220707160925-6a936691c838/go.mod h1:zWEPlKrWBUVpko/tOgDS+qrp7BmzaCcmUrh9+ver1iQ= github.com/sourcegraph/scip v0.2.0 h1:Z9rR9TNONtRhqcpm0JP/yEBUy0fBKaSVbWIZKih5v04= github.com/sourcegraph/scip v0.2.0/go.mod h1:EYyT39nXdZDNVmgbJAlyIVWbEb1txnAOKpJPSYpvgXk= -github.com/sourcegraph/sourcegraph/lib v0.0.0-20220816103048-5fb36f9b800c h1:KmI6ZEtlP8P4h59rn6s0SSbwkX8Yg7dQBtadOLPYCrc= -github.com/sourcegraph/sourcegraph/lib v0.0.0-20220816103048-5fb36f9b800c/go.mod h1:9wnFUNfpORLAOJn4XAO7ZeWnYkf6/CxlWaTU1vlpuKc= +github.com/sourcegraph/sourcegraph/lib v0.0.0-20220816145032-2e96fa544bee h1:7K0kuLsVwHjwSaYOQt846J43dD3cccnYkliISLcGDAA= +github.com/sourcegraph/sourcegraph/lib v0.0.0-20220816145032-2e96fa544bee/go.mod h1:9wnFUNfpORLAOJn4XAO7ZeWnYkf6/CxlWaTU1vlpuKc= github.com/sourcegraph/yaml v1.0.1-0.20200714132230-56936252f152 h1:z/MpntplPaW6QW95pzcAR/72Z5TWDyDnSo0EOcyij9o= github.com/sourcegraph/yaml v1.0.1-0.20200714132230-56936252f152/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= @@ -421,8 +421,9 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.4 h1:zNWRjYUW32G9KirMXYHQHVNFkXvMI7LpgNW2AgYAoIs= github.com/yuin/goldmark v1.4.4/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg= +github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark-emoji v1.0.1 h1:ctuWEyzGBwiucEqxzwe0SOYDXPAucOrE9NQC18Wa1os= github.com/yuin/goldmark-emoji v1.0.1/go.mod h1:2w1E6FEWLcDQkoTE+7HU6QF1F6SLlNGjRIBbIZQFqkQ= go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= @@ -486,8 +487,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220526153639-5463443f8c37 h1:lUkvobShwKsOesNfWWlCS5q7fnbG1MEliIzwu886fn8= -golang.org/x/net v0.0.0-20220526153639-5463443f8c37/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -497,8 +498,9 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -533,8 +535,8 @@ golang.org/x/sys v0.0.0-20211102192858-4dd72447c267/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211213223007-03aa0b5f6827/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e h1:NHvCuwuS43lGnYhten69ZWqi2QOj/CiDNcKbVqwVoew= -golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20220411215600-e5f449aeb171 h1:EH1Deb8WZJ0xc0WK//leUHXcX9aLE5SymusoTmMZye8= golang.org/x/term v0.0.0-20220411215600-e5f449aeb171/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -567,8 +569,8 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.8-0.20211102182255-bb4add04ddef/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -golang.org/x/tools v0.1.11 h1:loJ25fNOEhSXfHrpoGj91eCUThwdNX6u24rO1xnNteY= -golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= +golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/internal/batches/ui/exec_ui.go b/internal/batches/ui/exec_ui.go index 52a5f91637..ecedfcfcac 100644 --- a/internal/batches/ui/exec_ui.go +++ b/internal/batches/ui/exec_ui.go @@ -22,11 +22,8 @@ type ExecUI interface { DeterminingWorkspaceCreatorType() DeterminingWorkspaceCreatorTypeSuccess(wt workspace.CreatorType) - ResolvingRepositories() - ResolvingRepositoriesDone(repos []*graphql.Repository, unsupported batches.UnsupportedRepoSet, ignored batches.IgnoredRepoSet) - DeterminingWorkspaces() - DeterminingWorkspacesSuccess(num int) + DeterminingWorkspacesSuccess(workspacesCount, reposCount int, unsupported batches.UnsupportedRepoSet, ignored batches.IgnoredRepoSet) CheckingCache() CheckingCacheSuccess(cachedSpecsFound int, tasksToExecute int) diff --git a/internal/batches/ui/json_lines.go b/internal/batches/ui/json_lines.go index ceade9e4c0..54795ec6ba 100644 --- a/internal/batches/ui/json_lines.go +++ b/internal/batches/ui/json_lines.go @@ -66,22 +66,16 @@ func (ui *JSONLines) DeterminingWorkspaceCreatorTypeSuccess(wt workspace.Creator logOperationSuccess(batcheslib.LogEventOperationDeterminingWorkspaceType, &batcheslib.DeterminingWorkspaceTypeMetadata{Type: t}) } -func (ui *JSONLines) ResolvingRepositories() { - logOperationStart(batcheslib.LogEventOperationResolvingRepositories, &batcheslib.ResolvingRepositoriesMetadata{}) -} -func (ui *JSONLines) ResolvingRepositoriesDone(repos []*graphql.Repository, unsupported batches.UnsupportedRepoSet, ignored batches.IgnoredRepoSet) { - logOperationSuccess(batcheslib.LogEventOperationResolvingRepositories, &batcheslib.ResolvingRepositoriesMetadata{ - Unsupported: len(unsupported), - Ignored: len(ignored), - Count: len(repos), - }) -} - func (ui *JSONLines) DeterminingWorkspaces() { logOperationStart(batcheslib.LogEventOperationDeterminingWorkspaces, &batcheslib.DeterminingWorkspacesMetadata{}) } -func (ui *JSONLines) DeterminingWorkspacesSuccess(num int) { - logOperationSuccess(batcheslib.LogEventOperationDeterminingWorkspaces, &batcheslib.DeterminingWorkspacesMetadata{Count: num}) +func (ui *JSONLines) DeterminingWorkspacesSuccess(workspacesCount, reposCount int, unsupported batches.UnsupportedRepoSet, ignored batches.IgnoredRepoSet) { + logOperationSuccess(batcheslib.LogEventOperationDeterminingWorkspaces, &batcheslib.DeterminingWorkspacesMetadata{ + Unsupported: len(unsupported), + Ignored: len(ignored), + RepoCount: reposCount, + WorkspaceCount: workspacesCount, + }) } func (ui *JSONLines) CheckingCache() { diff --git a/internal/batches/ui/tui.go b/internal/batches/ui/tui.go index 16b5f735b1..423526503e 100644 --- a/internal/batches/ui/tui.go +++ b/internal/batches/ui/tui.go @@ -93,11 +93,11 @@ func (ui *TUI) DeterminingWorkspaceCreatorTypeSuccess(wt workspace.CreatorType) batchCompletePending(ui.pending, "Set workspace type") } -func (ui *TUI) ResolvingRepositories() { - ui.pending = batchCreatePending(ui.Out, "Resolving repositories") +func (ui *TUI) DeterminingWorkspaces() { + ui.pending = batchCreatePending(ui.Out, "Determining workspaces") } -func (ui *TUI) ResolvingRepositoriesDone(repos []*graphql.Repository, unsupported batches.UnsupportedRepoSet, ignored batches.IgnoredRepoSet) { - batchCompletePending(ui.pending, fmt.Sprintf("Resolved %d repositories", len(repos))) +func (ui *TUI) DeterminingWorkspacesSuccess(workspacesCount, reposCount int, unsupported batches.UnsupportedRepoSet, ignored batches.IgnoredRepoSet) { + batchCompletePending(ui.pending, fmt.Sprintf("Resolved %d repositories with %d workspaces", reposCount, workspacesCount)) if len(unsupported) != 0 { block := ui.Out.Block(output.Line(" ", output.StyleWarning, "Some repositories are hosted on unsupported code hosts and will be skipped. Use the -allow-unsupported flag to avoid skipping them.")) @@ -114,14 +114,6 @@ func (ui *TUI) ResolvingRepositoriesDone(repos []*graphql.Repository, unsupporte } } -func (ui *TUI) DeterminingWorkspaces() { - ui.pending = batchCreatePending(ui.Out, "Determining workspaces") -} - -func (ui *TUI) DeterminingWorkspacesSuccess(num int) { - batchCompletePending(ui.pending, fmt.Sprintf("Found %d workspaces with steps to execute", num)) -} - func (ui *TUI) CheckingCache() { ui.pending = batchCreatePending(ui.Out, "Checking cache for changeset specs") } From d83c3c921f97ea3fc9a7a34eda8cb362c9d3fa73 Mon Sep 17 00:00:00 2001 From: Erik Seliger Date: Mon, 22 Aug 2022 16:36:46 +0200 Subject: [PATCH 4/5] Pin go mod --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 07e1305860..9d37a66f31 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/sourcegraph/go-diff v0.6.1 github.com/sourcegraph/jsonx v0.0.0-20200629203448-1a936bd500cf github.com/sourcegraph/scip v0.2.0 - github.com/sourcegraph/sourcegraph/lib v0.0.0-20220816145032-2e96fa544bee + github.com/sourcegraph/sourcegraph/lib v0.0.0-20220822143138-d621aac70d3d github.com/stretchr/testify v1.7.2 golang.org/x/net v0.0.0-20220722155237-a158d28d115b golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 @@ -103,7 +103,7 @@ require ( go.uber.org/zap v1.21.0 // indirect golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect - golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect + golang.org/x/sys v0.0.0-20220818161305-2296e01440c6 // indirect golang.org/x/term v0.0.0-20220411215600-e5f449aeb171 // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/tools v0.1.12 // indirect diff --git a/go.sum b/go.sum index 757a3cc5c2..fe55304b2e 100644 --- a/go.sum +++ b/go.sum @@ -370,8 +370,8 @@ github.com/sourcegraph/log v0.0.0-20220707160925-6a936691c838 h1:8wknDSCUVYbaRT6 github.com/sourcegraph/log v0.0.0-20220707160925-6a936691c838/go.mod h1:zWEPlKrWBUVpko/tOgDS+qrp7BmzaCcmUrh9+ver1iQ= github.com/sourcegraph/scip v0.2.0 h1:Z9rR9TNONtRhqcpm0JP/yEBUy0fBKaSVbWIZKih5v04= github.com/sourcegraph/scip v0.2.0/go.mod h1:EYyT39nXdZDNVmgbJAlyIVWbEb1txnAOKpJPSYpvgXk= -github.com/sourcegraph/sourcegraph/lib v0.0.0-20220816145032-2e96fa544bee h1:7K0kuLsVwHjwSaYOQt846J43dD3cccnYkliISLcGDAA= -github.com/sourcegraph/sourcegraph/lib v0.0.0-20220816145032-2e96fa544bee/go.mod h1:9wnFUNfpORLAOJn4XAO7ZeWnYkf6/CxlWaTU1vlpuKc= +github.com/sourcegraph/sourcegraph/lib v0.0.0-20220822143138-d621aac70d3d h1:bUaXAbtXSWbcv8LjDwwYXo0grERhlOJDn2T8ROe/Mmc= +github.com/sourcegraph/sourcegraph/lib v0.0.0-20220822143138-d621aac70d3d/go.mod h1:9wnFUNfpORLAOJn4XAO7ZeWnYkf6/CxlWaTU1vlpuKc= github.com/sourcegraph/yaml v1.0.1-0.20200714132230-56936252f152 h1:z/MpntplPaW6QW95pzcAR/72Z5TWDyDnSo0EOcyij9o= github.com/sourcegraph/yaml v1.0.1-0.20200714132230-56936252f152/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= @@ -535,8 +535,8 @@ golang.org/x/sys v0.0.0-20211102192858-4dd72447c267/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211213223007-03aa0b5f6827/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220818161305-2296e01440c6 h1:Sx/u41w+OwrInGdEckYmEuU5gHoGSL4QbDz3S9s6j4U= +golang.org/x/sys v0.0.0-20220818161305-2296e01440c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20220411215600-e5f449aeb171 h1:EH1Deb8WZJ0xc0WK//leUHXcX9aLE5SymusoTmMZye8= golang.org/x/term v0.0.0-20220411215600-e5f449aeb171/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= From 8745b66fc6940acea5f1e8334f36d2932efb5b6e Mon Sep 17 00:00:00 2001 From: Erik Seliger Date: Wed, 24 Aug 2022 15:37:09 +0200 Subject: [PATCH 5/5] Update internal/batches/ui/tui.go Co-authored-by: Kelli Rockwell --- internal/batches/ui/tui.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/batches/ui/tui.go b/internal/batches/ui/tui.go index 423526503e..bedec35639 100644 --- a/internal/batches/ui/tui.go +++ b/internal/batches/ui/tui.go @@ -97,7 +97,7 @@ func (ui *TUI) DeterminingWorkspaces() { ui.pending = batchCreatePending(ui.Out, "Determining workspaces") } func (ui *TUI) DeterminingWorkspacesSuccess(workspacesCount, reposCount int, unsupported batches.UnsupportedRepoSet, ignored batches.IgnoredRepoSet) { - batchCompletePending(ui.pending, fmt.Sprintf("Resolved %d repositories with %d workspaces", reposCount, workspacesCount)) + batchCompletePending(ui.pending, fmt.Sprintf("Resolved %d workspaces from %d repositories", workspacesCount, reposCount)) if len(unsupported) != 0 { block := ui.Out.Block(output.Line(" ", output.StyleWarning, "Some repositories are hosted on unsupported code hosts and will be skipped. Use the -allow-unsupported flag to avoid skipping them."))