github.com/jfrog/jfrog-cli-core/v2@v2.51.0/artifactory/commands/repository/template.go (about)

     1  package repository
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  	"os"
     8  	"strings"
     9  
    10  	"github.com/c-bata/go-prompt"
    11  	"github.com/jfrog/jfrog-cli-core/v2/artifactory/commands/utils"
    12  	"github.com/jfrog/jfrog-cli-core/v2/utils/config"
    13  	"github.com/jfrog/jfrog-cli-core/v2/utils/ioutils"
    14  	"github.com/jfrog/jfrog-client-go/utils/errorutils"
    15  	"github.com/jfrog/jfrog-client-go/utils/log"
    16  )
    17  
    18  type RepoTemplateCommand struct {
    19  	path string
    20  }
    21  
    22  const (
    23  	// Strings for prompt questions
    24  	SelectConfigKeyMsg = "Select the next configuration key" + ioutils.PressTabMsg
    25  
    26  	TemplateType = "templateType"
    27  	Create       = "create"
    28  	Update       = "update"
    29  
    30  	MandatoryUrl = "mandatoryUrl"
    31  
    32  	// Common repository configuration JSON keys
    33  	Key             = "key"
    34  	Rclass          = "rclass"
    35  	PackageType     = "packageType"
    36  	Description     = "description"
    37  	Notes           = "notes"
    38  	IncludePatterns = "includesPattern"
    39  	ExcludePatterns = "excludesPattern"
    40  	RepoLayoutRef   = "repoLayoutRef"
    41  	ProjectKey      = "projectKey"
    42  	Environment     = "environment"
    43  
    44  	// Mutual local and remote repository configuration JSON keys
    45  	HandleReleases               = "handleReleases"
    46  	HandleSnapshots              = "handleSnapshots"
    47  	MaxUniqueSnapshots           = "maxUniqueSnapshots"
    48  	SuppressPomConsistencyChecks = "suppressPomConsistencyChecks"
    49  	BlackedOut                   = "blackedOut"
    50  	XrayIndex                    = "xrayIndex"
    51  	PropertySets                 = "propertySets"
    52  	DownloadRedirect             = "downloadRedirect"
    53  	BlockPushingSchema1          = "blockPushingSchema1"
    54  
    55  	// Mutual local and virtual repository configuration JSON keys
    56  	DebianTrivialLayout             = "debianTrivialLayout"
    57  	OptionalIndexCompressionFormats = "optionalIndexCompressionFormats"
    58  	PrimaryKeyPairRef               = "primaryKeyPairRef"
    59  
    60  	// Mutual remote and virtual repository configuration JSON keys
    61  	ExternalDependenciesEnabled  = "externalDependenciesEnabled"
    62  	ExternalDependenciesPatterns = "externalDependenciesPatterns"
    63  
    64  	// Unique local repository configuration JSON keys
    65  	ChecksumPolicyType       = "checksumPolicyType"
    66  	MaxUniqueTags            = "maxUniqueTags"
    67  	SnapshotVersionBehavior  = "snapshotVersionBehavior"
    68  	ArchiveBrowsingEnabled   = "archiveBrowsingEnabled"
    69  	CalculateYumMetadata     = "calculateYumMetadata"
    70  	YumRootDepth             = "yumRootDepth"
    71  	DockerApiVersion         = "dockerApiVersion"
    72  	EnableFileListsIndexing  = "enableFileListsIndexing"
    73  	ForceNugetAuthentication = "forceNugetAuthentication"
    74  
    75  	// Unique remote repository configuration JSON keys
    76  	Url                               = "url"
    77  	Username                          = "username"
    78  	Password                          = "password"
    79  	Proxy                             = "proxy"
    80  	RemoteRepoChecksumPolicyType      = "remoteRepoChecksumPolicyType"
    81  	HardFail                          = "hardFail"
    82  	Offline                           = "offline"
    83  	StoreArtifactsLocally             = "storeArtifactsLocally"
    84  	SocketTimeoutMillis               = "socketTimeoutMillis"
    85  	LocalAddress                      = "localAddress"
    86  	RetrievalCachePeriodSecs          = "retrievalCachePeriodSecs"
    87  	FailedRetrievalCachePeriodSecs    = "failedRetrievalCachePeriodSecs"
    88  	MissedRetrievalCachePeriodSecs    = "missedRetrievalCachePeriodSecs"
    89  	UnusedArtifactsCleanupEnabled     = "unusedArtifactsCleanupEnabled"
    90  	UnusedArtifactsCleanupPeriodHours = "unusedArtifactsCleanupPeriodHours"
    91  	AssumedOfflinePeriodSecs          = "assumedOfflinePeriodSecs"
    92  	FetchJarsEagerly                  = "fetchJarsEagerly"
    93  	FetchSourcesEagerly               = "fetchSourcesEagerly"
    94  	RejectInvalidJars                 = "rejectInvalidJars"
    95  	ShareConfiguration                = "shareConfiguration"
    96  	SynchronizeProperties             = "synchronizeProperties"
    97  	BlockMismatchingMimeTypes         = "blockMismatchingMimeTypes"
    98  	AllowAnyHostAuth                  = "allowAnyHostAuth"
    99  	EnableCookieManagement            = "enableCookieManagement"
   100  	BowerRegistryUrl                  = "bowerRegistryUrl"
   101  	ComposerRegistryUrl               = "composerRegistryUrl"
   102  	PyPIRegistryUrl                   = "pyPIRegistryUrl"
   103  	VcsType                           = "vcsType"
   104  	VcsGitProvider                    = "vcsGitProvider"
   105  	VcsGitDownloadUrl                 = "vcsGitDownloadUrl"
   106  	BypassHeadRequests                = "bypassHeadRequests"
   107  	ClientTlsCertificate              = "clientTlsCertificate"
   108  	FeedContextPath                   = "feedContextPath"
   109  	DownloadContextPath               = "downloadContextPath"
   110  	V3FeedUrl                         = "v3FeedUrl"
   111  	ContentSynchronisation            = "contentSynchronisation"
   112  	ListRemoteFolderItems             = "listRemoteFolderItems"
   113  	EnableTokenAuthentication         = "enableTokenAuthentication"
   114  	PodsSpecsRepoUrl                  = "podsSpecsRepoUrl"
   115  
   116  	// Unique virtual repository configuration JSON keys
   117  	Repositories                                  = "repositories"
   118  	ArtifactoryRequestsCanRetrieveRemoteArtifacts = "artifactoryRequestsCanRetrieveRemoteArtifacts"
   119  	KeyPair                                       = "keyPair"
   120  	PomRepositoryReferencesCleanupPolicy          = "pomRepositoryReferencesCleanupPolicy"
   121  	DefaultDeploymentRepo                         = "defaultDeploymentRepo"
   122  	ForceMavenAuthentication                      = "forceMavenAuthentication"
   123  	ExternalDependenciesRemoteRepo                = "externalDependenciesRemoteRepo"
   124  
   125  	// rclasses
   126  	Local     = "local"
   127  	Remote    = "remote"
   128  	Virtual   = "virtual"
   129  	Federated = "federated"
   130  
   131  	// PackageTypes
   132  	Generic   = "generic"
   133  	Maven     = "maven"
   134  	Gradle    = "gradle"
   135  	Ivy       = "ivy"
   136  	Sbt       = "sbt"
   137  	Helm      = "helm"
   138  	Cocoapods = "cocoapods"
   139  	Opkg      = "opkg"
   140  	Rpm       = "rpm"
   141  	Nuget     = "nuget"
   142  	Cran      = "cran"
   143  	Gems      = "gems"
   144  	Npm       = "npm"
   145  	Bower     = "bower"
   146  	Debian    = "debian"
   147  	Composer  = "composer"
   148  	Pypi      = "pypi"
   149  	Docker    = "docker"
   150  	Vagrant   = "vagrant"
   151  	Gitlfs    = "gitlfs"
   152  	Go        = "go"
   153  	Yum       = "yum"
   154  	Conan     = "conan"
   155  	Chef      = "chef"
   156  	Puppet    = "puppet"
   157  	Vcs       = "vcs"
   158  	Alpine    = "alpine"
   159  	Conda     = "conda"
   160  	P2        = "p2"
   161  	Swift     = "swift"
   162  	Terraform = "terraform"
   163  	Cargo     = "cargo"
   164  
   165  	// Repo layout Refs
   166  	BowerDefaultRepoLayout    = "bower-default"
   167  	buildDefaultRepoLayout    = "build-default"
   168  	ComposerDefaultRepoLayout = "composer-default"
   169  	ConanDefaultRepoLayout    = "conan-default"
   170  	GoDefaultRepoLayout       = "go-default"
   171  	GradleDefaultRepoLayout   = "maven-2-default"
   172  	IvyDefaultRepoLayout      = "ivy-default"
   173  	Maven1DefaultRepoLayout   = "maven-1-default"
   174  	Maven2DefaultRepoLayout   = "maven-2-default"
   175  	NpmDefaultRepoLayout      = "npm-default"
   176  	NugetDefaultRepoLayout    = "nuget-default"
   177  	puppetDefaultRepoLayout   = "puppet-default"
   178  	SbtDefaultRepoLayout      = "sbt-default"
   179  	SimpleDefaultRepoLayout   = "simple-default"
   180  	VcsDefaultRepoLayout      = "vcs-default"
   181  
   182  	// Checksum Policies
   183  	ClientChecksumPolicy           = "client-checksums"
   184  	ServerGeneratedChecksumsPolicy = "server-generated-checksums"
   185  
   186  	// Snapshot version behaviors
   187  	UniqueBehavior    = "unique"
   188  	NonUniqueBehavior = "non-unique"
   189  	DeployerBehavior  = "deployer"
   190  
   191  	// Optional index compression formats
   192  	Bz2Compression  = "bz2"
   193  	LzmaCompression = "lzma"
   194  	XzCompression   = "xz"
   195  
   196  	// Docker api versions
   197  	DockerApiV1 = "V1"
   198  	DockerApiV2 = "V2"
   199  
   200  	// Remote repo checksum policies
   201  	GenerateIfAbsentPolicy  = "generate-if-absent"
   202  	FailPolicy              = "fail"
   203  	IgnoreAndGeneratePolicy = "ignore-and-generate"
   204  	PassThruPolicy          = "pass-thru"
   205  
   206  	// Vcs Types
   207  	Git = "GIT"
   208  
   209  	// Vcs git provider
   210  	GithubVcsProvider      = "GITHUB"
   211  	BitbucketVcsProvider   = "BITBUCKET"
   212  	OldstashVcsProvider    = "OLDSTASH"
   213  	StashVcsProvider       = "STASH"
   214  	ArtifactoryVcsProvider = "ARTIFACTORY"
   215  	CustomVcsProvider      = "CUSTOM"
   216  
   217  	// POM repository references cleanup policies
   218  	DiscardActiveRefrencePolicy = "discard_active_reference"
   219  	DiscardAnyReferencePolicy   = "discard_any_reference"
   220  	NothingPolicy               = "nothing"
   221  )
   222  
   223  var optionalSuggestsMap = map[string]prompt.Suggest{
   224  	ioutils.SaveAndExit:               {Text: ioutils.SaveAndExit},
   225  	Description:                       {Text: Description},
   226  	Notes:                             {Text: Notes},
   227  	IncludePatterns:                   {Text: IncludePatterns},
   228  	ExcludePatterns:                   {Text: ExcludePatterns},
   229  	RepoLayoutRef:                     {Text: RepoLayoutRef},
   230  	ProjectKey:                        {Text: ProjectKey},
   231  	Environment:                       {Text: Environment},
   232  	HandleReleases:                    {Text: HandleReleases},
   233  	HandleSnapshots:                   {Text: HandleSnapshots},
   234  	MaxUniqueSnapshots:                {Text: MaxUniqueSnapshots},
   235  	SuppressPomConsistencyChecks:      {Text: SuppressPomConsistencyChecks},
   236  	BlackedOut:                        {Text: BlackedOut},
   237  	DownloadRedirect:                  {Text: DownloadRedirect},
   238  	BlockPushingSchema1:               {Text: BlockPushingSchema1},
   239  	DebianTrivialLayout:               {Text: DebianTrivialLayout},
   240  	ExternalDependenciesEnabled:       {Text: ExternalDependenciesEnabled},
   241  	ExternalDependenciesPatterns:      {Text: ExternalDependenciesPatterns},
   242  	ChecksumPolicyType:                {Text: ChecksumPolicyType},
   243  	MaxUniqueTags:                     {Text: MaxUniqueTags},
   244  	SnapshotVersionBehavior:           {Text: SnapshotVersionBehavior},
   245  	XrayIndex:                         {Text: XrayIndex},
   246  	PropertySets:                      {Text: PropertySets},
   247  	ArchiveBrowsingEnabled:            {Text: ArchiveBrowsingEnabled},
   248  	CalculateYumMetadata:              {Text: CalculateYumMetadata},
   249  	YumRootDepth:                      {Text: YumRootDepth},
   250  	DockerApiVersion:                  {Text: DockerApiVersion},
   251  	EnableFileListsIndexing:           {Text: EnableFileListsIndexing},
   252  	OptionalIndexCompressionFormats:   {Text: OptionalIndexCompressionFormats},
   253  	Url:                               {Text: Url},
   254  	Username:                          {Text: Username},
   255  	Password:                          {Text: Password},
   256  	Proxy:                             {Text: Proxy},
   257  	PrimaryKeyPairRef:                 {Text: PrimaryKeyPairRef},
   258  	RemoteRepoChecksumPolicyType:      {Text: RemoteRepoChecksumPolicyType},
   259  	HardFail:                          {Text: HardFail},
   260  	Offline:                           {Text: Offline},
   261  	StoreArtifactsLocally:             {Text: StoreArtifactsLocally},
   262  	SocketTimeoutMillis:               {Text: SocketTimeoutMillis},
   263  	LocalAddress:                      {Text: LocalAddress},
   264  	RetrievalCachePeriodSecs:          {Text: RetrievalCachePeriodSecs},
   265  	FailedRetrievalCachePeriodSecs:    {Text: FailedRetrievalCachePeriodSecs},
   266  	MissedRetrievalCachePeriodSecs:    {Text: MissedRetrievalCachePeriodSecs},
   267  	UnusedArtifactsCleanupEnabled:     {Text: UnusedArtifactsCleanupEnabled},
   268  	UnusedArtifactsCleanupPeriodHours: {Text: UnusedArtifactsCleanupPeriodHours},
   269  	AssumedOfflinePeriodSecs:          {Text: AssumedOfflinePeriodSecs},
   270  	FetchJarsEagerly:                  {Text: FetchJarsEagerly},
   271  	FetchSourcesEagerly:               {Text: FetchSourcesEagerly},
   272  	RejectInvalidJars:                 {Text: RejectInvalidJars},
   273  	ShareConfiguration:                {Text: ShareConfiguration},
   274  	SynchronizeProperties:             {Text: SynchronizeProperties},
   275  	BlockMismatchingMimeTypes:         {Text: BlockMismatchingMimeTypes},
   276  	AllowAnyHostAuth:                  {Text: AllowAnyHostAuth},
   277  	EnableCookieManagement:            {Text: EnableCookieManagement},
   278  	BowerRegistryUrl:                  {Text: BowerRegistryUrl},
   279  	ComposerRegistryUrl:               {Text: ComposerRegistryUrl},
   280  	PyPIRegistryUrl:                   {Text: PyPIRegistryUrl},
   281  	VcsType:                           {Text: VcsType},
   282  	VcsGitProvider:                    {Text: VcsGitProvider},
   283  	VcsGitDownloadUrl:                 {Text: VcsGitDownloadUrl},
   284  	BypassHeadRequests:                {Text: BypassHeadRequests},
   285  	ClientTlsCertificate:              {Text: ClientTlsCertificate},
   286  	FeedContextPath:                   {Text: FeedContextPath},
   287  	DownloadContextPath:               {Text: DownloadContextPath},
   288  	V3FeedUrl:                         {Text: V3FeedUrl},
   289  	ContentSynchronisation:            {Text: ContentSynchronisation},
   290  	ListRemoteFolderItems:             {Text: ListRemoteFolderItems},
   291  	PodsSpecsRepoUrl:                  {Text: PodsSpecsRepoUrl},
   292  	EnableTokenAuthentication:         {Text: EnableTokenAuthentication},
   293  	Repositories:                      {Text: Repositories},
   294  	ArtifactoryRequestsCanRetrieveRemoteArtifacts: {Text: ArtifactoryRequestsCanRetrieveRemoteArtifacts},
   295  	KeyPair:                              {Text: KeyPair},
   296  	PomRepositoryReferencesCleanupPolicy: {Text: PomRepositoryReferencesCleanupPolicy},
   297  	DefaultDeploymentRepo:                {Text: DefaultDeploymentRepo},
   298  	ForceMavenAuthentication:             {Text: ForceMavenAuthentication},
   299  	ForceNugetAuthentication:             {Text: ForceNugetAuthentication},
   300  	ExternalDependenciesRemoteRepo:       {Text: ExternalDependenciesRemoteRepo},
   301  }
   302  
   303  var baseLocalRepoConfKeys = []string{
   304  	Description, Notes, IncludePatterns, ExcludePatterns, RepoLayoutRef, ProjectKey, Environment, BlackedOut, XrayIndex,
   305  	PropertySets, ArchiveBrowsingEnabled, OptionalIndexCompressionFormats, DownloadRedirect, BlockPushingSchema1,
   306  }
   307  
   308  var mavenGradleLocalRepoConfKeys = []string{
   309  	MaxUniqueSnapshots, HandleReleases, HandleSnapshots, SuppressPomConsistencyChecks, SnapshotVersionBehavior, ChecksumPolicyType,
   310  }
   311  
   312  var rpmLocalRepoConfKeys = []string{
   313  	YumRootDepth, CalculateYumMetadata, EnableFileListsIndexing, PrimaryKeyPairRef,
   314  }
   315  
   316  var nugetLocalRepoConfKeys = []string{
   317  	MaxUniqueSnapshots, ForceNugetAuthentication,
   318  }
   319  
   320  var debianLocalRepoConfKeys = []string{
   321  	DebianTrivialLayout, PrimaryKeyPairRef,
   322  }
   323  
   324  var dockerLocalRepoConfKeys = []string{
   325  	DockerApiVersion, MaxUniqueTags,
   326  }
   327  
   328  var baseRemoteRepoConfKeys = []string{
   329  	Username, Password, Proxy, Description, Notes, IncludePatterns, ExcludePatterns, RepoLayoutRef, ProjectKey, Environment, HardFail, Offline,
   330  	BlackedOut, XrayIndex, StoreArtifactsLocally, SocketTimeoutMillis, LocalAddress, RetrievalCachePeriodSecs, FailedRetrievalCachePeriodSecs,
   331  	MissedRetrievalCachePeriodSecs, UnusedArtifactsCleanupEnabled, UnusedArtifactsCleanupPeriodHours, AssumedOfflinePeriodSecs,
   332  	ShareConfiguration, SynchronizeProperties, BlockMismatchingMimeTypes, PropertySets, AllowAnyHostAuth, EnableCookieManagement,
   333  	BypassHeadRequests, ClientTlsCertificate, DownloadRedirect, BlockPushingSchema1, ContentSynchronisation,
   334  }
   335  
   336  var mavenGradleRemoteRepoConfKeys = []string{
   337  	FetchJarsEagerly, FetchSourcesEagerly, RemoteRepoChecksumPolicyType, HandleReleases, HandleSnapshots,
   338  	SuppressPomConsistencyChecks, RejectInvalidJars,
   339  }
   340  
   341  var cocoapodsRemoteRepoConfKeys = []string{
   342  	PodsSpecsRepoUrl,
   343  }
   344  
   345  var opkgRemoteRepoConfKeys = []string{
   346  	ListRemoteFolderItems,
   347  }
   348  
   349  var rpmRemoteRepoConfKeys = []string{
   350  	ListRemoteFolderItems,
   351  }
   352  
   353  var nugetRemoteRepoConfKeys = []string{
   354  	FeedContextPath, DownloadContextPath, V3FeedUrl, ForceNugetAuthentication,
   355  }
   356  
   357  var gemsRemoteRepoConfKeys = []string{
   358  	ListRemoteFolderItems,
   359  }
   360  
   361  var npmRemoteRepoConfKeys = []string{
   362  	ListRemoteFolderItems,
   363  }
   364  
   365  var bowerRemoteRepoConfKeys = []string{
   366  	BowerRegistryUrl,
   367  }
   368  
   369  var debianRemoteRepoConfKeys = []string{
   370  	ListRemoteFolderItems,
   371  }
   372  
   373  var composerRemoteRepoConfKeys = []string{
   374  	ComposerRegistryUrl,
   375  }
   376  
   377  var pypiRemoteRepoConfKeys = []string{
   378  	PyPIRegistryUrl, ListRemoteFolderItems,
   379  }
   380  
   381  var dockerRemoteRepoConfKeys = []string{
   382  	ExternalDependenciesEnabled, ExternalDependenciesPatterns, EnableTokenAuthentication,
   383  }
   384  
   385  var gitlfsRemoteRepoConfKeys = []string{
   386  	ListRemoteFolderItems,
   387  }
   388  
   389  var vcsRemoteRepoConfKeys = []string{
   390  	VcsGitProvider, VcsType, MaxUniqueSnapshots, VcsGitDownloadUrl, ListRemoteFolderItems,
   391  }
   392  
   393  var baseVirtualRepoConfKeys = []string{
   394  	Repositories, Description, Notes, IncludePatterns, ExcludePatterns, RepoLayoutRef, ProjectKey, Environment, ArtifactoryRequestsCanRetrieveRemoteArtifacts,
   395  	DefaultDeploymentRepo, OptionalIndexCompressionFormats, PrimaryKeyPairRef,
   396  }
   397  
   398  var mavenGradleVirtualRepoConfKeys = []string{
   399  	ForceMavenAuthentication, PomRepositoryReferencesCleanupPolicy, KeyPair,
   400  }
   401  
   402  var nugetVirtualRepoConfKeys = []string{
   403  	ForceNugetAuthentication,
   404  }
   405  
   406  var npmVirtualRepoConfKeys = []string{
   407  	ExternalDependenciesEnabled, ExternalDependenciesPatterns, ExternalDependenciesRemoteRepo,
   408  }
   409  
   410  var bowerVirtualRepoConfKeys = []string{
   411  	ExternalDependenciesEnabled, ExternalDependenciesPatterns, ExternalDependenciesRemoteRepo,
   412  }
   413  
   414  var debianVirtualRepoConfKeys = []string{
   415  	DebianTrivialLayout,
   416  }
   417  
   418  var goVirtualRepoConfKeys = []string{
   419  	ExternalDependenciesEnabled, ExternalDependenciesPatterns,
   420  }
   421  
   422  var commonPkgTypes = []string{
   423  	Maven, Gradle, Ivy, Sbt, Helm, Rpm, Nuget, Cran, Gems, Npm, Bower, Debian, Pypi, Docker, Gitlfs, Go, Conan,
   424  	Chef, Puppet, Alpine, Generic,
   425  }
   426  
   427  var localRepoAdditionalPkgTypes = []string{
   428  	Cocoapods, Opkg, Composer, Vagrant, Yum,
   429  }
   430  
   431  var remoteRepoAdditionalPkgTypes = []string{
   432  	Cocoapods, Opkg, Composer, Conda, P2, Vcs, Yum,
   433  }
   434  
   435  var virtualRepoAdditionalPkgTypes = []string{
   436  	Conda, P2, Yum,
   437  }
   438  
   439  var federatedRepoAdditionalPkgTypes = []string{
   440  	Vagrant, Opkg, Conda, Composer, Cocoapods,
   441  }
   442  
   443  var pkgTypeSuggestsMap = map[string]prompt.Suggest{
   444  	Generic:   {Text: Generic},
   445  	Maven:     {Text: Maven},
   446  	Gradle:    {Text: Gradle},
   447  	Ivy:       {Text: Ivy},
   448  	Sbt:       {Text: Sbt},
   449  	Helm:      {Text: Helm},
   450  	Cocoapods: {Text: Cocoapods},
   451  	Opkg:      {Text: Opkg},
   452  	Rpm:       {Text: Rpm},
   453  	Nuget:     {Text: Nuget},
   454  	Cran:      {Text: Cran},
   455  	Gems:      {Text: Gems},
   456  	Npm:       {Text: Npm},
   457  	Bower:     {Text: Bower},
   458  	Debian:    {Text: Debian},
   459  	Composer:  {Text: Composer},
   460  	Pypi:      {Text: Pypi},
   461  	Docker:    {Text: Docker},
   462  	Vagrant:   {Text: Vagrant},
   463  	Gitlfs:    {Text: Gitlfs},
   464  	Go:        {Text: Go},
   465  	Yum:       {Text: Yum},
   466  	Conan:     {Text: Conan},
   467  	Chef:      {Text: Chef},
   468  	Puppet:    {Text: Puppet},
   469  	Vcs:       {Text: Vcs},
   470  	Conda:     {Text: Conda},
   471  	P2:        {Text: P2},
   472  	Alpine:    {Text: Alpine},
   473  }
   474  
   475  func NewRepoTemplateCommand() *RepoTemplateCommand {
   476  	return &RepoTemplateCommand{}
   477  }
   478  
   479  func (rtc *RepoTemplateCommand) SetTemplatePath(path string) *RepoTemplateCommand {
   480  	rtc.path = path
   481  	return rtc
   482  }
   483  
   484  func (rtc *RepoTemplateCommand) ServerDetails() (*config.ServerDetails, error) {
   485  	// Since it's a local command, usage won't be reported.
   486  	return nil, nil
   487  }
   488  
   489  func (rtc *RepoTemplateCommand) Run() (err error) {
   490  	err = utils.ValidateTemplatePath(rtc.path)
   491  	if err != nil {
   492  		return
   493  	}
   494  	repoTemplateQuestionnaire := &ioutils.InteractiveQuestionnaire{
   495  		MandatoryQuestionsKeys: []string{TemplateType, Key, Rclass},
   496  		QuestionsMap:           questionMap,
   497  	}
   498  	err = repoTemplateQuestionnaire.Perform()
   499  	if err != nil {
   500  		return err
   501  	}
   502  	resBytes, err := json.Marshal(repoTemplateQuestionnaire.AnswersMap)
   503  	if err != nil {
   504  		return errorutils.CheckError(err)
   505  	}
   506  	if err = os.WriteFile(rtc.path, resBytes, 0644); err != nil {
   507  		return errorutils.CheckError(err)
   508  	}
   509  	log.Info(fmt.Sprintf("Repository configuration template successfully created at %s.", rtc.path))
   510  
   511  	return nil
   512  }
   513  
   514  func (rtc *RepoTemplateCommand) CommandName() string {
   515  	return "rt_repo_template"
   516  }
   517  
   518  func rclassCallback(iq *ioutils.InteractiveQuestionnaire, rclass string) (string, error) {
   519  	var pkgTypes = commonPkgTypes
   520  	switch rclass {
   521  	case Remote:
   522  		// For create template url is mandatory, for update we will allow url as an optional key
   523  		if _, ok := iq.AnswersMap[TemplateType]; !ok {
   524  			return "", errors.New("package type is missing in configuration map")
   525  		}
   526  		if iq.AnswersMap[TemplateType] == Create {
   527  			_, err := iq.AskQuestion(iq.QuestionsMap[MandatoryUrl])
   528  			if err != nil {
   529  				return "", err
   530  			}
   531  		}
   532  		pkgTypes = append(pkgTypes, remoteRepoAdditionalPkgTypes...)
   533  	case Local:
   534  		pkgTypes = append(pkgTypes, localRepoAdditionalPkgTypes...)
   535  	case Virtual:
   536  		pkgTypes = append(pkgTypes, virtualRepoAdditionalPkgTypes...)
   537  	case Federated:
   538  		pkgTypes = append(pkgTypes, federatedRepoAdditionalPkgTypes...)
   539  	default:
   540  		return "", errors.New("unsupported rclass")
   541  	}
   542  	// PackageType is also mandatory. Since the possible types depend on which rcalss was chosen, we ask the question here.
   543  	var pkgTypeQuestion = ioutils.QuestionInfo{
   544  		Options:      ioutils.GetSuggestsFromKeys(pkgTypes, pkgTypeSuggestsMap),
   545  		Msg:          "",
   546  		PromptPrefix: "Select the repository's package type" + ioutils.PressTabMsg,
   547  		AllowVars:    false,
   548  		Writer:       ioutils.WriteStringAnswer,
   549  		MapKey:       PackageType,
   550  		Callback:     pkgTypeCallback,
   551  	}
   552  	return iq.AskQuestion(pkgTypeQuestion)
   553  }
   554  
   555  func pkgTypeCallback(iq *ioutils.InteractiveQuestionnaire, pkgType string) (string, error) {
   556  	// Each combination of (rclass,packageType) has its own optional configuration keys.
   557  	// We set the questionnaire's optionalKeys suggests according to the selected combination.
   558  	if _, ok := iq.AnswersMap[Rclass]; !ok {
   559  		return "", errors.New("rclass is missing in configuration map")
   560  	}
   561  	switch iq.AnswersMap[Rclass] {
   562  	case Local:
   563  		iq.OptionalKeysSuggests = getLocalRepoConfKeys(pkgType)
   564  	case Remote:
   565  		// For update template we need to allow url as an optional key
   566  		if _, ok := iq.AnswersMap[TemplateType]; !ok {
   567  			return "", errors.New("package type is missing in configuration map")
   568  		}
   569  		iq.OptionalKeysSuggests = getRemoteRepoConfKeys(pkgType, fmt.Sprint(iq.AnswersMap[TemplateType]))
   570  	case Virtual:
   571  		iq.OptionalKeysSuggests = getVirtualRepoConfKeys(pkgType)
   572  	case Federated:
   573  		iq.OptionalKeysSuggests = getLocalRepoConfKeys(pkgType)
   574  	default:
   575  		return "", errors.New("unsupported rclass was configured")
   576  	}
   577  	// We don't need the templateType value in the final configuration
   578  	delete(iq.AnswersMap, TemplateType)
   579  	return "", nil
   580  }
   581  
   582  // Repo key must have a prefix of "<projectKey>-". This callback adds the prefix to the repo key if it is missing.
   583  func projectKeyCallback(iq *ioutils.InteractiveQuestionnaire, projectKey string) (string, error) {
   584  	if _, ok := iq.AnswersMap[Key]; !ok {
   585  		return "", errorutils.CheckErrorf("repository key is missing in configuration map")
   586  	}
   587  	requiredProjectPrefix := projectKey + "-"
   588  	currentRepoKey, ok := iq.AnswersMap[Key].(string)
   589  	if !ok {
   590  		return "", errorutils.CheckErrorf("template syntax error: the value for the repository key is not a string type")
   591  	}
   592  
   593  	if !strings.HasPrefix(currentRepoKey, requiredProjectPrefix) {
   594  		newRepoKey := requiredProjectPrefix + currentRepoKey
   595  		log.Info("Repository key should start with the projectKey followed by a dash. Modifying repo key to: '" + newRepoKey + "'.")
   596  		iq.AnswersMap[Key] = newRepoKey
   597  	}
   598  	return "", nil
   599  }
   600  
   601  func getLocalRepoConfKeys(pkgType string) []prompt.Suggest {
   602  	optionalKeys := []string{ioutils.SaveAndExit}
   603  	optionalKeys = append(optionalKeys, baseLocalRepoConfKeys...)
   604  	switch pkgType {
   605  	case Maven, Gradle:
   606  		optionalKeys = append(optionalKeys, mavenGradleLocalRepoConfKeys...)
   607  	case Rpm:
   608  		optionalKeys = append(optionalKeys, rpmLocalRepoConfKeys...)
   609  	case Nuget:
   610  		optionalKeys = append(optionalKeys, nugetLocalRepoConfKeys...)
   611  	case Debian:
   612  		optionalKeys = append(optionalKeys, debianLocalRepoConfKeys...)
   613  	case Docker:
   614  		optionalKeys = append(optionalKeys, dockerLocalRepoConfKeys...)
   615  	}
   616  	return ioutils.GetSuggestsFromKeys(optionalKeys, optionalSuggestsMap)
   617  }
   618  
   619  func getRemoteRepoConfKeys(pkgType, templateType string) []prompt.Suggest {
   620  	optionalKeys := []string{ioutils.SaveAndExit}
   621  	if templateType == Update {
   622  		optionalKeys = append(optionalKeys, Url)
   623  	}
   624  	optionalKeys = append(optionalKeys, baseRemoteRepoConfKeys...)
   625  	switch pkgType {
   626  	case Maven, Gradle:
   627  		optionalKeys = append(optionalKeys, mavenGradleRemoteRepoConfKeys...)
   628  	case Cocoapods:
   629  		optionalKeys = append(optionalKeys, cocoapodsRemoteRepoConfKeys...)
   630  	case Opkg:
   631  		optionalKeys = append(optionalKeys, opkgRemoteRepoConfKeys...)
   632  	case Rpm:
   633  		optionalKeys = append(optionalKeys, rpmRemoteRepoConfKeys...)
   634  	case Nuget:
   635  		optionalKeys = append(optionalKeys, nugetRemoteRepoConfKeys...)
   636  	case Gems:
   637  		optionalKeys = append(optionalKeys, gemsRemoteRepoConfKeys...)
   638  	case Npm:
   639  		optionalKeys = append(optionalKeys, npmRemoteRepoConfKeys...)
   640  	case Bower:
   641  		optionalKeys = append(optionalKeys, bowerRemoteRepoConfKeys...)
   642  	case Debian:
   643  		optionalKeys = append(optionalKeys, debianRemoteRepoConfKeys...)
   644  	case Composer:
   645  		optionalKeys = append(optionalKeys, composerRemoteRepoConfKeys...)
   646  	case Pypi:
   647  		optionalKeys = append(optionalKeys, pypiRemoteRepoConfKeys...)
   648  	case Docker:
   649  		optionalKeys = append(optionalKeys, dockerRemoteRepoConfKeys...)
   650  	case Gitlfs:
   651  		optionalKeys = append(optionalKeys, gitlfsRemoteRepoConfKeys...)
   652  	case Vcs:
   653  		optionalKeys = append(optionalKeys, vcsRemoteRepoConfKeys...)
   654  	}
   655  	return ioutils.GetSuggestsFromKeys(optionalKeys, optionalSuggestsMap)
   656  }
   657  
   658  func getVirtualRepoConfKeys(pkgType string) []prompt.Suggest {
   659  	optionalKeys := []string{ioutils.SaveAndExit}
   660  	optionalKeys = append(optionalKeys, baseVirtualRepoConfKeys...)
   661  	switch pkgType {
   662  	case Maven, Gradle:
   663  		optionalKeys = append(optionalKeys, mavenGradleVirtualRepoConfKeys...)
   664  	case Nuget:
   665  		optionalKeys = append(optionalKeys, nugetVirtualRepoConfKeys...)
   666  	case Npm:
   667  		optionalKeys = append(optionalKeys, npmVirtualRepoConfKeys...)
   668  	case Bower:
   669  		optionalKeys = append(optionalKeys, bowerVirtualRepoConfKeys...)
   670  	case Debian:
   671  		optionalKeys = append(optionalKeys, debianVirtualRepoConfKeys...)
   672  	case Go:
   673  		optionalKeys = append(optionalKeys, goVirtualRepoConfKeys...)
   674  	}
   675  	return ioutils.GetSuggestsFromKeys(optionalKeys, optionalSuggestsMap)
   676  }
   677  
   678  func contentSynchronisationCallBack(iq *ioutils.InteractiveQuestionnaire, answer string) (value string, err error) {
   679  	// contentSynchronisation has an object value with 4 bool fields.
   680  	// We ask for the rest of the values and writes the values in comma separated list.
   681  	if err != nil {
   682  		return "", nil
   683  	}
   684  	answer += "," + ioutils.AskFromList("", "Insert the value for statistic.enable >", false, ioutils.GetBoolSuggests(), "")
   685  	// cs.Statistics.Enabled, err = strconv.ParseBool(enabled)
   686  	if err != nil {
   687  		return "", nil
   688  	}
   689  	answer += "," + ioutils.AskFromList("", "Insert the value for properties.enable >", false, ioutils.GetBoolSuggests(), "")
   690  	// cs.Properties.Enabled, err = strconv.ParseBool(enabled)
   691  	if err != nil {
   692  		return "", nil
   693  	}
   694  	answer += "," + ioutils.AskFromList("", "Insert the value for source.originAbsenceDetection >", false, ioutils.GetBoolSuggests(), "")
   695  	// cs.Source.OriginAbsenceDetection, err = strconv.ParseBool(enabled)
   696  	if err != nil {
   697  		return "", nil
   698  	}
   699  	iq.AnswersMap[ContentSynchronisation] = answer
   700  	return "", nil
   701  }
   702  
   703  // Specific writers for repo templates, since all the values in the templates should be written as string
   704  var BoolToStringQuestionInfo = ioutils.QuestionInfo{
   705  	Options:   ioutils.GetBoolSuggests(),
   706  	AllowVars: true,
   707  	Writer:    ioutils.WriteStringAnswer,
   708  }
   709  
   710  var IntToStringQuestionInfo = ioutils.QuestionInfo{
   711  	Options:   nil,
   712  	AllowVars: true,
   713  	Writer:    ioutils.WriteStringAnswer,
   714  }
   715  
   716  var StringListToStringQuestionInfo = ioutils.QuestionInfo{
   717  	Msg:       ioutils.CommaSeparatedListMsg,
   718  	Options:   nil,
   719  	AllowVars: true,
   720  	Writer:    ioutils.WriteStringAnswer,
   721  }
   722  
   723  var questionMap = map[string]ioutils.QuestionInfo{
   724  	TemplateType: {
   725  		Options: []prompt.Suggest{
   726  			{Text: Create, Description: "Template for creating a new repository"},
   727  			{Text: Update, Description: "Template for updating an existing repository"},
   728  		},
   729  		Msg:          "",
   730  		PromptPrefix: "Select the template type" + ioutils.PressTabMsg,
   731  		AllowVars:    false,
   732  		Writer:       ioutils.WriteStringAnswer,
   733  		MapKey:       TemplateType,
   734  		Callback:     nil,
   735  	},
   736  	ioutils.OptionalKey: {
   737  		Msg:          "",
   738  		PromptPrefix: SelectConfigKeyMsg,
   739  		AllowVars:    false,
   740  		Writer:       nil,
   741  		MapKey:       "",
   742  		Callback:     ioutils.OptionalKeyCallback,
   743  	},
   744  	Key: {
   745  		Msg:          "",
   746  		PromptPrefix: "Insert the repository key >",
   747  		AllowVars:    true,
   748  		Writer:       ioutils.WriteStringAnswer,
   749  		MapKey:       Key,
   750  		Callback:     nil,
   751  	},
   752  	Rclass: {
   753  		Options: []prompt.Suggest{
   754  			{Text: Local, Description: "A physical, locally-managed repository into which you can deploy artifacts"},
   755  			{Text: Remote, Description: "A caching proxy for a repository managed at a remote URL"},
   756  			{Text: Virtual, Description: "An Aggregation of several repositories with the same package type under a common URL."},
   757  			{Text: Federated, Description: "A Federation is a collection of repositories of Federated type in different JPDs that are automatically configured for full bi-directional mirroring."},
   758  		},
   759  		Msg:          "",
   760  		PromptPrefix: "Select the repository class" + ioutils.PressTabMsg,
   761  		AllowVars:    false,
   762  		Writer:       ioutils.WriteStringAnswer,
   763  		MapKey:       Rclass,
   764  		Callback:     rclassCallback,
   765  	},
   766  	MandatoryUrl: {
   767  		Msg:          "",
   768  		PromptPrefix: "Insert the remote repository URL >",
   769  		AllowVars:    true,
   770  		Writer:       ioutils.WriteStringAnswer,
   771  		MapKey:       Url,
   772  		Callback:     nil,
   773  	},
   774  	Url:             ioutils.FreeStringQuestionInfo,
   775  	Description:     ioutils.FreeStringQuestionInfo,
   776  	Notes:           ioutils.FreeStringQuestionInfo,
   777  	IncludePatterns: StringListToStringQuestionInfo,
   778  	ExcludePatterns: StringListToStringQuestionInfo,
   779  	RepoLayoutRef: {
   780  		Options: []prompt.Suggest{
   781  			{Text: BowerDefaultRepoLayout},
   782  			{Text: buildDefaultRepoLayout},
   783  			{Text: ComposerDefaultRepoLayout},
   784  			{Text: ConanDefaultRepoLayout},
   785  			{Text: GoDefaultRepoLayout},
   786  			{Text: GradleDefaultRepoLayout},
   787  			{Text: IvyDefaultRepoLayout},
   788  			{Text: Maven1DefaultRepoLayout},
   789  			{Text: Maven2DefaultRepoLayout},
   790  			{Text: NpmDefaultRepoLayout},
   791  			{Text: NugetDefaultRepoLayout},
   792  			{Text: puppetDefaultRepoLayout},
   793  			{Text: SbtDefaultRepoLayout},
   794  			{Text: SimpleDefaultRepoLayout},
   795  			{Text: VcsDefaultRepoLayout},
   796  		},
   797  		AllowVars: true,
   798  		Writer:    ioutils.WriteStringAnswer,
   799  	},
   800  	ProjectKey: {
   801  		Options:   nil,
   802  		AllowVars: false,
   803  		Writer:    ioutils.WriteStringAnswer,
   804  		Callback:  projectKeyCallback,
   805  	},
   806  	Environment: {
   807  		PromptPrefix: "Insert the name of the environment to assign to >",
   808  		AllowVars:    true,
   809  		MapKey:       environmentsKey,
   810  		Writer:       ioutils.WriteStringAnswer,
   811  	},
   812  	HandleReleases:               BoolToStringQuestionInfo,
   813  	HandleSnapshots:              BoolToStringQuestionInfo,
   814  	MaxUniqueSnapshots:           IntToStringQuestionInfo,
   815  	SuppressPomConsistencyChecks: BoolToStringQuestionInfo,
   816  	BlackedOut:                   BoolToStringQuestionInfo,
   817  	DownloadRedirect:             BoolToStringQuestionInfo,
   818  	BlockPushingSchema1:          BoolToStringQuestionInfo,
   819  	DebianTrivialLayout:          BoolToStringQuestionInfo,
   820  	ExternalDependenciesEnabled:  BoolToStringQuestionInfo,
   821  	ExternalDependenciesPatterns: StringListToStringQuestionInfo,
   822  	ChecksumPolicyType: {
   823  		Options: []prompt.Suggest{
   824  			{Text: ClientChecksumPolicy},
   825  			{Text: ServerGeneratedChecksumsPolicy},
   826  		},
   827  		AllowVars: true,
   828  		Writer:    ioutils.WriteStringAnswer,
   829  	},
   830  	MaxUniqueTags: IntToStringQuestionInfo,
   831  	SnapshotVersionBehavior: {
   832  		Options: []prompt.Suggest{
   833  			{Text: UniqueBehavior},
   834  			{Text: NonUniqueBehavior},
   835  			{Text: DeployerBehavior},
   836  		},
   837  		AllowVars: true,
   838  		Writer:    ioutils.WriteStringAnswer,
   839  	},
   840  	XrayIndex:              BoolToStringQuestionInfo,
   841  	PropertySets:           StringListToStringQuestionInfo,
   842  	ArchiveBrowsingEnabled: BoolToStringQuestionInfo,
   843  	CalculateYumMetadata:   BoolToStringQuestionInfo,
   844  	YumRootDepth:           IntToStringQuestionInfo,
   845  	DockerApiVersion: {
   846  		Options: []prompt.Suggest{
   847  			{Text: DockerApiV1},
   848  			{Text: DockerApiV2},
   849  		},
   850  		AllowVars: true,
   851  		Writer:    ioutils.WriteStringAnswer,
   852  	},
   853  	EnableFileListsIndexing: BoolToStringQuestionInfo,
   854  	OptionalIndexCompressionFormats: {
   855  		Msg:       "Enter a comma separated list of values from " + strings.Join([]string{Bz2Compression, LzmaCompression, XzCompression}, ","),
   856  		Options:   nil,
   857  		AllowVars: true,
   858  		Writer:    ioutils.WriteStringAnswer,
   859  	},
   860  	PrimaryKeyPairRef: ioutils.FreeStringQuestionInfo,
   861  	Username:          ioutils.FreeStringQuestionInfo,
   862  	Password:          ioutils.FreeStringQuestionInfo,
   863  	Proxy:             ioutils.FreeStringQuestionInfo,
   864  	RemoteRepoChecksumPolicyType: {
   865  		Options: []prompt.Suggest{
   866  			{Text: GenerateIfAbsentPolicy},
   867  			{Text: FailPolicy},
   868  			{Text: IgnoreAndGeneratePolicy},
   869  			{Text: PassThruPolicy},
   870  		},
   871  		AllowVars: true,
   872  		Writer:    ioutils.WriteStringAnswer,
   873  	},
   874  	HardFail:                          BoolToStringQuestionInfo,
   875  	Offline:                           BoolToStringQuestionInfo,
   876  	StoreArtifactsLocally:             BoolToStringQuestionInfo,
   877  	SocketTimeoutMillis:               IntToStringQuestionInfo,
   878  	LocalAddress:                      ioutils.FreeStringQuestionInfo,
   879  	RetrievalCachePeriodSecs:          IntToStringQuestionInfo,
   880  	FailedRetrievalCachePeriodSecs:    IntToStringQuestionInfo,
   881  	MissedRetrievalCachePeriodSecs:    IntToStringQuestionInfo,
   882  	UnusedArtifactsCleanupEnabled:     BoolToStringQuestionInfo,
   883  	UnusedArtifactsCleanupPeriodHours: IntToStringQuestionInfo,
   884  	AssumedOfflinePeriodSecs:          IntToStringQuestionInfo,
   885  	FetchJarsEagerly:                  BoolToStringQuestionInfo,
   886  	FetchSourcesEagerly:               BoolToStringQuestionInfo,
   887  	RejectInvalidJars:                 BoolToStringQuestionInfo,
   888  	ShareConfiguration:                BoolToStringQuestionInfo,
   889  	SynchronizeProperties:             BoolToStringQuestionInfo,
   890  	BlockMismatchingMimeTypes:         BoolToStringQuestionInfo,
   891  	AllowAnyHostAuth:                  BoolToStringQuestionInfo,
   892  	EnableCookieManagement:            BoolToStringQuestionInfo,
   893  	BowerRegistryUrl:                  ioutils.FreeStringQuestionInfo,
   894  	ComposerRegistryUrl:               ioutils.FreeStringQuestionInfo,
   895  	PyPIRegistryUrl:                   ioutils.FreeStringQuestionInfo,
   896  	VcsType: {
   897  		Options: []prompt.Suggest{
   898  			{Text: Git},
   899  		},
   900  		AllowVars: true,
   901  		Writer:    ioutils.WriteStringAnswer,
   902  	},
   903  	VcsGitProvider: {
   904  		Options: []prompt.Suggest{
   905  			{Text: GithubVcsProvider},
   906  			{Text: BitbucketVcsProvider},
   907  			{Text: OldstashVcsProvider},
   908  			{Text: StashVcsProvider},
   909  			{Text: ArtifactoryVcsProvider},
   910  			{Text: CustomVcsProvider},
   911  		},
   912  		AllowVars: true,
   913  		Writer:    ioutils.WriteStringAnswer,
   914  	},
   915  	VcsGitDownloadUrl:         ioutils.FreeStringQuestionInfo,
   916  	BypassHeadRequests:        BoolToStringQuestionInfo,
   917  	ClientTlsCertificate:      ioutils.FreeStringQuestionInfo,
   918  	FeedContextPath:           ioutils.FreeStringQuestionInfo,
   919  	DownloadContextPath:       ioutils.FreeStringQuestionInfo,
   920  	V3FeedUrl:                 ioutils.FreeStringQuestionInfo,
   921  	ListRemoteFolderItems:     BoolToStringQuestionInfo,
   922  	EnableTokenAuthentication: BoolToStringQuestionInfo,
   923  	PodsSpecsRepoUrl:          ioutils.FreeStringQuestionInfo,
   924  	ContentSynchronisation: {
   925  		Options:   ioutils.GetBoolSuggests(),
   926  		AllowVars: true,
   927  		Writer:    nil,
   928  		Callback:  contentSynchronisationCallBack,
   929  	},
   930  	Repositories: StringListToStringQuestionInfo,
   931  	ArtifactoryRequestsCanRetrieveRemoteArtifacts: BoolToStringQuestionInfo,
   932  	KeyPair: ioutils.FreeStringQuestionInfo,
   933  	PomRepositoryReferencesCleanupPolicy: {
   934  		Options: []prompt.Suggest{
   935  			{Text: DiscardActiveRefrencePolicy},
   936  			{Text: DiscardAnyReferencePolicy},
   937  			{Text: NothingPolicy},
   938  		},
   939  		AllowVars: true,
   940  		Writer:    ioutils.WriteStringAnswer,
   941  	},
   942  	DefaultDeploymentRepo:          ioutils.FreeStringQuestionInfo,
   943  	ForceMavenAuthentication:       BoolToStringQuestionInfo,
   944  	ForceNugetAuthentication:       BoolToStringQuestionInfo,
   945  	ExternalDependenciesRemoteRepo: ioutils.FreeStringQuestionInfo,
   946  }