diff --git a/src/code/PublishPSResource.cs b/src/code/PublishPSResource.cs index 2854da350..752255eae 100644 --- a/src/code/PublishPSResource.cs +++ b/src/code/PublishPSResource.cs @@ -236,6 +236,7 @@ protected override void EndProcessing() try { Utils.ValidateModuleManifest(resourceFilePath, out errorMsgs); + } finally { if (errorMsgs.Length > 0) @@ -884,17 +885,9 @@ private bool CheckDependenciesExist(Hashtable dependencies, string repositoryNam FindHelper findHelper = new FindHelper(_cancellationToken, this); bool depPrerelease = depVersion.Contains("-"); - var foundDependencies = findHelper.FindByResourceName( - name: depName, - type: ResourceType.Module, - version: depVersion, - prerelease: depPrerelease, - tag: null, - repository: new[] { repositoryName }, - credential: Credential, - includeDependencies: false); - - if (foundDependencies.Count is 0) + var repository = new[] { repositoryName }; + var dependencyFound = findHelper.FindByResourceName(depName, ResourceType.Module, depVersion, depPrerelease, null, repository, Credential, false); + if (dependencyFound == null || !dependencyFound.Any()) { var message = String.Format("Dependency '{0}' was not found in repository '{1}'. Make sure the dependency is published to the repository before publishing this module.", dependency, repositoryName); var ex = new ArgumentException(message); @@ -904,7 +897,6 @@ private bool CheckDependenciesExist(Hashtable dependencies, string repositoryNam return false; } } - return true; } diff --git a/src/code/RegisterPSResourceRepository.cs b/src/code/RegisterPSResourceRepository.cs index 8f0c16a2a..871be13e3 100644 --- a/src/code/RegisterPSResourceRepository.cs +++ b/src/code/RegisterPSResourceRepository.cs @@ -105,10 +105,16 @@ class RegisterPSResourceRepository : PSCmdlet public PSCredential ProxyCredential { get; set; } /// - /// When specified, displays the succcessfully registered repository and its information + /// When specified, displays the succcessfully registered repository and its information. /// [Parameter] public SwitchParameter PassThru { get; set; } + + /// + /// When specified, will overwrite information for any existing repository with the same name. + /// + [Parameter] + public SwitchParameter Force { get; set; } #endregion @@ -144,7 +150,16 @@ protected override void ProcessRecord() try { - items.Add(NameParameterSetHelper(Name, _uri, Priority, Trusted, CredentialInfo)); + items.Add(RepositorySettings.AddRepository(Name, _uri, Priority, Trusted, CredentialInfo, Force, this, out string errorMsg)); + + if (!string.IsNullOrEmpty(errorMsg)) + { + ThrowTerminatingError(new ErrorRecord( + new PSInvalidOperationException(errorMsg), + "ErrorInNameParameterSet", + ErrorCategory.InvalidArgument, + this)); + } } catch (Exception e) { @@ -201,71 +216,30 @@ protected override void ProcessRecord() } } - private PSRepositoryInfo AddToRepositoryStoreHelper(string repoName, Uri repoUri, int repoPriority, bool repoTrusted, PSCredentialInfo repoCredentialInfo) - { - // remove trailing and leading whitespaces, and if Name is just whitespace Name should become null now and be caught by following condition - repoName = repoName.Trim(' '); - if (String.IsNullOrEmpty(repoName) || repoName.Contains("*")) - { - throw new ArgumentException("Name cannot be null/empty, contain asterisk or be just whitespace"); - } - - if (repoUri == null || !(repoUri.Scheme == System.Uri.UriSchemeHttp || repoUri.Scheme == System.Uri.UriSchemeHttps || repoUri.Scheme == System.Uri.UriSchemeFtp || repoUri.Scheme == System.Uri.UriSchemeFile)) - { - throw new ArgumentException("Invalid Uri, must be one of the following Uri schemes: HTTPS, HTTP, FTP, File Based"); - } - - if (repoCredentialInfo != null) - { - bool isSecretManagementModuleAvailable = Utils.IsSecretManagementModuleAvailable(repoName, this); - - if (repoCredentialInfo.Credential != null) - { - if (!isSecretManagementModuleAvailable) - { - ThrowTerminatingError(new ErrorRecord( - new PSInvalidOperationException($"Microsoft.PowerShell.SecretManagement module is not found, but is required for saving PSResourceRepository {repoName}'s Credential in a vault."), - "RepositoryCredentialSecretManagementUnavailableModule", - ErrorCategory.ResourceUnavailable, - this)); - } - else - { - Utils.SaveRepositoryCredentialToSecretManagementVault(repoName, repoCredentialInfo, this); - } - } - - if (!isSecretManagementModuleAvailable) - { - WriteWarning($"Microsoft.PowerShell.SecretManagement module cannot be found. Make sure it is installed before performing PSResource operations in order to successfully authenticate to PSResourceRepository \"{repoName}\" with its CredentialInfo."); - } - } - - WriteVerbose("All required values to add to repository provided, calling internal Add() API now"); - if (!ShouldProcess(repoName, "Register repository to repository store")) - { - return null; - } - - return RepositorySettings.Add(repoName, repoUri, repoPriority, repoTrusted, repoCredentialInfo); - } - - private PSRepositoryInfo NameParameterSetHelper(string repoName, Uri repoUri, int repoPriority, bool repoTrusted, PSCredentialInfo repoCredentialInfo) - { - if (repoName.Equals("PSGallery", StringComparison.OrdinalIgnoreCase)) - { - WriteVerbose("Provided Name (NameParameterSet) but with invalid value of PSGallery"); - throw new ArgumentException("Cannot register PSGallery with -Name parameter. Try: Register-PSResourceRepository -PSGallery"); - } - - return AddToRepositoryStoreHelper(repoName, repoUri, repoPriority, repoTrusted, repoCredentialInfo); - } private PSRepositoryInfo PSGalleryParameterSetHelper(int repoPriority, bool repoTrusted) { Uri psGalleryUri = new Uri(PSGalleryRepoUri); WriteVerbose("(PSGallerySet) internal name and uri values for Add() API are hardcoded and validated, priority and trusted values, if passed in, also validated"); - return AddToRepositoryStoreHelper(PSGalleryRepoName, psGalleryUri, repoPriority, repoTrusted, repoCredentialInfo: null); + var addedRepo = RepositorySettings.AddToRepositoryStore(PSGalleryRepoName, + psGalleryUri, + repoPriority, + repoTrusted, + repoCredentialInfo: null, + Force, + this, + out string errorMsg); + + if (!string.IsNullOrEmpty(errorMsg)) + { + ThrowTerminatingError(new ErrorRecord( + new PSInvalidOperationException(errorMsg), + "RepositoryCredentialSecretManagementUnavailableModule", + ErrorCategory.ResourceUnavailable, + this)); + } + + return addedRepo; } private List RepositoriesParameterSetHelper() @@ -316,7 +290,7 @@ private List RepositoriesParameterSetHelper() private PSRepositoryInfo RepoValidationHelper(Hashtable repo) { - if (!repo.ContainsKey("Name") || String.IsNullOrEmpty(repo["Name"].ToString())) + if (!repo.ContainsKey("Name") || repo["Name"] == null || String.IsNullOrWhiteSpace(repo["Name"].ToString())) { WriteError(new ErrorRecord( new PSInvalidOperationException("Repository name cannot be null"), @@ -336,7 +310,7 @@ private PSRepositoryInfo RepoValidationHelper(Hashtable repo) return null; } - if (!repo.ContainsKey("Uri") || String.IsNullOrEmpty(repo["Uri"].ToString())) + if (!repo.ContainsKey("Uri") || repo["Uri"] == null || String.IsNullOrEmpty(repo["Uri"].ToString())) { WriteError(new ErrorRecord( new PSInvalidOperationException("Repository Uri cannot be null"), @@ -369,11 +343,25 @@ private PSRepositoryInfo RepoValidationHelper(Hashtable repo) try { WriteVerbose(String.Format("(RepositoriesParameterSet): on repo: {0}. Registers Name based repository", repo["Name"])); - return NameParameterSetHelper(repo["Name"].ToString(), + var addedRepo = RepositorySettings.AddRepository(repo["Name"].ToString(), repoUri, repo.ContainsKey("Priority") ? Convert.ToInt32(repo["Priority"].ToString()) : DefaultPriority, repo.ContainsKey("Trusted") ? Convert.ToBoolean(repo["Trusted"].ToString()) : DefaultTrusted, - repoCredentialInfo); + repoCredentialInfo, + Force, + this, + out string errorMsg); + + if (!string.IsNullOrEmpty(errorMsg)) + { + ThrowTerminatingError(new ErrorRecord( + new PSInvalidOperationException(errorMsg), + "RegisterRepositoryError", + ErrorCategory.ResourceUnavailable, + this)); + } + + return addedRepo; } catch (Exception e) { diff --git a/src/code/RepositorySettings.cs b/src/code/RepositorySettings.cs index 76e68a27e..47c6185d5 100644 --- a/src/code/RepositorySettings.cs +++ b/src/code/RepositorySettings.cs @@ -60,7 +60,7 @@ public static void CheckRepositoryStore() // Add PSGallery to the newly created store Uri psGalleryUri = new Uri(PSGalleryRepoUri); - Add(PSGalleryRepoName, psGalleryUri, DefaultPriority, DefaultTrusted, repoCredentialInfo: null); + Add(PSGalleryRepoName, psGalleryUri, DefaultPriority, DefaultTrusted, repoCredentialInfo: null, force: false); } // Open file (which should exist now), if cannot/is corrupted then throw error @@ -74,12 +74,159 @@ public static void CheckRepositoryStore() } } + public static PSRepositoryInfo AddRepository(string repoName, Uri repoUri, int repoPriority, bool repoTrusted, PSCredentialInfo repoCredentialInfo, bool force, PSCmdlet cmdletPassedIn, out string errorMsg) + { + errorMsg = String.Empty; + if (repoName.Equals("PSGallery", StringComparison.OrdinalIgnoreCase)) + { + errorMsg = "Cannot register PSGallery with -Name parameter. Try: Register-PSResourceRepository -PSGallery"; + return null; + } + + return AddToRepositoryStore(repoName, repoUri, repoPriority, repoTrusted, repoCredentialInfo, force, cmdletPassedIn, out errorMsg); + } + + + public static PSRepositoryInfo AddToRepositoryStore(string repoName, Uri repoUri, int repoPriority, bool repoTrusted, PSCredentialInfo repoCredentialInfo, bool force, PSCmdlet cmdletPassedIn, out string errorMsg) + { + errorMsg = string.Empty; + // remove trailing and leading whitespaces, and if Name is just whitespace Name should become null now and be caught by following condition + repoName = repoName.Trim(' '); + if (String.IsNullOrEmpty(repoName) || repoName.Contains("*")) + { + throw new ArgumentException("Name cannot be null/empty, contain asterisk or be just whitespace"); + } + + if (repoUri == null || !(repoUri.Scheme == System.Uri.UriSchemeHttp || repoUri.Scheme == System.Uri.UriSchemeHttps || repoUri.Scheme == System.Uri.UriSchemeFtp || repoUri.Scheme == System.Uri.UriSchemeFile)) + { + errorMsg = "Invalid Uri, must be one of the following Uri schemes: HTTPS, HTTP, FTP, File Based"; + return null; + } + + if (repoCredentialInfo != null) + { + bool isSecretManagementModuleAvailable = Utils.IsSecretManagementModuleAvailable(repoName, cmdletPassedIn); + + if (repoCredentialInfo.Credential != null) + { + if (!isSecretManagementModuleAvailable) + { + errorMsg = $"Microsoft.PowerShell.SecretManagement module is not found, but is required for saving PSResourceRepository {repoName}'s Credential in a vault."; + return null; + } + else + { + Utils.SaveRepositoryCredentialToSecretManagementVault(repoName, repoCredentialInfo, cmdletPassedIn); + } + } + + if (!isSecretManagementModuleAvailable) + { + cmdletPassedIn.WriteWarning($"Microsoft.PowerShell.SecretManagement module cannot be found. Make sure it is installed before performing PSResource operations in order to successfully authenticate to PSResourceRepository \"{repoName}\" with its CredentialInfo."); + } + } + + if (!cmdletPassedIn.ShouldProcess(repoName, "Register repository to repository store")) + { + return null; + } + + if (!string.IsNullOrEmpty(errorMsg)) + { + return null; + } + + var repo = RepositorySettings.Add(repoName, repoUri, repoPriority, repoTrusted, repoCredentialInfo, force); + + return repo; + } + + + public static PSRepositoryInfo UpdateRepositoryStore(string repoName, Uri repoUri, int repoPriority, bool repoTrusted, bool isSet, int defaultPriority, PSCredentialInfo repoCredentialInfo, PSCmdlet cmdletPassedIn, out string errorMsg) + { + errorMsg = string.Empty; + if (repoUri != null && !(repoUri.Scheme == System.Uri.UriSchemeHttp || repoUri.Scheme == System.Uri.UriSchemeHttps || repoUri.Scheme == System.Uri.UriSchemeFtp || repoUri.Scheme == System.Uri.UriSchemeFile)) + { + errorMsg = "Invalid Uri, Uri must be one of the following schemes: HTTPS, HTTP, FTP, File Based"; + return null; + } + + // check repoName can't contain * or just be whitespace + // remove trailing and leading whitespaces, and if Name is just whitespace Name should become null now and be caught by following condition + repoName = repoName.Trim(); + if (String.IsNullOrEmpty(repoName) || repoName.Contains("*")) + { + errorMsg = "Name cannot be null or empty, or contain wildcards"; + return null; + } + + // check PSGallery Uri is not trying to be set + if (repoName.Equals("PSGallery", StringComparison.OrdinalIgnoreCase) && repoUri != null) + { + errorMsg = "The PSGallery repository has a predefined Uri. Setting the -Uri parameter for this repository is not allowed. Please run 'Register-PSResourceRepository -PSGallery' to register the PowerShell Gallery."; + return null; + } + + // check PSGallery CredentialInfo is not trying to be set + if (repoName.Equals("PSGallery", StringComparison.OrdinalIgnoreCase) && repoCredentialInfo != null) + { + errorMsg = "Setting the -CredentialInfo parameter for PSGallery is not allowed. Run 'Register-PSResourceRepository -PSGallery' to register the PowerShell Gallery."; + return null; + } + + // determine trusted value to pass in (true/false if set, null otherwise, hence the nullable bool variable) + bool? _trustedNullable = isSet ? new bool?(repoTrusted) : new bool?(); + + if (repoCredentialInfo != null) + { + bool isSecretManagementModuleAvailable = Utils.IsSecretManagementModuleAvailable(repoName, cmdletPassedIn); + + if (repoCredentialInfo.Credential != null) + { + if (!isSecretManagementModuleAvailable) + { + errorMsg = $"Microsoft.PowerShell.SecretManagement module is not found, but is required for saving PSResourceRepository {repoName}'s Credential in a vault."; + return null; + } + else + { + Utils.SaveRepositoryCredentialToSecretManagementVault(repoName, repoCredentialInfo, cmdletPassedIn); + } + } + + if (!isSecretManagementModuleAvailable) + { + cmdletPassedIn.WriteWarning($"Microsoft.PowerShell.SecretManagement module cannot be found. Make sure it is installed before performing PSResource operations in order to successfully authenticate to PSResourceRepository \"{repoName}\" with its CredentialInfo."); + } + } + + // determine if either 1 of 4 values are attempting to be set: Uri, Priority, Trusted, CredentialInfo. + // if none are (i.e only Name parameter was provided, write error) + if (repoUri == null && repoPriority == defaultPriority && _trustedNullable == null && repoCredentialInfo == null) + { + errorMsg = "Must set Uri, Priority, Trusted or CredentialInfo parameter"; + return null; + } + + if (!cmdletPassedIn.ShouldProcess(repoName, "Set repository's value(s) in repository store")) + { + return null; + } + + if (!string.IsNullOrEmpty(errorMsg)) + { + return null; + } + + return Update(repoName, repoUri, repoPriority, _trustedNullable, repoCredentialInfo, cmdletPassedIn, out errorMsg); + } + /// /// Add a repository to the store /// Returns: PSRepositoryInfo containing information about the repository just added to the repository store /// /// - public static PSRepositoryInfo Add(string repoName, Uri repoUri, int repoPriority, bool repoTrusted, PSCredentialInfo repoCredentialInfo) + public static PSRepositoryInfo Add(string repoName, Uri repoUri, int repoPriority, bool repoTrusted, PSCredentialInfo repoCredentialInfo, bool force) { try { @@ -87,7 +234,22 @@ public static PSRepositoryInfo Add(string repoName, Uri repoUri, int repoPriorit XDocument doc = LoadXDocument(FullRepositoryPath); if (FindRepositoryElement(doc, repoName) != null) { - throw new PSInvalidOperationException(String.Format("The PSResource Repository '{0}' already exists.", repoName)); + if (!force) + { + throw new PSInvalidOperationException(String.Format("The PSResource Repository '{0}' already exists.", repoName)); + } + + // Delete the existing repository before overwriting it (otherwire multiple repos with the same name will be added) + List removedRepositories = RepositorySettings.Remove(new string[] { repoName }, out string[] errorList); + + // Need to load the document again because of changes after removing + doc = LoadXDocument(FullRepositoryPath); + + if (errorList.Count() > 0) + { + throw new PSInvalidOperationException($"The PSResource Repository '{repoName}' cannot be overwritten: ${errorList.FirstOrDefault()}"); + } + } // Else, keep going @@ -126,8 +288,9 @@ public static PSRepositoryInfo Add(string repoName, Uri repoUri, int repoPriorit /// Updates a repository name, Uri, priority, installation policy, or credential information /// Returns: void /// - public static PSRepositoryInfo Update(string repoName, Uri repoUri, int repoPriority, bool? repoTrusted, PSCredentialInfo repoCredentialInfo) + public static PSRepositoryInfo Update(string repoName, Uri repoUri, int repoPriority, bool? repoTrusted, PSCredentialInfo repoCredentialInfo, PSCmdlet cmdletPassedIn, out string errorMsg) { + errorMsg = string.Empty; PSRepositoryInfo updatedRepo; try { @@ -136,7 +299,9 @@ public static PSRepositoryInfo Update(string repoName, Uri repoUri, int repoPrio XElement node = FindRepositoryElement(doc, repoName); if (node == null) { - throw new ArgumentException("Cannot find the repository because it does not exist. Try registering the repository using 'Register-PSResourceRepository'"); + bool repoIsTrusted = !(repoTrusted == null || repoTrusted == false); + repoPriority = repoPriority < 0 ? DefaultPriority : repoPriority; + return AddToRepositoryStore(repoName, repoUri, repoPriority, repoIsTrusted, repoCredentialInfo, force:true, cmdletPassedIn, out errorMsg); } // Check that repository node we are attempting to update has all required attributes: Name, Url (or Uri), Priority, Trusted. @@ -144,19 +309,22 @@ public static PSRepositoryInfo Update(string repoName, Uri repoUri, int repoPrio if (node.Attribute("Priority") == null) { - throw new ArgumentException("Repository element does not contain neccessary 'Priority' attribute, in file located at path: {0}. Fix this in your file and run again.", FullRepositoryPath); + errorMsg = $"Repository element does not contain neccessary 'Priority' attribute, in file located at path: {FullRepositoryPath}. Fix this in your file and run again."; + return null; } if (node.Attribute("Trusted") == null) { - throw new ArgumentException("Repository element does not contain neccessary 'Trusted' attribute, in file located at path: {0}. Fix this in your file and run again.", FullRepositoryPath); + errorMsg = $"Repository element does not contain neccessary 'Trusted' attribute, in file located at path: {FullRepositoryPath}. Fix this in your file and run again."; + return null; } bool urlAttributeExists = node.Attribute("Url") != null; bool uriAttributeExists = node.Attribute("Uri") != null; if (!urlAttributeExists && !uriAttributeExists) { - throw new ArgumentException("Repository element does not contain neccessary 'Url' attribute (or alternatively 'Uri' attribute), in file located at path: {0}. Fix this in your file and run again.", FullRepositoryPath); + errorMsg = $"Repository element does not contain neccessary 'Url' attribute (or alternatively 'Uri' attribute), in file located at path: {FullRepositoryPath}. Fix this in your file and run again."; + return null; } // Else, keep going @@ -176,7 +344,8 @@ public static PSRepositoryInfo Update(string repoName, Uri repoUri, int repoPrio // Create Uri from node Uri attribute to create PSRepositoryInfo item to return. if (!Uri.TryCreate(node.Attribute("Url").Value, UriKind.Absolute, out thisUrl)) { - throw new PSInvalidOperationException(String.Format("Unable to read incorrectly formatted Url for repo {0}", repoName)); + errorMsg = $"Unable to read incorrectly formatted Url for repo {repoName}"; + return null; } } else @@ -185,7 +354,8 @@ public static PSRepositoryInfo Update(string repoName, Uri repoUri, int repoPrio node.Attribute("Uri").Value = repoUri.AbsoluteUri; if (!Uri.TryCreate(node.Attribute("Uri").Value, UriKind.Absolute, out thisUrl)) { - throw new PSInvalidOperationException(String.Format("Unable to read incorrectly formatted Uri for repo {0}", repoName)); + errorMsg = $"Unable to read incorrectly formatted Uri for repo {repoName}"; + return null; } } } diff --git a/src/code/SetPSResourceRepository.cs b/src/code/SetPSResourceRepository.cs index 8963b76b7..7f874a56e 100644 --- a/src/code/SetPSResourceRepository.cs +++ b/src/code/SetPSResourceRepository.cs @@ -89,7 +89,7 @@ public SwitchParameter Trusted public PSCredentialInfo CredentialInfo { get; set; } /// - /// When specified, displays the successfully registered repository and its information + /// When specified, displays the successfully registered repository and its information. /// [Parameter] public SwitchParameter PassThru { get; set; } @@ -121,7 +121,24 @@ protected override void ProcessRecord() case NameParameterSet: try { - items.Add(UpdateRepositoryStoreHelper(Name, _uri, Priority, Trusted, CredentialInfo)); + items.Add(RepositorySettings.UpdateRepositoryStore(Name, + _uri, + Priority, + Trusted, + isSet, + DefaultPriority, + CredentialInfo, + this, + out string errorMsg)); + + if (!string.IsNullOrEmpty(errorMsg)) + { + ThrowTerminatingError(new ErrorRecord( + new PSInvalidOperationException(errorMsg), + "ErrorInNameParameterSet", + ErrorCategory.InvalidArgument, + this)); + } } catch (Exception e) { @@ -162,77 +179,6 @@ protected override void ProcessRecord() } } - private PSRepositoryInfo UpdateRepositoryStoreHelper(string repoName, Uri repoUri, int repoPriority, bool repoTrusted, PSCredentialInfo repoCredentialInfo) - { - if (repoUri != null && !(repoUri.Scheme == System.Uri.UriSchemeHttp || repoUri.Scheme == System.Uri.UriSchemeHttps || repoUri.Scheme == System.Uri.UriSchemeFtp || repoUri.Scheme == System.Uri.UriSchemeFile)) - { - throw new ArgumentException("Invalid Uri, must be one of the following Uri schemes: HTTPS, HTTP, FTP, File Based"); - } - - // check repoName can't contain * or just be whitespace - // remove trailing and leading whitespaces, and if Name is just whitespace Name should become null now and be caught by following condition - repoName = repoName.Trim(); - if (String.IsNullOrEmpty(repoName) || repoName.Contains("*")) - { - throw new ArgumentException("Name cannot be null/empty, contain asterisk or be just whitespace"); - } - - // check PSGallery Uri is not trying to be set - if (repoName.Equals("PSGallery", StringComparison.OrdinalIgnoreCase) && repoUri != null) - { - throw new ArgumentException("The PSGallery repository has a pre-defined Uri. Setting the -Uri parameter for this repository is not allowed, instead try running 'Register-PSResourceRepository -PSGallery'."); - } - - // check PSGallery CredentialInfo is not trying to be set - if (repoName.Equals("PSGallery", StringComparison.OrdinalIgnoreCase) && repoCredentialInfo != null) - { - throw new ArgumentException("The PSGallery repository does not require authentication. Setting the -CredentialInfo parameter for this repository is not allowed, instead try running 'Register-PSResourceRepository -PSGallery'."); - } - - // determine trusted value to pass in (true/false if set, null otherwise, hence the nullable bool variable) - bool? _trustedNullable = isSet ? new bool?(repoTrusted) : new bool?(); - - if (repoCredentialInfo != null) - { - bool isSecretManagementModuleAvailable = Utils.IsSecretManagementModuleAvailable(repoName, this); - - if (repoCredentialInfo.Credential != null) - { - if (!isSecretManagementModuleAvailable) - { - ThrowTerminatingError(new ErrorRecord( - new PSInvalidOperationException($"Microsoft.PowerShell.SecretManagement module is not found, but is required for saving PSResourceRepository {repoName}'s Credential in a vault."), - "RepositoryCredentialSecretManagementUnavailableModule", - ErrorCategory.ResourceUnavailable, - this)); - } - else - { - Utils.SaveRepositoryCredentialToSecretManagementVault(repoName, repoCredentialInfo, this); - } - } - - if (!isSecretManagementModuleAvailable) - { - WriteWarning($"Microsoft.PowerShell.SecretManagement module cannot be found. Make sure it is installed before performing PSResource operations in order to successfully authenticate to PSResourceRepository \"{repoName}\" with its CredentialInfo."); - } - } - - // determine if either 1 of 4 values are attempting to be set: Uri, Priority, Trusted, CredentialInfo. - // if none are (i.e only Name parameter was provided, write error) - if (repoUri == null && repoPriority == DefaultPriority && _trustedNullable == null && repoCredentialInfo == null) - { - throw new ArgumentException("Either Uri, Priority, Trusted or CredentialInfo parameters must be requested to be set"); - } - - WriteVerbose("All required values to set repository provided, calling internal Update() API now"); - if (!ShouldProcess(repoName, "Set repository's value(s) in repository store")) - { - return null; - } - return RepositorySettings.Update(repoName, repoUri, repoPriority, _trustedNullable, repoCredentialInfo); - } - private List RepositoriesParameterSetHelper() { List reposUpdatedFromHashtable = new List(); @@ -305,11 +251,26 @@ private PSRepositoryInfo RepoValidationHelper(Hashtable repo) try { - return UpdateRepositoryStoreHelper(repo["Name"].ToString(), + var updatedRepo = RepositorySettings.UpdateRepositoryStore(repo["Name"].ToString(), repoUri, repo.ContainsKey("Priority") ? Convert.ToInt32(repo["Priority"].ToString()) : DefaultPriority, repoTrusted, - repoCredentialInfo); + isSet, + DefaultPriority, + repoCredentialInfo, + this, + out string errorMsg); + + if (!string.IsNullOrEmpty(errorMsg)) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException(errorMsg), + "ErrorSettingRepository", + ErrorCategory.InvalidData, + this)); + } + + return updatedRepo; } catch (Exception e) { diff --git a/test/RegisterPSResourceRepository.Tests.ps1 b/test/RegisterPSResourceRepository.Tests.ps1 index acaeca848..4853495ac 100644 --- a/test/RegisterPSResourceRepository.Tests.ps1 +++ b/test/RegisterPSResourceRepository.Tests.ps1 @@ -234,23 +234,94 @@ Describe "Test Register-PSResourceRepository" { $res3.Name | Should -Be $TestRepoName3 } - $testCases2 = @{Type = "-Name is not specified"; IncorrectHashTable = @{Uri = $tmpDir1Path}; ErrorId = "NullNameForRepositoriesParameterSetRegistration,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"}, - @{Type = "-Name is PSGallery"; IncorrectHashTable = @{Name = $PSGalleryName; Uri = $tmpDir1Path}; ErrorId = "PSGalleryProvidedAsNameRepoPSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"}, - @{Type = "-Uri not specified"; IncorrectHashTable = @{Name = $TestRepoName1}; ErrorId = "NullUriForRepositoriesParameterSetRegistration,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"}, - @{Type = "-Uri is not valid scheme"; IncorrectHashTable = @{Name = $TestRepoName1; Uri="www.google.com"}; ErrorId = "InvalidUri,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"} + It "not register incorrectly formatted -Name type repo among correct ones, where incorrect one is missing -Name" { + $correctHashtable1 = @{Name = $TestRepoName2; Uri = $tmpDir2Path; Trusted = $True} + $correctHashtable2 = @{Name = $TestRepoName3; Uri = $tmpDir3Path; Trusted = $True; Priority = 20} + $correctHashtable3 = @{PSGallery = $True; Priority = 30}; + $IncorrectHashTable = @{Uri = $tmpDir1Path}; + + $arrayOfHashtables = $correctHashtable1, $correctHashtable2, $IncorrectHashTable, $correctHashtable3 + Unregister-PSResourceRepository -Name $PSGalleryName + Register-PSResourceRepository -Repository $arrayOfHashtables -ErrorVariable err -ErrorAction SilentlyContinue + + $ErrorId = "NullNameForRepositoriesParameterSetRegistration,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -Be $ErrorId + + $res = Get-PSResourceRepository -Name $TestRepoName2 + $res.Name | Should -Be $TestRepoName2 + + $res2 = Get-PSResourceRepository -Name $TestRepoName3 + $res2.Name | Should -Be $TestRepoName3 + + $res3 = Get-PSResourceRepository -Name $PSGalleryName + $res3.Name | Should -Be $PSGalleryName + $res3.Priority | Should -Be 30 + } + + It "not register incorrectly formatted -Name type repo among correct ones, where incorrect type has -Name of PSGallery" { + $correctHashtable1 = @{Name = $TestRepoName2; Uri = $tmpDir2Path; Trusted = $True} + $correctHashtable2 = @{Name = $TestRepoName3; Uri = $tmpDir3Path; Trusted = $True; Priority = 20} + $correctHashtable3 = @{PSGallery = $True; Priority = 30}; + $IncorrectHashTable = @{Name = $PSGalleryName; Uri = $tmpDir1Path}; + + $arrayOfHashtables = $correctHashtable1, $correctHashtable2, $IncorrectHashTable, $correctHashtable3 + Unregister-PSResourceRepository -Name $PSGalleryName + Register-PSResourceRepository -Repository $arrayOfHashtables -ErrorVariable err -ErrorAction SilentlyContinue + + $ErrorId = "PSGalleryProvidedAsNameRepoPSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -Be $ErrorId + + $res = Get-PSResourceRepository -Name $TestRepoName2 + $res.Name | Should -Be $TestRepoName2 + + $res2 = Get-PSResourceRepository -Name $TestRepoName3 + $res2.Name | Should -Be $TestRepoName3 - It "not register incorrectly formatted Name type repo among correct ones when incorrect type is " -TestCases $testCases2 { - param($Type, $IncorrectHashTable, $ErrorId) + $res3 = Get-PSResourceRepository -Name $PSGalleryName + $res3.Name | Should -Be $PSGalleryName + $res3.Priority | Should -Be 30 + } + It "not register incorrectly formatted Name type repo among correct ones when incorrect type is -Uri not specified" { $correctHashtable1 = @{Name = $TestRepoName2; Uri = $tmpDir2Path; Trusted = $True} $correctHashtable2 = @{Name = $TestRepoName3; Uri = $tmpDir3Path; Trusted = $True; Priority = 20} $correctHashtable3 = @{PSGallery = $True; Priority = 30}; + $IncorrectHashTable = @{Name = $TestRepoName1}; $arrayOfHashtables = $correctHashtable1, $correctHashtable2, $IncorrectHashTable, $correctHashtable3 Unregister-PSResourceRepository -Name $PSGalleryName Register-PSResourceRepository -Repository $arrayOfHashtables -ErrorVariable err -ErrorAction SilentlyContinue + + $ErrorId = "NullUriForRepositoriesParameterSetRegistration,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" $err.Count | Should -Not -Be 0 - $err[0].FullyQualifiedErrorId | Should -BeExactly $ErrorId + $err[0].FullyQualifiedErrorId | Should -Be $ErrorId + + $res = Get-PSResourceRepository -Name $TestRepoName2 + $res.Name | Should -Be $TestRepoName2 + + $res2 = Get-PSResourceRepository -Name $TestRepoName3 + $res2.Name | Should -Be $TestRepoName3 + + $res3 = Get-PSResourceRepository -Name $PSGalleryName + $res3.Name | Should -Be $PSGalleryName + $res3.Priority | Should -Be 30 + } + + It "not register incorrectly formatted Name type repo among correct ones when incorrect type is -Uri is not valid scheme" { + $correctHashtable1 = @{Name = $TestRepoName2; Uri = $tmpDir2Path; Trusted = $True} + $correctHashtable2 = @{Name = $TestRepoName3; Uri = $tmpDir3Path; Trusted = $True; Priority = 20} + $correctHashtable3 = @{PSGallery = $True; Priority = 30}; + $IncorrectHashTable = @{Name = $TestRepoName1; Uri="www.google.com"}; + + $arrayOfHashtables = $correctHashtable1, $correctHashtable2, $IncorrectHashTable, $correctHashtable3 + Unregister-PSResourceRepository -Name $PSGalleryName + Register-PSResourceRepository -Repository $arrayOfHashtables -ErrorVariable err -ErrorAction SilentlyContinue + + $ErrorId = "InvalidUri,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -Be $ErrorId $res = Get-PSResourceRepository -Name $TestRepoName2 $res.Name | Should -Be $TestRepoName2 @@ -273,6 +344,17 @@ Describe "Test Register-PSResourceRepository" { $res.Priority | Should -Be 50 } + It "should update a repository if -Force is used" { + Register-PSResourceRepository -Name $TestRepoName1 -Uri "./" + Register-PSResourceRepository -Name $TestRepoName1 -Uri "./" -Priority 3 -Force + $res = Get-PSResourceRepository -Name $TestRepoName1 + + $res.Name | Should -Be $TestRepoName1 + $Res.Uri.LocalPath | Should -Contain $relativeCurrentPath + $res.Trusted | Should -Be False + $res.Priority | Should -Be 3 + } + It "should register local file share NuGet based repository" { Register-PSResourceRepository -Name "localFileShareTestRepo" -Uri "\\hcgg.rest.of.domain.name\test\ITxx\team\NuGet\" $res = Get-PSResourceRepository -Name "localFileShareTestRepo" @@ -290,7 +372,7 @@ Describe "Test Register-PSResourceRepository" { } It "throws error if CredentialInfo is passed in with Credential property without SecretManagement module setup" { - { Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path -Trusted -Priority 20 -CredentialInfo $credentialInfo2 } | Should -Throw -ErrorId "RepositoryCredentialSecretManagementUnavailableModule" + { Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path -Trusted -Priority 20 -CredentialInfo $credentialInfo2 } | Should -Throw -ErrorId "ErrorInNameParameterSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" $res = Get-PSResourceRepository -Name $TestRepoName1 -ErrorAction Ignore $res | Should -BeNullOrEmpty diff --git a/test/SetPSResourceRepository.Tests.ps1 b/test/SetPSResourceRepository.Tests.ps1 index d3d15a9a9..cc8661258 100644 --- a/test/SetPSResourceRepository.Tests.ps1 +++ b/test/SetPSResourceRepository.Tests.ps1 @@ -109,8 +109,8 @@ Describe "Test Set-PSResourceRepository" { {Set-PSResourceRepository -Name $Name -Priority 25 -ErrorAction Stop} | Should -Throw -ErrorId "$ErrorId,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" } - $testCases2 = @{Type = "contains *"; Name = "test*Repository2"; ErrorId = "ErrorSettingIndividualRepoFromRepositories"}, - @{Type = "is whitespace"; Name = " "; ErrorId = "ErrorSettingIndividualRepoFromRepositories"}, + $testCases2 = @{Type = "contains *"; Name = "test*Repository2"; ErrorId = "ErrorSettingRepository"}, + @{Type = "is whitespace"; Name = " "; ErrorId = "ErrorSettingRepository"}, @{Type = "is null"; Name = $null; ErrorId = "NullNameForRepositoriesParameterSetRepo"} It "not set repository and write error given Name (RepositoriesParameterSet)" -TestCases $testCases2 { param($Type, $Name, $ErrorId) @@ -205,7 +205,7 @@ Describe "Test Set-PSResourceRepository" { Set-PSResourceRepository -Repository $arrayOfHashtables -ErrorVariable err -ErrorAction SilentlyContinue $err.Count | Should -Not -Be 0 - $err[0].FullyQualifiedErrorId | Should -BeExactly "ErrorSettingIndividualRepoFromRepositories,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" + $err[0].FullyQualifiedErrorId | Should -BeExactly "ErrorSettingRepository,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" $res = Get-PSResourceRepository -Name $TestRepoName1 $Res.Uri.LocalPath | Should -Contain $tmpDir1Path @@ -235,7 +235,7 @@ Describe "Test Set-PSResourceRepository" { Set-PSResourceRepository -Repository $arrayOfHashtables -ErrorVariable err -ErrorAction SilentlyContinue $err.Count | Should -Not -Be 0 - $err[0].FullyQualifiedErrorId | Should -BeExactly "ErrorSettingIndividualRepoFromRepositories,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" + $err[0].FullyQualifiedErrorId | Should -BeExactly "ErrorSettingRepository,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" $res = Get-PSResourceRepository -Name $TestRepoName1 $Res.Uri.LocalPath | Should -Contain $tmpDir1Path @@ -252,6 +252,17 @@ Describe "Test Set-PSResourceRepository" { $Res.Uri.LocalPath | Should -Contain "\\hcgg.rest.of.domain.name\test\ITxx\team\NuGet\" } + It "set repository should register repository if it does not already exist" { + $testRepoName = "NewForceTestRepo" + Set-PSResourceRepository -Name $testRepoName -Uri $tmpDir1Path -PassThru + + $res = Get-PSResourceRepository -Name $testRepoName + $res.Name | Should -Be $testRepoName + $Res.Uri.LocalPath | Should -Contain $tmpDir1Path + $res.Priority | Should -Be 50 + $res.Trusted | Should -Be False + } + It "set repository and see updated repository with -PassThru" { Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path $res = Set-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir2Path -PassThru @@ -274,7 +285,7 @@ Describe "Test Set-PSResourceRepository" { { Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path Set-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path -CredentialInfo $credentialInfo2 - } | Should -Throw -ErrorId "RepositoryCredentialSecretManagementUnavailableModule" + } | Should -Throw -ErrorId "ErrorInNameParameterSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" $res = Get-PSResourceRepository -Name $TestRepoName1 -ErrorAction Ignore $res.CredentialInfo | Should -BeNullOrEmpty