-
Notifications
You must be signed in to change notification settings - Fork 36
Migrate life cycle commands #47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 7 commits
35180c8
69240b2
8a1e2a1
534189e
5e0d5ba
8b914cf
7b48300
3e6cbd4
a51dc30
2508544
d3b697b
25dd80b
905d9ad
0706bc4
47e44b1
573092e
7561558
49271c4
581055a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| package cmddefs | ||
|
|
||
| const ( | ||
| // Distribution V1 Commands | ||
| ReleaseBundleV1Create = "release-bundle-v1-create" | ||
| ReleaseBundleV1Update = "release-bundle-v1-update" | ||
| ReleaseBundleV1Sign = "release-bundle-v1-sign" | ||
| ReleaseBundleV1Distribute = "release-bundle-v1-distribute" | ||
| ReleaseBundleV1Delete = "release-bundle-v1-delete" | ||
|
|
||
| // Lifecycle Commands | ||
| ReleaseBundleCreate = "release-bundle-create" | ||
| ReleaseBundlePromote = "release-bundle-promote" | ||
| ReleaseBundleDistribute = "release-bundle-distribute" | ||
| ReleaseBundleDeleteLocal = "release-bundle-delete-local" | ||
| ReleaseBundleDeleteRemote = "release-bundle-delete-remote" | ||
| ReleaseBundleExport = "release-bundle-export" | ||
| ReleaseBundleImport = "release-bundle-import" | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| package distribution | ||
|
|
||
| import ( | ||
| "github.com/jfrog/jfrog-cli-core/v2/common/spec" | ||
| pluginsCommon "github.com/jfrog/jfrog-cli-core/v2/plugins/common" | ||
| "github.com/jfrog/jfrog-cli-core/v2/plugins/components" | ||
| distributionUtils "github.com/jfrog/jfrog-client-go/utils/distribution" | ||
| ) | ||
|
|
||
| func CreateDefaultDistributionRules(c *components.Context) *spec.DistributionRules { | ||
| return &spec.DistributionRules{ | ||
| DistributionRules: []spec.DistributionRule{{ | ||
| SiteName: c.GetStringFlagValue("site"), | ||
| CityName: c.GetStringFlagValue("city"), | ||
| CountryCodes: pluginsCommon.GetStringsArrFlagValue(c, "country-codes"), | ||
| }}, | ||
| } | ||
| } | ||
|
|
||
| func ValidateReleaseBundleDistributeCmd(c *components.Context) error { | ||
| if len(c.Arguments) != 2 { | ||
| return pluginsCommon.WrongNumberOfArgumentsHandler(c) | ||
| } | ||
| if c.IsFlagSet("max-wait-minutes") && !c.IsFlagSet("sync") { | ||
| return pluginsCommon.PrintHelpAndReturnError("The --max-wait-minutes option can't be used without --sync", c) | ||
| } | ||
|
|
||
| if c.IsFlagSet("dist-rules") && (c.IsFlagSet("site") || c.IsFlagSet("city") || c.IsFlagSet("country-code")) { | ||
| return pluginsCommon.PrintHelpAndReturnError("The --dist-rules option can't be used with --site, --city or --country-code", c) | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| func InitReleaseBundleDistributeCmd(c *components.Context) (distributionRules *spec.DistributionRules, maxWaitMinutes int, params distributionUtils.DistributionParams, err error) { | ||
| if c.IsFlagSet("dist-rules") { | ||
| distributionRules, err = spec.CreateDistributionRulesFromFile(c.GetStringFlagValue("dist-rules")) | ||
| if err != nil { | ||
| return | ||
| } | ||
| } else { | ||
| distributionRules = CreateDefaultDistributionRules(c) | ||
| } | ||
|
|
||
| maxWaitMinutes, err = c.GetDefaultIntFlagValueIfNotSet("max-wait-minutes", 60) | ||
| if err != nil { | ||
| return | ||
| } | ||
|
|
||
| params = distributionUtils.NewDistributeReleaseBundleParams(c.Arguments[0], c.Arguments[1]) | ||
| return | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,201 @@ | ||
| package flagkit | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since this is only used by distribution / lifecycle commands, I suggest placing it under a non common package.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In addition, please remove all unused flags from jfrog-cli
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it is only used distribution, lifecycle since we have moved only those 2 categories for now, all command flags including artifactory or any other types if moved in future can be placed here hence the common package. Removed unused flags from |
||
|
|
||
| import ( | ||
| "github.com/jfrog/jfrog-cli-artifactory/cliutils/cmddefs" | ||
| pluginsCommon "github.com/jfrog/jfrog-cli-core/v2/plugins/common" | ||
| "github.com/jfrog/jfrog-cli-core/v2/plugins/components" | ||
| "strconv" | ||
| ) | ||
|
|
||
| const ( | ||
| distUrl = "dist-url" | ||
| DownloadMinSplitKb = 5120 | ||
| DownloadSplitCount = 3 | ||
|
|
||
| // Unique release-bundle-* v1 flags | ||
| releaseBundleV1Prefix = "rbv1-" | ||
| rbDryRun = releaseBundleV1Prefix + dryRun | ||
| rbRepo = releaseBundleV1Prefix + repo | ||
| rbPassphrase = releaseBundleV1Prefix + passphrase | ||
| distTarget = releaseBundleV1Prefix + target | ||
| rbDetailedSummary = releaseBundleV1Prefix + detailedSummary | ||
| sign = "sign" | ||
| desc = "desc" | ||
| releaseNotesPath = "release-notes-path" | ||
| releaseNotesSyntax = "release-notes-syntax" | ||
| deleteFromDist = "delete-from-dist" | ||
|
|
||
| // Common release-bundle-* v1&v2 flags | ||
| DistRules = "dist-rules" | ||
| site = "site" | ||
| city = "city" | ||
| countryCodes = "country-codes" | ||
| sync = "sync" | ||
| maxWaitMinutes = "max-wait-minutes" | ||
| CreateRepo = "create-repo" | ||
|
|
||
| // Base flags | ||
| platformUrl = "platform-url" | ||
| user = "user" | ||
| password = "password" | ||
| accessToken = "access-token" | ||
| serverId = "server-id" | ||
| url = "url" | ||
|
|
||
| // Client certification flags | ||
| InsecureTls = "insecure-tls" | ||
|
|
||
| // Spec flags | ||
| specFlag = "spec" | ||
| specVars = "spec-vars" | ||
|
|
||
| // Generic commands flags | ||
| exclusions = "exclusions" | ||
| dryRun = "dry-run" | ||
| targetProps = "target-props" | ||
| quiet = "quiet" | ||
| detailedSummary = "detailed-summary" | ||
| deletePrefix = "delete-" | ||
| deleteQuiet = deletePrefix + quiet | ||
| repo = "repo" | ||
| target = "target" | ||
| name = "name" | ||
| passphrase = "passphrase" | ||
| Project = "project" | ||
| IncludeRepos = "include-repos" | ||
| ExcludeRepos = "exclude-repos" | ||
|
|
||
| // Unique lifecycle flags | ||
| Sync = "sync" | ||
| lifecyclePrefix = "lc-" | ||
| lcSync = lifecyclePrefix + Sync | ||
| lcProject = lifecyclePrefix + Project | ||
| Builds = "builds" | ||
| lcBuilds = lifecyclePrefix + Builds | ||
| ReleaseBundles = "release-bundles" | ||
| lcReleaseBundles = lifecyclePrefix + ReleaseBundles | ||
| SigningKey = "signing-key" | ||
| lcSigningKey = lifecyclePrefix + SigningKey | ||
| PathMappingPattern = "mapping-pattern" | ||
| lcPathMappingPattern = lifecyclePrefix + PathMappingPattern | ||
| PathMappingTarget = "mapping-target" | ||
| lcPathMappingTarget = lifecyclePrefix + PathMappingTarget | ||
| lcDryRun = lifecyclePrefix + dryRun | ||
| lcIncludeRepos = lifecyclePrefix + IncludeRepos | ||
| lcExcludeRepos = lifecyclePrefix + ExcludeRepos | ||
| setupRepo = repo | ||
|
|
||
| // Build Info flags | ||
| BuildName = "build-name" | ||
| BuildNumber = "build-number" | ||
|
|
||
| // Unique Download Flags | ||
| downloadPrefix = "download-" | ||
| downloadMinSplit = downloadPrefix + MinSplit | ||
| downloadSplitCount = downloadPrefix + SplitCount | ||
|
|
||
| // Generic Command Flags | ||
| MinSplit = "min-split" | ||
| SplitCount = "split-count" | ||
| ) | ||
|
|
||
| var commandFlags = map[string][]string{ | ||
| cmddefs.ReleaseBundleV1Create: { | ||
| distUrl, user, password, accessToken, serverId, specFlag, specVars, targetProps, | ||
| rbDryRun, sign, desc, exclusions, releaseNotesPath, releaseNotesSyntax, rbPassphrase, rbRepo, InsecureTls, distTarget, rbDetailedSummary, | ||
| }, | ||
| cmddefs.ReleaseBundleV1Update: { | ||
| distUrl, user, password, accessToken, serverId, specFlag, specVars, targetProps, | ||
| rbDryRun, sign, desc, exclusions, releaseNotesPath, releaseNotesSyntax, rbPassphrase, rbRepo, InsecureTls, distTarget, rbDetailedSummary, | ||
| }, | ||
| cmddefs.ReleaseBundleV1Sign: { | ||
| distUrl, user, password, accessToken, serverId, rbPassphrase, rbRepo, | ||
| InsecureTls, rbDetailedSummary, | ||
| }, | ||
| cmddefs.ReleaseBundleV1Distribute: { | ||
| distUrl, user, password, accessToken, serverId, rbDryRun, DistRules, | ||
| site, city, countryCodes, sync, maxWaitMinutes, InsecureTls, CreateRepo, | ||
| }, | ||
| cmddefs.ReleaseBundleV1Delete: { | ||
| distUrl, user, password, accessToken, serverId, rbDryRun, DistRules, | ||
| site, city, countryCodes, sync, maxWaitMinutes, InsecureTls, deleteFromDist, deleteQuiet, | ||
| }, | ||
| cmddefs.ReleaseBundleCreate: { | ||
| platformUrl, user, password, accessToken, serverId, lcSigningKey, lcSync, lcProject, lcBuilds, lcReleaseBundles, | ||
| specFlag, specVars, BuildName, BuildNumber, | ||
| }, | ||
| cmddefs.ReleaseBundlePromote: { | ||
| platformUrl, user, password, accessToken, serverId, lcSigningKey, lcSync, lcProject, lcIncludeRepos, lcExcludeRepos, | ||
| }, | ||
| cmddefs.ReleaseBundleDistribute: { | ||
| platformUrl, user, password, accessToken, serverId, lcProject, DistRules, site, city, countryCodes, | ||
| lcDryRun, CreateRepo, lcPathMappingPattern, lcPathMappingTarget, lcSync, maxWaitMinutes, | ||
| }, | ||
| cmddefs.ReleaseBundleDeleteLocal: { | ||
| platformUrl, user, password, accessToken, serverId, deleteQuiet, lcSync, lcProject, | ||
| }, | ||
| cmddefs.ReleaseBundleDeleteRemote: { | ||
| platformUrl, user, password, accessToken, serverId, deleteQuiet, lcDryRun, DistRules, site, city, countryCodes, | ||
| lcSync, maxWaitMinutes, lcProject, | ||
| }, | ||
| cmddefs.ReleaseBundleExport: { | ||
| platformUrl, user, password, accessToken, serverId, lcPathMappingTarget, lcPathMappingPattern, Project, | ||
| downloadMinSplit, downloadSplitCount, | ||
| }, | ||
| cmddefs.ReleaseBundleImport: { | ||
| user, password, accessToken, serverId, platformUrl, | ||
| }, | ||
| } | ||
|
|
||
| var flagsMap = map[string]components.Flag{ | ||
| distUrl: components.NewStringFlag(url, "JFrog Distribution URL. (example: https://acme.jfrog.io/distribution)", components.SetMandatoryFalse()), | ||
| user: components.NewStringFlag(user, "JFrog username.", components.SetMandatoryFalse()), | ||
| password: components.NewStringFlag(password, "JFrog password.", components.SetMandatoryFalse()), | ||
| accessToken: components.NewStringFlag(accessToken, "JFrog access token.", components.SetMandatoryFalse()), | ||
| serverId: components.NewStringFlag(serverId, "Server ID configured using the 'jf config' command.", components.SetMandatoryFalse()), | ||
| specFlag: components.NewStringFlag(specFlag, "Path to a File Spec.", components.SetMandatoryFalse()), | ||
| specVars: components.NewStringFlag(specVars, "List of semicolon-separated(;) variables in the form of \"key1=value1;key2=value2;...\" to be replaced in the File Spec.", components.SetMandatoryFalse()), | ||
| targetProps: components.NewStringFlag(targetProps, "List of semicolon-separated(;) properties, in the form of \"key1=value1;key2=value2;...\" to be added to the artifacts after distribution of the release bundle.", components.SetMandatoryFalse()), | ||
| rbDryRun: components.NewBoolFlag(dryRun, "Set to true to disable communication with JFrog Distribution.", components.WithBoolDefaultValueFalse()), | ||
| sign: components.NewBoolFlag(sign, "If set to true, automatically signs the release bundle version.", components.WithBoolDefaultValueFalse()), | ||
| desc: components.NewStringFlag(desc, "Description of the release bundle.", components.SetMandatoryFalse()), | ||
| exclusions: components.NewStringFlag(exclusions, "List of semicolon-separated(;) exclusions. Exclusions can include the * and the ? wildcards.", components.SetMandatoryFalse()), | ||
| releaseNotesPath: components.NewStringFlag(releaseNotesPath, "Path to a file describes the release notes for the release bundle version.", components.SetMandatoryFalse()), | ||
| releaseNotesSyntax: components.NewStringFlag(releaseNotesSyntax, "The syntax for the release notes. Can be one of 'markdown', 'asciidoc', or 'plain_text.", components.SetMandatoryFalse()), | ||
| rbPassphrase: components.NewStringFlag(passphrase, "The passphrase for the signing key.", components.SetMandatoryFalse()), | ||
| rbRepo: components.NewStringFlag(repo, "A repository name at source Artifactory to store release bundle artifacts in. If not provided, Artifactory will use the default one.", components.SetMandatoryFalse()), | ||
| InsecureTls: components.NewBoolFlag(InsecureTls, "Set to true to skip TLS certificates verification.", components.WithBoolDefaultValueFalse()), | ||
| distTarget: components.NewStringFlag(target, "The target path for distributed artifacts on the edge node.", components.SetMandatoryFalse()), | ||
| rbDetailedSummary: components.NewBoolFlag(detailedSummary, "Set to true to get a command summary with details about the release bundle artifact.", components.WithBoolDefaultValueFalse()), | ||
| DistRules: components.NewStringFlag(DistRules, "Path to distribution rules.", components.SetMandatoryFalse()), | ||
| site: components.NewStringFlag(site, "Wildcard filter for site name.", components.SetMandatoryFalse()), | ||
| city: components.NewStringFlag(city, "Wildcard filter for site city name.", components.SetMandatoryFalse()), | ||
| countryCodes: components.NewStringFlag(countryCodes, "List of semicolon-separated(;) wildcard filters for site country codes.", components.SetMandatoryFalse()), | ||
| sync: components.NewBoolFlag(sync, "Set to true to enable sync distribution (the command execution will end when the distribution process ends).", components.WithBoolDefaultValueFalse()), | ||
| maxWaitMinutes: components.NewStringFlag(maxWaitMinutes, "Max minutes to wait for sync distribution.", components.WithStrDefaultValue("60")), | ||
| deleteFromDist: components.NewBoolFlag(deleteFromDist, "Set to true to delete release bundle version in JFrog Distribution itself after deletion is complete.", components.WithBoolDefaultValueFalse()), | ||
| deleteQuiet: components.NewBoolFlag(quiet, "Set to true to skip the delete confirmation message.", components.WithBoolDefaultValueFalse()), | ||
| CreateRepo: components.NewBoolFlag(CreateRepo, "Set to true to create the repository on the edge if it does not exist.", components.WithBoolDefaultValueFalse()), | ||
| lcSync: components.NewBoolFlag(Sync, "Set to false to run asynchronously.", components.WithBoolDefaultValueTrue()), | ||
| lcProject: components.NewStringFlag(Project, "Project key associated with the Release Bundle version.", components.SetMandatoryFalse()), | ||
| lcBuilds: components.NewStringFlag(Builds, "Path to a JSON file containing information of the source builds from which to create a release bundle.", components.WithHiddenTrue(), components.SetMandatoryFalse()), | ||
| lcReleaseBundles: components.NewStringFlag(ReleaseBundles, "Path to a JSON file containing information of the source release bundles from which to create a release bundle.", components.WithHiddenTrue(), components.SetMandatoryFalse()), | ||
| lcSigningKey: components.NewStringFlag(SigningKey, "The GPG/RSA key-pair name given in Artifactory. If the key isn't provided, the command creates or uses the default key.", components.SetMandatoryFalse()), | ||
| lcPathMappingPattern: components.NewStringFlag(PathMappingPattern, "Specify along with "+PathMappingTarget+" to distribute artifacts to a different path on the edge node. You can use wildcards to specify multiple artifacts.", components.SetMandatoryFalse()), | ||
| lcPathMappingTarget: components.NewStringFlag(PathMappingTarget, "The target path for distributed artifacts on the edge node. If not specified, the artifacts will have the same path and name on the edge node, as on the source Artifactory server. "+ | ||
| "For flexibility in specifying the distribution path, you can include placeholders in the form of {1}, {2} which are replaced by corresponding tokens in the pattern path that are enclosed in parenthesis.` `", components.SetMandatoryFalse()), | ||
| lcDryRun: components.NewBoolFlag(dryRun, "Set to true to only simulate the distribution of the release bundle.", components.WithBoolDefaultValueFalse()), | ||
| lcIncludeRepos: components.NewStringFlag(IncludeRepos, "List of semicolon-separated(;) repositories to include in the promotion. If this property is left undefined, all repositories (except those specifically excluded) are included in the promotion. "+ | ||
| "If one or more repositories are specifically included, all other repositories are excluded.` `", components.SetMandatoryFalse()), | ||
| lcExcludeRepos: components.NewStringFlag(ExcludeRepos, "List of semicolon-separated(;) repositories to exclude from the promotion.` `", components.SetMandatoryFalse()), | ||
| platformUrl: components.NewStringFlag(url, "JFrog platform URL. (example: https://acme.jfrog.io)` `", components.SetMandatoryFalse()), | ||
| downloadMinSplit: components.NewStringFlag(MinSplit, "[Default: "+strconv.Itoa(DownloadMinSplitKb)+"] Minimum file size in KB to split into ranges when downloading. Set to -1 for no splits.` `"), | ||
| downloadSplitCount: components.NewStringFlag(SplitCount, "[Default: "+strconv.Itoa(DownloadSplitCount)+"] Number of parts to split a file when downloading. Set to 0 for no splits.` `"), | ||
| Project: components.NewStringFlag(Project, "JFrog Artifactory project key.` `", components.SetMandatoryFalse()), | ||
| BuildName: components.NewStringFlag(BuildName, "Providing this option will collect and record build info for this build name. Build number option is mandatory when this option is provided.` `", components.SetMandatoryFalse()), | ||
| BuildNumber: components.NewStringFlag(BuildNumber, "Providing this option will collect and record build info for this build number. Build name option is mandatory when this option is provided.` `", components.SetMandatoryFalse()), | ||
| } | ||
|
|
||
| func GetCommandFlags(cmdKey string) []components.Flag { | ||
| return pluginsCommon.GetCommandFlags(cmdKey, commandFlags, flagsMap) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| package flagkit | ||
|
|
||
| import ( | ||
| "testing" | ||
|
|
||
| "github.com/stretchr/testify/assert" | ||
| ) | ||
|
|
||
| func TestCommandFlags(t *testing.T) { | ||
| for cmdKey, flags := range commandFlags { | ||
| t.Run(cmdKey, func(t *testing.T) { | ||
| assert.Equal(t, len(flags), len(commandFlags[cmdKey]), "Number of flags mismatch for command: %s", cmdKey) | ||
|
|
||
| for _, flag := range flags { | ||
| _, exists := flagsMap[flag] | ||
| if !exists { | ||
| t.Logf("Flag %s not found in flagsMap for command: %s", flag, cmdKey) | ||
| } | ||
| assert.True(t, exists, "Flag %s not found in flagsMap for command: %s", flag, cmdKey) | ||
| } | ||
| }) | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.