diff --git a/README.md b/README.md index efb1c1b..297a1d4 100644 --- a/README.md +++ b/README.md @@ -59,13 +59,13 @@ Full path to an SSIS deployment file (with ispac extension). If a deployment fil Required. Full Name of the target SQL Server instance. - **-Catalog:** - Required. Name of the SSIS Catalog on the target server. + Name of the SSIS Catalog on the target server. If not supplied, then SSISDB value is used. - **-Folder:** -Required. Deployment folder within destination catalog.. +Required. Deployment folder within destination catalog. - **-ProjectName:** -Required. Name of the project in the destination folder. +Name of the project in the destination folder. If not supplied, then deployment file name is used. - **-ProjectPassword:** Password to decrypt sensitive data for deployment. diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 84c7cde..1ab3086 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,3 +1,8 @@ +#### 2.1.2 (Released 2017/02/25) +* Added powershell parameters documentation +* Made Catalog and ProjectName parameters Optional in deployer + + #### 2.1.1 (Released 2017/02/25) * Fixed an issue with Powershell passing empty strings instead of nulls in parameters * Replaced parameter type for EraseSensitiveInfo from bool to SwitchParameter in Publish-SsisDeploymentPackage powershell CmdLet diff --git a/SsisBuild.nuspec b/SsisBuild.nuspec index 7ea55a3..9e35098 100644 --- a/SsisBuild.nuspec +++ b/SsisBuild.nuspec @@ -2,7 +2,7 @@ SSISBuild - 2.1.1 + 2.1.2 SSIS Build Roman Tumaykin Roman Tumaykin @@ -10,8 +10,8 @@ https://github.com/rtumaykin/ssis-build/ false A set of utilities that allow to autonomously build a Visual Studio SSIS project (dtproj) into a deployment package (ispac), and deploy the package to an SSIS catalog. - Fixed an issue with Powershell passing empty strings instead of nulls in parameters -Replaced parameter type for EraseSensitiveInfo from bool to SwitchParameter in Publish-SsisDeploymentPackage powershell CmdLet + Added powershell parameters documentation +Made Catalog and ProjectName parameters Optional in deployer Copyright © 2017 Roman Tumaykin SSIS build tools diff --git a/src/SharedAssemblyInfo.cs b/src/SharedAssemblyInfo.cs index 1bc69d2..5c29d25 100644 --- a/src/SharedAssemblyInfo.cs +++ b/src/SharedAssemblyInfo.cs @@ -4,5 +4,5 @@ [assembly: AssemblyCompanyAttribute("Roman Tumaykin")] [assembly: AssemblyCopyrightAttribute("Copyright © 2017 Roman Tumaykin")] [assembly: AssemblyTrademarkAttribute("")] -[assembly: AssemblyVersionAttribute("2.1.1.0")] -[assembly: AssemblyFileVersionAttribute("2.1.1.0")] +[assembly: AssemblyVersionAttribute("2.1.2.0")] +[assembly: AssemblyFileVersionAttribute("2.1.2.0")] diff --git a/src/SsisBuild.Core.Tests/BuildArgumentsTests.cs b/src/SsisBuild.Core.Tests/BuildArgumentsTests.cs index e236458..bbbd892 100644 --- a/src/SsisBuild.Core.Tests/BuildArgumentsTests.cs +++ b/src/SsisBuild.Core.Tests/BuildArgumentsTests.cs @@ -68,12 +68,12 @@ public void Pass_Process_AllProperties() } } - + [Fact] public void Fail_Validate_NoConfiguration() { // Setup - + // Execute var exception = Record.Exception(() => new BuildArguments(null, null, null, null, null, null, null, null, null)); @@ -116,69 +116,5 @@ public void Pass_Validate_ValidProtectionLevel(string protectionLevelString) // Assert Assert.Null(exception); } - - [Theory] - [InlineData(nameof(ProtectionLevel.DontSaveSensitive), true, false)] - [InlineData(nameof(ProtectionLevel.DontSaveSensitive), false, false)] - [InlineData(nameof(ProtectionLevel.EncryptAllWithPassword), false, true)] - [InlineData(nameof(ProtectionLevel.EncryptAllWithPassword), true, true)] - [InlineData(nameof(ProtectionLevel.EncryptAllWithPassword), true, false)] - [InlineData(nameof(ProtectionLevel.EncryptSensitiveWithPassword), false, true)] - [InlineData(nameof(ProtectionLevel.EncryptSensitiveWithPassword), true, true)] - [InlineData(nameof(ProtectionLevel.EncryptSensitiveWithPassword), true, false)] - public void Pass_Validate_ProtectionLevelPasswordCombination(string protectionLevelString, bool password, bool newPassword) - { - // Setup - - // Execute - var exception = - Record.Exception( - () => - new BuildArguments(null, null, null, protectionLevelString, password ? Fakes.RandomString() : null, newPassword ? Fakes.RandomString() : null, - Fakes.RandomString(), null, null)); - - // Assert - Assert.Null(exception); - } - - [Theory] - [InlineData(nameof(ProtectionLevel.EncryptAllWithPassword))] - [InlineData(nameof(ProtectionLevel.EncryptSensitiveWithPassword))] - public void Fail_Validate_ProtectionLevelPasswordCombination(string protectionLevelString) - { - // Setup - var testException = new PasswordRequiredException(protectionLevelString); - - - // Execute - var exception = Record.Exception(() => new BuildArguments(null, null, null, protectionLevelString, null, null, Fakes.RandomString(), null, null)); - - // Assert - Assert.NotNull(exception); - Assert.IsType(exception); - Assert.Equal(exception.Message, testException.Message, StringComparer.InvariantCultureIgnoreCase); - } - - [Theory] - [InlineData(nameof(ProtectionLevel.DontSaveSensitive), true, true)] - [InlineData(nameof(ProtectionLevel.DontSaveSensitive), false, true)] - public void Fail_Validate_ProtectionLevelDontSaveSensitiveWithPassword(string protectionLevelString, bool password, bool newPassword) - { - // Setup - var testException = new DontSaveSensitiveWithPasswordException(); - - - // Execute - var exception = - Record.Exception( - () => - new BuildArguments(null, null, null, protectionLevelString, password ? Fakes.RandomString() : null, newPassword ? Fakes.RandomString() : null, - Fakes.RandomString(), null, null)); - - // Assert - Assert.NotNull(exception); - Assert.IsType(exception); - Assert.Equal(exception.Message, testException.Message, StringComparer.InvariantCultureIgnoreCase); - } } } diff --git a/src/SsisBuild.Core.Tests/BuilderTests.cs b/src/SsisBuild.Core.Tests/BuilderTests.cs index 06905ac..63f79a8 100644 --- a/src/SsisBuild.Core.Tests/BuilderTests.cs +++ b/src/SsisBuild.Core.Tests/BuilderTests.cs @@ -438,6 +438,52 @@ public void Pass_New() Assert.NotNull(builder); } + [Theory] + [InlineData(nameof(ProtectionLevel.DontSaveSensitive), true, false)] + [InlineData(nameof(ProtectionLevel.DontSaveSensitive), false, false)] + [InlineData(nameof(ProtectionLevel.EncryptAllWithPassword), false, true)] + [InlineData(nameof(ProtectionLevel.EncryptAllWithPassword), true, true)] + [InlineData(nameof(ProtectionLevel.EncryptAllWithPassword), true, false)] + [InlineData(nameof(ProtectionLevel.EncryptSensitiveWithPassword), false, true)] + [InlineData(nameof(ProtectionLevel.EncryptSensitiveWithPassword), true, true)] + [InlineData(nameof(ProtectionLevel.EncryptSensitiveWithPassword), true, false)] + public void Pass_Validate_ProtectionLevelPasswordCombination(string protectionLevelString, bool password, bool newPassword) + { + // Setup + var builder = new Builder.Builder(_loggerMock.Object, _projectMock.Object); + _projectMock.Setup(p => p.Parameters).Returns(new Dictionary()); + + // Execute + var exception = + Record.Exception( + () => + builder.Build(new BuildArguments(Fakes.RandomString(), Fakes.RandomString(), null, protectionLevelString, password ? Fakes.RandomString() : null, newPassword ? Fakes.RandomString() : null, + Fakes.RandomString(), null, null))); + + // Assert + Assert.Null(exception); + } + + [Theory] + [InlineData(nameof(ProtectionLevel.EncryptAllWithPassword))] + [InlineData(nameof(ProtectionLevel.EncryptSensitiveWithPassword))] + public void Fail_Validate_ProtectionLevelPasswordCombination(string protectionLevelString) + { + // Setup + var builder = new Builder.Builder(_loggerMock.Object, _projectMock.Object); + _projectMock.Setup(p => p.Parameters).Returns(new Dictionary()); + var testException = new PasswordRequiredException(protectionLevelString); + + + // Execute + var exception = Record.Exception(() => builder.Build(new BuildArguments(Fakes.RandomString(), Fakes.RandomString(), null, protectionLevelString, null, null, Fakes.RandomString(), null, null))); + + // Assert + Assert.NotNull(exception); + Assert.IsType(exception); + Assert.Equal(exception.Message, testException.Message, StringComparer.InvariantCultureIgnoreCase); + } + private IParameter CreateParameter(string name, string value, bool sensitive, ParameterSource source) { var parameterMock = new Mock(); diff --git a/src/SsisBuild.Core.Tests/DeployArgumentsTests.cs b/src/SsisBuild.Core.Tests/DeployArgumentsTests.cs index 7deafeb..07ce2db 100644 --- a/src/SsisBuild.Core.Tests/DeployArgumentsTests.cs +++ b/src/SsisBuild.Core.Tests/DeployArgumentsTests.cs @@ -64,34 +64,6 @@ public void Fail_New_MissingServerInstance() Assert.True(((MissingRequiredArgumentException) exception).MissingArgument == nameof(DeployArguments.ServerInstance)); } - [Fact] - public void Fail_New_MissingCatalog() - { - // Setup - - // Execute - var exception = Record.Exception(() => new DeployArguments(null, null, Fakes.RandomString(), null, Fakes.RandomString(), Fakes.RandomString(), null, Fakes.RandomBool())); - - // Assert - Assert.NotNull(exception); - Assert.IsType(exception); - Assert.True(((MissingRequiredArgumentException)exception).MissingArgument == nameof(DeployArguments.Catalog)); - } - - [Fact] - public void Fail_New_MissingProjectName() - { - // Setup - - // Execute - var exception = Record.Exception(() => new DeployArguments(null, null, Fakes.RandomString(), Fakes.RandomString(), Fakes.RandomString(), null, null, Fakes.RandomBool())); - - // Assert - Assert.NotNull(exception); - Assert.IsType(exception); - Assert.True(((MissingRequiredArgumentException)exception).MissingArgument == nameof(DeployArguments.ProjectName)); - } - [Fact] public void Fail_New_MissingFolder() { diff --git a/src/SsisBuild.Core.Tests/SsisBuildPowershellTests.cs b/src/SsisBuild.Core.Tests/SsisBuildPowershellTests.cs index 9166a0a..a5fdecd 100644 --- a/src/SsisBuild.Core.Tests/SsisBuildPowershellTests.cs +++ b/src/SsisBuild.Core.Tests/SsisBuildPowershellTests.cs @@ -47,7 +47,7 @@ public void Pass_ProcessRecord() var outputFolder = Fakes.RandomString(); var releaseNotes = Fakes.RandomString(); - var parametersCount = Fakes.RandomInt(0, 10); + var parametersCount = Fakes.RandomInt(1, 10); var parameters = new Dictionary(); for (var i = 0; i < parametersCount; i++) { diff --git a/src/SsisBuild.Core/Builder/BuildArguments.cs b/src/SsisBuild.Core/Builder/BuildArguments.cs index 636061e..3d0cd20 100644 --- a/src/SsisBuild.Core/Builder/BuildArguments.cs +++ b/src/SsisBuild.Core/Builder/BuildArguments.cs @@ -69,16 +69,6 @@ private void Validate() if (Configuration == null) throw new MissingRequiredArgumentException(nameof(Configuration)); - - if (new[] { - nameof(ProjectManagement.ProtectionLevel.EncryptAllWithPassword), - nameof(ProjectManagement.ProtectionLevel.EncryptSensitiveWithPassword) - }.Contains(ProtectionLevel) && string.IsNullOrWhiteSpace(NewPassword ?? Password)) - throw new PasswordRequiredException(ProtectionLevel); - - if (ProtectionLevel == nameof(ProjectManagement.ProtectionLevel.DontSaveSensitive) && !string.IsNullOrWhiteSpace(NewPassword)) - throw new DontSaveSensitiveWithPasswordException(); - } } } diff --git a/src/SsisBuild.Core/Builder/DontSaveSensitiveWithPasswordException.cs b/src/SsisBuild.Core/Builder/DontSaveSensitiveWithPasswordException.cs deleted file mode 100644 index d0f2c23..0000000 --- a/src/SsisBuild.Core/Builder/DontSaveSensitiveWithPasswordException.cs +++ /dev/null @@ -1,23 +0,0 @@ -//----------------------------------------------------------------------- -// Copyright 2017 Roman Tumaykin -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//----------------------------------------------------------------------- - -namespace SsisBuild.Core.Builder -{ - public class DontSaveSensitiveWithPasswordException : BuildArgumentsValidationException - { - public DontSaveSensitiveWithPasswordException () : base ("NewPassword argument should not be specified when ProtectionLevel is DontSaveSensitive.") { } - } -} diff --git a/src/SsisBuild.Core/Builder/SsisBuildPowershell.cs b/src/SsisBuild.Core/Builder/SsisBuildPowershell.cs index 486f915..18b2637 100644 --- a/src/SsisBuild.Core/Builder/SsisBuildPowershell.cs +++ b/src/SsisBuild.Core/Builder/SsisBuildPowershell.cs @@ -24,32 +24,38 @@ namespace SsisBuild.Core.Builder [Cmdlet(VerbsCommon.New, "SsisDeploymentPackage")] public class SsisBuildPowershell : PSCmdlet { - [Parameter( - Position = 0, - HelpMessage = - "Full path to a SSIS project file (with dtproj extension). If a project file is not specified, ssisbuild searches current working directory, for a file with dtproj extension and uses that file." - )] + [Parameter(HelpMessage = "Full path to a SSIS project file (with dtproj extension). " + + "If a project file is not specified, ssisbuild searches current working directory for a " + + "file with dtproj extension and uses that file.", + Position = 0 + )] public string ProjectPath { get; set; } - [Parameter] + [Parameter(HelpMessage = "Full path to a folder where the ispac file will be created. " + + "If ommitted, then the ispac file will be created in the bin/ subfolder of the project folder.")] public string OutputFolder { get; set; } - [Parameter] + [Parameter(HelpMessage = "Overrides current project protection level. " + + "Available values are DontSaveSensitive, EncryptAllWithPassword, EncryptSensitiveWithPassword")] public string ProtectionLevel { get; set; } - [Parameter] + [Parameter(HelpMessage = "Password to decrypt original project data if its current protection level is either EncryptAllWithPassword or " + + "EncryptSensitiveWithPassword, in which case the value should be supplied, otherwise build will fail.")] public string Password { get; set; } - [Parameter] + [Parameter(HelpMessage = "Password to encrypt resulting deployment packageif its resulting protection level is either EncryptAllWithPassword " + + "or EncryptSensitiveWithPassword. If ommitted, the value of the -Password switch is used for encryption, " + + "unless original protection level was DontSaveSensitive. In this case the value should be supplied, otherwise build will fail.")] public string NewPassword { get; set; } - [Parameter(Mandatory = true)] + [Parameter(Mandatory = true, HelpMessage = "Required. Name of project configuration to use.")] public string Configuration { get; set; } - [Parameter] + [Parameter(HelpMessage = "Path to a release notes file. Supports simple or complex release notes format, as defined here: " + + "http://fsharp.github.io/FAKE/apidocs/fake-releasenoteshelper.html")] public string ReleaseNotes { get; set; } - [Parameter] + [Parameter(HelpMessage = "A collection of replacement project parameters.")] public Hashtable Parameters { get; set; } private IBuilder _builder; diff --git a/src/SsisBuild.Core/Deployer/DeployArguments.cs b/src/SsisBuild.Core/Deployer/DeployArguments.cs index 772989f..a254d56 100644 --- a/src/SsisBuild.Core/Deployer/DeployArguments.cs +++ b/src/SsisBuild.Core/Deployer/DeployArguments.cs @@ -52,13 +52,6 @@ public void Validate() if (string.IsNullOrWhiteSpace(ServerInstance)) throw new MissingRequiredArgumentException(nameof(ServerInstance)); - if (string.IsNullOrWhiteSpace(Catalog)) - throw new MissingRequiredArgumentException(nameof(Catalog)); - - - if (string.IsNullOrWhiteSpace(ProjectName)) - throw new MissingRequiredArgumentException(nameof(ProjectName)); - if (string.IsNullOrWhiteSpace(Folder)) throw new MissingRequiredArgumentException(nameof(Folder)); } diff --git a/src/SsisBuild.Core/Deployer/SsisDeployPowershell.cs b/src/SsisBuild.Core/Deployer/SsisDeployPowershell.cs index eca30b8..fe3e11a 100644 --- a/src/SsisBuild.Core/Deployer/SsisDeployPowershell.cs +++ b/src/SsisBuild.Core/Deployer/SsisDeployPowershell.cs @@ -22,29 +22,31 @@ namespace SsisBuild.Core.Deployer [Cmdlet(VerbsData.Publish, "SsisDeploymentPackage")] public class SsisDeployPowershell : PSCmdlet { - [Parameter( - Position = 0, - HelpMessage = - "Full path to a SSIS deployment file (with ispac extension). If a project file is not specified, ssisdeploy searches current working directory, for a file with ispac extension and uses that file." + [Parameter(HelpMessage = "Full path to an SSIS deployment file (with ispac extension). If a deployment file is not specified, " + + "ssisdeploy searches current working directory for a file with ispac extension and uses that file.", + Position = 0 )] public string DeploymentFilePath { get; set; } - [Parameter(Mandatory = true)] + [Parameter(HelpMessage= "Required. Full Name of the target SQL Server instance.", + Mandatory = true)] public string ServerInstance { get; set; } - [Parameter] + [Parameter(HelpMessage = "Name of the SSIS Catalog on the target server. If not supplied, then SSISDB value is used.")] public string Catalog { get; set; } - [Parameter(Mandatory = true)] + [Parameter(HelpMessage = "Required. Deployment folder within destination catalog.", + Mandatory = true)] public string Folder { get; set; } - [Parameter] + [Parameter(HelpMessage = "Name of the project in the destination folder. If not supplied, then deployment file name is used.")] public string ProjectName { get; set; } - [Parameter] + [Parameter(HelpMessage = "Password to decrypt sensitive data for deployment.")] public string ProjectPassword { get; set; } - [Parameter] + [Parameter(HelpMessage = "Option to remove all sensitive info from the deployment ispac and deploy all sensitive parameters separately. " + + "If not specified then sensitive data will not be removed.")] public SwitchParameter EraseSensitiveInfo { get; set; } private IDeployer _deployer; diff --git a/src/SsisBuild.Core/SsisBuild.Core.csproj b/src/SsisBuild.Core/SsisBuild.Core.csproj index 23fa41c..4ac4e50 100644 --- a/src/SsisBuild.Core/SsisBuild.Core.csproj +++ b/src/SsisBuild.Core/SsisBuild.Core.csproj @@ -60,7 +60,6 @@ -