Skip to content

Commit c72d7d8

Browse files
authored
Support Lifecycle Release Bundle Distribute (#2068)
1 parent d71026b commit c72d7d8

File tree

12 files changed

+297
-103
lines changed

12 files changed

+297
-103
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: Lifecycle Tests
2+
on:
3+
push:
4+
branches:
5+
- '**'
6+
tags-ignore:
7+
- '**'
8+
# Triggers the workflow on labeled PRs only.
9+
pull_request_target:
10+
types: [labeled]
11+
# Ensures that only the latest commit is running for each PR at a time.
12+
concurrency:
13+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}-${{ github.ref }}
14+
cancel-in-progress: true
15+
jobs:
16+
Lifecycle-Tests:
17+
if: contains(github.event.pull_request.labels.*.name, 'safe to test') || github.event_name == 'push'
18+
name: ${{ matrix.os }}
19+
strategy:
20+
fail-fast: false
21+
matrix:
22+
os: [ubuntu-latest, macos-latest, windows-latest]
23+
runs-on: ${{ matrix.os }}
24+
steps:
25+
- name: Install Go
26+
uses: actions/setup-go@v3
27+
with:
28+
go-version: 1.20.x
29+
- name: Checkout code
30+
uses: actions/checkout@v3
31+
with:
32+
ref: ${{ github.event.pull_request.head.sha }}
33+
- name: Go Cache
34+
uses: actions/cache@v3
35+
with:
36+
path: ~/go/pkg/mod
37+
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
38+
restore-keys: ${{ runner.os }}-go-
39+
- name: Checkout code
40+
uses: actions/checkout@v3
41+
with:
42+
ref: ${{ github.event.pull_request.head.sha }}
43+
- name: Run Lifecycle tests
44+
run: go test -v github.com/jfrog/jfrog-cli --timeout 0 --test.lifecycle --jfrog.url=${{ secrets.PLATFORM_URL }} --jfrog.adminToken=${{ secrets.PLATFORM_ADMIN_TOKEN }} --jfrog.user=${{ secrets.PLATFORM_USER }} --ci.runId=${{ runner.os }}-lifecycle

distribution/cli.go

Lines changed: 25 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,6 @@ package distribution
22

