-
Notifications
You must be signed in to change notification settings - Fork 44
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add CLI arg resolver for builds (#253)
* Add CLI arg resolver for builds * Add tests for CLI resolver
- Loading branch information
1 parent
5bace3f
commit ed5208e
Showing
2 changed files
with
155 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package resolver | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"strconv" | ||
"strings" | ||
|
||
"github.com/buildkite/cli/v3/internal/build" | ||
"github.com/buildkite/cli/v3/internal/config" | ||
pipelineResolver "github.com/buildkite/cli/v3/internal/pipeline/resolver" | ||
) | ||
|
||
func ResolveFromPositionalArgument(args []string, index int, pipeline pipelineResolver.PipelineResolverFn, conf *config.Config) BuildResolverFn { | ||
return func(ctx context.Context) (*build.Build, error) { | ||
// if args does not have values, skip this resolver | ||
if len(args) < 1 { | ||
return nil, nil | ||
} | ||
// if the index is out of bounds | ||
if (len(args) - 1) < index { | ||
return nil, nil | ||
} | ||
|
||
build := parseBuildArg(ctx, args[index], pipeline) | ||
// if we get here, we should be able to parse the value and return an error if not | ||
// this is because a user has explicitly given an input value for us to use - we shouldnt ignore it on error | ||
if build == nil { | ||
return nil, fmt.Errorf("unable to parse the input build argument: \"%s\"", args[index]) | ||
} | ||
|
||
return build, nil | ||
} | ||
} | ||
|
||
func parseBuildArg(ctx context.Context, arg string, pipeline pipelineResolver.PipelineResolverFn) *build.Build { | ||
buildIsURL := strings.Contains(arg, ":") | ||
buildIsSlug := !buildIsURL && strings.Contains(arg, "/") | ||
|
||
if buildIsURL { | ||
return splitBuildURL(arg) | ||
} else if buildIsSlug { | ||
part := strings.Split(arg, "/") | ||
if len(part) < 3 { | ||
return nil | ||
} | ||
num, err := strconv.Atoi(part[2]) | ||
if err != nil { | ||
return nil | ||
} | ||
return &build.Build{ | ||
Organization: part[0], | ||
Pipeline: part[1], | ||
BuildNumber: num, | ||
} | ||
} | ||
|
||
num, err := strconv.Atoi(arg) | ||
if err != nil { | ||
return nil | ||
} | ||
p, err := pipeline(ctx) | ||
if err != nil || p == nil { | ||
return nil | ||
} | ||
return &build.Build{ | ||
Organization: p.Org, | ||
Pipeline: p.Name, | ||
BuildNumber: num, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package resolver_test | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
|
||
"github.com/buildkite/cli/v3/internal/build/resolver" | ||
"github.com/buildkite/cli/v3/internal/config" | ||
"github.com/buildkite/cli/v3/internal/pipeline" | ||
"github.com/spf13/afero" | ||
) | ||
|
||
func TestParseBuildArg(t *testing.T) { | ||
t.Parallel() | ||
|
||
testcases := map[string]struct { | ||
url, org, pipeline string | ||
num int | ||
}{ | ||
"org_pipeline_slug": { | ||
url: "buildkite/cli/34", | ||
org: "buildkite", | ||
pipeline: "cli", | ||
num: 34, | ||
}, | ||
"pipeline_slug": { | ||
url: "42", | ||
org: "testing", | ||
pipeline: "abcd", | ||
num: 42, | ||
}, | ||
"url": { | ||
url: "https://buildkite.com/buildkite/buildkite-cli/builds/99", | ||
org: "buildkite", | ||
pipeline: "buildkite-cli", | ||
num: 99, | ||
}, | ||
} | ||
|
||
for name, testcase := range testcases { | ||
testcase := testcase | ||
t.Run(name, func(t *testing.T) { | ||
t.Parallel() | ||
|
||
conf := config.New(afero.NewMemMapFs(), nil) | ||
conf.SelectOrganization("testing") | ||
res := func(context.Context) (*pipeline.Pipeline, error) { | ||
return &pipeline.Pipeline{ | ||
Name: testcase.pipeline, | ||
Org: testcase.org, | ||
}, nil | ||
} | ||
f := resolver.ResolveFromPositionalArgument([]string{testcase.url}, 0, res, conf) | ||
build, err := f(context.Background()) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
if build.Organization != testcase.org { | ||
t.Error("parsed organization slug did not match expected") | ||
} | ||
if build.Pipeline != testcase.pipeline { | ||
t.Error("parsed pipeline name did not match expected") | ||
} | ||
if build.BuildNumber != testcase.num { | ||
t.Error("parsed build number did not match expected") | ||
} | ||
}) | ||
} | ||
|
||
t.Run("Returns error if failed parsing", func(t *testing.T) { | ||
t.Parallel() | ||
|
||
conf := config.New(afero.NewMemMapFs(), nil) | ||
conf.SelectOrganization("testing") | ||
f := resolver.ResolveFromPositionalArgument([]string{"https://buildkite.com/"}, 0, nil, conf) | ||
build, err := f(context.Background()) | ||
if err == nil { | ||
t.Error("should have failed parsing build") | ||
} | ||
if build != nil { | ||
t.Error("no build should be returned") | ||
} | ||
}) | ||
} |