/
artifact_search.go
175 lines (138 loc) · 4.91 KB
/
artifact_search.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
package clicommand
import (
"context"
"fmt"
"strconv"
"strings"
"time"
"github.com/buildkite/agent/v3/agent"
"github.com/buildkite/agent/v3/api"
"github.com/urfave/cli"
)
const searchHelpDescription = `Usage:
buildkite-agent artifact search [options] <query>
Description:
Searches for build artifacts specified by <query> on Buildkite
Note: You need to ensure that your search query is surrounded by quotes if
using a wild card as the built-in shell path globbing will provide files,
which will break the search.
Example:
$ buildkite-agent artifact search "pkg/*.tar.gz" --build xxx
This will search across all uploaded artifacts in a build for files that match that query.
The first argument is the search query.
If you're trying to find a specific file, and there are multiple artifacts from different
jobs, you can target the particular job you want to search the artifacts from using --step:
$ buildkite-agent artifact search "pkg/*.tar.gz" --step "tests" --build xxx
You can also use the step's job id (provided by the environment variable $BUILDKITE_JOB_ID)
Output formatting can be altered with the -format flag as follows:
$ buildkite-agent artifact search "*" -format "%p\n"
The above will return a list of filenames separated by newline.`
const artifactSearchHelpTemplate = `{{.Description}}
Options:
{{range .VisibleFlags}} {{.}}
{{end}}
Format specifiers:
%i UUID of the artifact
%p Artifact path
%c Artifact creation time (an ISO 8601 / RFC-3339 formatted UTC timestamp)
%j UUID of the job that uploaded the artifact, helpful for subsequent artifact downloads
%s File size of the artifact in bytes
%S SHA1 checksum of the artifact
%u Download URL for the artifact, though consider using 'buildkite-agent artifact download' instead`
type ArtifactSearchConfig struct {
Query string `cli:"arg:0" label:"artifact search query" validate:"required"`
Step string `cli:"step"`
Build string `cli:"build" validate:"required"`
IncludeRetriedJobs bool `cli:"include-retried-jobs"`
AllowEmptyResults bool `cli:"allow-empty-results"`
PrintFormat string `cli:"format"`
// Global flags
Debug bool `cli:"debug"`
LogLevel string `cli:"log-level"`
NoColor bool `cli:"no-color"`
Experiments []string `cli:"experiment" normalize:"list"`
Profile string `cli:"profile"`
// API config
DebugHTTP bool `cli:"debug-http"`
AgentAccessToken string `cli:"agent-access-token" validate:"required"`
Endpoint string `cli:"endpoint" validate:"required"`
NoHTTP2 bool `cli:"no-http2"`
}
var ArtifactSearchCommand = cli.Command{
Name: "search",
Usage: "Searches artifacts in Buildkite",
Description: searchHelpDescription,
CustomHelpTemplate: artifactSearchHelpTemplate,
Flags: []cli.Flag{
cli.StringFlag{
Name: "step",
Value: "",
Usage: "Scope the search to a particular step by using either its name or job ID",
},
cli.StringFlag{
Name: "build",
Value: "",
EnvVar: "BUILDKITE_BUILD_ID",
Usage: "The build that the artifacts were uploaded to",
},
cli.BoolFlag{
Name: "include-retried-jobs",
EnvVar: "BUILDKITE_AGENT_INCLUDE_RETRIED_JOBS",
Usage: "Include artifacts from retried jobs in the search",
},
cli.BoolFlag{
Name: "allow-empty-results",
Usage: "By default, searches exit 1 if there are no results. If this flag is set, searches will exit 0 with an empty set",
},
cli.StringFlag{
Name: "format",
Value: "%j %p %c\n",
Usage: "Output formatting of results. See below for listing of available format specifiers.",
},
// API Flags
AgentAccessTokenFlag,
EndpointFlag,
NoHTTP2Flag,
DebugHTTPFlag,
// Global flags
NoColorFlag,
DebugFlag,
LogLevelFlag,
ExperimentsFlag,
ProfileFlag,
},
Action: func(c *cli.Context) error {
ctx := context.Background()
ctx, cfg, l, _, done := setupLoggerAndConfig[ArtifactSearchConfig](ctx, c)
defer done()
// Create the API client
client := api.NewClient(l, loadAPIClientConfig(cfg, "AgentAccessToken"))
// Setup the searcher and try get the artifacts
searcher := agent.NewArtifactSearcher(l, client, cfg.Build)
artifacts, err := searcher.Search(ctx, cfg.Query, cfg.Step, cfg.IncludeRetriedJobs, true)
if err != nil {
return err
}
if len(artifacts) == 0 {
if !cfg.AllowEmptyResults {
return fmt.Errorf("no matches found for %q", cfg.Query)
}
l.Info("No matches found for %q", cfg.Query)
}
for _, artifact := range artifacts {
r := strings.NewReplacer(
"%p", artifact.Path,
"%c", artifact.CreatedAt.Format(time.RFC3339),
"%j", artifact.JobID,
"%s", strconv.FormatInt(artifact.FileSize, 10),
"%S", artifact.Sha1Sum,
"%u", artifact.URL,
"%i", artifact.ID,
)
if _, err := fmt.Fprint(c.App.Writer, r.Replace(cfg.PrintFormat)); err != nil {
return err
}
}
return nil
},
}