33
import (
44
"errors"
5-
"os"
6-
"path/filepath"
7-
"strings"
8-
95
"github.com/jfrog/jfrog-cli-core/v2/common/commands"
106
"github.com/jfrog/jfrog-cli-core/v2/common/spec"
117
distributionCommands "github.com/jfrog/jfrog-cli-core/v2/distribution/commands"
@@ -18,10 +14,14 @@ import (
1814
"github.com/jfrog/jfrog-cli/docs/artifactory/releasebundleupdate"
1915
"github.com/jfrog/jfrog-cli/docs/common"
2016
"github.com/jfrog/jfrog-cli/utils/cliutils"
17+
"github.com/jfrog/jfrog-cli/utils/distribution"
2118
distributionServices "github.com/jfrog/jfrog-client-go/distribution/services"
2219
distributionServicesUtils "github.com/jfrog/jfrog-client-go/distribution/services/utils"
2320
"github.com/jfrog/jfrog-client-go/utils/errorutils"
2421
"github.com/urfave/cli"
22+
"os"
23+
"path/filepath"
24+
"strings"
2525
)
2626

2727
func GetCommands() []cli.Command {
@@ -111,11 +111,11 @@ func releaseBundleCreateCmd(c *cli.Context) error {
111111
return err
112112
}
113113
releaseBundleCreateCmd := distributionCommands.NewReleaseBundleCreateCommand()
114-
rtDetails, err := createArtifactoryDetailsByFlags(c)
114+
dsDetails, err := createDistributionDetailsByFlags(c)
115115
if err != nil {
116116
return err
117117
}
118-
releaseBundleCreateCmd.SetServerDetails(rtDetails).SetReleaseBundleCreateParams(params).SetSpec(releaseBundleCreateSpec).SetDryRun(c.Bool("dry-run")).SetDetailedSummary(c.Bool("detailed-summary"))
118+
releaseBundleCreateCmd.SetServerDetails(dsDetails).SetReleaseBundleCreateParams(params).SetSpec(releaseBundleCreateSpec).SetDryRun(c.Bool("dry-run")).SetDetailedSummary(c.Bool("detailed-summary"))
119119

120120
err = commands.Exec(releaseBundleCreateCmd)
121121
if releaseBundleCreateCmd.IsDetailedSummary() {
@@ -153,11 +153,11 @@ func releaseBundleUpdateCmd(c *cli.Context) error {
153153
return err
154154
}
155155
releaseBundleUpdateCmd := distributionCommands.NewReleaseBundleUpdateCommand()
156-
rtDetails, err := createArtifactoryDetailsByFlags(c)
156+
dsDetails, err := createDistributionDetailsByFlags(c)
157157
if err != nil {
158158
return err
159159
}
160-
releaseBundleUpdateCmd.SetServerDetails(rtDetails).SetReleaseBundleUpdateParams(params).SetSpec(releaseBundleUpdateSpec).SetDryRun(c.Bool("dry-run")).SetDetailedSummary(c.Bool("detailed-summary"))
160+
releaseBundleUpdateCmd.SetServerDetails(dsDetails).SetReleaseBundleUpdateParams(params).SetSpec(releaseBundleUpdateSpec).SetDryRun(c.Bool("dry-run")).SetDetailedSummary(c.Bool("detailed-summary"))
161161

162162
err = commands.Exec(releaseBundleUpdateCmd)
163163
if releaseBundleUpdateCmd.IsDetailedSummary() {
@@ -177,11 +177,11 @@ func releaseBundleSignCmd(c *cli.Context) error {
177177
params.StoringRepository = c.String("repo")
178178
params.GpgPassphrase = c.String("passphrase")
179179
releaseBundleSignCmd := distributionCommands.NewReleaseBundleSignCommand()
180-
rtDetails, err := createArtifactoryDetailsByFlags(c)
180+
dsDetails, err := createDistributionDetailsByFlags(c)
181181
if err != nil {
182182
return err
183183
}
184-
releaseBundleSignCmd.SetServerDetails(rtDetails).SetReleaseBundleSignParams(params).SetDetailedSummary(c.Bool("detailed-summary"))
184+
releaseBundleSignCmd.SetServerDetails(dsDetails).SetReleaseBundleSignParams(params).SetDetailedSummary(c.Bool("detailed-summary"))
185185
err = commands.Exec(releaseBundleSignCmd)
186186
if releaseBundleSignCmd.IsDetailedSummary() {
187187
if summary := releaseBundleSignCmd.GetSummary(); summary != nil {
@@ -192,45 +192,29 @@ func releaseBundleSignCmd(c *cli.Context) error {
192192
}
193193

194194
func releaseBundleDistributeCmd(c *cli.Context) error {
195-
if c.NArg() != 2 {
196-
return cliutils.WrongNumberOfArgumentsHandler(c)
197-
}
198-
if c.IsSet("max-wait-minutes") && !c.IsSet("sync") {
199-
return cliutils.PrintHelpAndReturnError("The --max-wait-minutes option can't be used without --sync", c)
200-
}
201-
var distributionRules *spec.DistributionRules
202-
if c.IsSet("dist-rules") {
203-
if c.IsSet("site") || c.IsSet("city") || c.IsSet("country-code") {
204-
return cliutils.PrintHelpAndReturnError("The --dist-rules option can't be used with --site, --city or --country-code", c)
205-
}
206-
var err error
207-
distributionRules, err = spec.CreateDistributionRulesFromFile(c.String("dist-rules"))
208-
if err != nil {
209-
return err
210-
}
211-
} else {
212-
distributionRules = createDefaultDistributionRules(c)
195+
if err := distribution.ValidateReleaseBundleDistributeCmd(c); err != nil {
196+
return err
213197
}
214198

215-
params := distributionServices.NewDistributeReleaseBundleParams(c.Args().Get(0), c.Args().Get(1))
216-
releaseBundleDistributeCmd := distributionCommands.NewReleaseBundleDistributeCommand()
217-
rtDetails, err := createArtifactoryDetailsByFlags(c)
199+
dsDetails, err := createDistributionDetailsByFlags(c)
218200
if err != nil {
219201
return err
220202
}
221-
maxWaitMinutes, err := cliutils.GetIntFlagValue(c, "max-wait-minutes", 60)
203+
distributionRules, maxWaitMinutes, params, err := distribution.InitReleaseBundleDistributeCmd(c)
222204
if err != nil {
223205
return err
224206
}
225-
releaseBundleDistributeCmd.SetServerDetails(rtDetails).
207+
208+
distributeCmd := distributionCommands.NewReleaseBundleDistributeV1Command()
209+
distributeCmd.SetServerDetails(dsDetails).
226210
SetDistributeBundleParams(params).
227211
SetDistributionRules(distributionRules).
228212
SetDryRun(c.Bool("dry-run")).
229213
SetSync(c.Bool("sync")).
230214
SetMaxWaitMinutes(maxWaitMinutes).
231215
SetAutoCreateRepo(c.Bool("create-repo"))
232216

233-
return commands.Exec(releaseBundleDistributeCmd)
217+
return commands.Exec(distributeCmd)
234218
}
235219

236220
func releaseBundleDeleteCmd(c *cli.Context) error {
@@ -248,7 +232,7 @@ func releaseBundleDeleteCmd(c *cli.Context) error {
248232
return err
249233
}
250234
} else {
251-
distributionRules = createDefaultDistributionRules(c)
235+
distributionRules = distribution.CreateDefaultDistributionRules(c)
252236
}
253237

254238
params := distributionServices.NewDeleteReleaseBundleParams(c.Args().Get(0), c.Args().Get(1))
@@ -260,11 +244,11 @@ func releaseBundleDeleteCmd(c *cli.Context) error {
260244
}
261245
params.MaxWaitMinutes = maxWaitMinutes
262246
distributeBundleCmd := distributionCommands.NewReleaseBundleDeleteParams()
263-
rtDetails, err := createArtifactoryDetailsByFlags(c)
247+
dsDetails, err := createDistributionDetailsByFlags(c)
264248
if err != nil {
265249
return err
266250
}
267-
distributeBundleCmd.SetQuiet(cliutils.GetQuietValue(c)).SetServerDetails(rtDetails).SetDistributeBundleParams(params).SetDistributionRules(distributionRules).SetDryRun(c.Bool("dry-run"))
251+
distributeBundleCmd.SetQuiet(cliutils.GetQuietValue(c)).SetServerDetails(dsDetails).SetDistributeBundleParams(params).SetDistributionRules(distributionRules).SetDryRun(c.Bool("dry-run"))
268252

269253
return commands.Exec(distributeBundleCmd)
270254
}
@@ -283,16 +267,6 @@ func createDefaultReleaseBundleSpec(c *cli.Context) *spec.SpecFiles {
283267
BuildSpec()
284268
}
285269

286-
func createDefaultDistributionRules(c *cli.Context) *spec.DistributionRules {
287-
return &spec.DistributionRules{
288-
DistributionRules: []spec.DistributionRule{{
289-
SiteName: c.String("site"),
290-
CityName: c.String("city"),
291-
CountryCodes: cliutils.GetStringsArrFlagValue(c, "country-codes"),
292-
}},
293-
}
294-
}
295-
296270
func createReleaseBundleCreateUpdateParams(c *cli.Context, bundleName, bundleVersion string) (distributionServicesUtils.ReleaseBundleParams, error) {
297271
releaseBundleParams := distributionServicesUtils.NewReleaseBundleParams(bundleName, bundleVersion)
298272
releaseBundleParams.SignImmediately = c.Bool("sign")
@@ -336,13 +310,13 @@ func populateReleaseNotesSyntax(c *cli.Context) (distributionServicesUtils.Relea
336310
return distributionServicesUtils.PlainText, nil
337311
}
338312

339-
func createArtifactoryDetailsByFlags(c *cli.Context) (*coreConfig.ServerDetails, error) {
340-
artDetails, err := cliutils.CreateServerDetailsWithConfigOffer(c, true, cliutils.Ds)
313+
func createDistributionDetailsByFlags(c *cli.Context) (*coreConfig.ServerDetails, error) {
314+
dsDetails, err := cliutils.CreateServerDetailsWithConfigOffer(c, true, cliutils.Ds)
341315
if err != nil {
342316
return nil, err
343317
}
344-
if artDetails.DistributionUrl == "" {
318+
if dsDetails.DistributionUrl == "" {
345319
return nil, errors.New("the --dist-url option is mandatory")
346320
}
347-
return artDetails, nil
321+
return dsDetails, nil
348322
}

distribution_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
distributionServices "github.com/jfrog/jfrog-client-go/distribution/services"
1515
clientDistUtils "github.com/jfrog/jfrog-client-go/distribution/services/utils"
1616
clientUtils "github.com/jfrog/jfrog-client-go/utils"
17+
"github.com/jfrog/jfrog-client-go/utils/distribution"
1718
"github.com/jfrog/jfrog-client-go/utils/io/fileutils"
1819
"github.com/jfrog/jfrog-client-go/utils/io/httputils"
1920
"github.com/jfrog/jfrog-client-go/utils/log"
@@ -566,7 +567,7 @@ func TestDistributeSyncTimeout(t *testing.T) {
566567
testServer, mockServerDetails, _ := coreTestUtils.CreateDsRestsMockServer(t, func(w http.ResponseWriter, r *http.Request) {
567568
if r.RequestURI == "/api/v1/distribution/"+tests.BundleName+"/"+bundleVersion {
568569
w.WriteHeader(http.StatusOK)
569-
content, err := json.Marshal(distributionServices.DistributionResponseBody{TrackerId: json.Number(trackerId)})
570+
content, err := json.Marshal(distribution.DistributionResponseBody{TrackerId: json.Number(trackerId)})
570571
assert.NoError(t, err)
571572
_, err = w.Write(content)
572573
assert.NoError(t, err)

docs/lifecycle/distribute/help.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package distribute
2+
3+
var Usage = []string{"rbd [command options] <release bundle name> <release bundle version>"}
4+
5+
func GetDescription() string {
6+
return "Distribute a release bundle."
7+
}
8+
9+
func GetArguments() string {
10+
return ` release bundle name
11+
Name of the Release Bundle to distribute.
12+
13+
release bundle version
14+
Version of the Release Bundle to distribute.`
15+
}

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,8 @@ require (
124124

125125
// replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go v1.8.9-0.20230828134416-f0db33dd9344
126126

127-
// replace github.com/jfrog/jfrog-cli-core/v2 => github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20230828140932-e44caa02288e
127+
replace github.com/jfrog/jfrog-cli-core/v2 => github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20230830130857-c5a2b11b52be
128128

129129
// replace github.com/jfrog/gofrog => github.com/jfrog/gofrog v1.2.6-0.20230418122323-2bf299dd6d27
130130

131-
// replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20230803140217-0a5f43783ae8
131+
replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20230830130057-df2d2a80b555

go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -241,10 +241,10 @@ github.com/jfrog/build-info-go v1.9.9 h1:YMA9okHawBNL8SrCWzqULSf5M4W+YnWyUhmkWSj
241241
github.com/jfrog/build-info-go v1.9.9/go.mod h1:t31QRpH5xUJKw8XkQlAA+Aq7aanyS1rrzpcK8xSNVts=
242242
github.com/jfrog/gofrog v1.3.0 h1:o4zgsBZE4QyDbz2M7D4K6fXPTBJht+8lE87mS9bw7Gk=
243243
github.com/jfrog/gofrog v1.3.0/go.mod h1:IFMc+V/yf7rA5WZ74CSbXe+Lgf0iApEQLxRZVzKRUR0=
244-
github.com/jfrog/jfrog-cli-core/v2 v2.41.4 h1:+V35NN+UaKl6ZFSjAyZFZ4VijCgsORnGsHug02DROdE=
245-
github.com/jfrog/jfrog-cli-core/v2 v2.41.4/go.mod h1:Mi3WFUzG2CU6tlLpGsMNRaKkhH/tIMuci4tjnPZ9S3M=
246-
github.com/jfrog/jfrog-client-go v1.31.6 h1:uWuyT4BDm9s5ES6oDTBny9Gl6yf8iKFjcbmHSHQZrDc=
247-
github.com/jfrog/jfrog-client-go v1.31.6/go.mod h1:icb00ZJN/mMMNkQduHDkzpqsXH9Flwi3f3COYexq3Nc=
244+
github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20230830130857-c5a2b11b52be h1:MjbSKQy937o0WFBKCXtvkX4EUSPCaA1LIhGISJUjYbU=
245+
github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20230830130857-c5a2b11b52be/go.mod h1:kaFzB3X83/jdzMcuGOYOaqnlz5MVTnDYt/asrOsCv18=
246+
github.com/jfrog/jfrog-client-go v1.28.1-0.20230830130057-df2d2a80b555 h1:yaF5J4LNk+ws5+j+BFMJ43NMqpKuCtF7dUfCeGLttl8=
247+
github.com/jfrog/jfrog-client-go v1.28.1-0.20230830130057-df2d2a80b555/go.mod h1:icb00ZJN/mMMNkQduHDkzpqsXH9Flwi3f3COYexq3Nc=
248248
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
249249
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
250250
github.com/jszwec/csvutil v1.8.0 h1:G7vS2LGdpZZDH1HmHeNbxOaJ/ZnJlpwGFvOkTkJzzNk=

lifecycle/cli.go

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ import (
88
coreConfig "github.com/jfrog/jfrog-cli-core/v2/utils/config"
99
"github.com/jfrog/jfrog-cli/docs/common"
1010
rbCreate "github.com/jfrog/jfrog-cli/docs/lifecycle/create"
11+
rbDistribute "github.com/jfrog/jfrog-cli/docs/lifecycle/distribute"
1112
rbPromote "github.com/jfrog/jfrog-cli/docs/lifecycle/promote"
1213
"github.com/jfrog/jfrog-cli/utils/cliutils"
14+
"github.com/jfrog/jfrog-cli/utils/distribution"
1315
"github.com/jfrog/jfrog-client-go/utils"
1416
"github.com/jfrog/jfrog-client-go/utils/errorutils"
1517
"github.com/urfave/cli"
@@ -43,6 +45,19 @@ func GetCommands() []cli.Command {
4345
Category: lcCategory,
4446
Action: promote,
4547
},
48+
{
49+
Name: "release-bundle-distribute",
50+
Aliases: []string{"rbd"},
51+
Flags: cliutils.GetCommandFlags(cliutils.ReleaseBundleDistribute),
52+
Usage: rbDistribute.GetDescription(),
53+
HelpName: coreCommon.CreateUsage("rbd", rbDistribute.GetDescription(), rbDistribute.Usage),
54+
UsageText: rbDistribute.GetArguments(),
55+
ArgsUsage: common.CreateEnvVars(),
56+
BashComplete: coreCommon.CreateBashCompletionFunc(),
57+
Category: lcCategory,
58+
Hidden: true,
59+
Action: distribute,
60+
},
4661
})
4762
}
4863

@@ -77,7 +92,7 @@ func create(c *cli.Context) (err error) {
7792
return
7893
}
7994

80-
createCmd := lifecycle.NewReleaseBundleCreate().SetServerDetails(lcDetails).SetReleaseBundleName(c.Args().Get(0)).
95+
createCmd := lifecycle.NewReleaseBundleCreateCommand().SetServerDetails(lcDetails).SetReleaseBundleName(c.Args().Get(0)).
8196
SetReleaseBundleVersion(c.Args().Get(1)).SetSigningKeyName(c.String(cliutils.SigningKey)).SetSync(c.Bool(cliutils.Sync)).
8297
SetReleaseBundleProject(cliutils.GetProject(c)).SetBuildsSpecPath(c.String(cliutils.Builds)).
8398
SetReleaseBundlesSpecPath(c.String(cliutils.ReleaseBundles))
@@ -102,12 +117,51 @@ func promote(c *cli.Context) error {
102117
return err
103118
}
104119

105-
createCmd := lifecycle.NewReleaseBundlePromote().SetServerDetails(lcDetails).SetReleaseBundleName(c.Args().Get(0)).
120+
createCmd := lifecycle.NewReleaseBundlePromoteCommand().SetServerDetails(lcDetails).SetReleaseBundleName(c.Args().Get(0)).
106121
SetReleaseBundleVersion(c.Args().Get(1)).SetEnvironment(c.Args().Get(2)).SetSigningKeyName(c.String(cliutils.SigningKey)).
107122
SetSync(c.Bool(cliutils.Sync)).SetReleaseBundleProject(cliutils.GetProject(c)).SetOverwrite(c.Bool(cliutils.Overwrite))
108123
return commands.Exec(createCmd)
109124
}
110125

126+
func distribute(c *cli.Context) error {
127+
if err := validateDistributeCommand(c); err != nil {
128+
return err
129+
}
130+
131+
lcDetails, err := createLifecycleDetailsByFlags(c)
132+
if err != nil {
133+
return err
134+
}
135+
distributionRules, _, params, err := distribution.InitReleaseBundleDistributeCmd(c)
136+
if err != nil {
137+
return err
138+
}
139+
140+
distributeCmd := lifecycle.NewReleaseBundleDistributeCommand()
141+
distributeCmd.SetServerDetails(lcDetails).
142+
SetDistributeBundleParams(params).
143+
SetDistributionRules(distributionRules).
144+
SetDryRun(c.Bool("dry-run")).
145+
SetAutoCreateRepo(c.Bool(cliutils.CreateRepo)).
146+
SetPathMappingPattern(c.String(cliutils.PathMappingPattern)).
147+
SetPathMappingTarget(c.String(cliutils.PathMappingTarget))
148+
return commands.Exec(distributeCmd)
149+
}
150+
151+
func validateDistributeCommand(c *cli.Context) error {
152+
if err := distribution.ValidateReleaseBundleDistributeCmd(c); err != nil {
153+
return err
154+
}
155+
156+
mappingPatternProvided := c.IsSet(cliutils.PathMappingPattern)
157+
mappingTargetProvided := c.IsSet(cliutils.PathMappingTarget)
158+
if (mappingPatternProvided && !mappingTargetProvided) ||
159+
(!mappingPatternProvided && mappingTargetProvided) {
160+
return errorutils.CheckErrorf("the options --%s and --%s must be provided together", cliutils.PathMappingPattern, cliutils.PathMappingTarget)
161+
}
162+
return nil
163+
}
164+
111165
func assertSigningKeyProvided(c *cli.Context) error {
112166
if c.String(cliutils.SigningKey) == "" {
113167
return errorutils.CheckErrorf("the --%s option is mandatory", cliutils.SigningKey)

0 commit comments

Comments
 (0)