├── .eslintignore
├── .eslintrc.js
├── .gitattributes
├── .gitignore
├── .vscode
└── settings.json
├── Common
└── PowerShell3
│ └── VstsAzureHelpers
│ ├── FindSqlPackagePath.ps1
│ ├── HelperFunctions.ps1
│ ├── ImportFunctions.ps1
│ ├── InitializeFunctions.ps1
│ ├── VstsAzureHelpers.psm1
│ └── module.json
├── Extension
├── LICENSE.txt
├── Screenshots
│ ├── Add-Tasks.png
│ └── TestBuild.png
├── extension-icon.png
├── overview.md
└── vss-extension.json
├── GitVersion.yml
├── LICENSE.md
├── README.md
├── Tasks
├── AzCopy
│ ├── azCopy.ts
│ ├── azureEndpointConnection.ts
│ ├── icon.png
│ ├── package.json
│ ├── task.json
│ └── yarn.lock
├── ExecuteSql
│ ├── ExecuteSql.ps1
│ ├── SqlPredefinedScripts
│ │ ├── AddRoleMember.sql
│ │ ├── CreateDbOwner.sql
│ │ └── CreateUser.sql
│ ├── icon.png
│ ├── package.json
│ ├── task.json
│ └── yarn.lock
├── RestoreSqlDatabaseToSqlDatabase
│ ├── RestoreSqlDatabaseToSqlDatabase.ps1
│ ├── icon.png
│ ├── package.json
│ ├── task.json
│ └── yarn.lock
├── SqlMultiDacpacDeployment
│ ├── SqlMultiDacpacDeployment.ps1
│ ├── SqlScripts
│ │ └── GetDatabaseVersion.sql
│ ├── icon.png
│ ├── package.json
│ ├── task.json
│ └── yarn.lock
├── StartWebApp
│ ├── StartWebApp.ps1
│ ├── icon.png
│ ├── package.json
│ ├── task.json
│ └── yarn.lock
├── StopWebApp
│ ├── StopWebApp.ps1
│ ├── icon.png
│ ├── package.json
│ ├── task.json
│ └── yarn.lock
└── SwapSlots
│ ├── SwapSlots.ps1
│ ├── icon.png
│ ├── package.json
│ ├── task.json
│ └── yarn.lock
├── Tests
├── Node
│ ├── AzCopy
│ │ └── azCopy.spec.ts
│ ├── chutzpah.json
│ ├── jasmine.json
│ └── settings.sample.json
└── PowerShell3
│ ├── GeekLearning.VstsTasks.Azure.Tests.sln
│ ├── GeekLearning.VstsTasks.Azure.Tests
│ ├── GeekLearning.VstsTasks.Azure.Tests.pssproj
│ ├── Helpers.ps1
│ ├── Run-Tests.ps1
│ ├── SampleDirectory
│ │ └── SqlMultiDacpacDeployment
│ │ │ ├── 1.0.0.0.dacpac
│ │ │ ├── 1.0.0.1.dacpac
│ │ │ └── GeekLearning.Tasks.Database.dacpac
│ ├── SqlMultiDacpacDeployment.Tests.ps1
│ └── appsettings.json
│ └── global.json
├── configuration.json
├── package.json
├── tsconfig.json
├── tslint.json
├── typings.json
└── yarn.lock
/.eslintignore:
--------------------------------------------------------------------------------
1 | **/node_modules/**/*.*
2 | **/*.d.ts
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | parser: "@typescript-eslint/parser",
3 | plugins: ["@typescript-eslint"],
4 | extends: ["plugin:@typescript-eslint/recommended"],
5 | rules: {
6 | "@typescript-eslint/indent": ["error", 2],
7 | "@typescript-eslint/explicit-function-return-type": [
8 | "error",
9 | {
10 | allowExpressions: true,
11 | allowTypedFunctionExpressions: true
12 | }
13 | ]
14 | }
15 | };
16 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | # Shell scripts should always use line feed not crlf
7 | *.sh text eol=lf
8 |
9 | ###############################################################################
10 | # Set default behavior for command prompt diff.
11 | #
12 | # This is need for earlier builds of msysgit that does not have it on by
13 | # default for csharp files.
14 | # Note: This is only used by command line
15 | ###############################################################################
16 | #*.cs diff=csharp
17 |
18 | ###############################################################################
19 | # Set the merge driver for project and solution files
20 | #
21 | # Merging from the command prompt will add diff markers to the files if there
22 | # are conflicts (Merging from VS is not affected by the settings below, in VS
23 | # the diff markers are never inserted). Diff markers may cause the following
24 | # file extensions to fail to load in VS. An alternative would be to treat
25 | # these files as binary and thus will always conflict and require user
26 | # intervention with every merge. To do so, just uncomment the entries below
27 | ###############################################################################
28 | *.js text
29 | *.json text
30 | *.resjson text
31 | *.htm text
32 | *.html text
33 | *.xml text
34 | *.txt text
35 | *.ini text
36 | *.inc text
37 | #*.sln merge=binary
38 | #*.csproj merge=binary
39 | #*.vbproj merge=binary
40 | #*.vcxproj merge=binary
41 | #*.vcproj merge=binary
42 | #*.dbproj merge=binary
43 | #*.fsproj merge=binary
44 | #*.lsproj merge=binary
45 | #*.wixproj merge=binary
46 | #*.modelproj merge=binary
47 | #*.sqlproj merge=binary
48 | #*.wwaproj merge=binary
49 |
50 | ###############################################################################
51 | # behavior for image files
52 | #
53 | # image files are treated as binary by default.
54 | ###############################################################################
55 | *.png binary
56 | *.jpg binary
57 | *.jpeg binary
58 | *.gif binary
59 | *.ico binary
60 | *.mov binary
61 | *.mp4 binary
62 | *.mp3 binary
63 | *.flv binary
64 | *.fla binary
65 | *.swf binary
66 | *.gz binary
67 | *.zip binary
68 | *.7z binary
69 | *.ttf binary
70 |
71 | ###############################################################################
72 | # diff behavior for common document formats
73 | #
74 | # Convert binary document formats to text before diffing them. This feature
75 | # is only available from the command line. Turn it on by uncommenting the
76 | # entries below.
77 | ###############################################################################
78 | *.doc diff=astextplain
79 | *.DOC diff=astextplain
80 | *.docx diff=astextplain
81 | *.DOCX diff=astextplain
82 | *.dot diff=astextplain
83 | *.DOT diff=astextplain
84 | *.pdf diff=astextplain
85 | *.PDF diff=astextplain
86 | *.rtf diff=astextplain
87 | *.RTF diff=astextplain
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | [Xx]64/
19 | [Xx]86/
20 | [Bb]uild/
21 | bld/
22 | [Bb]in/
23 | [Oo]bj/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | artifacts/
46 |
47 | *_i.c
48 | *_p.c
49 | *_i.h
50 | *.ilk
51 | *.meta
52 | *.obj
53 | *.pch
54 | *.pdb
55 | *.pgc
56 | *.pgd
57 | *.rsp
58 | *.sbr
59 | *.tlb
60 | *.tli
61 | *.tlh
62 | *.tmp
63 | *.tmp_proj
64 | *.log
65 | *.vspscc
66 | *.vssscc
67 | .builds
68 | *.pidb
69 | *.svclog
70 | *.scc
71 |
72 | # Chutzpah Test files
73 | _Chutzpah*
74 |
75 | # Visual C++ cache files
76 | ipch/
77 | *.aps
78 | *.ncb
79 | *.opendb
80 | *.opensdf
81 | *.sdf
82 | *.cachefile
83 | *.VC.db
84 |
85 | # Visual Studio profiler
86 | *.psess
87 | *.vsp
88 | *.vspx
89 | *.sap
90 |
91 | # TFS 2012 Local Workspace
92 | $tf/
93 |
94 | # Guidance Automation Toolkit
95 | *.gpState
96 |
97 | # ReSharper is a .NET coding add-in
98 | _ReSharper*/
99 | *.[Rr]e[Ss]harper
100 | *.DotSettings.user
101 |
102 | # JustCode is a .NET coding add-in
103 | .JustCode
104 |
105 | # TeamCity is a build add-in
106 | _TeamCity*
107 |
108 | # DotCover is a Code Coverage Tool
109 | *.dotCover
110 |
111 | # NCrunch
112 | _NCrunch_*
113 | .*crunch*.local.xml
114 | nCrunchTemp_*
115 |
116 | # MightyMoose
117 | *.mm.*
118 | AutoTest.Net/
119 |
120 | # Web workbench (sass)
121 | .sass-cache/
122 |
123 | # Installshield output folder
124 | [Ee]xpress/
125 |
126 | # DocProject is a documentation generator add-in
127 | DocProject/buildhelp/
128 | DocProject/Help/*.HxT
129 | DocProject/Help/*.HxC
130 | DocProject/Help/*.hhc
131 | DocProject/Help/*.hhk
132 | DocProject/Help/*.hhp
133 | DocProject/Help/Html2
134 | DocProject/Help/html
135 |
136 | # Click-Once directory
137 | publish/
138 |
139 | # Publish Web Output
140 | *.[Pp]ublish.xml
141 | *.azurePubxml
142 |
143 | # TODO: Un-comment the next line if you do not want to checkin
144 | # your web deploy settings because they may include unencrypted
145 | # passwords
146 | #*.pubxml
147 | *.publishproj
148 |
149 | # NuGet Packages
150 | *.nupkg
151 | # The packages folder can be ignored because of Package Restore
152 | **/packages/*
153 | # except build/, which is used as an MSBuild target.
154 | !**/packages/build/
155 | # Uncomment if necessary however generally it will be regenerated when needed
156 | #!**/packages/repositories.config
157 | # NuGet v3's project.json files produces more ignoreable files
158 | *.nuget.props
159 | *.nuget.targets
160 |
161 | # Microsoft Azure Build Output
162 | csx/
163 | *.build.csdef
164 |
165 | # Microsoft Azure Emulator
166 | ecf/
167 | rcf/
168 |
169 | # Microsoft Azure ApplicationInsights config file
170 | ApplicationInsights.config
171 |
172 | # Windows Store app package directory
173 | AppPackages/
174 | BundleArtifacts/
175 |
176 | # Visual Studio cache files
177 | # files ending in .cache can be ignored
178 | *.[Cc]ache
179 | # but keep track of directories ending in .cache
180 | !*.[Cc]ache/
181 |
182 | # Others
183 | ClientBin/
184 | [Ss]tyle[Cc]op.*
185 | ~$*
186 | *~
187 | *.dbmdl
188 | *.dbproj.schemaview
189 | *.pfx
190 | *.publishsettings
191 | node_modules/
192 | orleans.codegen.cs
193 |
194 | # RIA/Silverlight projects
195 | Generated_Code/
196 |
197 | # Backup & report files from converting an old project file
198 | # to a newer Visual Studio version. Backup files are not needed,
199 | # because we have git ;-)
200 | _UpgradeReport_Files/
201 | Backup*/
202 | UpgradeLog*.XML
203 | UpgradeLog*.htm
204 |
205 | # SQL Server files
206 | *.mdf
207 | *.ldf
208 |
209 | # Business Intelligence projects
210 | *.rdl.data
211 | *.bim.layout
212 | *.bim_*.settings
213 |
214 | # Microsoft Fakes
215 | FakesAssemblies/
216 |
217 | # GhostDoc plugin setting file
218 | *.GhostDoc.xml
219 |
220 | # Node.js Tools for Visual Studio
221 | .ntvs_analysis.dat
222 |
223 | # Visual Studio 6 build log
224 | *.plg
225 |
226 | # Visual Studio 6 workspace options file
227 | *.opt
228 |
229 | # Visual Studio LightSwitch build output
230 | **/*.HTMLClient/GeneratedArtifacts
231 | **/*.DesktopClient/GeneratedArtifacts
232 | **/*.DesktopClient/ModelManifest.xml
233 | **/*.Server/GeneratedArtifacts
234 | **/*.Server/ModelManifest.xml
235 | _Pvt_Extensions
236 |
237 | # LightSwitch generated files
238 | GeneratedArtifacts/
239 | ModelManifest.xml
240 |
241 | # Paket dependency manager
242 | .paket/paket.exe
243 |
244 | # FAKE - F# Make
245 | .fake/
246 |
247 | # PowerShell dependencies
248 | ps_modules
249 |
250 | .BuildOutput
251 |
252 | appsettings.development.json
253 |
254 | Tests/**/TEST-*.xml
255 | Tests/**/dump.txt
256 | Tests/**/*.js
257 | Tests/**/*.js.map
258 | Tests/**/*.d.ts
259 | Tests/Node/settings.json
260 |
261 | Tasks/**/*.js
262 | Tasks/**/*.js.map
263 | Tasks/**/*.d.ts
264 | Tasks/*/common/**/*.*
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.codeActionsOnSave": {}
3 | }
4 |
--------------------------------------------------------------------------------
/Common/PowerShell3/VstsAzureHelpers/FindSqlPackagePath.ps1:
--------------------------------------------------------------------------------
1 | function Get-SqlPackageOnTargetMachine {
2 | try {
3 | $sqlDacPath, $sqlVersion = Get-HighestVersionSqlPackageWithSqlLocation
4 | $sqlVersionNumber = [decimal] $sqlVersion
5 | }
6 | catch [System.Exception] {
7 | Write-VstsTaskVerbose -Message ("Failed to get Dac Framework (installed with SQL Server) location with exception: " + $_.Exception.Message)
8 | $sqlVersionNumber = 0
9 | }
10 |
11 | try {
12 | $sqlMsiDacPath, $sqlMsiVersion = Get-HighestVersionSqlPackageWithDacMsiLocation
13 | $sqlMsiVersionNumber = [decimal] $sqlMsiVersion
14 | }
15 | catch [System.Exception] {
16 | Write-VstsTaskVerbose -Message ("Failed to get Dac Framework (installed with DAC Framework) location with exception: " + $_.Exception.Message)
17 | $sqlMsiVersionNumber = 0
18 | }
19 |
20 | try {
21 | $vsDacPath, $vsVersion = Get-HighestVersionSqlPackageInVSLocation
22 | $vsVersionNumber = [decimal] $vsVersion
23 | }
24 | catch [System.Exception] {
25 | Write-VstsTaskVerbose -Message ("Failed to get Dac Framework (installed with Visual Studio) location with exception: " + $_.Exception.Message)
26 | $vsVersionNumber = 0
27 | }
28 |
29 | if (($vsVersionNumber -ge $sqlVersionNumber) -and ($vsVersionNumber -ge $sqlMsiVersionNumber)) {
30 | $dacPath = $vsDacPath
31 | }
32 | elseif ($sqlVersionNumber -ge $sqlMsiVersionNumber) {
33 | $dacPath = $sqlDacPath
34 | }
35 | else {
36 | $dacPath = $sqlMsiDacPath
37 | }
38 |
39 | if ($dacPath -eq $null) {
40 | $client = new-object System.Net.WebClient
41 |
42 | $archive = $env:BUILD_SOURCESDIRECTORY + "\dataTools.zip"
43 | $dataToolsRoot = $env:BUILD_SOURCESDIRECTORY + "\dataTools"
44 |
45 | $client.DownloadFile("https://www.nuget.org/api/v2/package/Microsoft.Data.Tools.Msbuild/10.0.61710.120", $archive);
46 |
47 | Expand-Archive $archive -DestinationPath $dataToolsRoot
48 |
49 | $dacPath = $dataToolsRoot + "\lib\net46\sqlpackage.exe"
50 |
51 | return $dacPath
52 | #throw "Unable to find the location of Dac Framework (SqlPackage.exe) from registry on machine $env:COMPUTERNAME"
53 | }
54 | else {
55 | return $dacPath
56 | }
57 | }
58 |
59 | function Get-RegistryValueIgnoreError {
60 | param
61 | (
62 | [parameter(Mandatory = $true)]
63 | [Microsoft.Win32.RegistryHive]
64 | $RegistryHive,
65 |
66 | [parameter(Mandatory = $true)]
67 | [System.String]
68 | $Key,
69 |
70 | [parameter(Mandatory = $true)]
71 | [System.String]
72 | $Value,
73 |
74 | [parameter(Mandatory = $true)]
75 | [Microsoft.Win32.RegistryView]
76 | $RegistryView
77 | )
78 |
79 | try {
80 | $baseKey = [Microsoft.Win32.RegistryKey]::OpenBaseKey($RegistryHive, $RegistryView)
81 | $subKey = $baseKey.OpenSubKey($Key)
82 | if ($subKey -ne $null) {
83 | return $subKey.GetValue($Value)
84 | }
85 | }
86 | catch {
87 | }
88 |
89 | return $null
90 | }
91 |
92 | function Get-SubKeysInFloatFormat($keys) {
93 | $targetKeys = @()
94 | foreach ($key in $keys) {
95 | try {
96 | $targetKeys += [decimal] $key
97 | }
98 | catch {
99 | }
100 | }
101 |
102 | $targetKeys
103 | }
104 |
105 | function Get-SqlPackageForSqlVersion([int] $majorVersion, [bool] $wow6432Node) {
106 | $sqlInstallRootRegKey = "SOFTWARE", "Microsoft", "Microsoft SQL Server", "$majorVersion" -join [System.IO.Path]::DirectorySeparatorChar
107 |
108 | if ($wow6432Node -eq $true) {
109 | $sqlInstallRootPath = Get-RegistryValueIgnoreError LocalMachine "$sqlInstallRootRegKey" "VerSpecificRootDir" Registry64
110 | }
111 | else {
112 | $sqlInstallRootPath = Get-RegistryValueIgnoreError LocalMachine "$sqlInstallRootRegKey" "VerSpecificRootDir" Registry32
113 | }
114 |
115 | if ($sqlInstallRootPath -eq $null) {
116 | return $null
117 | }
118 |
119 | Write-VstsTaskVerbose -Message "Sql Version Specific Root Dir for version $majorVersion as read from registry: $sqlInstallRootPath"
120 |
121 | $DacInstallPath = [System.IO.Path]::Combine($sqlInstallRootPath, "Dac", "bin", "SqlPackage.exe")
122 |
123 | if (Test-Path $DacInstallPath) {
124 | Write-VstsTaskVerbose -Message "Dac Framework installed with SQL Version $majorVersion found at $DacInstallPath on machine $env:COMPUTERNAME"
125 | return $DacInstallPath
126 | }
127 |
128 | return $null
129 | }
130 |
131 | function Get-HighestVersionSqlPackageWithSqlLocation() {
132 | $sqlRegKey = "HKLM:", "SOFTWARE", "Wow6432Node", "Microsoft", "Microsoft SQL Server" -join [System.IO.Path]::DirectorySeparatorChar
133 | $sqlRegKey64 = "HKLM:", "SOFTWARE", "Microsoft", "Microsoft SQL Server" -join [System.IO.Path]::DirectorySeparatorChar
134 |
135 | if (-not (Test-Path $sqlRegKey)) {
136 | $sqlRegKey = $sqlRegKey64
137 | }
138 |
139 | if (-not (Test-Path $sqlRegKey)) {
140 | return $null, 0
141 | }
142 |
143 | $keys = Get-Item $sqlRegKey | % {$_.GetSubKeyNames()}
144 | $versions = Get-SubKeysInFloatFormat $keys | Sort-Object -Descending
145 |
146 | Write-VstsTaskVerbose -Message "Sql Versions installed on machine $env:COMPUTERNAME as read from registry: $versions"
147 |
148 | foreach ($majorVersion in $versions) {
149 | $DacInstallPathWow6432Node = Get-SqlPackageForSqlVersion $majorVersion $true
150 | $DacInstallPath = Get-SqlPackageForSqlVersion $majorVersion $false
151 |
152 | if ($DacInstallPathWow6432Node -ne $null) {
153 | return $DacInstallPathWow6432Node, $majorVersion
154 | }
155 | elseif ($DacInstallPath -ne $null) {
156 | return $DacInstallPath, $majorVersion
157 | }
158 | }
159 |
160 | Write-VstsTaskVerbose -Message "Dac Framework (installed with SQL) not found on machine $env:COMPUTERNAME"
161 |
162 | return $null, 0
163 | }
164 |
165 | function Get-HighestVersionSqlPackageWithDacMsiLocation() {
166 | $sqlDataTierFrameworkRegKeyWow = "HKLM:", "SOFTWARE", "Wow6432Node", "Microsoft", "Microsoft SQL Server", "Data-Tier Application Framework" -join [System.IO.Path]::DirectorySeparatorChar
167 | $sqlDataTierFrameworkRegKey = "HKLM:", "SOFTWARE", "Microsoft", "Microsoft SQL Server", "Data-Tier Application Framework" -join [System.IO.Path]::DirectorySeparatorChar
168 |
169 | if (-not (Test-Path $sqlDataTierFrameworkRegKey)) {
170 | $sqlDataTierFrameworkRegKey = $sqlDataTierFrameworkRegKeyWow
171 | }
172 |
173 | if ((Test-Path $sqlDataTierFrameworkRegKey)) {
174 | $keys = Get-Item $sqlDataTierFrameworkRegKey | % {$_.GetSubKeyNames()}
175 | $versions = Get-SubKeysInFloatFormat $keys | Sort-Object -Descending
176 |
177 | foreach ($majorVersion in $versions) {
178 | $sqlInstallRootRegKey = "SOFTWARE", "Microsoft", "Microsoft SQL Server", "Data-Tier Application Framework", "$majorVersion" -join [System.IO.Path]::DirectorySeparatorChar
179 | $sqlInstallRootPath64 = Get-RegistryValueIgnoreError LocalMachine "$sqlInstallRootRegKey" "InstallDir" Registry64
180 | $sqlInstallRootPath32 = Get-RegistryValueIgnoreError LocalMachine "$sqlInstallRootRegKey" "InstallDir" Registry32
181 | if ($sqlInstallRootPath64 -ne $null) {
182 | $sqlInstallRootPath = $sqlInstallRootPath64
183 | break
184 | }
185 | if ($sqlInstallRootPath32 -ne $null) {
186 | $sqlInstallRootPath = $sqlInstallRootPath32
187 | break
188 | }
189 | }
190 |
191 | $DacInstallPath = [System.IO.Path]::Combine($sqlInstallRootPath, "SqlPackage.exe")
192 |
193 | if (Test-Path $DacInstallPath) {
194 | Write-Verbose "Dac Framework installed with SQL Version $majorVersion found at $DacInstallPath on machine $env:COMPUTERNAME"
195 | return $DacInstallPath, $majorVersion
196 | }
197 | }
198 |
199 | $sqlRegKeyWow = "HKLM:", "SOFTWARE", "Wow6432Node", "Microsoft", "Microsoft SQL Server", "DACFramework", "CurrentVersion" -join [System.IO.Path]::DirectorySeparatorChar
200 | $sqlRegKey = "HKLM:", "SOFTWARE", "Microsoft", "Microsoft SQL Server", "DACFramework", "CurrentVersion" -join [System.IO.Path]::DirectorySeparatorChar
201 |
202 | $sqlKey = "SOFTWARE", "Microsoft", "Microsoft SQL Server", "DACFramework", "CurrentVersion" -join [System.IO.Path]::DirectorySeparatorChar
203 |
204 | if (Test-Path $sqlRegKey) {
205 | $dacVersion = Get-RegistryValueIgnoreError LocalMachine "$sqlKey" "Version" Registry64
206 | $majorVersion = $dacVersion.Substring(0, $dacVersion.IndexOf(".")) + "0"
207 | }
208 |
209 | if (Test-Path $sqlRegKeyWow) {
210 | $dacVersionX86 = Get-RegistryValueIgnoreError LocalMachine "$sqlKey" "Version" Registry32
211 | $majorVersionX86 = $dacVersionX86.Substring(0, $dacVersionX86.IndexOf(".")) + "0"
212 | }
213 |
214 | if ((-not($dacVersion)) -and (-not($dacVersionX86))) {
215 | Write-VstsTaskVerbose -Message "Dac Framework (installed with DAC Framework) not found on machine $env:COMPUTERNAME"
216 | return $null, 0
217 | }
218 |
219 | if ($majorVersionX86 -gt $majorVersion) {
220 | $majorVersion = $majorVersionX86
221 | }
222 |
223 | $dacRelativePath = "Microsoft SQL Server", "$majorVersion", "DAC", "bin", "SqlPackage.exe" -join [System.IO.Path]::DirectorySeparatorChar
224 | $programFiles = $env:ProgramFiles
225 | $programFilesX86 = "${env:ProgramFiles(x86)}"
226 |
227 | if (-not ($programFilesX86 -eq $null)) {
228 | $dacPath = $programFilesX86, $dacRelativePath -join [System.IO.Path]::DirectorySeparatorChar
229 |
230 | if (Test-Path("$dacPath")) {
231 | Write-VstsTaskVerbose -Message "Dac Framework (installed with DAC Framework Msi) found on machine $env:COMPUTERNAME at $dacPath"
232 | return $dacPath, $majorVersion
233 | }
234 | }
235 |
236 | if (-not ($programFiles -eq $null)) {
237 | $dacPath = $programFiles, $dacRelativePath -join [System.IO.Path]::DirectorySeparatorChar
238 |
239 | if (Test-Path($dacPath)) {
240 | Write-VstsTaskVerbose -Message "Dac Framework (installed with DAC Framework Msi) found on machine $env:COMPUTERNAME at $dacPath"
241 | return $dacPath, $majorVersion
242 | }
243 | }
244 |
245 | return $null, 0
246 | }
247 |
248 | function Get-SqlPackageInVSLocation([string] $version) {
249 | $vsRegKeyForVersion = "SOFTWARE", "Microsoft", "VisualStudio", $version -join [System.IO.Path]::DirectorySeparatorChar
250 |
251 | $vsInstallDir = Get-RegistryValueIgnoreError LocalMachine "$vsRegKeyForVersion" "InstallDir" Registry64
252 |
253 | if ($vsInstallDir -eq $null) {
254 | $vsInstallDir = Get-RegistryValueIgnoreError LocalMachine "$vsRegKeyForVersion" "InstallDir" Registry32
255 | }
256 |
257 | if ($vsInstallDir) {
258 | Write-VstsTaskVerbose -Message "Visual Studio install location: $vsInstallDir"
259 |
260 | $dacExtensionPath = [System.IO.Path]::Combine("Extensions", "Microsoft", "SQLDB", "DAC")
261 | $dacParentDir = [System.IO.Path]::Combine($vsInstallDir, $dacExtensionPath)
262 |
263 | if (Test-Path $dacParentDir) {
264 | $dacVersionDirs = Get-ChildItem $dacParentDir | Sort-Object @{e = {$_.Name -as [int]}} -Descending
265 |
266 | foreach ($dacVersionDir in $dacVersionDirs) {
267 | $dacVersion = $dacVersionDir.Name
268 | $dacFullPath = [System.IO.Path]::Combine($dacVersionDir.FullName, "SqlPackage.exe")
269 |
270 | if (Test-Path $dacFullPath -pathtype leaf) {
271 | Write-VstsTaskVerbose -Message "Dac Framework installed with Visual Studio found at $dacFullPath on machine $env:COMPUTERNAME"
272 | return $dacFullPath, $dacVersion
273 | }
274 | else {
275 | Write-VstsTaskVerbose -Message "Unable to find Dac framework installed with Visual Studio at $($dacVersionDir.FullName) on machine $env:COMPUTERNAME"
276 | }
277 | }
278 | }
279 | }
280 |
281 | return $null, 0
282 | }
283 |
284 | function Get-HighestVersionSqlPackageInVSLocation() {
285 | $vsRegKey = "HKLM:", "SOFTWARE", "Wow6432Node", "Microsoft", "VisualStudio" -join [System.IO.Path]::DirectorySeparatorChar
286 | $vsRegKey64 = "HKLM:", "SOFTWARE", "Microsoft", "VisualStudio" -join [System.IO.Path]::DirectorySeparatorChar
287 |
288 | if (-not (Test-Path $vsRegKey)) {
289 | $vsRegKey = $vsRegKey64
290 | }
291 |
292 | if (-not (Test-Path $vsRegKey)) {
293 | Write-VstsTaskVerbose -Message "Visual Studio not found on machine $env:COMPUTERNAME"
294 | return $null, 0
295 | }
296 |
297 | $keys = Get-Item $vsRegKey | % {$_.GetSubKeyNames()}
298 | $versions = Get-SubKeysInFloatFormat $keys | Sort-Object -Descending
299 |
300 | Write-VstsTaskVerbose -Message "Visual Studio versions found on machine $env:COMPUTERNAME as read from registry: $versions"
301 |
302 | foreach ($majorVersion in $versions) {
303 | $dacFullPath, $dacVersion = Get-SqlPackageInVSLocation $majorVersion
304 |
305 | if ($dacFullPath -ne $null) {
306 | return $dacFullPath, $dacVersion
307 | }
308 | }
309 |
310 | Write-VstsTaskVerbose -Message "Dac Framework (installed with Visual Studio) not found on machine $env:COMPUTERNAME "
311 |
312 | return $null, 0
313 | }
314 |
--------------------------------------------------------------------------------
/Common/PowerShell3/VstsAzureHelpers/HelperFunctions.ps1:
--------------------------------------------------------------------------------
1 | function Get-AgentStartIPAddress {
2 | $data = (Invoke-WebRequest -Uri "checkip.dyndns.org" -UseBasicParsing -Verbose).Content
3 |
4 | $ipRegex = "(?
((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))"
5 | if ($data -Match $ipRegex) {
6 | $startIP = $Matches.Address
7 | }
8 | else {
9 | throw (Get-VstsLocString -Key AZ_CannotRetrieveExternalIp0 -ArgumentList $data)
10 | }
11 |
12 | return $startIP
13 | }
14 |
15 | function Get-ResourceGroupName {
16 | param([String] [Parameter(Mandatory = $true)] $resourceName,
17 | [String] [Parameter(Mandatory = $true)] $resourceType)
18 |
19 | try {
20 | Write-VstsTaskVerbose -Message "[Azure Call] Getting resource details for resource: $resourceName with resource type: $resourceType"
21 | $resourceDetails = (Get-AzureRMResource -ErrorAction Stop) | Where-Object { ($_.ResourceName -eq $resourceName -or $_.Name -eq $resourceName) -and $_.ResourceType -eq $resourceType } -Verbose
22 | Write-VstsTaskVerbose -Message "[Azure Call] Retrieved resource details successfully for resource: $resourceName with resource type: $resourceType"
23 | $resourceGroupName = $resourceDetails.ResourceGroupName
24 | Write-VstsTaskVerbose -Message "Resource Group Name for '$resourceName' of type '$resourceType': '$resourceGroupName'."
25 | return $resourceGroupName
26 | }
27 | finally {
28 | if ([string]::IsNullOrEmpty($resourceGroupName)) {
29 | throw (Get-VstsLocString -Key AZ_ResourceNotFound0 -ArgumentList $resourceName)
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Common/PowerShell3/VstsAzureHelpers/ImportFunctions.ps1:
--------------------------------------------------------------------------------
1 | function Import-AzureModule {
2 | [CmdletBinding()]
3 | param(
4 | [Parameter(Mandatory = $true)]
5 | [ValidateSet('Azure', 'AzureRM')]
6 | [string[]]$PreferredModule)
7 |
8 | Trace-VstsEnteringInvocation $MyInvocation
9 | try {
10 | Write-VstsTaskVerbose -Message "Env:PSModulePath: '$env:PSMODULEPATH'"
11 | if ($PreferredModule -contains 'Azure' -and $PreferredModule -contains 'AzureRM') {
12 | # Attempt to import Azure and AzureRM.
13 | $azure = (Import-FromModulePath -Classic:$true) -or (Import-FromSdkPath -Classic:$true)
14 | $azureRM = (Import-FromModulePath -Classic:$false) -or (Import-FromSdkPath -Classic:$false)
15 | if (!$azure -and !$azureRM) {
16 | throw (Get-VstsLocString -Key AZ_ModuleNotFound)
17 | }
18 | } elseif ($PreferredModule -contains 'Azure') {
19 | # Attempt to import Azure but fallback to AzureRM.
20 | if (!(Import-FromModulePath -Classic:$true) -and
21 | !(Import-FromSdkPath -Classic:$true) -and
22 | !(Import-FromModulePath -Classic:$false) -and
23 | !(Import-FromSdkPath -Classic:$false))
24 | {
25 | throw (Get-VstsLocString -Key AZ_ModuleNotFound)
26 | }
27 | } else {
28 | # Attempt to import AzureRM but fallback to Azure.
29 | if (!(Import-FromModulePath -Classic:$false) -and
30 | !(Import-FromSdkPath -Classic:$false) -and
31 | !(Import-FromModulePath -Classic:$true) -and
32 | !(Import-FromSdkPath -Classic:$true))
33 | {
34 | throw (Get-VstsLocString -Key AZ_ModuleNotFound)
35 | }
36 | }
37 |
38 | # Validate the Classic version.
39 | $minimumVersion = [version]'0.8.10.1'
40 | if ($script:azureModule -and $script:azureModule.Version -lt $minimumVersion) {
41 | throw (Get-VstsLocString -Key AZ_RequiresMinVersion0 -ArgumentList $minimumVersion)
42 | }
43 | } finally {
44 | Trace-VstsLeavingInvocation $MyInvocation
45 | }
46 | }
47 |
48 | function Import-FromModulePath {
49 | [CmdletBinding()]
50 | param(
51 | [switch]$Classic)
52 |
53 | Trace-VstsEnteringInvocation $MyInvocation
54 | try {
55 | # Determine which module to look for.
56 | if ($Classic) {
57 | $name = "Azure"
58 | } else {
59 | $name = "AzureRM"
60 | }
61 |
62 | # Attempt to resolve the module.
63 | Write-VstsTaskVerbose -Message "Attempting to find the module '$name' from the module path."
64 | $module = Get-Module -Name $name -ListAvailable | Select-Object -First 1
65 | if (!$module) {
66 | return $false
67 | }
68 |
69 | # Import the module.
70 | Write-Host "##[command]Import-Module -Name $($module.Path) -Global"
71 | $module = Import-Module -Name $module.Path -Global -PassThru
72 | Write-VstsTaskVerbose -Message "Imported module version: $($module.Version)"
73 |
74 | if ($Classic) {
75 | # Store the imported Azure module.
76 | $script:azureModule = $module
77 | } else {
78 | # The AzureRM module was imported.
79 |
80 | # Validate the AzureRM.profile module can be found.
81 | $profileModule = Get-Module -Name AzureRM.profile -ListAvailable | Select-Object -First 1
82 | if (!$profileModule) {
83 | throw (Get-VstsLocString -Key AZ_AzureRMProfileModuleNotFound)
84 | }
85 |
86 | # Import and then store the AzureRM.profile module.
87 | Write-Host "##[command]Import-Module -Name $($profileModule.Path) -Global"
88 | $script:azureRMProfileModule = Import-Module -Name $profileModule.Path -Global -PassThru
89 | Write-VstsTaskVerbose -Message "Imported module version: $($script:azureRMProfileModule.Version)"
90 | }
91 |
92 | return $true
93 | } finally {
94 | Trace-VstsLeavingInvocation $MyInvocation
95 | }
96 | }
97 |
98 | function Import-FromSdkPath {
99 | [CmdletBinding()]
100 | param([switch]$Classic)
101 |
102 | Trace-VstsEnteringInvocation $MyInvocation
103 | try {
104 | if ($Classic) {
105 | $partialPath = 'Microsoft SDKs\Azure\PowerShell\ServiceManagement\Azure\Azure.psd1'
106 | } else {
107 | $partialPath = 'Microsoft SDKs\Azure\PowerShell\ResourceManager\AzureResourceManager\AzureRM.Profile\AzureRM.Profile.psd1'
108 | }
109 |
110 | foreach ($programFiles in @(${env:ProgramFiles(x86)}, $env:ProgramFiles)) {
111 | if (!$programFiles) {
112 | continue
113 | }
114 |
115 | $path = [System.IO.Path]::Combine($programFiles, $partialPath)
116 | Write-VstsTaskVerbose -Message "Checking if path exists: $path"
117 | if (Test-Path -LiteralPath $path -PathType Leaf) {
118 | # Import the module.
119 | Write-Host "##[command]Import-Module -Name $path -Global"
120 | $module = Import-Module -Name $path -Global -PassThru
121 | Write-VstsTaskVerbose -Message "Imported module version: $($module.Version)"
122 |
123 | # Store the imported module.
124 | if ($Classic) {
125 | $script:azureModule = $module
126 | } else {
127 | $script:azureRMProfileModule = $module
128 | }
129 |
130 | return $true
131 | }
132 | }
133 |
134 | return $false
135 | } finally {
136 | Trace-VstsLeavingInvocation $MyInvocation
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/Common/PowerShell3/VstsAzureHelpers/InitializeFunctions.ps1:
--------------------------------------------------------------------------------
1 | function Add-Certificate {
2 | [CmdletBinding()]
3 | param([Parameter(Mandatory=$true)]$Endpoint)
4 |
5 | # Add the certificate to the cert store.
6 | $bytes = [System.Convert]::FromBase64String($Endpoint.Auth.Parameters.Certificate)
7 | $certificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
8 | $certificate.Import($bytes)
9 | $store = New-Object System.Security.Cryptography.X509Certificates.X509Store(
10 | ([System.Security.Cryptography.X509Certificates.StoreName]::My),
11 | ([System.Security.Cryptography.X509Certificates.StoreLocation]::CurrentUser))
12 | $store.Open(([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite))
13 | $store.Add($certificate)
14 | $store.Close()
15 | return $certificate
16 | }
17 |
18 | function Format-Splat {
19 | [CmdletBinding()]
20 | param([Parameter(Mandatory = $true)][hashtable]$Hashtable)
21 |
22 | # Collect the parameters (names and values) in an array.
23 | $parameters = foreach ($key in $Hashtable.Keys) {
24 | $value = $Hashtable[$key]
25 | # If the value is a bool, format the parameter as a switch (ending with ':').
26 | if ($value -is [bool]) { "-$($key):" } else { "-$key" }
27 | $value
28 | }
29 |
30 | $OFS = " "
31 | "$parameters" # String join the array.
32 | }
33 |
34 | function Initialize-AzureSubscription {
35 | [CmdletBinding()]
36 | param(
37 | [Parameter(Mandatory=$true)]
38 | $Endpoint,
39 | [Parameter(Mandatory=$false)]
40 | [string]$StorageAccount)
41 |
42 | #Set UserAgent for Azure Calls
43 | Set-UserAgent
44 |
45 | if ($Endpoint.Auth.Scheme -eq 'Certificate') {
46 | # Certificate is only supported for the Azure module.
47 | if (!$script:azureModule) {
48 | throw (Get-VstsLocString -Key AZ_CertificateAuthNotSupported)
49 | }
50 |
51 | # Add the certificate to the cert store.
52 | $certificate = Add-Certificate -Endpoint $Endpoint
53 |
54 | # Setup the additional parameters.
55 | $additional = @{ }
56 | if ($StorageAccount) {
57 | $additional['CurrentStorageAccountName'] = $StorageAccount
58 | }
59 |
60 | $environmentName = "AzureCloud"
61 | if( $Endpoint.Data.Environment ) {
62 | $environmentName = $Endpoint.Data.Environment
63 | }
64 |
65 | # Set the subscription.
66 | Write-Host "##[command]Set-AzureSubscription -SubscriptionName $($Endpoint.Data.SubscriptionName) -SubscriptionId $($Endpoint.Data.SubscriptionId) -Certificate ******** -Environment $environmentName $(Format-Splat $additional)"
67 | Set-AzureSubscription -SubscriptionName $Endpoint.Data.SubscriptionName -SubscriptionId $Endpoint.Data.SubscriptionId -Certificate $certificate -Environment $environmentName @additional
68 | Set-CurrentAzureSubscription -SubscriptionId $Endpoint.Data.SubscriptionId -StorageAccount $StorageAccount
69 | } elseif ($Endpoint.Auth.Scheme -eq 'UserNamePassword') {
70 | $psCredential = New-Object System.Management.Automation.PSCredential(
71 | $Endpoint.Auth.Parameters.UserName,
72 | (ConvertTo-SecureString $Endpoint.Auth.Parameters.Password -AsPlainText -Force))
73 |
74 | # Add account (Azure).
75 | if ($script:azureModule) {
76 | try {
77 | Write-Host "##[command]Add-AzureAccount -Credential $psCredential"
78 | $null = Add-AzureAccount -Credential $psCredential
79 | } catch {
80 | # Provide an additional, custom, credentials-related error message.
81 | Write-VstsTaskError -Message $_.Exception.Message
82 | throw (New-Object System.Exception((Get-VstsLocString -Key AZ_CredentialsError), $_.Exception))
83 | }
84 | }
85 |
86 | # Add account (AzureRM).
87 | if ($script:azureRMProfileModule) {
88 | try {
89 | Write-Host "##[command]Add-AzureRMAccount -Credential $psCredential"
90 | $null = Add-AzureRMAccount -Credential $psCredential
91 | } catch {
92 | # Provide an additional, custom, credentials-related error message.
93 | Write-VstsTaskError -Message $_.Exception.Message
94 | throw (New-Object System.Exception((Get-VstsLocString -Key AZ_CredentialsError), $_.Exception))
95 | }
96 | }
97 |
98 | # Select subscription (Azure).
99 | if ($script:azureModule) {
100 | Set-CurrentAzureSubscription -SubscriptionId $Endpoint.Data.SubscriptionId -StorageAccount $StorageAccount
101 | }
102 |
103 | # Select subscription (AzureRM).
104 | if ($script:azureRMProfileModule) {
105 | Set-CurrentAzureRMSubscription -SubscriptionId $Endpoint.Data.SubscriptionId
106 | }
107 | } elseif ($Endpoint.Auth.Scheme -eq 'ServicePrincipal') {
108 | $psCredential = New-Object System.Management.Automation.PSCredential(
109 | $Endpoint.Auth.Parameters.ServicePrincipalId,
110 | (ConvertTo-SecureString $Endpoint.Auth.Parameters.ServicePrincipalKey -AsPlainText -Force))
111 | if ($script:azureModule -and $script:azureModule.Version -lt ([version]'0.9.9')) {
112 | # Service principals arent supported from 0.9.9 and greater in the Azure module.
113 | try {
114 | Write-Host "##[command]Add-AzureAccount -ServicePrincipal -Tenant $($Endpoint.Auth.Parameters.TenantId) -Credential $psCredential"
115 | $null = Add-AzureAccount -ServicePrincipal -Tenant $Endpoint.Auth.Parameters.TenantId -Credential $psCredential
116 | } catch {
117 | # Provide an additional, custom, credentials-related error message.
118 | Write-VstsTaskError -Message $_.Exception.Message
119 | throw (New-Object System.Exception((Get-VstsLocString -Key AZ_ServicePrincipalError), $_.Exception))
120 | }
121 |
122 | Set-CurrentAzureSubscription -SubscriptionId $Endpoint.Data.SubscriptionId -StorageAccount $StorageAccount
123 | } elseif ($script:azureModule) {
124 | # Throw if >=0.9.9 Azure.
125 | throw (Get-VstsLocString -Key "AZ_ServicePrincipalAuthNotSupportedAzureVersion0" -ArgumentList $script:azureModule.Version)
126 | } else {
127 | # Else, this is AzureRM.
128 | try {
129 | Write-Host "##[command]Add-AzureRMAccount -ServicePrincipal -Tenant $($Endpoint.Auth.Parameters.TenantId) -Credential $psCredential"
130 | $null = Add-AzureRMAccount -ServicePrincipal -Tenant $Endpoint.Auth.Parameters.TenantId -Credential $psCredential
131 | } catch {
132 | # Provide an additional, custom, credentials-related error message.
133 | Write-VstsTaskError -Message $_.Exception.Message
134 | throw (New-Object System.Exception((Get-VstsLocString -Key AZ_ServicePrincipalError), $_.Exception))
135 | }
136 |
137 | Set-CurrentAzureRMSubscription -SubscriptionId $Endpoint.Data.SubscriptionId -TenantId $Endpoint.Auth.Parameters.TenantId
138 | }
139 | } else {
140 | throw (Get-VstsLocString -Key AZ_UnsupportedAuthScheme0 -ArgumentList $Endpoint.Auth.Scheme)
141 | }
142 | }
143 |
144 | function Set-CurrentAzureSubscription {
145 | [CmdletBinding()]
146 | param(
147 | [Parameter(Mandatory=$true)]
148 | [string]$SubscriptionId,
149 | [string]$StorageAccount)
150 |
151 | $additional = @{ }
152 | if ($script:azureModule.Version -lt ([version]'0.8.15')) {
153 | $additional['Default'] = $true # The Default switch is required prior to 0.8.15.
154 | }
155 |
156 | Write-Host "##[command]Select-AzureSubscription -SubscriptionId $SubscriptionId $(Format-Splat $additional)"
157 | $null = Select-AzureSubscription -SubscriptionId $SubscriptionId @additional
158 | if ($StorageAccount) {
159 | Write-Host "##[command]Set-AzureSubscription -SubscriptionId $SubscriptionId -CurrentStorageAccountName $StorageAccount"
160 | Set-AzureSubscription -SubscriptionId $SubscriptionId -CurrentStorageAccountName $StorageAccount
161 | }
162 | }
163 |
164 | function Set-CurrentAzureRMSubscription {
165 | [CmdletBinding()]
166 | param(
167 | [Parameter(Mandatory=$true)]
168 | [string]$SubscriptionId,
169 | [string]$TenantId)
170 |
171 | $additional = @{ }
172 | if ($TenantId) { $additional['TenantId'] = $TenantId }
173 | Write-Host "##[command]Select-AzureRMSubscription -SubscriptionId $SubscriptionId $(Format-Splat $additional)"
174 | $null = Select-AzureRMSubscription -SubscriptionId $SubscriptionId @additional
175 | }
176 |
177 | function Set-UserAgent {
178 | [CmdletBinding()]
179 | param()
180 |
181 | $userAgent = Get-VstsTaskVariable -Name AZURE_HTTP_USER_AGENT
182 | if ($userAgent) {
183 | Set-UserAgent_Core -UserAgent $userAgent
184 | }
185 | }
186 |
187 | function Set-UserAgent_Core {
188 | [CmdletBinding()]
189 | param(
190 | [Parameter(Mandatory = $true)]
191 | [string]$UserAgent)
192 |
193 | Trace-VstsEnteringInvocation $MyInvocation
194 | try {
195 | [Microsoft.Azure.Common.Authentication.AzureSession]::ClientFactory.AddUserAgent($UserAgent)
196 | } catch {
197 | Write-VstsTaskVerbose -Message "Set-UserAgent failed with exception message: $_.Exception.Message"
198 | } finally {
199 | Trace-VstsLeavingInvocation $MyInvocation
200 | }
201 | }
202 |
--------------------------------------------------------------------------------
/Common/PowerShell3/VstsAzureHelpers/VstsAzureHelpers.psm1:
--------------------------------------------------------------------------------
1 | # Private module-scope variables.
2 | $script:azureModule = $null
3 | $script:azureRMProfileModule = $null
4 |
5 | # Override the DebugPreference.
6 | if ($global:DebugPreference -eq 'Continue') {
7 | Write-VstsTaskVerbose -Message '$OVERRIDING $global:DebugPreference from ''Continue'' to ''SilentlyContinue''.'
8 | $global:DebugPreference = 'SilentlyContinue'
9 | }
10 |
11 | # Import the loc strings.
12 | Import-VstsLocStrings -LiteralPath $PSScriptRoot/module.json
13 |
14 | # Dot source the private functions.
15 | . $PSScriptRoot/InitializeFunctions.ps1
16 | . $PSScriptRoot/ImportFunctions.ps1
17 | . $PSScriptRoot/HelperFunctions.ps1
18 | . $PSScriptRoot/FindSqlPackagePath.ps1
19 |
20 | function Initialize-Azure {
21 | [CmdletBinding()]
22 | param()
23 | Trace-VstsEnteringInvocation $MyInvocation
24 | try {
25 | # Get the inputs.
26 | $serviceNameInput = Get-VstsInput -Name ConnectedServiceNameSelector -Default 'ConnectedServiceName'
27 | $serviceName = Get-VstsInput -Name $serviceNameInput -Default (Get-VstsInput -Name DeploymentEnvironmentName)
28 | if (!$serviceName) {
29 | # Let the task SDK throw an error message if the input isn't defined.
30 | Get-VstsInput -Name $serviceNameInput -Require
31 | }
32 |
33 | $endpoint = Get-VstsEndpoint -Name $serviceName -Require
34 | $storageAccount = Get-VstsInput -Name StorageAccount
35 |
36 | # Determine which modules are preferred.
37 | $preferredModules = @( )
38 | if ($endpoint.Auth.Scheme -eq 'ServicePrincipal') {
39 | $preferredModules += 'AzureRM'
40 | } elseif ($endpoint.Auth.Scheme -eq 'UserNamePassword') {
41 | $preferredModules += 'Azure'
42 | $preferredModules += 'AzureRM'
43 | } else {
44 | $preferredModules += 'Azure'
45 | }
46 |
47 | # Import/initialize the Azure module.
48 | Import-AzureModule -PreferredModule $preferredModules
49 | Initialize-AzureSubscription -Endpoint $endpoint -StorageAccount $storageAccount
50 |
51 | # Check the installed Azure Powershell version
52 | $currentVersion = (Get-Module -Name AzureRM.profile).Version
53 | Write-VstsTaskVerbose -Message "Installed Azure PowerShell version: $currentVersion"
54 |
55 | $minimumAzureVersion = New-Object System.Version(0, 9, 9)
56 | if (-not ($currentVersion -and $currentVersion -gt $minimumAzureVersion)) {
57 | throw (Get-VstsLocString -Key AZ_RequiresMinVersion0 -ArgumentList $minimumAzureVersion)
58 | }
59 | } finally {
60 | Trace-VstsLeavingInvocation $MyInvocation
61 | }
62 | }
63 |
64 | function Get-AgentIPAddress {
65 | param([String] $startIPAddress,
66 | [String] $endIPAddress,
67 | [String] [Parameter(Mandatory = $true)] $ipDetectionMethod)
68 |
69 | [HashTable]$iPAddress = @{}
70 | if($ipDetectionMethod -eq "IPAddressRange") {
71 | $iPAddress.StartIPAddress = $startIPAddress
72 | $iPAddress.EndIPAddress = $endIPAddress
73 | }
74 | elseif($ipDetectionMethod -eq "AutoDetect") {
75 | $iPAddress.StartIPAddress = Get-AgentStartIPAddress
76 | $iPAddress.EndIPAddress = $IPAddress.StartIPAddress
77 | }
78 |
79 | Write-VstsTaskVerbose -Message "Agent IP Addresses:"
80 | Write-VstsTaskVerbose -Message " Start IP: $($iPAddress.StartIPAddress)"
81 | Write-VstsTaskVerbose -Message " End IP: $($iPAddress.EndIPAddress)"
82 |
83 | return $iPAddress
84 | }
85 |
86 | function Add-AzureSqlDatabaseServerFirewallRule {
87 | param([String] [Parameter(Mandatory = $true)] $startIp,
88 | [String] [Parameter(Mandatory = $true)] $endIp,
89 | [String] [Parameter(Mandatory = $true)] $serverName)
90 |
91 | [HashTable]$firewallSettings = @{}
92 | $firewallRuleName = [System.Guid]::NewGuid().ToString()
93 |
94 | $azureResourceGroupName = Get-AzureSqlDatabaseServerResourceGroupName -serverName $serverName
95 |
96 | try {
97 | Write-VstsTaskVerbose -Message "[Azure Call] Creating firewall rule $firewallRuleName on Azure SQL Server: $serverName"
98 | $null = New-AzureRMSqlServerFirewallRule -ResourceGroupName $azureResourceGroupName -StartIPAddress $startIp -EndIPAddress $endIp -ServerName $serverName -FirewallRuleName $firewallRuleName -ErrorAction Stop
99 | Write-VstsTaskVerbose -Message "[Azure Call] Firewall rule $firewallRuleName created on Azure SQL Server: $serverName"
100 | }
101 | catch [Hyak.Common.CloudException] {
102 | $exceptionMessage = $_.Exception.Message.ToString()
103 | Write-VstsTaskVerbose -Message "ExceptionMessage: $exceptionMessage"
104 | throw (Get-VstsLocString -Key AZ_InvalidIpAddress)
105 | }
106 |
107 | $firewallSettings.IsConfigured = $true
108 | $firewallSettings.RuleName = $firewallRuleName
109 |
110 | Write-VstsTaskVerbose -Message "Add Azure SQL Database Server Firewall Rule:"
111 | Write-VstsTaskVerbose -Message " IsConfigured: $($firewallSettings.IsConfigured)"
112 | Write-VstsTaskVerbose -Message " RuleName: $($firewallSettings.RuleName)"
113 |
114 | return $firewallSettings
115 | }
116 |
117 | function Remove-AzureSqlDatabaseServerFirewallRule {
118 | param([String] [Parameter(Mandatory = $true)] $serverName,
119 | [String] $firewallRuleName,
120 | [String] $isFirewallConfigured,
121 | [String] [Parameter(Mandatory = $true)] $deleteFireWallRule)
122 |
123 | if ($deleteFireWallRule -eq "true" -and $isFirewallConfigured -eq "true") {
124 | $azureResourceGroupName = Get-AzureSqlDatabaseServerResourceGroupName -serverName $serverName
125 | Write-VstsTaskVerbose -Message "[Azure Call] Deleting firewall rule $firewallRuleName on Azure SQL Server: $serverName"
126 | $null = Remove-AzureRMSqlServerFirewallRule -ResourceGroupName $azureResourceGroupName -ServerName $serverName -FirewallRuleName $firewallRuleName -Force -ErrorAction Stop
127 | Write-VstsTaskVerbose -Message "[Azure Call] Firewall rule $firewallRuleName deleted on Azure SQL Server: $serverName"
128 | }
129 | }
130 |
131 | function Get-AzureSqlDatabaseServerResourceGroupName {
132 | param([String] [Parameter(Mandatory = $true)] $serverName)
133 |
134 | return Get-ResourceGroupName -resourceName $serverName -resourceType "Microsoft.Sql/servers"
135 | }
136 |
137 | function Get-WebAppResourceGroupName {
138 | param([String] [Parameter(Mandatory = $true)] $webAppName)
139 |
140 | return Get-ResourceGroupName -resourceName $webAppName -resourceType "Microsoft.Web/sites"
141 | }
142 |
143 | function Get-SqlPackagePath {
144 | $sqlPackage = Get-SqlPackageOnTargetMachine
145 | Write-VstsTaskVerbose -Message "SqlPackage Path: '$sqlPackage'"
146 | return $sqlPackage
147 | }
148 |
149 | function Get-DacpacVersions {
150 | param([System.Array] [Parameter(Mandatory = $true)] $dacpacFilePaths)
151 |
152 | $dotnetVersion = [Environment]::Version
153 | if (!($dotnetVersion.Major -ge 4 -and $dotnetversion.Build -ge 30319)) {
154 | throw (Get-VstsLocString -Key "You have not Microsoft .Net Framework 4.5 installed on build agent.")
155 | }
156 |
157 | Add-Type -As System.IO.Compression.FileSystem
158 | $dacpacFileExtension = ".dacpac"
159 | $dacFilesWithVersion = @{}
160 |
161 | foreach ($dacpacFilePath in $dacpacFilePaths) {
162 | if ([System.IO.Path]::GetExtension($dacpacFilePath) -ne $dacpacFileExtension) {
163 | throw (Get-VstsLocString -Key "Invalid Dacpac file '{0}' provided" -ArgumentList $dacpacFilePath)
164 | }
165 |
166 | $dacMetadataXml = $null
167 | $dacVersion = $null
168 |
169 | $zip = [IO.Compression.ZipFile]::OpenRead($dacpacFilePath)
170 | $zip.Entries | Where-Object { $_.Name.EndsWith("DacMetadata.xml") } | ForEach-Object {
171 | $memoryStream = New-Object System.IO.MemoryStream
172 | $file = $_.Open()
173 | $file.CopyTo($memoryStream)
174 | $file.Dispose()
175 | $memoryStream.Position = 0
176 | $reader = New-Object System.IO.StreamReader($memoryStream)
177 | $dacMetadataXml = $reader.ReadToEnd()
178 | $reader.Dispose()
179 | $memoryStream.Dispose()
180 | }
181 |
182 | $zip.Dispose()
183 |
184 | if ($dacMetadataXml -ne $null) {
185 | $dacVersion = Select-Xml -XPath "//dac:DacType/dac:Version" -Content $dacMetadataXml -Namespace @{ dac = "http://schemas.microsoft.com/sqlserver/dac/Serialization/2012/02" }
186 | $dacFilesWithVersion.Add([Version]($dacVersion.ToString()), $dacpacFilePath)
187 | }
188 | else {
189 | throw (Get-VstsLocString -Key "Invalid Dacpac file '{0}' provided" -ArgumentList $dacpacFile)
190 | }
191 | }
192 |
193 | $dacFilesWithVersion = $dacFilesWithVersion.GetEnumerator() | Sort-Object Name
194 | Write-VstsTaskVerbose -Message "DACPAC files with version:"
195 | foreach ($dacFileWithVersion in $dacFilesWithVersion) {
196 | Write-VstsTaskVerbose -Message " Version: $($dacFileWithVersion.Name) Path: $($dacFileWithVersion.Value)"
197 | }
198 |
199 | return $dacFilesWithVersion
200 | }
201 |
202 | function Send-ExecuteCommand {
203 | param([String][Parameter(Mandatory=$true)] $command,
204 | [String][Parameter(Mandatory=$true)] $arguments,
205 | [String][Parameter(Mandatory=$true)] $secureArguments)
206 |
207 | $errorActionPreferenceRestore = $ErrorActionPreference
208 | $ErrorActionPreference="SilentlyContinue"
209 |
210 | $errout = $stdout = ""
211 |
212 | $arguments = $arguments.Replace(';', '`;')
213 |
214 | Write-VstsTaskVerbose -Message "[CMD Call] Executing: & `"$command`" $secureArguments 2>''"
215 | $null = Invoke-Expression "& `"$command`" $arguments 2>''" -ErrorVariable errout -OutVariable stdout
216 | Write-VstsTaskVerbose -Message "[CMD Call] Executed"
217 |
218 | $ErrorActionPreference = $errorActionPreferenceRestore
219 |
220 | foreach ($out in $stdout) {
221 | Write-VstsTaskVerbose -Message $out
222 | }
223 |
224 | if ($LastExitCode -gt 0) {
225 | foreach ($out in $errout) {
226 | Write-VstsTaskError -Message $out
227 | }
228 |
229 | throw $errout[0].Exception
230 | }
231 | }
232 |
233 | function Get-SqlPackageCommandArguments {
234 | param([String] $dacpacFile,
235 | [String] $serverName,
236 | [String] $databaseName,
237 | [String] $sqlUsername,
238 | [String] $sqlPassword,
239 | [String] $connectionString,
240 | [String] $publishProfile,
241 | [String] $additionalArguments,
242 | [switch] $isOutputSecure)
243 |
244 | $ErrorActionPreference = 'Stop'
245 | $SqlPackageOptions = @{
246 | SourceFile = "/SourceFile:";
247 | Action = "/Action:";
248 | TargetServerName = "/TargetServerName:";
249 | TargetDatabaseName = "/TargetDatabaseName:";
250 | TargetUser = "/TargetUser:";
251 | TargetPassword = "/TargetPassword:";
252 | TargetConnectionString = "/TargetConnectionString:";
253 | Profile = "/Profile:";
254 | }
255 |
256 | $dacpacFileExtension = ".dacpac"
257 | if ([System.IO.Path]::GetExtension($dacpacFile) -ne $dacpacFileExtension) {
258 | throw (Get-VstsLocString -Key "Invalid Dacpac file '{0}' provided" -ArgumentList $dacpacFile)
259 | }
260 |
261 | $sqlPackageArguments = @($SqlPackageOptions.SourceFile + "`"$dacpacFile`"")
262 | $sqlPackageArguments += @($SqlPackageOptions.Action + "Publish")
263 | $sqlPackageArguments += @($SqlPackageOptions.TargetServerName + "`"$serverName`"")
264 | if ($databaseName) {
265 | $sqlPackageArguments += @($SqlPackageOptions.TargetDatabaseName + "`"$databaseName`"")
266 | }
267 |
268 | if ($sqlUsername) {
269 | $sqlPackageArguments += @($SqlPackageOptions.TargetUser + "`"$sqlUsername`"")
270 | if (-not($sqlPassword)) {
271 | throw (Get-VstsLocString -Key "No password specified for the SQL User: '{0}'" -ArgumentList $sqlUserName)
272 | }
273 |
274 | if ($isOutputSecure) {
275 | $sqlPassword = "********"
276 | }
277 | else {
278 | $sqlPassword = $sqlPassword.Replace('"', '\"')
279 | }
280 |
281 | $sqlPackageArguments += @($SqlPackageOptions.TargetPassword + "`"$sqlPassword`"")
282 | }
283 |
284 | if ($publishProfile) {
285 | if([System.IO.Path]::GetExtension($publishProfile) -ne ".xml") {
286 | throw (Get-VstsLocString -Key "Invalid Publish Profile '{0}' provided" -ArgumentList $publishProfile)
287 | }
288 |
289 | $sqlPackageArguments += @($SqlPackageOptions.Profile + "`"$publishProfile`"")
290 | }
291 |
292 | $sqlPackageArguments += @("$additionalArguments")
293 | $scriptArgument = ($sqlPackageArguments -join " ")
294 |
295 | return $scriptArgument
296 | }
297 |
298 | function Initialize-Sqlps {
299 | [CmdletBinding()]
300 | param()
301 |
302 | Trace-VstsEnteringInvocation $MyInvocation
303 |
304 | try {
305 | # pushd and popd to avoid import from changing the current directory (ref: http://stackoverflow.com/questions/12915299/sql-server-2012-sqlps-module-changing-current-location-automatically)
306 | # 3>&1 puts warning stream to standard output stream (see https://connect.microsoft.com/PowerShell/feedback/details/297055/capture-warning-verbose-debug-and-host-output-via-alternate-streams)
307 | # out-null blocks that output, so we don't see the annoying warnings described here: https://www.codykonior.com/2015/05/30/whats-wrong-with-sqlps/
308 | Push-Location
309 |
310 | $sqlModule = Get-Module -ListAvailable | where -Property Name -eq SqlServer
311 | $sqlps = Get-Module -ListAvailable | where -Property Name -eq sqlps
312 |
313 | if ($sqlps) {
314 | Import-Module -Name sqlps -Global -PassThru -Cmdlet Invoke-Sqlcmd 3>&1 | Out-Null
315 | Write-VstsTaskVerbose -Message "SQLPS Module Imported"
316 | } else {
317 | if(!$sqlModule) {
318 | Install-module -Name SqlServer -Scope CurrentUser -Force
319 | }
320 |
321 | Import-Module -Name SqlServer -Global -PassThru -Cmdlet Invoke-Sqlcmd 3>&1 | Out-Null
322 | Write-VstsTaskVerbose -Message "SqlServer Module Imported"
323 | }
324 |
325 | Pop-Location
326 | }
327 | finally {
328 | Trace-VstsLeavingInvocation $MyInvocation
329 | }
330 | }
331 |
332 | function Get-SqlServerFriendlyName {
333 | param([String] [Parameter(Mandatory = $true)] $serverName)
334 |
335 | $serverName = $serverName.ToLower()
336 | if (-not $serverName.Contains(".database.windows.net")){
337 | Write-VstsTaskWarning -Message "Bad task configuration: the ServerName parameter should be given with an Azure SQL Server name, like FabrikamSQL.database.windows.net,1433 or FabrikamSQL.database.windows.net"
338 | }
339 |
340 | $serverFriendlyName = $serverName.split(".")[0]
341 | Write-VstsTaskVerbose -Message "Server friendly name is $serverFriendlyName"
342 |
343 | return $serverFriendlyName
344 | }
345 |
346 | Export-ModuleMember -Function Initialize-Azure
347 | Export-ModuleMember -Function Get-AgentIPAddress
348 | Export-ModuleMember -Function Add-AzureSqlDatabaseServerFirewallRule
349 | Export-ModuleMember -Function Remove-AzureSqlDatabaseServerFirewallRule
350 | Export-ModuleMember -Function Get-AzureSqlDatabaseServerResourceGroupName
351 | Export-ModuleMember -Function Get-WebAppResourceGroupName
352 | Export-ModuleMember -Function Get-SqlPackagePath
353 | Export-ModuleMember -Function Get-DacpacVersions
354 | Export-ModuleMember -Function Send-ExecuteCommand
355 | Export-ModuleMember -Function Get-SqlPackageCommandArguments
356 | Export-ModuleMember -Function Initialize-Sqlps
357 | Export-ModuleMember -Function Get-SqlServerFriendlyName
358 |
--------------------------------------------------------------------------------
/Common/PowerShell3/VstsAzureHelpers/module.json:
--------------------------------------------------------------------------------
1 | {
2 | "messages": {
3 | "AZ_AzureRMProfileModuleNotFound": "Module 'AzureRM.Profile' not found. The 'AzureRM' module may not be fully installed. Running the following PowerShell commands from an elevated session may resolve the issue: Import-Module AzureRM ; Install-AzureRM",
4 | "AZ_CertificateAuthNotSupported": "Certificate based authentication is not supported. Azure PowerShell module is not found.",
5 | "AZ_CredentialsError": "There was an error with the Azure credentials used for the deployment.",
6 | "AZ_ModuleNotFound": "Neither the Azure module nor the AzureRM module was found. If the module was recently installed, retry after restarting the VSTS task agent.",
7 | "AZ_RequiresMinVersion0": "The required minimum version ({0}) of the Azure PowerShell module is not installed.",
8 | "AZ_ServicePrincipalError": "There was an error with the service principal used for the deployment.",
9 | "AZ_ServicePrincipalAuthNotSupportedAzureVersion0": "Service principal authentication is not supported in version '{0}' of the Azure module.",
10 | "AZ_UnsupportedAuthScheme0": "Unsupported authentication scheme '{0}' for Azure endpoint.",
11 | "AZ_CannotRetrieveExternalIp0": "Cannot parse external IP returned from service: '{0}'.",
12 | "AZ_InvalidIpAddress": "IPAddress mentioned is not a valid IPv4 address.",
13 | "AZ_ResourceNotFound0": "Azure Resource: '{0}' not found."
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Extension/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | =====================
3 |
4 | Copyright © `2016` `Geek Learning, Adrien Siffermann, Cyprien Autexier`
5 |
6 | Permission is hereby granted, free of charge, to any person
7 | obtaining a copy of this software and associated documentation
8 | files (the “Software”), to deal in the Software without
9 | restriction, including without limitation the rights to use,
10 | copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the
12 | Software is furnished to do so, subject to the following
13 | conditions:
14 |
15 | The above copyright notice and this permission notice shall be
16 | included in all copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | OTHER DEALINGS IN THE SOFTWARE.
26 |
--------------------------------------------------------------------------------
/Extension/Screenshots/Add-Tasks.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeklearningio/gl-vsts-tasks-azure/5da85062a3925111f3b87469220fe04ed3e3956c/Extension/Screenshots/Add-Tasks.png
--------------------------------------------------------------------------------
/Extension/Screenshots/TestBuild.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeklearningio/gl-vsts-tasks-azure/5da85062a3925111f3b87469220fe04ed3e3956c/Extension/Screenshots/TestBuild.png
--------------------------------------------------------------------------------
/Extension/extension-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeklearningio/gl-vsts-tasks-azure/5da85062a3925111f3b87469220fe04ed3e3956c/Extension/extension-icon.png
--------------------------------------------------------------------------------
/Extension/overview.md:
--------------------------------------------------------------------------------
1 | # Build and release tasks for Microsoft Azure
2 |
3 | Visual Studio Team Services Build and Release Management extensions that help you to build and publish your applications on Microsoft Azure.
4 |
5 | [Learn more](https://github.com/geeklearningio/gl-vsts-tasks-azure/wiki) about this extension on the wiki!
6 |
7 | > Note that we new agents features hence TFS 2015 is not supported.
8 |
9 | ## Tasks included
10 |
11 | * **[Azure Web App Slots Swap](https://github.com/geeklearningio/gl-vsts-tasks-azure/wiki/Azure-Web-App-Slots-Swap)**: Swap two deployment slots of an Azure Web App
12 | * **[Azure Web App Start](https://github.com/geeklearningio/gl-vsts-tasks-azure/wiki/Azure-Web-App-Start)**: Start an Azure Web App, or one of its slot
13 | * **[Azure Web App Stop](https://github.com/geeklearningio/gl-vsts-tasks-azure/wiki/Azure-Web-App-Stop)**: Stop an Azure Web App, or one of its slot
14 | * **[Azure SQL Execute Query](https://github.com/geeklearningio/gl-vsts-tasks-azure/wiki/Azure-SQL-Execute-Query)**: Execute a SQL query on an Azure SQL Database
15 | * **[Azure SQL Database Restore](https://github.com/geeklearningio/gl-vsts-tasks-azure/wiki/Azure-SQL-Database-Restore)**: Restore an Azure SQL Database to another Azure SQL Database on the same server using the latest point-in-time backup
16 | * **[Azure SQL Database Incremental Deployment](https://github.com/geeklearningio/gl-vsts-tasks-azure/wiki/Azure-SQL-Database-Incremental-Deployment)**: Deploy an Azure SQL Database using multiple DACPAC and performing incremental deployments based on current Data-Tier Application version
17 | * **[AzCopy](https://github.com/geeklearningio/gl-vsts-tasks-azure/wiki/AzCopy)**: Copy blobs across Azure Storage accounts using AzCopy
18 |
19 | ## Steps
20 |
21 | After installing the extension, you can add one (or more) of the tasks to a new or existing [build definition](https://www.visualstudio.com/en-us/docs/build/define/create) or [release definition](https://www.visualstudio.com/en-us/docs/release/author-release-definition/more-release-definition)
22 |
23 | 
24 |
25 | ## Learn more
26 |
27 | The [source](https://github.com/geeklearningio/gl-vsts-tasks-azure) for this extension is on GitHub. Take, fork, and extend.
28 |
29 | ## Release Notes
30 |
31 | > **10-24-2016**
32 | > - Added: AzCopy Tool Task
33 |
34 | > **8-19-2016**
35 | > - Added: Azure SQL Database Incremental Deployment
36 |
37 | > **8-1-2016**
38 | > - Added: Azure SQL Execute Query
39 |
40 | > **7-31-2016**
41 | > - Added: Azure RM Support
42 |
--------------------------------------------------------------------------------
/Extension/vss-extension.json:
--------------------------------------------------------------------------------
1 | {
2 | "manifestVersion": 1,
3 | "id": "gl-vsts-tasks-azure",
4 | "name": "Microsoft Azure Build and Release Tasks",
5 | "version": "0.0.0",
6 | "publisher": "geeklearningio",
7 | "targets": [
8 | {
9 | "id": "Microsoft.VisualStudio.Services"
10 | }
11 | ],
12 | "description": "Build and publish your applications on Microsoft Azure using these Build and Release Management tasks.",
13 | "categories": [
14 | "Build and release"
15 | ],
16 | "icons": {
17 | "default": "extension-icon.png"
18 | },
19 | "tags": [
20 | "Azure",
21 | "Resource Manager",
22 | "WebApp",
23 | "Swap",
24 | "Start",
25 | "Stop",
26 | "SQL",
27 | "Restore",
28 | "DACPAC"
29 | ],
30 | "screenshots": [
31 | {
32 | "path": "Screenshots/TestBuild.png"
33 | },
34 | {
35 | "path": "Screenshots/Add-Tasks.png"
36 | }
37 | ],
38 | "content": {
39 | "details": {
40 | "path": "overview.md"
41 | },
42 | "license": {
43 | "path": "LICENSE.txt"
44 | }
45 | },
46 | "links": {
47 | "getstarted": {
48 | "uri": "https://github.com/geeklearningio/gl-vsts-tasks-azure/wiki"
49 | },
50 | "support": {
51 | "uri": "https://github.com/geeklearningio/gl-vsts-tasks-azure/issues"
52 | },
53 | "repository": {
54 | "uri": "https://github.com/geeklearningio/gl-vsts-tasks-azure"
55 | },
56 | "issues": {
57 | "uri": "https://github.com/geeklearningio/gl-vsts-tasks-azure/issues"
58 | }
59 | },
60 | "branding": {
61 | "color": "#008B8B",
62 | "theme": "dark"
63 | },
64 | "files": [
65 | {
66 | "path": "Tasks"
67 | },
68 | {
69 | "path": "Screenshots",
70 | "addressable": true
71 | }
72 | ]
73 | }
74 |
--------------------------------------------------------------------------------
/GitVersion.yml:
--------------------------------------------------------------------------------
1 | mode: ContinuousDeployment
2 | branches:
3 | dev(elop)?(ment)?$:
4 | tag: alpha
5 | features?[/-]:
6 | tag: alpha.{BranchName}
7 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | =====================
3 |
4 | Copyright © `2016` `Geek Learning, Adrien Siffermann, Cyprien Autexier`
5 |
6 | Permission is hereby granted, free of charge, to any person
7 | obtaining a copy of this software and associated documentation
8 | files (the “Software”), to deal in the Software without
9 | restriction, including without limitation the rights to use,
10 | copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the
12 | Software is furnished to do so, subject to the following
13 | conditions:
14 |
15 | The above copyright notice and this permission notice shall be
16 | included in all copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | OTHER DEALINGS IN THE SOFTWARE.
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # Microsoft Azure Build and Release Tasks
4 |
5 | [](https://geeklearning.visualstudio.com/gl-github/_build/latest?definitionId=37)
6 |
7 | Visual Studio Team Services Build and Release Management extensions that help you to build and publish your applications on Microsoft Azure.
8 |
9 | [Learn more](https://github.com/geeklearningio/gl-vsts-tasks-azure/wiki) about this extension on the wiki!
10 |
11 | ## Tasks included
12 |
13 | * **[Azure Web App Slots Swap](https://github.com/geeklearningio/gl-vsts-tasks-azure/wiki/Azure-Web-App-Slots-Swap)**: Swap two deployment slots of an Azure Web App
14 | * **[Azure Web App Start](https://github.com/geeklearningio/gl-vsts-tasks-azure/wiki/Azure-Web-App-Start)**: Start an Azure Web App, or one of its slot
15 | * **[Azure Web App Stop](https://github.com/geeklearningio/gl-vsts-tasks-azure/wiki/Azure-Web-App-Stop)**: Stop an Azure Web App, or one of its slot
16 | * **[Azure SQL Execute Query](https://github.com/geeklearningio/gl-vsts-tasks-azure/wiki/Azure-SQL-Execute-Query)**: Execute a SQL query on an Azure SQL Database
17 | * **[Azure SQL Database Restore](https://github.com/geeklearningio/gl-vsts-tasks-azure/wiki/Azure-SQL-Database-Restore)**: Restore an Azure SQL Database to another Azure SQL Database on the same server using the latest point-in-time backup
18 | * **[Azure SQL Database Incremental Deployment](https://github.com/geeklearningio/gl-vsts-tasks-azure/wiki/Azure-SQL-Database-Incremental-Deployment)**: Deploy an Azure SQL Database using multiple DACPAC and performing incremental deployments based on current Data-Tier Application version
19 | * **[Azure Copy Files](https://github.com/geeklearningio/gl-vsts-tasks-azure/wiki/AzCopy)**: Copy blobs across Azure Storage accounts using AzCopy
20 |
21 | ## To contribute
22 |
23 | 1. Globally install typescript and tfx-cli (to package VSTS extensions): `npm install -g typescript tfx-cli`
24 | 2. From the root of the repo run `npm install`. This will pull down the necessary modules for the different tasks and for the build tools.
25 | 3. Run `npm run build` to compile the build tasks.
26 | 4. Run `npm run package -- --version ` to create the .vsix extension packages (supports multiple environments) that includes the build tasks.
27 |
28 | ## Release Notes
29 |
30 | > **10-24-2016**
31 | > - Added: AzCopy Tool Task
32 |
33 | > **8-19-2016**
34 | > - Added: Azure SQL Database Incremental Deployment
35 |
36 | > **8-1-2016**
37 | > - Added: Azure SQL Execute Query
38 | > - New build tools for all GL tasks
39 |
40 | > **7-31-2016**
41 | > - Added: Azure RM Support
42 |
43 | ## Contributors
44 |
45 | This extension was created by [Geek Learning](http://geeklearning.io/), with help from the community.
46 |
47 | ## Attributions
48 |
49 | * [AzureWebPowerShellDeployment icon from the VSTS Tasks project](https://github.com/Microsoft/vsts-tasks)
50 | * [SqlAzureDacpacDeployment icon from the VSTS Tasks project](https://github.com/Microsoft/vsts-tasks)
51 | * [Lightning by Carla Dias from the Noun Project](https://thenounproject.com/search/?q=lightning&i=542899)
52 | * [Restore by Arthur Shlain from the Noun Project](https://thenounproject.com/search/?q=restore&i=52760)
53 | * [Trade by Michelle Fosse from the Noun Project](https://thenounproject.com/search/?q=swap&i=560173)
54 | * [Stop by NAS from the Noun Project](https://thenounproject.com/search/?q=stop&i=55668)
55 | * [Play by NAS from the Noun Project](https://thenounproject.com/search/?q=play&i=55667)
56 | * [Checkmarks by Matt Saling from the Noun Project](https://thenounproject.com/search/?q=Checkmarks&i=202337)
57 |
--------------------------------------------------------------------------------
/Tasks/AzCopy/azCopy.ts:
--------------------------------------------------------------------------------
1 | import { StorageManagementClient } from "azure-arm-storage";
2 | import fs = require("fs-extra");
3 | import path = require("path");
4 | import q = require("q");
5 | import * as tl from "azure-pipelines-task-lib/task";
6 | import XRegExp = require("xregexp");
7 | import azureEndpointConnection = require("./azureEndpointConnection");
8 |
9 | const recursive: boolean = tl.getBoolInput("Recursive");
10 | const pattern: string = tl.getInput("Pattern");
11 | const excludeNewer: boolean = tl.getBoolInput("ExcludeNewer");
12 | const excludeOlder: boolean = tl.getBoolInput("ExcludeOlder");
13 | const sourceKind: string = tl.getInput("SourceKind");
14 | const sourcePath: string = tl.getInput("SourcePath");
15 | const sourceConnectedServiceName: string = tl.getInput(
16 | "SourceConnectedServiceName"
17 | );
18 | const sourceAccount: string = tl.getInput("SourceAccount");
19 | const sourceObject: string = tl.getInput("SourceObject");
20 | const destinationKind: string = tl.getInput("DestinationKind");
21 | const destinationPath: string = tl.getInput("DestinationPath");
22 | const destinationConnectedServiceName: string = tl.getInput(
23 | "DestinationConnectedServiceName"
24 | );
25 | const destinationAccount: string = tl.getInput("DestinationAccount");
26 | const destinationObject: string = tl.getInput("DestinationObject");
27 |
28 | const programFiles: string = tl.getVariable("ProgramFiles(x86)");
29 | const additionalArguments: string = tl.getVariable("Arguments");
30 |
31 | const azCopyknownLocations: string[] = [
32 | path.join(
33 | tl.getVariable("Agent.HomeDirectory"),
34 | "externals/azcopy/azcopy.exe"
35 | ),
36 | path.join(__dirname, "../../azcopy.exe"),
37 | path.join(
38 | programFiles ? programFiles : "C:\\ProgramFiles(x86)",
39 | "Microsoft SDKs/Azure/AzCopy/azcopy.exe"
40 | ),
41 | ];
42 |
43 | const accountIdRegex: RegExp = XRegExp(
44 | "/subscriptions/(?.*?)" +
45 | "/resourceGroups/(?.*?)" +
46 | "/providers/Microsoft.Storage" +
47 | "/storageAccounts/(?.*?)"
48 | );
49 |
50 | function getConnectedServiceCredentials(
51 | connectedService: string
52 | ): q.Promise {
53 | const endpointAuth: tl.EndpointAuthorization = tl.getEndpointAuthorization(
54 | connectedService,
55 | true
56 | );
57 | const servicePrincipalId: string = endpointAuth.parameters.serviceprincipalid;
58 | const servicePrincipalKey: string =
59 | endpointAuth.parameters.serviceprincipalkey;
60 | const tenantId: string = endpointAuth.parameters.tenantid;
61 | const subscriptionName: string = tl.getEndpointDataParameter(
62 | connectedService,
63 | "SubscriptionName",
64 | true
65 | );
66 | const subscriptionId: string = tl.getEndpointDataParameter(
67 | connectedService,
68 | "SubscriptionId",
69 | true
70 | );
71 |
72 | return azureEndpointConnection.getConnectedServiceCredentials(
73 | connectedService,
74 | servicePrincipalId,
75 | servicePrincipalKey,
76 | tenantId,
77 | subscriptionName,
78 | subscriptionId
79 | );
80 | }
81 |
82 | function getStorageAccount(
83 | credentials: ICachedSubscriptionCredentals,
84 | accountName: string
85 | ): q.Promise {
86 | const deferal: q.Deferred = q.defer();
87 |
88 | const client: StorageManagementClient = new StorageManagementClient(
89 | credentials.creds,
90 | credentials.id
91 | );
92 | client.storageAccounts.list((listError: any, result: any): void => {
93 | if (listError) {
94 | deferal.reject(listError);
95 | }
96 |
97 | const account: any = result.filter((x: any) => x.name === accountName)[0];
98 | const parsedAccountId: any = XRegExp.exec(
99 | account.id,
100 | accountIdRegex
101 | ) as any;
102 | const resourceGroupName: any = parsedAccountId.resourceGroupName;
103 |
104 | client.storageAccounts.getProperties(
105 | resourceGroupName,
106 | accountName,
107 | (getPropertiesError: any, properties: any): void => {
108 | if (getPropertiesError) {
109 | deferal.reject(getPropertiesError);
110 | } else {
111 | client.storageAccounts.listKeys(
112 | resourceGroupName,
113 | accountName,
114 | (listKeysError: any, keys: any): void => {
115 | if (listKeysError) {
116 | deferal.reject(listKeysError);
117 | } else {
118 | deferal.resolve({
119 | blobEndpoint: properties.primaryEndpoints.blob,
120 | key: keys.keys[0].value,
121 | resourceGroupName,
122 | tableEndpoint: properties.primaryEndpoints.table,
123 | });
124 | }
125 | }
126 | );
127 | }
128 | }
129 | );
130 | });
131 |
132 | return deferal.promise;
133 | }
134 |
135 | (async function execute(): Promise {
136 | try {
137 | const azCopy: string[] = azCopyknownLocations.filter((x) =>
138 | fs.existsSync(x)
139 | );
140 | if (azCopy.length) {
141 | tl.debug("AzCopy utility found at path : " + azCopy[0]);
142 |
143 | const toolRunner = tl.tool(azCopy[0]);
144 |
145 | if (sourceKind === "Storage") {
146 | tl.debug("retrieving source account details");
147 | const sourceCredentials: any = await getConnectedServiceCredentials(
148 | sourceConnectedServiceName
149 | );
150 | const sourceStorageAccount: IStorageAccount = await getStorageAccount(
151 | sourceCredentials,
152 | sourceAccount
153 | );
154 | tl.debug(sourceStorageAccount.blobEndpoint + sourceObject);
155 | toolRunner.arg(
156 | "/Source:" + sourceStorageAccount.blobEndpoint + sourceObject
157 | );
158 | toolRunner.arg("/SourceKey:" + sourceStorageAccount.key);
159 | } else {
160 | toolRunner.arg("/Source:" + sourcePath);
161 | }
162 |
163 | if (destinationKind === "Storage") {
164 | const destCredentials: any = await getConnectedServiceCredentials(
165 | destinationConnectedServiceName
166 | );
167 | const destStorageAccount: IStorageAccount = await getStorageAccount(
168 | destCredentials,
169 | destinationAccount
170 | );
171 | tl.debug(destStorageAccount.blobEndpoint + destinationObject);
172 | toolRunner.arg(
173 | "/Dest:" + destStorageAccount.blobEndpoint + destinationObject
174 | );
175 | toolRunner.arg("/DestKey:" + destStorageAccount.key);
176 | } else {
177 | toolRunner.arg("/Dest:" + destinationPath);
178 | }
179 |
180 | if (recursive) {
181 | toolRunner.arg("/S");
182 | }
183 |
184 | if (pattern) {
185 | toolRunner.arg("/Pattern:" + pattern);
186 | }
187 |
188 | if (excludeNewer) {
189 | toolRunner.arg("/XN");
190 | }
191 |
192 | if (excludeOlder) {
193 | toolRunner.arg("/XO");
194 | }
195 |
196 | if (additionalArguments) {
197 | toolRunner.line(additionalArguments);
198 | }
199 |
200 | toolRunner.arg("/Y");
201 |
202 | const result: number = await toolRunner.exec();
203 | if (result) {
204 | tl.setResult(tl.TaskResult.Failed, "An error occured during azcopy");
205 | } else {
206 | tl.setResult(tl.TaskResult.Succeeded, "Files copied successfully");
207 | }
208 | } else {
209 | tl.setResult(
210 | tl.TaskResult.Failed,
211 | "AzCopy utility was not found, please refer to documentation for installation instructions."
212 | );
213 | }
214 | } catch (err) {
215 | tl.debug(err.stack);
216 | tl.setResult(tl.TaskResult.Failed, err);
217 | }
218 | })();
219 |
220 | interface ICachedSubscriptionCredentals {
221 | name: string;
222 | id: string;
223 | creds: any;
224 | }
225 |
226 | interface IStorageAccount {
227 | resourceGroupName: string;
228 | blobEndpoint: string;
229 | tableEndpoint: string;
230 | key: string;
231 | }
232 |
--------------------------------------------------------------------------------
/Tasks/AzCopy/azureEndpointConnection.ts:
--------------------------------------------------------------------------------
1 | import msRestAzure = require("ms-rest-azure");
2 | import q = require("q");
3 |
4 | const connectedServiceCredentialsCache: {
5 | [key: string]: ICachedSubscriptionCredentals;
6 | } = {};
7 |
8 | export function getConnectedServiceCredentials(
9 | connectedService: string,
10 | servicePrincipalId: string,
11 | servicePrincipalKey: string,
12 | tenantId: string,
13 | subscriptionName: string,
14 | subscriptionId: string
15 | ): q.Promise {
16 | if (connectedServiceCredentialsCache[connectedService]) {
17 | return q.when(connectedServiceCredentialsCache[connectedService]);
18 | } else {
19 | const deferal = q.defer();
20 | msRestAzure.loginWithServicePrincipalSecret(
21 | servicePrincipalId,
22 | servicePrincipalKey,
23 | tenantId,
24 | {},
25 | (err: any, credentials: any) => {
26 | if (err) {
27 | deferal.reject(err);
28 | return;
29 | }
30 |
31 | const result = (connectedServiceCredentialsCache[connectedService] = {
32 | creds: credentials,
33 | id: subscriptionId,
34 | name: subscriptionName,
35 | });
36 |
37 | deferal.resolve(result);
38 | }
39 | );
40 |
41 | return deferal.promise;
42 | }
43 | }
44 |
45 | export interface ICachedSubscriptionCredentals {
46 | name: string;
47 | id: string;
48 | creds: any;
49 | }
50 |
--------------------------------------------------------------------------------
/Tasks/AzCopy/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeklearningio/gl-vsts-tasks-azure/5da85062a3925111f3b87469220fe04ed3e3956c/Tasks/AzCopy/icon.png
--------------------------------------------------------------------------------
/Tasks/AzCopy/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "az-copy",
3 | "private": true,
4 | "version": "0.1.0",
5 | "dependencies": {
6 | "azure-devops-node-api": "^10.1.1",
7 | "azure-pipelines-task-lib": "^2.9.6",
8 | "azure-arm-storage": "^8.1.0",
9 | "fs-extra": "9.0.1",
10 | "ms-rest-azure": "^3.0.0",
11 | "q": "1.5.1",
12 | "xregexp": "4.3.0"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Tasks/AzCopy/task.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "cf964a85-dfeb-4313-aa53-dad0d5e320e3",
3 | "name": "AzCopy",
4 | "friendlyName": "Azure File Copy Extended",
5 | "description": "Copy files to or from Azure Storage",
6 | "helpMarkDown": "[More Information](https://github.com/geeklearningio/gl-vsts-tasks-azure/wiki/AzCopy) (Version #{Version}#)",
7 | "category": "Deploy",
8 | "visibility": ["Build", "Release"],
9 | "author": "Geek Learning",
10 | "version": {
11 | "Major": 0,
12 | "Minor": 0,
13 | "Patch": 0
14 | },
15 | "demands": ["cmd"],
16 | "minimumAgentVersion": "1.91.0",
17 | "instanceNameFormat": "Copy files from or to Azure Storage",
18 | "groups": [
19 | {
20 | "name": "source",
21 | "displayName": "Source",
22 | "isExpanded": true
23 | },
24 | {
25 | "name": "destination",
26 | "displayName": "Destination",
27 | "isExpanded": true
28 | },
29 | {
30 | "name": "containerCopyOptions",
31 | "displayName": "Container Copy Options",
32 | "isExpanded": true
33 | },
34 | {
35 | "name": "advanced",
36 | "displayName": "Additional Options",
37 | "isExpanded": true
38 | }
39 | ],
40 | "inputs": [
41 | {
42 | "name": "SourceKind",
43 | "type": "radio",
44 | "label": "Source Kind",
45 | "options": {
46 | "FileSystem": "File System",
47 | "Storage": "Azure Storage"
48 | },
49 | "defaultValue": "Storage",
50 | "required": true,
51 | "groupName": "source",
52 | "helpMarkDown": ""
53 | },
54 | {
55 | "name": "SourcePath",
56 | "type": "filePath",
57 | "label": "Source Directory",
58 | "defaultValue": "",
59 | "visibleRule": "SourceKind = FileSystem",
60 | "required": true,
61 | "groupName": "source",
62 | "helpMarkDown": "Source directory"
63 | },
64 | {
65 | "name": "SourceConnectedServiceName",
66 | "type": "connectedService:AzureRM",
67 | "label": "Azure RM Subscription",
68 | "defaultValue": "",
69 | "required": true,
70 | "groupName": "source",
71 | "visibleRule": "SourceKind = Storage",
72 | "helpMarkDown": "Source Azure Resource Manager subscription"
73 | },
74 | {
75 | "name": "SourceAccount",
76 | "type": "pickList",
77 | "label": "Source Account Name",
78 | "defaultValue": "",
79 | "required": true,
80 | "properties": {
81 | "EditableOptions": "True"
82 | },
83 | "groupName": "source",
84 | "visibleRule": "SourceKind = Storage",
85 | "helpMarkDown": "Enter or Select the name of an existing AzureRM Storage Account"
86 | },
87 | {
88 | "name": "SourceObject",
89 | "type": "string",
90 | "label": "Source Container",
91 | "defaultValue": "",
92 | "required": true,
93 | "visibleRule": "SourceKind = Storage",
94 | "groupName": "source",
95 | "helpMarkDown": "The name of the container to copy."
96 | },
97 | {
98 | "name": "DestinationKind",
99 | "type": "radio",
100 | "label": "Destination Kind",
101 | "options": {
102 | "FileSystem": "File System",
103 | "Storage": "Azure Storage"
104 | },
105 | "defaultValue": "Storage",
106 | "required": true,
107 | "groupName": "destination",
108 | "helpMarkDown": ""
109 | },
110 | {
111 | "name": "DestinationPath",
112 | "type": "filePath",
113 | "label": "Destintion path",
114 | "defaultValue": "",
115 | "required": true,
116 | "groupName": "destination",
117 | "visibleRule": "DestinationKind = FileSystem",
118 | "helpMarkDown": "The name of the artifact to create."
119 | },
120 | {
121 | "name": "DestinationConnectedServiceName",
122 | "type": "connectedService:AzureRM",
123 | "label": "Azure RM Subscription",
124 | "defaultValue": "",
125 | "required": true,
126 | "groupName": "destination",
127 | "visibleRule": "DestinationKind = Storage",
128 | "helpMarkDown": "Destination Azure Resource Manager subscription"
129 | },
130 | {
131 | "name": "DestinationAccount",
132 | "type": "pickList",
133 | "label": "Destination Account Name",
134 | "defaultValue": "",
135 | "required": true,
136 | "properties": {
137 | "EditableOptions": "True"
138 | },
139 | "groupName": "destination",
140 | "visibleRule": "DestinationKind = Storage",
141 | "helpMarkDown": "Enter or Select the name of an existing AzureRM Storage Account"
142 | },
143 | {
144 | "name": "DestinationObject",
145 | "type": "string",
146 | "label": "Destination Container",
147 | "defaultValue": "",
148 | "required": true,
149 | "groupName": "destination",
150 | "visibleRule": "DestinationKind = Storage",
151 | "helpMarkDown": "Destination container"
152 | },
153 | {
154 | "name": "Recursive",
155 | "type": "boolean",
156 | "label": "Recursive copy",
157 | "groupName": "containerCopyOptions",
158 | "helpMarkDown": "Copy files recursively."
159 | },
160 | {
161 | "name": "Pattern",
162 | "type": "string",
163 | "label": "Pattern",
164 | "defaultValue": "",
165 | "required": false,
166 | "groupName": "containerCopyOptions",
167 | "helpMarkDown": "Specifies a file pattern that indicates which files to copy."
168 | },
169 | {
170 | "name": "ExcludeNewer",
171 | "type": "boolean",
172 | "label": "Exclude Newer",
173 | "required": false,
174 | "groupName": "containerCopyOptions",
175 | "helpMarkDown": "Excludes a newer source resource. The resource will not be copied if the source is the same or newer than destination."
176 | },
177 | {
178 | "name": "ExcludeOlder",
179 | "type": "boolean",
180 | "label": "Exclude Older",
181 | "required": false,
182 | "groupName": "containerCopyOptions",
183 | "helpMarkDown": "Excludes an older source resource. The resource will not be copied if the source resource is the same or older than destination."
184 | },
185 | {
186 | "name": "Arguments",
187 | "type": "string",
188 | "label": "Additional Arguments",
189 | "required": false,
190 | "groupName": "advanced",
191 | "helpMarkDown": "Appends additional arguments to the generated AzCopy command"
192 | }
193 | ],
194 | "dataSourceBindings": [
195 | {
196 | "target": "SourceAccount",
197 | "endpointId": "$(SourceConnectedServiceName)",
198 | "dataSourceName": "AzureStorageAccountRM"
199 | },
200 | {
201 | "target": "DestinationAccount",
202 | "endpointId": "$(DestinationConnectedServiceName)",
203 | "dataSourceName": "AzureStorageAccountRM"
204 | }
205 | ],
206 | "execution": {
207 | "Node10": {
208 | "target": "azCopy.js",
209 | "argumentFormat": ""
210 | }
211 | }
212 | }
213 |
--------------------------------------------------------------------------------
/Tasks/ExecuteSql/ExecuteSql.ps1:
--------------------------------------------------------------------------------
1 | [CmdletBinding()]
2 | param()
3 |
4 | Trace-VstsEnteringInvocation $MyInvocation
5 |
6 | try {
7 | $ScriptType = Get-VstsInput -Name ScriptType -Require
8 | $ScriptPath = Get-VstsInput -Name ScriptPath
9 | $PredefinedScript = Get-VstsInput -Name PredefinedScript
10 | $Variables = Get-VstsInput -Name Variables
11 | $InlineScript = Get-VstsInput -Name InlineScript
12 | $ServerName = Get-VstsInput -Name ServerName -Require
13 | $DatabaseName = Get-VstsInput -Name DatabaseName -Require
14 | $SqlUsername = Get-VstsInput -Name SqlUsername -Require
15 | $SqlPassword = Get-VstsInput -Name SqlPassword -Require
16 | $QueryTimeout = Get-VstsInput -Name QueryTimeout -Require
17 | $IpDetectionMethod = Get-VstsInput -Name IpDetectionMethod -Require
18 | $StartIpAddress = Get-VstsInput -Name StartIpAddress
19 | $EndIpAddress = Get-VstsInput -Name EndIpAddress
20 | $DeleteFirewallRule = Get-VstsInput -Name DeleteFirewallRule -Require
21 |
22 | Import-Module $PSScriptRoot\ps_modules\VstsAzureHelpers_
23 |
24 | Initialize-Azure
25 | Initialize-Sqlps
26 |
27 | Import-VstsLocStrings -LiteralPath $PSScriptRoot/Task.json
28 |
29 | $serverFriendlyName = Get-SqlServerFriendlyName -serverName $ServerName
30 |
31 | $ipAddress = Get-AgentIPAddress -startIPAddress $StartIpAddress -endIPAddress $EndIpAddress -ipDetectionMethod $IpDetectionMethod
32 | $firewallSettings = Add-AzureSqlDatabaseServerFirewallRule -startIP $ipAddress.StartIPAddress -endIP $ipAddress.EndIPAddress -serverName $serverFriendlyName
33 |
34 | try {
35 | if ($ScriptType -eq "PredefinedScript") {
36 | $ScriptType = "FilePath"
37 | $ScriptPath = "$PSScriptRoot\SqlPredefinedScripts\$PredefinedScript.sql"
38 | }
39 |
40 | $variableParameter = @()
41 | if ($Variables) {
42 | $variableParameter = ($Variables -split '[\r\n]') | ? { $_ }
43 | }
44 |
45 | $workingFolder = Split-Path $ScriptPath
46 | $workingFolderVariable = @("WorkingFolder=$workingFolder")
47 | if ($variableParameter -isnot [system.array]) {
48 | $variableParameter = @($variableParameter)
49 | }
50 |
51 | $variableParameter = $variableParameter + $workingFolderVariable
52 |
53 | if ($ScriptType -eq "FilePath") {
54 | Write-VstsTaskVerbose -Message "[Azure Call] Executing SQL query $ScriptPath on $DatabaseName with variables $variableParameter"
55 | Invoke-Sqlcmd -InputFile "$ScriptPath" -Database $DatabaseName -ServerInstance $ServerName -EncryptConnection -Username $SqlUsername -Password $SqlPassword -Variable $variableParameter -ErrorAction Stop -Verbose -QueryTimeout $QueryTimeout
56 | }
57 | else {
58 | Write-VstsTaskVerbose -Message "[Azure Call] Executing inline SQL query on $DatabaseName with variables $variableParameter"
59 | Invoke-Sqlcmd -Query "$InlineScript" -Database $DatabaseName -ServerInstance $ServerName -EncryptConnection -Username $SqlUsername -Password $SqlPassword -Variable $variableParameter -ErrorAction Stop -Verbose -QueryTimeout $QueryTimeout
60 | }
61 |
62 | Write-VstsTaskVerbose -Message "[Azure Call] SQL query executed on $DatabaseName"
63 |
64 | }
65 | finally {
66 | Remove-AzureSqlDatabaseServerFirewallRule -serverName $serverFriendlyName -firewallRuleName $firewallSettings.RuleName -isFirewallConfigured $firewallSettings.IsConfigured -deleteFireWallRule $DeleteFirewallRule
67 | }
68 | }
69 | finally {
70 | Trace-VstsLeavingInvocation $MyInvocation
71 | }
72 |
--------------------------------------------------------------------------------
/Tasks/ExecuteSql/SqlPredefinedScripts/AddRoleMember.sql:
--------------------------------------------------------------------------------
1 | if exists(select * from [sys].[sysusers] where name = '$(Login)')
2 | begin
3 | exec sp_addrolemember N'$(Role)', N'$(Login)'
4 | end
5 |
--------------------------------------------------------------------------------
/Tasks/ExecuteSql/SqlPredefinedScripts/CreateDbOwner.sql:
--------------------------------------------------------------------------------
1 | :setvar Role "db_owner"
2 |
3 | :r $(WorkingFolder)\CreateUser.sql
4 | :r $(WorkingFolder)\AddRoleMember.sql
--------------------------------------------------------------------------------
/Tasks/ExecuteSql/SqlPredefinedScripts/CreateUser.sql:
--------------------------------------------------------------------------------
1 | if not exists(select * from [sys].[sysusers] where name = '$(Login)')
2 | begin
3 | create user $(Login)
4 | for login $(Login)
5 | with default_schema = dbo
6 | end
7 |
--------------------------------------------------------------------------------
/Tasks/ExecuteSql/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeklearningio/gl-vsts-tasks-azure/5da85062a3925111f3b87469220fe04ed3e3956c/Tasks/ExecuteSql/icon.png
--------------------------------------------------------------------------------
/Tasks/ExecuteSql/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ExecuteSql",
3 | "private": true,
4 | "version": "0.0.0",
5 | "dependencies": {
6 | "azure-pipelines-task-lib": "^2.9.6"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Tasks/ExecuteSql/task.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "A93D571D-F32C-4FE7-A63A-3599DDDD5279",
3 | "name": "ExecuteSql",
4 | "friendlyName": "Azure SQL Execute Query",
5 | "description": "Execute a SQL query on an Azure SQL Database",
6 | "helpMarkDown": "[More Information](https://github.com/geeklearningio/gl-vsts-tasks-azure/wiki/Azure-SQL-Execute-Query) (Version #{Version}#)",
7 | "category": "Deploy",
8 | "visibility": [
9 | "Build",
10 | "Release"
11 | ],
12 | "author": "Geek Learning",
13 | "version": {
14 | "Major": 0,
15 | "Minor": 0,
16 | "Patch": 0
17 | },
18 | "demands": [
19 | "azureps",
20 | "sqlps"
21 | ],
22 | "minimumAgentVersion": "1.103.0",
23 | "instanceNameFormat": "Execute SQL on $(DatabaseName)",
24 | "groups": [
25 | {
26 | "name": "target",
27 | "displayName": "Target",
28 | "isExpanded": true
29 | },
30 | {
31 | "name": "firewall",
32 | "displayName": "Firewall",
33 | "isExpanded": false
34 | }
35 | ],
36 | "inputs": [
37 | {
38 | "name": "ConnectedServiceName",
39 | "type": "connectedService:AzureRM",
40 | "label": "Azure RM Subscription",
41 | "defaultValue": "",
42 | "required": true,
43 | "helpMarkDown": "Azure Resource Manager subscription to target for executing SQL"
44 | },
45 | {
46 | "name": "ScriptType",
47 | "type": "pickList",
48 | "label": "Type",
49 | "defaultValue": "FilePath",
50 | "required": true,
51 | "helpMarkDown": "Type of the script: File Path, Inline Script or Predefined Script.",
52 | "options": {
53 | "FilePath": "File Path",
54 | "InlineScript": "Inline Script",
55 | "PredefinedScript": "Predefined Script"
56 | }
57 | },
58 | {
59 | "name": "ScriptPath",
60 | "type": "filePath",
61 | "label": "Script Path",
62 | "defaultValue": "",
63 | "required": true,
64 | "visibleRule": "ScriptType = FilePath",
65 | "helpMarkDown": "Path of the script to execute. Should be fully qualified path or relative to the default working directory."
66 | },
67 | {
68 | "name": "PredefinedScript",
69 | "type": "pickList",
70 | "label": "Predefined Script",
71 | "defaultValue": "CreateUser",
72 | "required": true,
73 | "visibleRule": "ScriptType = PredefinedScript",
74 | "helpMarkDown": "Predefined script to execute. You can see the required variables for each predefined script on the [wiki](https://github.com/geeklearningio/gl-vsts-tasks-azure/wiki/Azure-SQL-Execute-Query).",
75 | "options": {
76 | "CreateUser": "Create User",
77 | "AddRoleMember": "Add Role Member",
78 | "CreateDbOwner": "Create Database Owner"
79 | }
80 | },
81 | {
82 | "name": "Variables",
83 | "type": "multiLine",
84 | "label": "Variables",
85 | "defaultValue": "",
86 | "required": false,
87 | "helpMarkDown": "Variables passed to the SQLCMD script with the -v option. Should be formatted like 'Var1=Value1', with one variable per line. It can then be used with the SQLCMD $(Var1) syntax in the script.",
88 | "properties": {
89 | "resizable": "true",
90 | "rows": "2"
91 | }
92 | },
93 | {
94 | "name": "InlineScript",
95 | "type": "multiLine",
96 | "label": "Inline Script",
97 | "defaultValue": "",
98 | "required": true,
99 | "helpMarkDown": "",
100 | "visibleRule": "ScriptType = InlineScript",
101 | "properties": {
102 | "resizable": "true",
103 | "rows": "10",
104 | "maxLength": "500"
105 | }
106 | },
107 | {
108 | "name": "ServerName",
109 | "type": "string",
110 | "label": "Azure SQL Server Name",
111 | "required": true,
112 | "groupName": "target",
113 | "defaultValue": "",
114 | "helpMarkDown": "Azure SQL Server name like, FabrikamSQL.database.windows.net,1433 or FabrikamSQL.database.windows.net."
115 | },
116 | {
117 | "name": "DatabaseName",
118 | "type": "string",
119 | "label": "Database Name",
120 | "required": true,
121 | "groupName": "target",
122 | "defaultValue": "",
123 | "helpMarkDown": "Name of the Azure SQL Database."
124 | },
125 | {
126 | "name": "SqlUsername",
127 | "type": "string",
128 | "label": "Server Admin Login",
129 | "required": false,
130 | "groupName": "target",
131 | "defaultValue": "",
132 | "helpMarkDown": "Specify the Azure SQL Server administrator login."
133 | },
134 | {
135 | "name": "SqlPassword",
136 | "type": "string",
137 | "label": "Password",
138 | "required": false,
139 | "groupName": "target",
140 | "defaultValue": "",
141 | "helpMarkDown": "Password for the Azure SQL Server administrator.
It can accept variable defined in Build/Release Definitions as '$(passwordVariable').
You may mark variable type as 'secret' to secure it."
142 | },
143 | {
144 | "name": "QueryTimeout",
145 | "type": "string",
146 | "label": "Query Timeout",
147 | "required": false,
148 | "groupName": "target",
149 | "defaultValue": "60",
150 | "helpMarkDown": "Number of seconds before the query will time out. Default is 60 seconds."
151 | },
152 | {
153 | "name": "IpDetectionMethod",
154 | "type": "pickList",
155 | "label": "Specify Firewall Rules Using",
156 | "required": true,
157 | "groupName": "firewall",
158 | "defaultValue": "AutoDetect",
159 | "helpMarkDown": "For the task to run, the IP Address of the automation agent has to be added to the 'Allowed IP Addresses' in the Azure SQL Server's Firewall. Provide the IP Address range of the automation agents, or select to auto-detect in case of hosted automation agent."
160 | },
161 | {
162 | "name": "StartIpAddress",
163 | "type": "string",
164 | "label": "Start IP Address",
165 | "required": true,
166 | "groupName": "firewall",
167 | "defaultValue": "",
168 | "visibleRule": "IpDetectionMethod = IPAddressRange",
169 | "helpMarkDown": "The starting IP Address of the automation agent machine pool like 196.21.30.50."
170 | },
171 | {
172 | "name": "EndIpAddress",
173 | "type": "string",
174 | "label": "End IP Address",
175 | "required": true,
176 | "groupName": "firewall",
177 | "defaultValue": "",
178 | "visibleRule": "IpDetectionMethod = IPAddressRange",
179 | "helpMarkDown": "The ending IP Address of the automation agent machine pool like 196.21.30.65."
180 | },
181 | {
182 | "name": "DeleteFirewallRule",
183 | "type": "boolean",
184 | "label": "Delete Rule After Task Ends",
185 | "required": false,
186 | "groupName": "firewall",
187 | "defaultValue": "true",
188 | "helpMarkDown": "If selected, then after the task ends, the IP Addresses specified here are deleted from the 'Allowed IP Addresses' list of the Azure SQL Server's Firewall."
189 | }
190 | ],
191 | "sourceDefinitions": [
192 | {
193 | "target": "IpDetectionMethod",
194 | "endpoint": "/_apis/vslabs/ipAddress/ipDetectionMethods",
195 | "selector": "jsonpath:$.value[*]",
196 | "authKey": "tfs:DevTestLabs"
197 | }
198 | ],
199 | "execution": {
200 | "PowerShell3": {
201 | "target": "ExecuteSql.ps1"
202 | }
203 | }
204 | }
205 |
--------------------------------------------------------------------------------
/Tasks/ExecuteSql/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | asap@~2.0.3:
6 | version "2.0.6"
7 | resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
8 | integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
9 |
10 | azure-pipelines-task-lib@^2.9.6:
11 | version "2.9.6"
12 | resolved "https://registry.yarnpkg.com/azure-pipelines-task-lib/-/azure-pipelines-task-lib-2.9.6.tgz#acae923dc070ce0524b37786b7fb195d843d3022"
13 | integrity sha512-KTJuFdMl/r1Y8Snh5lHyV2YOyTu9bKzltMlRlnod8YKLc9GfENDkxwm+z9cHH6NlDln+2YI3G82Ri9XcbhyuZg==
14 | dependencies:
15 | minimatch "3.0.4"
16 | mockery "^1.7.0"
17 | q "^1.1.2"
18 | semver "^5.1.0"
19 | shelljs "^0.3.0"
20 | sync-request "3.0.1"
21 | uuid "^3.0.1"
22 |
23 | balanced-match@^1.0.0:
24 | version "1.0.0"
25 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
26 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
27 |
28 | brace-expansion@^1.1.7:
29 | version "1.1.11"
30 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
31 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
32 | dependencies:
33 | balanced-match "^1.0.0"
34 | concat-map "0.0.1"
35 |
36 | buffer-from@^1.0.0:
37 | version "1.1.1"
38 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
39 | integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
40 |
41 | caseless@~0.11.0:
42 | version "0.11.0"
43 | resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7"
44 | integrity sha1-cVuW6phBWTzDMGeSP17GDr2k99c=
45 |
46 | concat-map@0.0.1:
47 | version "0.0.1"
48 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
49 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
50 |
51 | concat-stream@^1.4.6, concat-stream@^1.4.7:
52 | version "1.6.2"
53 | resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
54 | integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
55 | dependencies:
56 | buffer-from "^1.0.0"
57 | inherits "^2.0.3"
58 | readable-stream "^2.2.2"
59 | typedarray "^0.0.6"
60 |
61 | core-util-is@~1.0.0:
62 | version "1.0.2"
63 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
64 | integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
65 |
66 | http-basic@^2.5.1:
67 | version "2.5.1"
68 | resolved "https://registry.yarnpkg.com/http-basic/-/http-basic-2.5.1.tgz#8ce447bdb5b6c577f8a63e3fa78056ec4bb4dbfb"
69 | integrity sha1-jORHvbW2xXf4pj4/p4BW7Eu02/s=
70 | dependencies:
71 | caseless "~0.11.0"
72 | concat-stream "^1.4.6"
73 | http-response-object "^1.0.0"
74 |
75 | http-response-object@^1.0.0, http-response-object@^1.0.1, http-response-object@^1.1.0:
76 | version "1.1.0"
77 | resolved "https://registry.yarnpkg.com/http-response-object/-/http-response-object-1.1.0.tgz#a7c4e75aae82f3bb4904e4f43f615673b4d518c3"
78 | integrity sha1-p8TnWq6C87tJBOT0P2FWc7TVGMM=
79 |
80 | inherits@^2.0.3, inherits@~2.0.3:
81 | version "2.0.4"
82 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
83 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
84 |
85 | isarray@~1.0.0:
86 | version "1.0.0"
87 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
88 | integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
89 |
90 | minimatch@3.0.4:
91 | version "3.0.4"
92 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
93 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
94 | dependencies:
95 | brace-expansion "^1.1.7"
96 |
97 | mockery@^1.7.0:
98 | version "1.7.0"
99 | resolved "https://registry.yarnpkg.com/mockery/-/mockery-1.7.0.tgz#f4ede0d8750c1c9727c272ea2c60629e2c9a1c4f"
100 | integrity sha1-9O3g2HUMHJcnwnLqLGBiniyaHE8=
101 |
102 | process-nextick-args@~2.0.0:
103 | version "2.0.1"
104 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
105 | integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
106 |
107 | promise@^7.1.1:
108 | version "7.3.1"
109 | resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf"
110 | integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==
111 | dependencies:
112 | asap "~2.0.3"
113 |
114 | q@^1.1.2:
115 | version "1.5.1"
116 | resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
117 | integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=
118 |
119 | qs@^6.1.0:
120 | version "6.9.4"
121 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.4.tgz#9090b290d1f91728d3c22e54843ca44aea5ab687"
122 | integrity sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==
123 |
124 | readable-stream@^2.2.2:
125 | version "2.3.7"
126 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
127 | integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
128 | dependencies:
129 | core-util-is "~1.0.0"
130 | inherits "~2.0.3"
131 | isarray "~1.0.0"
132 | process-nextick-args "~2.0.0"
133 | safe-buffer "~5.1.1"
134 | string_decoder "~1.1.1"
135 | util-deprecate "~1.0.1"
136 |
137 | safe-buffer@~5.1.0, safe-buffer@~5.1.1:
138 | version "5.1.2"
139 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
140 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
141 |
142 | semver@^5.1.0:
143 | version "5.7.1"
144 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
145 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
146 |
147 | shelljs@^0.3.0:
148 | version "0.3.0"
149 | resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.3.0.tgz#3596e6307a781544f591f37da618360f31db57b1"
150 | integrity sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=
151 |
152 | string_decoder@~1.1.1:
153 | version "1.1.1"
154 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
155 | integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
156 | dependencies:
157 | safe-buffer "~5.1.0"
158 |
159 | sync-request@3.0.1:
160 | version "3.0.1"
161 | resolved "https://registry.yarnpkg.com/sync-request/-/sync-request-3.0.1.tgz#caa1235aaf889ba501076a1834c436830a82fb73"
162 | integrity sha1-yqEjWq+Im6UBB2oYNMQ2gwqC+3M=
163 | dependencies:
164 | concat-stream "^1.4.7"
165 | http-response-object "^1.0.1"
166 | then-request "^2.0.1"
167 |
168 | then-request@^2.0.1:
169 | version "2.2.0"
170 | resolved "https://registry.yarnpkg.com/then-request/-/then-request-2.2.0.tgz#6678b32fa0ca218fe569981bbd8871b594060d81"
171 | integrity sha1-ZnizL6DKIY/laZgbvYhxtZQGDYE=
172 | dependencies:
173 | caseless "~0.11.0"
174 | concat-stream "^1.4.7"
175 | http-basic "^2.5.1"
176 | http-response-object "^1.1.0"
177 | promise "^7.1.1"
178 | qs "^6.1.0"
179 |
180 | typedarray@^0.0.6:
181 | version "0.0.6"
182 | resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
183 | integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
184 |
185 | util-deprecate@~1.0.1:
186 | version "1.0.2"
187 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
188 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
189 |
190 | uuid@^3.0.1:
191 | version "3.4.0"
192 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
193 | integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
194 |
--------------------------------------------------------------------------------
/Tasks/RestoreSqlDatabaseToSqlDatabase/RestoreSqlDatabaseToSqlDatabase.ps1:
--------------------------------------------------------------------------------
1 | [CmdletBinding()]
2 | param()
3 |
4 | Trace-VstsEnteringInvocation $MyInvocation
5 |
6 | try {
7 | # Get inputs.
8 | $ServerName = Get-VstsInput -Name ServerName -Require
9 | $SourceDatabaseName = Get-VstsInput -Name SourceDatabaseName -Require
10 | $TargetDatabaseName = Get-VstsInput -Name TargetDatabaseName -Require
11 | $PointInTimeWindow = Get-VstsInput -Name PointInTimeWindow -Require
12 |
13 | # Initialize Azure.
14 | Import-Module $PSScriptRoot\ps_modules\VstsAzureHelpers_
15 | Initialize-Azure
16 |
17 | # Import SQL Azure Powershell cmdlets.
18 | Import-Module AzureRM.Sql
19 |
20 | # Import the loc strings.
21 | Import-VstsLocStrings -LiteralPath $PSScriptRoot/Task.json
22 |
23 | $serverFriendlyName = Get-SqlServerFriendlyName -serverName $ServerName
24 |
25 | $resourceGroupName = Get-AzureSqlDatabaseServerResourceGroupName -serverName $serverFriendlyName
26 |
27 | Write-VstsTaskVerbose -Message "[Azure Call] Getting Azure SQL Database details for target $TargetDatabaseName"
28 | $targetDatabase = Get-AzureRmSqlDatabase -ResourceGroupName $resourceGroupName -ServerName $serverFriendlyName -DatabaseName $TargetDatabaseName -ErrorAction SilentlyContinue -Verbose
29 |
30 | if ($targetDatabase) {
31 | Write-VstsTaskVerbose -Message "[Azure Call] Azure SQL Database details got for target $TargetDatabaseName :"
32 | Write-VstsTaskVerbose -Message ($targetDatabase | Format-List | Out-String)
33 |
34 | Write-VstsTaskVerbose -Message "[Azure Call] Azure SQL Database $TargetDatabaseName exists: removing it!"
35 | Remove-AzureRmSqlDatabase -ResourceGroupName $resourceGroupName -ServerName $serverFriendlyName -DatabaseName $TargetDatabaseName -Force -ErrorAction Stop -Verbose
36 | Write-VstsTaskVerbose -Message "[Azure Call] Azure SQL Database $TargetDatabaseName removed"
37 | }
38 | else {
39 | Write-VstsTaskVerbose -Message "[Azure Call] Target Azure SQL Database $TargetDatabaseName does not exists. Continuing..."
40 | }
41 |
42 | Write-VstsTaskVerbose -Message "[Azure Call] Getting Azure SQL Database details for source $SourceDatabaseName"
43 | $sourceDatabase = Get-AzureRmSqlDatabase -ResourceGroupName $resourceGroupName -ServerName $serverFriendlyName -DatabaseName $SourceDatabaseName
44 | Write-VstsTaskVerbose -Message "[Azure Call] Azure SQL Database details got for source $SourceDatabaseName :"
45 | Write-VstsTaskVerbose -Message ($sourceDatabase | Format-List | Out-String)
46 |
47 | $date = (Get-Date).AddMinutes( - ($PointInTimeWindow -as [int]))
48 |
49 | if ([string]::IsNullOrEmpty($sourceDatabase.ElasticPoolName)) {
50 | Write-VstsTaskVerbose -Message "[Azure Call] Restoring Azure SQL Database $SourceDatabaseName to $TargetDatabaseName (Edition $($sourceDatabase.Edition) $($sourceDatabase.CurrentServiceObjectiveName))"
51 |
52 | Restore-AzureRmSqlDatabase -FromPointInTimeBackup -PointInTime $date -ResourceGroupName $sourceDatabase.ResourceGroupName `
53 | -ServerName $serverFriendlyName -TargetDatabaseName $TargetDatabaseName -ResourceId $sourceDatabase.ResourceID `
54 | -Edition $sourceDatabase.Edition -ServiceObjectiveName $sourceDatabase.CurrentServiceObjectiveName -ErrorAction Stop -Verbose
55 |
56 | Write-VstsTaskVerbose -Message "[Azure Call] Azure SQL Database $SourceDatabaseName restored to $TargetDatabaseName (Edition $($sourceDatabase.Edition) $($sourceDatabase.CurrentServiceObjectiveName))"
57 | }
58 | else {
59 | Write-VstsTaskVerbose -Message "[Azure Call] Restoring Azure SQL Database $SourceDatabaseName to $TargetDatabaseName (ElasticPool $($sourceDatabase.ElasticPoolName))"
60 |
61 | Restore-AzureRmSqlDatabase -FromPointInTimeBackup -PointInTime $date -ResourceGroupName $sourceDatabase.ResourceGroupName `
62 | -ServerName $serverFriendlyName -TargetDatabaseName $TargetDatabaseName -ResourceId $sourceDatabase.ResourceID `
63 | -ElasticPoolName $sourceDatabase.ElasticPoolName -ErrorAction Stop -Verbose
64 |
65 | Write-VstsTaskVerbose -Message "[Azure Call] Azure SQL Database $SourceDatabaseName restored to $TargetDatabaseName (ElasticPool $($sourceDatabase.ElasticPoolName))"
66 | }
67 |
68 | }
69 | finally {
70 | Trace-VstsLeavingInvocation $MyInvocation
71 | }
72 |
--------------------------------------------------------------------------------
/Tasks/RestoreSqlDatabaseToSqlDatabase/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeklearningio/gl-vsts-tasks-azure/5da85062a3925111f3b87469220fe04ed3e3956c/Tasks/RestoreSqlDatabaseToSqlDatabase/icon.png
--------------------------------------------------------------------------------
/Tasks/RestoreSqlDatabaseToSqlDatabase/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "RestoreSqlDatabaseToSqlDatabase",
3 | "private": true,
4 | "version": "0.0.0",
5 | "dependencies": {
6 | "azure-pipelines-task-lib": "^2.9.6"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Tasks/RestoreSqlDatabaseToSqlDatabase/task.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "56EFEADB-7DF6-4DAC-8163-AF8E07298C8B",
3 | "name": "RestoreSqlDatabaseToSqlDatabase",
4 | "friendlyName": "Azure SQL Database Restore",
5 | "description": "Restore an Azure SQL Database to another Azure SQL Database on the same server using the latest point-in-time backup",
6 | "helpMarkDown": "[More Information](https://github.com/geeklearningio/gl-vsts-tasks-azure/wiki/Azure-SQL-Database-Restore) (Version #{Version}#)",
7 | "category": "Deploy",
8 | "visibility": ["Build", "Release"],
9 | "author": "Geek Learning",
10 | "version": {
11 | "Major": 0,
12 | "Minor": 0,
13 | "Patch": 0
14 | },
15 | "demands": ["azureps"],
16 | "minimumAgentVersion": "1.103.0",
17 | "instanceNameFormat": "Restore $(SourceDatabaseName) on $(TargetDatabaseName)",
18 | "inputs": [
19 | {
20 | "name": "ConnectedServiceName",
21 | "type": "connectedService:AzureRM",
22 | "label": "Azure RM Subscription",
23 | "defaultValue": "",
24 | "required": true,
25 | "helpMarkDown": "Azure Resource Manager subscription to target for executing SQL"
26 | },
27 | {
28 | "name": "ServerName",
29 | "type": "string",
30 | "label": "Azure SQL Server Name",
31 | "required": true,
32 | "defaultValue": "",
33 | "helpMarkDown": "Azure SQL Server name like, FabrikamSQL.database.windows.net,1433 or FabrikamSQL.database.windows.net."
34 | },
35 | {
36 | "name": "SourceDatabaseName",
37 | "type": "string",
38 | "label": "Source Database Name",
39 | "required": true,
40 | "defaultValue": "",
41 | "helpMarkDown": "Name of the source Azure SQL Database from which to restore."
42 | },
43 | {
44 | "name": "TargetDatabaseName",
45 | "type": "string",
46 | "label": "Target Database Name",
47 | "defaultValue": "",
48 | "required": true,
49 | "helpMarkDown": "Name of the target Azure SQL Database. If exists, will be deleted prior to restore!"
50 | },
51 | {
52 | "name": "PointInTimeWindow",
53 | "type": "string",
54 | "label": "Point In Time Window",
55 | "defaultValue": "6",
56 | "required": true,
57 | "helpMarkDown": "How many minutes into the past to look for a backup to restore from.",
58 | "validation": {
59 | "expression": "isMatch(value,'^\\d+$','IgnoreCase')",
60 | "message": "Must be an integer."
61 | }
62 | }
63 | ],
64 | "sourceDefinitions": [
65 | {
66 | "target": "IpDetectionMethod",
67 | "endpoint": "/_apis/vslabs/ipAddress/ipDetectionMethods",
68 | "selector": "jsonpath:$.value[*]",
69 | "authKey": "tfs:DevTestLabs"
70 | }
71 | ],
72 | "execution": {
73 | "PowerShell3": {
74 | "target": "RestoreSqlDatabaseToSqlDatabase.ps1"
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/Tasks/RestoreSqlDatabaseToSqlDatabase/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | asap@~2.0.3:
6 | version "2.0.6"
7 | resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
8 | integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
9 |
10 | azure-pipelines-task-lib@^2.9.6:
11 | version "2.9.6"
12 | resolved "https://registry.yarnpkg.com/azure-pipelines-task-lib/-/azure-pipelines-task-lib-2.9.6.tgz#acae923dc070ce0524b37786b7fb195d843d3022"
13 | integrity sha512-KTJuFdMl/r1Y8Snh5lHyV2YOyTu9bKzltMlRlnod8YKLc9GfENDkxwm+z9cHH6NlDln+2YI3G82Ri9XcbhyuZg==
14 | dependencies:
15 | minimatch "3.0.4"
16 | mockery "^1.7.0"
17 | q "^1.1.2"
18 | semver "^5.1.0"
19 | shelljs "^0.3.0"
20 | sync-request "3.0.1"
21 | uuid "^3.0.1"
22 |
23 | balanced-match@^1.0.0:
24 | version "1.0.0"
25 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
26 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
27 |
28 | brace-expansion@^1.1.7:
29 | version "1.1.11"
30 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
31 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
32 | dependencies:
33 | balanced-match "^1.0.0"
34 | concat-map "0.0.1"
35 |
36 | buffer-from@^1.0.0:
37 | version "1.1.1"
38 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
39 | integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
40 |
41 | caseless@~0.11.0:
42 | version "0.11.0"
43 | resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7"
44 | integrity sha1-cVuW6phBWTzDMGeSP17GDr2k99c=
45 |
46 | concat-map@0.0.1:
47 | version "0.0.1"
48 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
49 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
50 |
51 | concat-stream@^1.4.6, concat-stream@^1.4.7:
52 | version "1.6.2"
53 | resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
54 | integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
55 | dependencies:
56 | buffer-from "^1.0.0"
57 | inherits "^2.0.3"
58 | readable-stream "^2.2.2"
59 | typedarray "^0.0.6"
60 |
61 | core-util-is@~1.0.0:
62 | version "1.0.2"
63 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
64 | integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
65 |
66 | http-basic@^2.5.1:
67 | version "2.5.1"
68 | resolved "https://registry.yarnpkg.com/http-basic/-/http-basic-2.5.1.tgz#8ce447bdb5b6c577f8a63e3fa78056ec4bb4dbfb"
69 | integrity sha1-jORHvbW2xXf4pj4/p4BW7Eu02/s=
70 | dependencies:
71 | caseless "~0.11.0"
72 | concat-stream "^1.4.6"
73 | http-response-object "^1.0.0"
74 |
75 | http-response-object@^1.0.0, http-response-object@^1.0.1, http-response-object@^1.1.0:
76 | version "1.1.0"
77 | resolved "https://registry.yarnpkg.com/http-response-object/-/http-response-object-1.1.0.tgz#a7c4e75aae82f3bb4904e4f43f615673b4d518c3"
78 | integrity sha1-p8TnWq6C87tJBOT0P2FWc7TVGMM=
79 |
80 | inherits@^2.0.3, inherits@~2.0.3:
81 | version "2.0.4"
82 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
83 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
84 |
85 | isarray@~1.0.0:
86 | version "1.0.0"
87 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
88 | integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
89 |
90 | minimatch@3.0.4:
91 | version "3.0.4"
92 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
93 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
94 | dependencies:
95 | brace-expansion "^1.1.7"
96 |
97 | mockery@^1.7.0:
98 | version "1.7.0"
99 | resolved "https://registry.yarnpkg.com/mockery/-/mockery-1.7.0.tgz#f4ede0d8750c1c9727c272ea2c60629e2c9a1c4f"
100 | integrity sha1-9O3g2HUMHJcnwnLqLGBiniyaHE8=
101 |
102 | process-nextick-args@~2.0.0:
103 | version "2.0.1"
104 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
105 | integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
106 |
107 | promise@^7.1.1:
108 | version "7.3.1"
109 | resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf"
110 | integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==
111 | dependencies:
112 | asap "~2.0.3"
113 |
114 | q@^1.1.2:
115 | version "1.5.1"
116 | resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
117 | integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=
118 |
119 | qs@^6.1.0:
120 | version "6.9.4"
121 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.4.tgz#9090b290d1f91728d3c22e54843ca44aea5ab687"
122 | integrity sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==
123 |
124 | readable-stream@^2.2.2:
125 | version "2.3.7"
126 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
127 | integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
128 | dependencies:
129 | core-util-is "~1.0.0"
130 | inherits "~2.0.3"
131 | isarray "~1.0.0"
132 | process-nextick-args "~2.0.0"
133 | safe-buffer "~5.1.1"
134 | string_decoder "~1.1.1"
135 | util-deprecate "~1.0.1"
136 |
137 | safe-buffer@~5.1.0, safe-buffer@~5.1.1:
138 | version "5.1.2"
139 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
140 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
141 |
142 | semver@^5.1.0:
143 | version "5.7.1"
144 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
145 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
146 |
147 | shelljs@^0.3.0:
148 | version "0.3.0"
149 | resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.3.0.tgz#3596e6307a781544f591f37da618360f31db57b1"
150 | integrity sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=
151 |
152 | string_decoder@~1.1.1:
153 | version "1.1.1"
154 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
155 | integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
156 | dependencies:
157 | safe-buffer "~5.1.0"
158 |
159 | sync-request@3.0.1:
160 | version "3.0.1"
161 | resolved "https://registry.yarnpkg.com/sync-request/-/sync-request-3.0.1.tgz#caa1235aaf889ba501076a1834c436830a82fb73"
162 | integrity sha1-yqEjWq+Im6UBB2oYNMQ2gwqC+3M=
163 | dependencies:
164 | concat-stream "^1.4.7"
165 | http-response-object "^1.0.1"
166 | then-request "^2.0.1"
167 |
168 | then-request@^2.0.1:
169 | version "2.2.0"
170 | resolved "https://registry.yarnpkg.com/then-request/-/then-request-2.2.0.tgz#6678b32fa0ca218fe569981bbd8871b594060d81"
171 | integrity sha1-ZnizL6DKIY/laZgbvYhxtZQGDYE=
172 | dependencies:
173 | caseless "~0.11.0"
174 | concat-stream "^1.4.7"
175 | http-basic "^2.5.1"
176 | http-response-object "^1.1.0"
177 | promise "^7.1.1"
178 | qs "^6.1.0"
179 |
180 | typedarray@^0.0.6:
181 | version "0.0.6"
182 | resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
183 | integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
184 |
185 | util-deprecate@~1.0.1:
186 | version "1.0.2"
187 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
188 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
189 |
190 | uuid@^3.0.1:
191 | version "3.4.0"
192 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
193 | integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
194 |
--------------------------------------------------------------------------------
/Tasks/SqlMultiDacpacDeployment/SqlMultiDacpacDeployment.ps1:
--------------------------------------------------------------------------------
1 | [CmdletBinding()]
2 | param()
3 |
4 | Trace-VstsEnteringInvocation $MyInvocation
5 |
6 | try {
7 | $DacpacFiles = Get-VstsInput -Name DacpacFiles -Require
8 | $AdditionalArguments = Get-VstsInput -Name AdditionalArguments
9 | $ServerName = Get-VstsInput -Name ServerName -Require
10 | $DatabaseName = Get-VstsInput -Name DatabaseName -Require
11 | $SqlUsername = Get-VstsInput -Name SqlUsername
12 | $SqlPassword = Get-VstsInput -Name SqlPassword
13 | $PublishProfile = Get-VstsInput -Name PublishProfile
14 | $IpDetectionMethod = Get-VstsInput -Name IpDetectionMethod -Require
15 | $StartIpAddress = Get-VstsInput -Name StartIpAddress
16 | $EndIpAddress = Get-VstsInput -Name EndIpAddress
17 | $DeleteFirewallRule = Get-VstsInput -Name DeleteFirewallRule -Require
18 |
19 | Import-Module $PSScriptRoot\ps_modules\VstsAzureHelpers_
20 |
21 | Initialize-Azure
22 | Initialize-Sqlps
23 |
24 | Import-VstsLocStrings -LiteralPath $PSScriptRoot/Task.json
25 |
26 | $serverFriendlyName = Get-SqlServerFriendlyName -serverName $ServerName
27 |
28 | $dacpacFilePaths = Find-VstsFiles -LegacyPattern $DacpacFiles -Verbose
29 |
30 | if (!$dacpacFilePaths) {
31 | throw (Get-VstsLocString -Key "No files were found to deploy with search pattern {0}" -ArgumentList $DacpacFiles)
32 | }
33 |
34 | $publishProfilePath = ""
35 | if ([string]::IsNullOrWhitespace($PublishProfile) -eq $false -and $PublishProfile -ne $env:SYSTEM_DEFAULTWORKINGDIRECTORY -and $PublishProfile -ne [String]::Concat($env:SYSTEM_DEFAULTWORKINGDIRECTORY, "\")) {
36 | $publishProfilePath = Find-VstsFiles -LegacyPattern $PublishProfile
37 | if ($publishProfilePath -is [system.array]) {
38 | throw (Get-VstsLocString -Key "Found more than one file to deploy with search pattern {0}. There can be only one." -ArgumentList $PublishProfile)
39 | }
40 | elseif (!$publishProfilePath) {
41 | throw (Get-VstsLocString -Key "No files were found to deploy with search pattern {0}" -ArgumentList $PublishProfile)
42 | }
43 | }
44 |
45 | if ($dacpacFilePaths -isnot [System.Array]) {
46 | $dacpacFilePaths = @($dacpacFilePaths)
47 | }
48 |
49 | $dacFilesWithVersion = [Array](Get-DacpacVersions -dacpacFilePaths $dacpacFilePaths)
50 |
51 | $ipAddress = Get-AgentIPAddress -startIPAddress $StartIpAddress -endIPAddress $EndIpAddress -ipDetectionMethod $IpDetectionMethod
52 | $firewallSettings = Add-AzureSqlDatabaseServerFirewallRule -startIP $ipAddress.StartIPAddress -endIP $ipAddress.EndIPAddress -serverName $serverFriendlyName
53 |
54 | try {
55 | $variableParameter = @("DatabaseName='$DatabaseName'")
56 | Write-VstsTaskVerbose -Message "[SQL Call] Retrieving $DatabaseName DAC Version Number..."
57 | $databaseVersion = [Version]((Invoke-Sqlcmd -InputFile "$PSScriptRoot\SqlScripts\GetDatabaseVersion.sql" -Database "master" -ServerInstance $ServerName -EncryptConnection -Username $SqlUsername -Password $SqlPassword -Variable $variableParameter -ErrorAction Stop -Verbose).DatabaseVersion)
58 | Write-VstsTaskVerbose -Message "[SQL Call] $DatabaseName DAC Version Number retrieved: $databaseVersion"
59 |
60 | $dacFilesToDeploy = $dacFilesWithVersion.GetEnumerator() | Where-Object { $_.Name -gt $databaseVersion }
61 | if ($dacFilesToDeploy.Count -eq 0) {
62 | Write-VstsTaskWarning -Message "Nothing to deploy, the database version ($databaseVersion) is up to date"
63 | }
64 | else {
65 | $sqlPackagePath = Get-SqlPackagePath
66 |
67 | # Always register Data-Tier Application (as this task needs to retrieve later the database version number)
68 | if (-not ($AdditionalArguments -like "*RegisterDataTierApplication*")) {
69 | $AdditionalArguments += " /p:RegisterDataTierApplication=True"
70 | }
71 |
72 | foreach ($dacFileToDeploy in $dacFilesToDeploy) {
73 | Write-Host "Deploying Version: $($dacFileToDeploy.Name)"
74 |
75 | $scriptArguments = Get-SqlPackageCommandArguments -dacpacFile $dacFileToDeploy.Value -serverName $ServerName -databaseName $DatabaseName `
76 | -sqlUsername $SqlUsername -sqlPassword $SqlPassword -publishProfile $publishProfilePath -additionalArguments $AdditionalArguments
77 |
78 | $scriptArgumentsToBeLogged = Get-SqlPackageCommandArguments -dacpacFile $dacFileToDeploy.Value -serverName $ServerName -databaseName $DatabaseName `
79 | -sqlUsername $SqlUsername -sqlPassword $SqlPassword -publishProfile $publishProfilePath -additionalArguments $AdditionalArguments -isOutputSecure
80 |
81 | Send-ExecuteCommand -command $sqlPackagePath -arguments $scriptArguments -secureArguments $scriptArgumentsToBeLogged
82 |
83 | Write-Host "Version $($dacFileToDeploy.Name) deployed"
84 | }
85 | }
86 | }
87 | finally {
88 | Remove-AzureSqlDatabaseServerFirewallRule -serverName $serverFriendlyName -firewallRuleName $firewallSettings.RuleName -isFirewallConfigured $firewallSettings.IsConfigured -deleteFireWallRule $DeleteFirewallRule
89 | }
90 | }
91 | finally {
92 | Trace-VstsLeavingInvocation $MyInvocation
93 | }
94 |
--------------------------------------------------------------------------------
/Tasks/SqlMultiDacpacDeployment/SqlScripts/GetDatabaseVersion.sql:
--------------------------------------------------------------------------------
1 | declare @databaseVersion nvarchar(50)
2 |
3 | select @databaseVersion = type_version
4 | from master.dbo.sysdac_instances
5 | where instance_name = $(DatabaseName)
6 |
7 | select isnull(@databaseVersion, '0.0.0.0') as DatabaseVersion
--------------------------------------------------------------------------------
/Tasks/SqlMultiDacpacDeployment/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeklearningio/gl-vsts-tasks-azure/5da85062a3925111f3b87469220fe04ed3e3956c/Tasks/SqlMultiDacpacDeployment/icon.png
--------------------------------------------------------------------------------
/Tasks/SqlMultiDacpacDeployment/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "SqlMultiDacpacDeployment",
3 | "private": true,
4 | "version": "0.0.0",
5 | "dependencies": {
6 | "azure-pipelines-task-lib": "^2.9.6"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Tasks/SqlMultiDacpacDeployment/task.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "fc7c81bb-92a2-4750-a0c9-d0d88c749ac0",
3 | "name": "SqlMultiDacpacDeployment",
4 | "friendlyName": "Azure SQL Database Incremental Deployment",
5 | "description": "Deploy an Azure SQL Database using multiple DACPAC and performing incremental deployments based on current Data-Tier Application version",
6 | "helpMarkDown": "[More Information](https://github.com/geeklearningio/gl-vsts-tasks-azure/wiki/Azure-SQL-Database-Incremental-Deployment) (Version #{Version}#)",
7 | "category": "Deploy",
8 | "visibility": [
9 | "Build",
10 | "Release"
11 | ],
12 | "author": "Geek Learning",
13 | "version": {
14 | "Major": 0,
15 | "Minor": 0,
16 | "Patch": 0
17 | },
18 | "demands": [
19 | "azureps"
20 | ],
21 | "minimumAgentVersion": "1.103.0",
22 | "instanceNameFormat": "Deploy Azure SQL DACPAC: $(DacpacFiles)",
23 | "groups": [
24 | {
25 | "name": "target",
26 | "displayName": "Target",
27 | "isExpanded": true
28 | },
29 | {
30 | "name": "firewall",
31 | "displayName": "Firewall",
32 | "isExpanded": false
33 | }
34 | ],
35 | "inputs": [
36 | {
37 | "name": "ConnectedServiceName",
38 | "type": "connectedService:AzureRM",
39 | "label": "Azure RM Subscription",
40 | "defaultValue": "",
41 | "required": true,
42 | "helpMarkDown": "Azure Resource Manager subscription to target for executing SQL"
43 | },
44 | {
45 | "name": "DacpacFiles",
46 | "type": "filePath",
47 | "label": "DACPAC Files",
48 | "required": true,
49 | "defaultValue": "",
50 | "helpMarkDown": "Location of the DACPAC files on the automation agent or on a UNC path accessible to the automation agent like, \\\\\\\\BudgetIT\\Web\\Deploy\\*.dacpac. Predefined system variables like, $(Agent.ReleaseDirectory) can be also used here."
51 | },
52 | {
53 | "name": "ServerName",
54 | "type": "string",
55 | "label": "Azure SQL Server Name",
56 | "required": true,
57 | "groupName": "target",
58 | "defaultValue": "",
59 | "helpMarkDown": "Azure SQL Server name like, FabrikamSQL.database.windows.net,1433 or FabrikamSQL.database.windows.net."
60 | },
61 | {
62 | "name": "DatabaseName",
63 | "type": "string",
64 | "label": "Database Name",
65 | "required": true,
66 | "groupName": "target",
67 | "defaultValue": "",
68 | "helpMarkDown": "Name of the Azure SQL Database."
69 | },
70 | {
71 | "name": "SqlUsername",
72 | "type": "string",
73 | "label": "Server Admin Login",
74 | "required": false,
75 | "groupName": "target",
76 | "defaultValue": "",
77 | "helpMarkDown": "Specify the Azure SQL Server administrator login."
78 | },
79 | {
80 | "name": "SqlPassword",
81 | "type": "string",
82 | "label": "Password",
83 | "required": false,
84 | "groupName": "target",
85 | "defaultValue": "",
86 | "helpMarkDown": "Password for the Azure SQL Server administrator.
It can accept variable defined in Build/Release Definitions as '$(PasswordVariable').
You may mark variable type as 'secret' to secure it."
87 | },
88 | {
89 | "name": "PublishProfile",
90 | "type": "filePath",
91 | "label": "Publish Profile",
92 | "required": false,
93 | "groupName": "target",
94 | "defaultValue": "",
95 | "helpMarkDown": "Publish profile provides fine-grained control over Azure SQL Database creation or upgrades. Specify the path to the Publish profile XML file on the automation agent or on a UNC share. Predefined system variables like, $(Agent.BuildDirectory) or $(Agent.ReleaseDirectory) can be also used here."
96 | },
97 | {
98 | "name": "AdditionalArguments",
99 | "type": "string",
100 | "label": "Additional SqlPackage.exe Arguments",
101 | "required": false,
102 | "groupName": "target",
103 | "defaultValue": "",
104 | "helpMarkDown": "Additional SqlPackage.exe arguments that will be applied when creating or updating the Azure SQL Database like, /p:IgnoreAnsiNulls=True /p:IgnoreComments=True."
105 | },
106 | {
107 | "name": "IpDetectionMethod",
108 | "type": "pickList",
109 | "label": "Specify Firewall Rules Using",
110 | "required": true,
111 | "groupName": "firewall",
112 | "defaultValue": "AutoDetect",
113 | "helpMarkDown": "For the task to run, the IP Address of the automation agent has to be added to the 'Allowed IP Addresses' in the Azure SQL Server's Firewall. Provide the IP Address range of the automation agents, or select to auto-detect in case of hosted automation agent."
114 | },
115 | {
116 | "name": "StartIpAddress",
117 | "type": "string",
118 | "label": "Start IP Address",
119 | "required": true,
120 | "groupName": "firewall",
121 | "defaultValue": "",
122 | "visibleRule": "IpDetectionMethod = IPAddressRange",
123 | "helpMarkDown": "The starting IP Address of the automation agent machine pool like 196.21.30.50."
124 | },
125 | {
126 | "name": "EndIpAddress",
127 | "type": "string",
128 | "label": "End IP Address",
129 | "required": true,
130 | "groupName": "firewall",
131 | "defaultValue": "",
132 | "visibleRule": "IpDetectionMethod = IPAddressRange",
133 | "helpMarkDown": "The ending IP Address of the automation agent machine pool like 196.21.30.65."
134 | },
135 | {
136 | "name": "DeleteFirewallRule",
137 | "type": "boolean",
138 | "label": "Delete Rule After Task Ends",
139 | "required": false,
140 | "groupName": "firewall",
141 | "defaultValue": "true",
142 | "helpMarkDown": "If selected, then after the task ends, the IP Addresses specified here are deleted from the 'Allowed IP Addresses' list of the Azure SQL Server's Firewall."
143 | }
144 | ],
145 | "sourceDefinitions": [
146 | {
147 | "target": "IpDetectionMethod",
148 | "endpoint": "/_apis/vslabs/ipAddress/ipDetectionMethods",
149 | "selector": "jsonpath:$.value[*]",
150 | "authKey": "tfs:DevTestLabs"
151 | }
152 | ],
153 | "execution": {
154 | "PowerShell3": {
155 | "target": "SqlMultiDacpacDeployment.ps1"
156 | }
157 | }
158 | }
--------------------------------------------------------------------------------
/Tasks/SqlMultiDacpacDeployment/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | asap@~2.0.3:
6 | version "2.0.6"
7 | resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
8 | integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
9 |
10 | azure-pipelines-task-lib@^2.9.6:
11 | version "2.9.6"
12 | resolved "https://registry.yarnpkg.com/azure-pipelines-task-lib/-/azure-pipelines-task-lib-2.9.6.tgz#acae923dc070ce0524b37786b7fb195d843d3022"
13 | integrity sha512-KTJuFdMl/r1Y8Snh5lHyV2YOyTu9bKzltMlRlnod8YKLc9GfENDkxwm+z9cHH6NlDln+2YI3G82Ri9XcbhyuZg==
14 | dependencies:
15 | minimatch "3.0.4"
16 | mockery "^1.7.0"
17 | q "^1.1.2"
18 | semver "^5.1.0"
19 | shelljs "^0.3.0"
20 | sync-request "3.0.1"
21 | uuid "^3.0.1"
22 |
23 | balanced-match@^1.0.0:
24 | version "1.0.0"
25 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
26 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
27 |
28 | brace-expansion@^1.1.7:
29 | version "1.1.11"
30 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
31 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
32 | dependencies:
33 | balanced-match "^1.0.0"
34 | concat-map "0.0.1"
35 |
36 | buffer-from@^1.0.0:
37 | version "1.1.1"
38 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
39 | integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
40 |
41 | caseless@~0.11.0:
42 | version "0.11.0"
43 | resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7"
44 | integrity sha1-cVuW6phBWTzDMGeSP17GDr2k99c=
45 |
46 | concat-map@0.0.1:
47 | version "0.0.1"
48 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
49 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
50 |
51 | concat-stream@^1.4.6, concat-stream@^1.4.7:
52 | version "1.6.2"
53 | resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
54 | integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
55 | dependencies:
56 | buffer-from "^1.0.0"
57 | inherits "^2.0.3"
58 | readable-stream "^2.2.2"
59 | typedarray "^0.0.6"
60 |
61 | core-util-is@~1.0.0:
62 | version "1.0.2"
63 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
64 | integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
65 |
66 | http-basic@^2.5.1:
67 | version "2.5.1"
68 | resolved "https://registry.yarnpkg.com/http-basic/-/http-basic-2.5.1.tgz#8ce447bdb5b6c577f8a63e3fa78056ec4bb4dbfb"
69 | integrity sha1-jORHvbW2xXf4pj4/p4BW7Eu02/s=
70 | dependencies:
71 | caseless "~0.11.0"
72 | concat-stream "^1.4.6"
73 | http-response-object "^1.0.0"
74 |
75 | http-response-object@^1.0.0, http-response-object@^1.0.1, http-response-object@^1.1.0:
76 | version "1.1.0"
77 | resolved "https://registry.yarnpkg.com/http-response-object/-/http-response-object-1.1.0.tgz#a7c4e75aae82f3bb4904e4f43f615673b4d518c3"
78 | integrity sha1-p8TnWq6C87tJBOT0P2FWc7TVGMM=
79 |
80 | inherits@^2.0.3, inherits@~2.0.3:
81 | version "2.0.4"
82 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
83 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
84 |
85 | isarray@~1.0.0:
86 | version "1.0.0"
87 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
88 | integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
89 |
90 | minimatch@3.0.4:
91 | version "3.0.4"
92 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
93 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
94 | dependencies:
95 | brace-expansion "^1.1.7"
96 |
97 | mockery@^1.7.0:
98 | version "1.7.0"
99 | resolved "https://registry.yarnpkg.com/mockery/-/mockery-1.7.0.tgz#f4ede0d8750c1c9727c272ea2c60629e2c9a1c4f"
100 | integrity sha1-9O3g2HUMHJcnwnLqLGBiniyaHE8=
101 |
102 | process-nextick-args@~2.0.0:
103 | version "2.0.1"
104 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
105 | integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
106 |
107 | promise@^7.1.1:
108 | version "7.3.1"
109 | resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf"
110 | integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==
111 | dependencies:
112 | asap "~2.0.3"
113 |
114 | q@^1.1.2:
115 | version "1.5.1"
116 | resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
117 | integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=
118 |
119 | qs@^6.1.0:
120 | version "6.9.4"
121 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.4.tgz#9090b290d1f91728d3c22e54843ca44aea5ab687"
122 | integrity sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==
123 |
124 | readable-stream@^2.2.2:
125 | version "2.3.7"
126 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
127 | integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
128 | dependencies:
129 | core-util-is "~1.0.0"
130 | inherits "~2.0.3"
131 | isarray "~1.0.0"
132 | process-nextick-args "~2.0.0"
133 | safe-buffer "~5.1.1"
134 | string_decoder "~1.1.1"
135 | util-deprecate "~1.0.1"
136 |
137 | safe-buffer@~5.1.0, safe-buffer@~5.1.1:
138 | version "5.1.2"
139 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
140 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
141 |
142 | semver@^5.1.0:
143 | version "5.7.1"
144 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
145 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
146 |
147 | shelljs@^0.3.0:
148 | version "0.3.0"
149 | resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.3.0.tgz#3596e6307a781544f591f37da618360f31db57b1"
150 | integrity sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=
151 |
152 | string_decoder@~1.1.1:
153 | version "1.1.1"
154 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
155 | integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
156 | dependencies:
157 | safe-buffer "~5.1.0"
158 |
159 | sync-request@3.0.1:
160 | version "3.0.1"
161 | resolved "https://registry.yarnpkg.com/sync-request/-/sync-request-3.0.1.tgz#caa1235aaf889ba501076a1834c436830a82fb73"
162 | integrity sha1-yqEjWq+Im6UBB2oYNMQ2gwqC+3M=
163 | dependencies:
164 | concat-stream "^1.4.7"
165 | http-response-object "^1.0.1"
166 | then-request "^2.0.1"
167 |
168 | then-request@^2.0.1:
169 | version "2.2.0"
170 | resolved "https://registry.yarnpkg.com/then-request/-/then-request-2.2.0.tgz#6678b32fa0ca218fe569981bbd8871b594060d81"
171 | integrity sha1-ZnizL6DKIY/laZgbvYhxtZQGDYE=
172 | dependencies:
173 | caseless "~0.11.0"
174 | concat-stream "^1.4.7"
175 | http-basic "^2.5.1"
176 | http-response-object "^1.1.0"
177 | promise "^7.1.1"
178 | qs "^6.1.0"
179 |
180 | typedarray@^0.0.6:
181 | version "0.0.6"
182 | resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
183 | integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
184 |
185 | util-deprecate@~1.0.1:
186 | version "1.0.2"
187 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
188 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
189 |
190 | uuid@^3.0.1:
191 | version "3.4.0"
192 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
193 | integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
194 |
--------------------------------------------------------------------------------
/Tasks/StartWebApp/StartWebApp.ps1:
--------------------------------------------------------------------------------
1 | [CmdletBinding()]
2 | param()
3 |
4 | Trace-VstsEnteringInvocation $MyInvocation
5 |
6 | try {
7 | # Get inputs.
8 | $WebAppName = Get-VstsInput -Name WebAppName -Require
9 | $Slot = Get-VstsInput -Name Slot
10 | $StartedUrl = Get-VstsInput -Name StartedUrl
11 |
12 | # Initialize Azure.
13 | Import-Module $PSScriptRoot\ps_modules\VstsAzureHelpers_
14 | Initialize-Azure
15 |
16 | # Import the loc strings.
17 | Import-VstsLocStrings -LiteralPath $PSScriptRoot/Task.json
18 |
19 | $resourceGroupName = Get-WebAppResourceGroupName -webAppName $WebAppName
20 |
21 | if ($Slot) {
22 | Write-VstsTaskVerbose -Message "[Azure Call] Starting slot: $WebAppName / $Slot"
23 | $result = Start-AzureRmWebAppSlot -ResourceGroupName $resourceGroupName -Name $WebAppName -Slot $Slot -Verbose
24 | Write-VstsTaskVerbose -Message "[Azure Call] Slot started: $WebAppName / $Slot"
25 | }
26 | else {
27 | Write-VstsTaskVerbose -Message "[Azure Call] Starting Web App: $WebAppName"
28 | $result = Start-AzureRmWebApp -ResourceGroupName $resourceGroupName -Name $WebAppName -Verbose
29 | Write-VstsTaskVerbose -Message "[Azure Call] Web App started: $WebAppName"
30 | }
31 |
32 | $scheme = "http"
33 | $hostName = $result.HostNames[0]
34 | foreach ($hostNameSslState in $result.HostNameSslStates) {
35 | if ($hostName -eq $hostNameSslState.Name) {
36 | if (-not $hostNameSslState.SslState -eq 0) {
37 | $scheme = "https"
38 | }
39 |
40 | break
41 | }
42 | }
43 |
44 | $urlValue = "${scheme}://$hostName"
45 |
46 | Write-Host (Get-VstsLocString -Key "WebappsuccessfullystartedatUrl0" -ArgumentList $urlValue)
47 |
48 | # Set ouput variable with $destinationUrl
49 | if (-not [string]::IsNullOrEmpty($StartedUrl)) {
50 | if ([string]::IsNullOrEmpty($StartedUrl)) {
51 | Throw (Get-VstsLocString -Key "Unabletoretrievewebappurlforwebapp0" -ArgumentList $webAppName)
52 | }
53 |
54 | Set-VstsTaskVariable -Name $StartedUrl -Value $urlValue
55 | }
56 | }
57 | finally {
58 | Trace-VstsLeavingInvocation $MyInvocation
59 | }
60 |
--------------------------------------------------------------------------------
/Tasks/StartWebApp/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeklearningio/gl-vsts-tasks-azure/5da85062a3925111f3b87469220fe04ed3e3956c/Tasks/StartWebApp/icon.png
--------------------------------------------------------------------------------
/Tasks/StartWebApp/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "StartWebApp",
3 | "private": true,
4 | "version": "0.0.0",
5 | "dependencies": {
6 | "azure-pipelines-task-lib": "^2.9.6"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Tasks/StartWebApp/task.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "DF1611D6-6AEE-40B5-8AF6-143AF94D9F3E",
3 | "name": "StartWebApp",
4 | "friendlyName": "Azure Web App Start",
5 | "description": "Deprecated: use the official “Azure App Service Manage” task from Microsoft instead. You can then set the “Action” parameter to 'Start Azure App Service'.",
6 | "helpMarkDown": "",
7 | "category": "Deploy",
8 | "deprecated": true,
9 | "visibility": [
10 | "Build",
11 | "Release"
12 | ],
13 | "author": "Geek Learning",
14 | "version": {
15 | "Major": 0,
16 | "Minor": 0,
17 | "Patch": 0
18 | },
19 | "demands": [
20 | "azureps"
21 | ],
22 | "minimumAgentVersion": "1.103.0",
23 | "instanceNameFormat": "Start Azure Web App: $(WebAppName) $(Slot)",
24 | "groups": [{
25 | "name": "output",
26 | "displayName": "Output",
27 | "isExpanded": false
28 | }],
29 | "inputs": [{
30 | "name": "ConnectedServiceName",
31 | "type": "connectedService:AzureRM",
32 | "label": "Azure RM Subscription",
33 | "defaultValue": "",
34 | "required": true,
35 | "helpMarkDown": "Azure Resource Manager subscription to target for starting the Web App"
36 | },
37 | {
38 | "name": "WebAppName",
39 | "type": "pickList",
40 | "label": "Web App Name",
41 | "defaultValue": "",
42 | "required": true,
43 | "properties": {
44 | "EditableOptions": "True"
45 | },
46 | "helpMarkDown": "Enter or Select the name of an existing AzureRM Web Application"
47 | },
48 | {
49 | "name": "Slot",
50 | "type": "string",
51 | "label": "Slot",
52 | "defaultValue": "",
53 | "required": false,
54 | "helpMarkDown": "If provided, will start the specified slot instead of the Web App itself"
55 | },
56 | {
57 | "name": "StartedUrl",
58 | "type": "string",
59 | "label": "Started Url",
60 | "required": false,
61 | "defaultValue": "",
62 | "groupName": "output",
63 | "helpMarkDown": "Provide a name for the variable for the started url. The variable can be used as $(variableName) to refer to the hosted url of Web App in subsequent tasks like in the PowerShell on Target Machines task."
64 | }
65 | ],
66 | "dataSourceBindings": [{
67 | "target": "WebAppName",
68 | "endpointId": "$(ConnectedServiceName)",
69 | "dataSourceName": "AzureRMWebAppNames"
70 | }],
71 | "execution": {
72 | "PowerShell3": {
73 | "target": "StartWebApp.ps1"
74 | }
75 | },
76 | "messages": {
77 | "WebappsuccessfullystartedatUrl0": "Web App successfully started at Url: {0}",
78 | "Unabletoretrievewebappurlforwebapp0": "Unable to retrieve Web App url for Web App: {0}"
79 | }
80 | }
--------------------------------------------------------------------------------
/Tasks/StartWebApp/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | asap@~2.0.3:
6 | version "2.0.6"
7 | resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
8 | integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
9 |
10 | azure-pipelines-task-lib@^2.9.6:
11 | version "2.9.6"
12 | resolved "https://registry.yarnpkg.com/azure-pipelines-task-lib/-/azure-pipelines-task-lib-2.9.6.tgz#acae923dc070ce0524b37786b7fb195d843d3022"
13 | integrity sha512-KTJuFdMl/r1Y8Snh5lHyV2YOyTu9bKzltMlRlnod8YKLc9GfENDkxwm+z9cHH6NlDln+2YI3G82Ri9XcbhyuZg==
14 | dependencies:
15 | minimatch "3.0.4"
16 | mockery "^1.7.0"
17 | q "^1.1.2"
18 | semver "^5.1.0"
19 | shelljs "^0.3.0"
20 | sync-request "3.0.1"
21 | uuid "^3.0.1"
22 |
23 | balanced-match@^1.0.0:
24 | version "1.0.0"
25 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
26 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
27 |
28 | brace-expansion@^1.1.7:
29 | version "1.1.11"
30 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
31 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
32 | dependencies:
33 | balanced-match "^1.0.0"
34 | concat-map "0.0.1"
35 |
36 | buffer-from@^1.0.0:
37 | version "1.1.1"
38 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
39 | integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
40 |
41 | caseless@~0.11.0:
42 | version "0.11.0"
43 | resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7"
44 | integrity sha1-cVuW6phBWTzDMGeSP17GDr2k99c=
45 |
46 | concat-map@0.0.1:
47 | version "0.0.1"
48 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
49 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
50 |
51 | concat-stream@^1.4.6, concat-stream@^1.4.7:
52 | version "1.6.2"
53 | resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
54 | integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
55 | dependencies:
56 | buffer-from "^1.0.0"
57 | inherits "^2.0.3"
58 | readable-stream "^2.2.2"
59 | typedarray "^0.0.6"
60 |
61 | core-util-is@~1.0.0:
62 | version "1.0.2"
63 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
64 | integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
65 |
66 | http-basic@^2.5.1:
67 | version "2.5.1"
68 | resolved "https://registry.yarnpkg.com/http-basic/-/http-basic-2.5.1.tgz#8ce447bdb5b6c577f8a63e3fa78056ec4bb4dbfb"
69 | integrity sha1-jORHvbW2xXf4pj4/p4BW7Eu02/s=
70 | dependencies:
71 | caseless "~0.11.0"
72 | concat-stream "^1.4.6"
73 | http-response-object "^1.0.0"
74 |
75 | http-response-object@^1.0.0, http-response-object@^1.0.1, http-response-object@^1.1.0:
76 | version "1.1.0"
77 | resolved "https://registry.yarnpkg.com/http-response-object/-/http-response-object-1.1.0.tgz#a7c4e75aae82f3bb4904e4f43f615673b4d518c3"
78 | integrity sha1-p8TnWq6C87tJBOT0P2FWc7TVGMM=
79 |
80 | inherits@^2.0.3, inherits@~2.0.3:
81 | version "2.0.4"
82 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
83 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
84 |
85 | isarray@~1.0.0:
86 | version "1.0.0"
87 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
88 | integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
89 |
90 | minimatch@3.0.4:
91 | version "3.0.4"
92 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
93 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
94 | dependencies:
95 | brace-expansion "^1.1.7"
96 |
97 | mockery@^1.7.0:
98 | version "1.7.0"
99 | resolved "https://registry.yarnpkg.com/mockery/-/mockery-1.7.0.tgz#f4ede0d8750c1c9727c272ea2c60629e2c9a1c4f"
100 | integrity sha1-9O3g2HUMHJcnwnLqLGBiniyaHE8=
101 |
102 | process-nextick-args@~2.0.0:
103 | version "2.0.1"
104 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
105 | integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
106 |
107 | promise@^7.1.1:
108 | version "7.3.1"
109 | resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf"
110 | integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==
111 | dependencies:
112 | asap "~2.0.3"
113 |
114 | q@^1.1.2:
115 | version "1.5.1"
116 | resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
117 | integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=
118 |
119 | qs@^6.1.0:
120 | version "6.9.4"
121 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.4.tgz#9090b290d1f91728d3c22e54843ca44aea5ab687"
122 | integrity sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==
123 |
124 | readable-stream@^2.2.2:
125 | version "2.3.7"
126 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
127 | integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
128 | dependencies:
129 | core-util-is "~1.0.0"
130 | inherits "~2.0.3"
131 | isarray "~1.0.0"
132 | process-nextick-args "~2.0.0"
133 | safe-buffer "~5.1.1"
134 | string_decoder "~1.1.1"
135 | util-deprecate "~1.0.1"
136 |
137 | safe-buffer@~5.1.0, safe-buffer@~5.1.1:
138 | version "5.1.2"
139 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
140 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
141 |
142 | semver@^5.1.0:
143 | version "5.7.1"
144 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
145 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
146 |
147 | shelljs@^0.3.0:
148 | version "0.3.0"
149 | resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.3.0.tgz#3596e6307a781544f591f37da618360f31db57b1"
150 | integrity sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=
151 |
152 | string_decoder@~1.1.1:
153 | version "1.1.1"
154 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
155 | integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
156 | dependencies:
157 | safe-buffer "~5.1.0"
158 |
159 | sync-request@3.0.1:
160 | version "3.0.1"
161 | resolved "https://registry.yarnpkg.com/sync-request/-/sync-request-3.0.1.tgz#caa1235aaf889ba501076a1834c436830a82fb73"
162 | integrity sha1-yqEjWq+Im6UBB2oYNMQ2gwqC+3M=
163 | dependencies:
164 | concat-stream "^1.4.7"
165 | http-response-object "^1.0.1"
166 | then-request "^2.0.1"
167 |
168 | then-request@^2.0.1:
169 | version "2.2.0"
170 | resolved "https://registry.yarnpkg.com/then-request/-/then-request-2.2.0.tgz#6678b32fa0ca218fe569981bbd8871b594060d81"
171 | integrity sha1-ZnizL6DKIY/laZgbvYhxtZQGDYE=
172 | dependencies:
173 | caseless "~0.11.0"
174 | concat-stream "^1.4.7"
175 | http-basic "^2.5.1"
176 | http-response-object "^1.1.0"
177 | promise "^7.1.1"
178 | qs "^6.1.0"
179 |
180 | typedarray@^0.0.6:
181 | version "0.0.6"
182 | resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
183 | integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
184 |
185 | util-deprecate@~1.0.1:
186 | version "1.0.2"
187 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
188 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
189 |
190 | uuid@^3.0.1:
191 | version "3.4.0"
192 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
193 | integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
194 |
--------------------------------------------------------------------------------
/Tasks/StopWebApp/StopWebApp.ps1:
--------------------------------------------------------------------------------
1 | [CmdletBinding()]
2 | param()
3 |
4 | Trace-VstsEnteringInvocation $MyInvocation
5 |
6 | try {
7 | # Get inputs.
8 | $WebAppName = Get-VstsInput -Name WebAppName -Require
9 | $Slot = Get-VstsInput -Name Slot
10 | $StoppedUrl = Get-VstsInput -Name StoppedUrl
11 |
12 | # Initialize Azure.
13 | Import-Module $PSScriptRoot\ps_modules\VstsAzureHelpers_
14 | Initialize-Azure
15 |
16 | # Import the loc strings.
17 | Import-VstsLocStrings -LiteralPath $PSScriptRoot/Task.json
18 |
19 | $resourceGroupName = Get-WebAppResourceGroupName -webAppName $WebAppName
20 |
21 | if ($Slot) {
22 | Write-VstsTaskVerbose -Message "[Azure Call] Stopping slot: $WebAppName / $Slot"
23 | $result = Stop-AzureRmWebAppSlot -ResourceGroupName $resourceGroupName -Name $WebAppName -Slot $Slot -Verbose
24 | Write-VstsTaskVerbose -Message "[Azure Call] Slot stopped: $WebAppName / $Slot"
25 | }
26 | else {
27 | Write-VstsTaskVerbose -Message "[Azure Call] Stopping Web App: $WebAppName"
28 | $result = Stop-AzureRmWebApp -ResourceGroupName $resourceGroupName -Name $WebAppName -Verbose
29 | Write-VstsTaskVerbose -Message "[Azure Call] Web App stopped: $WebAppName"
30 | }
31 |
32 | $scheme = "http"
33 | $hostName = $result.HostNames[0]
34 | foreach ($hostNameSslState in $result.HostNameSslStates) {
35 | if ($hostName -eq $hostNameSslState.Name) {
36 | if (-not $hostNameSslState.SslState -eq 0) {
37 | $scheme = "https"
38 | }
39 |
40 | break
41 | }
42 | }
43 |
44 | $urlValue = "${scheme}://$hostName"
45 |
46 | Write-Host (Get-VstsLocString -Key "WebappsuccessfullystoppedatUrl0" -ArgumentList $urlValue)
47 |
48 | # Set ouput variable with $destinationUrl
49 | if (-not [string]::IsNullOrEmpty($StoppedUrl)) {
50 | if ([string]::IsNullOrEmpty($StoppedUrl)) {
51 | Throw (Get-VstsLocString -Key "Unabletoretrievewebappurlforwebapp0" -ArgumentList $webAppName)
52 | }
53 |
54 | Set-VstsTaskVariable -Name $StoppedUrl -Value $urlValue
55 | }
56 | }
57 | finally {
58 | Trace-VstsLeavingInvocation $MyInvocation
59 | }
60 |
--------------------------------------------------------------------------------
/Tasks/StopWebApp/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeklearningio/gl-vsts-tasks-azure/5da85062a3925111f3b87469220fe04ed3e3956c/Tasks/StopWebApp/icon.png
--------------------------------------------------------------------------------
/Tasks/StopWebApp/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "StopWebApp",
3 | "private": true,
4 | "version": "0.0.0",
5 | "dependencies": {
6 | "azure-pipelines-task-lib": "^2.9.6"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Tasks/StopWebApp/task.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "A3F35BB6-5341-413A-8091-10F93D390BB5",
3 | "name": "StopWebApp",
4 | "friendlyName": "Azure Web App Stop",
5 | "description": "Deprecated: use the official “Azure App Service Manage” task from Microsoft instead. You can then set the “Action” parameter to 'Stop Azure App Service'.",
6 | "helpMarkDown": "",
7 | "category": "Deploy",
8 | "deprecated": true,
9 | "visibility": [
10 | "Build",
11 | "Release"
12 | ],
13 | "author": "Geek Learning",
14 | "version": {
15 | "Major": 0,
16 | "Minor": 0,
17 | "Patch": 0
18 | },
19 | "demands": [
20 | "azureps"
21 | ],
22 | "minimumAgentVersion": "1.103.0",
23 | "instanceNameFormat": "Stop Azure Web App: $(WebAppName) $(Slot)",
24 | "groups": [
25 | {
26 | "name": "output",
27 | "displayName": "Output",
28 | "isExpanded": false
29 | }
30 | ],
31 | "inputs": [
32 | {
33 | "name": "ConnectedServiceName",
34 | "type": "connectedService:AzureRM",
35 | "label": "Azure RM Subscription",
36 | "defaultValue": "",
37 | "required": true,
38 | "helpMarkDown": "Azure Resource Manager subscription to target for stopping the Web App"
39 | },
40 | {
41 | "name": "WebAppName",
42 | "type": "pickList",
43 | "label": "Web App Name",
44 | "defaultValue": "",
45 | "required": true,
46 | "properties": {
47 | "EditableOptions": "True"
48 | },
49 | "helpMarkDown": "Enter or Select the name of an existing AzureRM Web Application"
50 | },
51 | {
52 | "name": "Slot",
53 | "type": "string",
54 | "label": "Slot",
55 | "defaultValue": "",
56 | "required": false,
57 | "helpMarkDown": "If provided, will stop the specified slot instead of the Web App itself"
58 | },
59 | {
60 | "name": "StoppedUrl",
61 | "type": "string",
62 | "label": "Stopped Url",
63 | "required": false,
64 | "defaultValue": "",
65 | "groupName": "output",
66 | "helpMarkDown": "Provide a name for the variable for the stopped url. The variable can be used as $(variableName) to refer to the hosted url of Web App in subsequent tasks like in the PowerShell on Target Machines task."
67 | }
68 | ],
69 | "dataSourceBindings": [
70 | {
71 | "target": "WebAppName",
72 | "endpointId": "$(ConnectedServiceName)",
73 | "dataSourceName": "AzureRMWebAppNames"
74 | }
75 | ],
76 | "execution": {
77 | "PowerShell3": {
78 | "target": "StopWebApp.ps1"
79 | }
80 | },
81 | "messages": {
82 | "WebappsuccessfullystoppedatUrl0": "Web App successfully stopped at Url: {0}",
83 | "Unabletoretrievewebappurlforwebapp0": "Unable to retrieve Web App url for Web App: {0}"
84 | }
85 | }
--------------------------------------------------------------------------------
/Tasks/StopWebApp/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | asap@~2.0.3:
6 | version "2.0.6"
7 | resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
8 | integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
9 |
10 | azure-pipelines-task-lib@^2.9.6:
11 | version "2.9.6"
12 | resolved "https://registry.yarnpkg.com/azure-pipelines-task-lib/-/azure-pipelines-task-lib-2.9.6.tgz#acae923dc070ce0524b37786b7fb195d843d3022"
13 | integrity sha512-KTJuFdMl/r1Y8Snh5lHyV2YOyTu9bKzltMlRlnod8YKLc9GfENDkxwm+z9cHH6NlDln+2YI3G82Ri9XcbhyuZg==
14 | dependencies:
15 | minimatch "3.0.4"
16 | mockery "^1.7.0"
17 | q "^1.1.2"
18 | semver "^5.1.0"
19 | shelljs "^0.3.0"
20 | sync-request "3.0.1"
21 | uuid "^3.0.1"
22 |
23 | balanced-match@^1.0.0:
24 | version "1.0.0"
25 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
26 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
27 |
28 | brace-expansion@^1.1.7:
29 | version "1.1.11"
30 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
31 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
32 | dependencies:
33 | balanced-match "^1.0.0"
34 | concat-map "0.0.1"
35 |
36 | buffer-from@^1.0.0:
37 | version "1.1.1"
38 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
39 | integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
40 |
41 | caseless@~0.11.0:
42 | version "0.11.0"
43 | resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7"
44 | integrity sha1-cVuW6phBWTzDMGeSP17GDr2k99c=
45 |
46 | concat-map@0.0.1:
47 | version "0.0.1"
48 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
49 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
50 |
51 | concat-stream@^1.4.6, concat-stream@^1.4.7:
52 | version "1.6.2"
53 | resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
54 | integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
55 | dependencies:
56 | buffer-from "^1.0.0"
57 | inherits "^2.0.3"
58 | readable-stream "^2.2.2"
59 | typedarray "^0.0.6"
60 |
61 | core-util-is@~1.0.0:
62 | version "1.0.2"
63 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
64 | integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
65 |
66 | http-basic@^2.5.1:
67 | version "2.5.1"
68 | resolved "https://registry.yarnpkg.com/http-basic/-/http-basic-2.5.1.tgz#8ce447bdb5b6c577f8a63e3fa78056ec4bb4dbfb"
69 | integrity sha1-jORHvbW2xXf4pj4/p4BW7Eu02/s=
70 | dependencies:
71 | caseless "~0.11.0"
72 | concat-stream "^1.4.6"
73 | http-response-object "^1.0.0"
74 |
75 | http-response-object@^1.0.0, http-response-object@^1.0.1, http-response-object@^1.1.0:
76 | version "1.1.0"
77 | resolved "https://registry.yarnpkg.com/http-response-object/-/http-response-object-1.1.0.tgz#a7c4e75aae82f3bb4904e4f43f615673b4d518c3"
78 | integrity sha1-p8TnWq6C87tJBOT0P2FWc7TVGMM=
79 |
80 | inherits@^2.0.3, inherits@~2.0.3:
81 | version "2.0.4"
82 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
83 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
84 |
85 | isarray@~1.0.0:
86 | version "1.0.0"
87 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
88 | integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
89 |
90 | minimatch@3.0.4:
91 | version "3.0.4"
92 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
93 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
94 | dependencies:
95 | brace-expansion "^1.1.7"
96 |
97 | mockery@^1.7.0:
98 | version "1.7.0"
99 | resolved "https://registry.yarnpkg.com/mockery/-/mockery-1.7.0.tgz#f4ede0d8750c1c9727c272ea2c60629e2c9a1c4f"
100 | integrity sha1-9O3g2HUMHJcnwnLqLGBiniyaHE8=
101 |
102 | process-nextick-args@~2.0.0:
103 | version "2.0.1"
104 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
105 | integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
106 |
107 | promise@^7.1.1:
108 | version "7.3.1"
109 | resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf"
110 | integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==
111 | dependencies:
112 | asap "~2.0.3"
113 |
114 | q@^1.1.2:
115 | version "1.5.1"
116 | resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
117 | integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=
118 |
119 | qs@^6.1.0:
120 | version "6.9.4"
121 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.4.tgz#9090b290d1f91728d3c22e54843ca44aea5ab687"
122 | integrity sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==
123 |
124 | readable-stream@^2.2.2:
125 | version "2.3.7"
126 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
127 | integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
128 | dependencies:
129 | core-util-is "~1.0.0"
130 | inherits "~2.0.3"
131 | isarray "~1.0.0"
132 | process-nextick-args "~2.0.0"
133 | safe-buffer "~5.1.1"
134 | string_decoder "~1.1.1"
135 | util-deprecate "~1.0.1"
136 |
137 | safe-buffer@~5.1.0, safe-buffer@~5.1.1:
138 | version "5.1.2"
139 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
140 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
141 |
142 | semver@^5.1.0:
143 | version "5.7.1"
144 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
145 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
146 |
147 | shelljs@^0.3.0:
148 | version "0.3.0"
149 | resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.3.0.tgz#3596e6307a781544f591f37da618360f31db57b1"
150 | integrity sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=
151 |
152 | string_decoder@~1.1.1:
153 | version "1.1.1"
154 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
155 | integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
156 | dependencies:
157 | safe-buffer "~5.1.0"
158 |
159 | sync-request@3.0.1:
160 | version "3.0.1"
161 | resolved "https://registry.yarnpkg.com/sync-request/-/sync-request-3.0.1.tgz#caa1235aaf889ba501076a1834c436830a82fb73"
162 | integrity sha1-yqEjWq+Im6UBB2oYNMQ2gwqC+3M=
163 | dependencies:
164 | concat-stream "^1.4.7"
165 | http-response-object "^1.0.1"
166 | then-request "^2.0.1"
167 |
168 | then-request@^2.0.1:
169 | version "2.2.0"
170 | resolved "https://registry.yarnpkg.com/then-request/-/then-request-2.2.0.tgz#6678b32fa0ca218fe569981bbd8871b594060d81"
171 | integrity sha1-ZnizL6DKIY/laZgbvYhxtZQGDYE=
172 | dependencies:
173 | caseless "~0.11.0"
174 | concat-stream "^1.4.7"
175 | http-basic "^2.5.1"
176 | http-response-object "^1.1.0"
177 | promise "^7.1.1"
178 | qs "^6.1.0"
179 |
180 | typedarray@^0.0.6:
181 | version "0.0.6"
182 | resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
183 | integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
184 |
185 | util-deprecate@~1.0.1:
186 | version "1.0.2"
187 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
188 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
189 |
190 | uuid@^3.0.1:
191 | version "3.4.0"
192 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
193 | integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
194 |
--------------------------------------------------------------------------------
/Tasks/SwapSlots/SwapSlots.ps1:
--------------------------------------------------------------------------------
1 | [CmdletBinding()]
2 | param()
3 |
4 | Trace-VstsEnteringInvocation $MyInvocation
5 |
6 | try {
7 |
8 | # Get inputs.
9 | $WebAppName = Get-VstsInput -Name WebAppName -Require
10 | $SourceSlot = Get-VstsInput -Name SourceSlot -Require
11 | $DestinationSlot = Get-VstsInput -Name DestinationSlot -Require
12 | $DestinationUrl = Get-VstsInput -Name DestinationUrl
13 |
14 | # Initialize Azure.
15 | Import-Module $PSScriptRoot\ps_modules\VstsAzureHelpers_
16 | Initialize-Azure
17 |
18 | # Import the loc strings.
19 | Import-VstsLocStrings -LiteralPath $PSScriptRoot/Task.json
20 |
21 | $resourceGroupName = Get-WebAppResourceGroupName -webAppName $WebAppName
22 | $parametersObject = @{targetSlot = "$DestinationSlot" }
23 | if ($SourceSlot -eq "production") {
24 | $resourceName = "$WebAppName"
25 | $resourceType = "Microsoft.Web/sites"
26 | }
27 | else {
28 | $resourceName = "$WebAppName/$SourceSlot"
29 | $resourceType = "Microsoft.Web/sites/slots"
30 | }
31 |
32 | Write-VstsTaskVerbose -Message "[Azure Call] Swapping slot: $resourceName with resource type: $resourceType to $DestinationSlot"
33 | $result = Invoke-AzureRmResourceAction -ResourceGroupName $resourceGroupName -ResourceType $resourceType -ResourceName $resourceName -Action slotsswap -Parameters $parametersObject -ApiVersion 2015-07-01 -Force -Verbose
34 | Write-VstsTaskVerbose -Message "[Azure Call] Slot swapped: $resourceName with resource type: $resourceType to $DestinationSlot"
35 |
36 | $scheme = "http"
37 | $hostName = $result.Properties.HostNames[0]
38 | foreach ($hostNameSslState in $result.Properties.HostNameSslStates) {
39 | if ($hostName -eq $hostNameSslState.Name) {
40 | if (-not $hostNameSslState.SslState -eq 0) {
41 | $scheme = "https"
42 | }
43 |
44 | break
45 | }
46 | }
47 |
48 | $destinationUrlValue = "${scheme}://$hostName"
49 |
50 | Write-Host (Get-VstsLocString -Key "WebappslotsuccessfullyswappedatUrl0" -ArgumentList $destinationUrlValue)
51 |
52 | # Set ouput variable with $destinationUrl
53 | if (-not [string]::IsNullOrEmpty($DestinationUrl)) {
54 | if ([string]::IsNullOrEmpty($destinationUrl)) {
55 | Throw (Get-VstsLocString -Key "Unabletoretrievewebapppublishurlforwebapp0" -ArgumentList $webAppName)
56 | }
57 |
58 | Set-VstsTaskVariable -Name $DestinationUrl -Value $destinationUrlValue
59 | }
60 | }
61 | finally {
62 | Trace-VstsLeavingInvocation $MyInvocation
63 | }
64 |
--------------------------------------------------------------------------------
/Tasks/SwapSlots/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeklearningio/gl-vsts-tasks-azure/5da85062a3925111f3b87469220fe04ed3e3956c/Tasks/SwapSlots/icon.png
--------------------------------------------------------------------------------
/Tasks/SwapSlots/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "SwapSlots",
3 | "private": true,
4 | "version": "0.0.0",
5 | "dependencies": {
6 | "azure-pipelines-task-lib": "^2.9.6"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Tasks/SwapSlots/task.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "8698E535-D070-4A41-8C0E-4624D6283F05",
3 | "name": "SwapSlots",
4 | "friendlyName": "Azure Web App Slots Swap",
5 | "description": "Deprecated: use the official “Azure App Service Manage” task from Microsoft instead. You can then set the “Action” parameter to 'Swap Slots'.",
6 | "helpMarkDown": "",
7 | "category": "Deploy",
8 | "deprecated": true,
9 | "visibility": [
10 | "Build",
11 | "Release"
12 | ],
13 | "author": "Geek Learning",
14 | "version": {
15 | "Major": 0,
16 | "Minor": 0,
17 | "Patch": 0
18 | },
19 | "demands": [
20 | "azureps"
21 | ],
22 | "minimumAgentVersion": "1.103.0",
23 | "instanceNameFormat": "Swap Azure Web App slots: $(SourceSlot) to $(DestinationSlot)",
24 | "groups": [
25 | {
26 | "name": "output",
27 | "displayName": "Output",
28 | "isExpanded": false
29 | }
30 | ],
31 | "inputs": [
32 | {
33 | "name": "ConnectedServiceName",
34 | "type": "connectedService:AzureRM",
35 | "label": "Azure RM Subscription",
36 | "defaultValue": "",
37 | "required": true,
38 | "helpMarkDown": "Azure Resource Manager subscription to target for swapping Web App deployment slots"
39 | },
40 | {
41 | "name": "WebAppName",
42 | "type": "pickList",
43 | "label": "Web App Name",
44 | "defaultValue": "",
45 | "required": true,
46 | "properties": {
47 | "EditableOptions": "True"
48 | },
49 | "helpMarkDown": "Enter or Select the name of an existing AzureRM Web Application"
50 | },
51 | {
52 | "name": "SourceSlot",
53 | "type": "string",
54 | "label": "Source Slot",
55 | "defaultValue": "",
56 | "required": true,
57 | "helpMarkDown": ""
58 | },
59 | {
60 | "name": "DestinationSlot",
61 | "type": "string",
62 | "label": "Destination Slot",
63 | "defaultValue": "",
64 | "required": true,
65 | "helpMarkDown": ""
66 | },
67 | {
68 | "name": "DestinationUrl",
69 | "type": "string",
70 | "label": "Destination Slot Url",
71 | "required": false,
72 | "defaultValue": "",
73 | "groupName": "output",
74 | "helpMarkDown": "Provide a name for the variable for the destination slot url. The variable can be used as $(variableName) to refer to the hosted url of Web App in subsequent tasks like in the PowerShell on Target Machines task."
75 | }
76 | ],
77 | "dataSourceBindings": [
78 | {
79 | "target": "WebAppName",
80 | "endpointId": "$(ConnectedServiceName)",
81 | "dataSourceName": "AzureRMWebAppNames"
82 | }
83 | ],
84 | "execution": {
85 | "PowerShell3": {
86 | "target": "SwapSlots.ps1"
87 | }
88 | },
89 | "messages": {
90 | "WebappslotsuccessfullyswappedatUrl0": "Web App slot successfully swapped at Url : {0}",
91 | "Unabletoretrievewebapppublishurlforwebapp0": "Unable to retrieve Web App slot url for webapp : '{0}'."
92 | }
93 | }
--------------------------------------------------------------------------------
/Tasks/SwapSlots/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | asap@~2.0.3:
6 | version "2.0.6"
7 | resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
8 | integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
9 |
10 | azure-pipelines-task-lib@^2.9.6:
11 | version "2.9.6"
12 | resolved "https://registry.yarnpkg.com/azure-pipelines-task-lib/-/azure-pipelines-task-lib-2.9.6.tgz#acae923dc070ce0524b37786b7fb195d843d3022"
13 | integrity sha512-KTJuFdMl/r1Y8Snh5lHyV2YOyTu9bKzltMlRlnod8YKLc9GfENDkxwm+z9cHH6NlDln+2YI3G82Ri9XcbhyuZg==
14 | dependencies:
15 | minimatch "3.0.4"
16 | mockery "^1.7.0"
17 | q "^1.1.2"
18 | semver "^5.1.0"
19 | shelljs "^0.3.0"
20 | sync-request "3.0.1"
21 | uuid "^3.0.1"
22 |
23 | balanced-match@^1.0.0:
24 | version "1.0.0"
25 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
26 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
27 |
28 | brace-expansion@^1.1.7:
29 | version "1.1.11"
30 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
31 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
32 | dependencies:
33 | balanced-match "^1.0.0"
34 | concat-map "0.0.1"
35 |
36 | buffer-from@^1.0.0:
37 | version "1.1.1"
38 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
39 | integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
40 |
41 | caseless@~0.11.0:
42 | version "0.11.0"
43 | resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7"
44 | integrity sha1-cVuW6phBWTzDMGeSP17GDr2k99c=
45 |
46 | concat-map@0.0.1:
47 | version "0.0.1"
48 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
49 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
50 |
51 | concat-stream@^1.4.6, concat-stream@^1.4.7:
52 | version "1.6.2"
53 | resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
54 | integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
55 | dependencies:
56 | buffer-from "^1.0.0"
57 | inherits "^2.0.3"
58 | readable-stream "^2.2.2"
59 | typedarray "^0.0.6"
60 |
61 | core-util-is@~1.0.0:
62 | version "1.0.2"
63 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
64 | integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
65 |
66 | http-basic@^2.5.1:
67 | version "2.5.1"
68 | resolved "https://registry.yarnpkg.com/http-basic/-/http-basic-2.5.1.tgz#8ce447bdb5b6c577f8a63e3fa78056ec4bb4dbfb"
69 | integrity sha1-jORHvbW2xXf4pj4/p4BW7Eu02/s=
70 | dependencies:
71 | caseless "~0.11.0"
72 | concat-stream "^1.4.6"
73 | http-response-object "^1.0.0"
74 |
75 | http-response-object@^1.0.0, http-response-object@^1.0.1, http-response-object@^1.1.0:
76 | version "1.1.0"
77 | resolved "https://registry.yarnpkg.com/http-response-object/-/http-response-object-1.1.0.tgz#a7c4e75aae82f3bb4904e4f43f615673b4d518c3"
78 | integrity sha1-p8TnWq6C87tJBOT0P2FWc7TVGMM=
79 |
80 | inherits@^2.0.3, inherits@~2.0.3:
81 | version "2.0.4"
82 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
83 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
84 |
85 | isarray@~1.0.0:
86 | version "1.0.0"
87 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
88 | integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
89 |
90 | minimatch@3.0.4:
91 | version "3.0.4"
92 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
93 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
94 | dependencies:
95 | brace-expansion "^1.1.7"
96 |
97 | mockery@^1.7.0:
98 | version "1.7.0"
99 | resolved "https://registry.yarnpkg.com/mockery/-/mockery-1.7.0.tgz#f4ede0d8750c1c9727c272ea2c60629e2c9a1c4f"
100 | integrity sha1-9O3g2HUMHJcnwnLqLGBiniyaHE8=
101 |
102 | process-nextick-args@~2.0.0:
103 | version "2.0.1"
104 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
105 | integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
106 |
107 | promise@^7.1.1:
108 | version "7.3.1"
109 | resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf"
110 | integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==
111 | dependencies:
112 | asap "~2.0.3"
113 |
114 | q@^1.1.2:
115 | version "1.5.1"
116 | resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
117 | integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=
118 |
119 | qs@^6.1.0:
120 | version "6.9.4"
121 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.4.tgz#9090b290d1f91728d3c22e54843ca44aea5ab687"
122 | integrity sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==
123 |
124 | readable-stream@^2.2.2:
125 | version "2.3.7"
126 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
127 | integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
128 | dependencies:
129 | core-util-is "~1.0.0"
130 | inherits "~2.0.3"
131 | isarray "~1.0.0"
132 | process-nextick-args "~2.0.0"
133 | safe-buffer "~5.1.1"
134 | string_decoder "~1.1.1"
135 | util-deprecate "~1.0.1"
136 |
137 | safe-buffer@~5.1.0, safe-buffer@~5.1.1:
138 | version "5.1.2"
139 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
140 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
141 |
142 | semver@^5.1.0:
143 | version "5.7.1"
144 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
145 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
146 |
147 | shelljs@^0.3.0:
148 | version "0.3.0"
149 | resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.3.0.tgz#3596e6307a781544f591f37da618360f31db57b1"
150 | integrity sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=
151 |
152 | string_decoder@~1.1.1:
153 | version "1.1.1"
154 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
155 | integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
156 | dependencies:
157 | safe-buffer "~5.1.0"
158 |
159 | sync-request@3.0.1:
160 | version "3.0.1"
161 | resolved "https://registry.yarnpkg.com/sync-request/-/sync-request-3.0.1.tgz#caa1235aaf889ba501076a1834c436830a82fb73"
162 | integrity sha1-yqEjWq+Im6UBB2oYNMQ2gwqC+3M=
163 | dependencies:
164 | concat-stream "^1.4.7"
165 | http-response-object "^1.0.1"
166 | then-request "^2.0.1"
167 |
168 | then-request@^2.0.1:
169 | version "2.2.0"
170 | resolved "https://registry.yarnpkg.com/then-request/-/then-request-2.2.0.tgz#6678b32fa0ca218fe569981bbd8871b594060d81"
171 | integrity sha1-ZnizL6DKIY/laZgbvYhxtZQGDYE=
172 | dependencies:
173 | caseless "~0.11.0"
174 | concat-stream "^1.4.7"
175 | http-basic "^2.5.1"
176 | http-response-object "^1.1.0"
177 | promise "^7.1.1"
178 | qs "^6.1.0"
179 |
180 | typedarray@^0.0.6:
181 | version "0.0.6"
182 | resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
183 | integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
184 |
185 | util-deprecate@~1.0.1:
186 | version "1.0.2"
187 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
188 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
189 |
190 | uuid@^3.0.1:
191 | version "3.4.0"
192 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
193 | integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
194 |
--------------------------------------------------------------------------------
/Tests/Node/AzCopy/azCopy.spec.ts:
--------------------------------------------------------------------------------
1 | import fs = require('fs');
2 | import path = require('path');
3 | import azureEndpointConnection = require('../../../Tasks/AzCopy/azureEndpointConnection');
4 |
5 | var settings = JSON.parse(fs.readFileSync(path.join(__dirname, '../settings.json'), 'utf-8'));
6 |
7 | var computeDigest = new Buffer("pat:" + settings.vsts.pat).toString('base64');
8 | var auhtorizationHeader = "Basic " + computeDigest;
9 |
10 | describe("AzureEndpointConnection", () => {
11 |
12 | it(": should support basic add.", (done: any) => {
13 | try {
14 | azureEndpointConnection.getConnectedServiceCredentials(
15 | settings.azure.connectionName,
16 | settings.azure.servicePrincipalId,
17 | settings.azure.servicePrincipalkey,
18 | settings.azure.tenantId,
19 | settings.azure.subscriptionName,
20 | settings.azure.subscriptionId)
21 | .then((result) => {
22 | console.log(result);
23 | expect(result).toBeDefined();
24 | expect(result.creds).toBeTruthy();
25 | expect(result.id).toBeTruthy();
26 | expect(result.name).toBeTruthy();
27 | done();
28 | })
29 | .catch((err) => {
30 | expect(err).toBeNull();
31 | done();
32 | });
33 | }
34 | catch (err) {
35 | expect(err).toBeUndefined();
36 | }
37 | }, 60000);
38 | });
--------------------------------------------------------------------------------
/Tests/Node/chutzpah.json:
--------------------------------------------------------------------------------
1 | {
2 | "Framework": "jasmine",
3 | "Tests": [
4 | { "Includes": ["**/*.spec.js"], "Excludes": [] }
5 | ]
6 | }
--------------------------------------------------------------------------------
/Tests/Node/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": "tests",
3 | "spec_files": [
4 | "**/*[sS]pec.js"
5 | ]
6 | }
--------------------------------------------------------------------------------
/Tests/Node/settings.sample.json:
--------------------------------------------------------------------------------
1 | {
2 | "vsts" : {
3 | "url" : "https://accountname.visualstudio.com",
4 | "pat" : "somepat"
5 | },
6 | "azure": {
7 | "ConnectionName": "A Connection Name",
8 | "SubscriptionId": "aguid0000-0000-0000-0000-00000000000",
9 | "SubscriptionName": "A Subscription Name",
10 | "ServicePrincipalId": "aguid0000-0000-0000-0000-00000000000",
11 | "ServicePrincipalkey": "asecretkey",
12 | "TenantId": "aguid0000-0000-0000-0000-00000000000"
13 | }
14 | }
--------------------------------------------------------------------------------
/Tests/PowerShell3/GeekLearning.VstsTasks.Azure.Tests.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{F5034706-568F-408A-B7B3-4D38C6DB8A32}") = "GeekLearning.VstsTasks.Azure.Tests", "GeekLearning.VstsTasks.Azure.Tests\GeekLearning.VstsTasks.Azure.Tests.pssproj", "{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | EndGlobal
23 |
--------------------------------------------------------------------------------
/Tests/PowerShell3/GeekLearning.VstsTasks.Azure.Tests/GeekLearning.VstsTasks.Azure.Tests.pssproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | 2.0
6 | 6CAFC0C6-A428-4d30-A9F9-700E829FEA51
7 | Exe
8 | MyApplication
9 | MyApplication
10 | GeekLearning.VstsTasks.Azure.Tests
11 |
12 |
13 | true
14 | full
15 | false
16 | bin\Debug\
17 | DEBUG;TRACE
18 | prompt
19 | 4
20 |
21 |
22 | pdbonly
23 | true
24 | bin\Release\
25 | TRACE
26 | prompt
27 | 4
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/Tests/PowerShell3/GeekLearning.VstsTasks.Azure.Tests/Helpers.ps1:
--------------------------------------------------------------------------------
1 | function Get-TestsConfiguration() {
2 | param(
3 | [Parameter(Mandatory=$true)][string]$invocationCommandPath
4 | )
5 |
6 | function ExtendJSON($base, $ext) {
7 | $propNames = $($ext | Get-Member -MemberType *Property).Name
8 | foreach ($propName in $propNames) {
9 | if ($base.PSObject.Properties.Match($propName).Count) {
10 | if ($base.$propName.GetType().Name -eq "PSCustomObject") {
11 | $base.$propName = ExtendJSON $base.$propName $ext.$propName
12 | }
13 | else {
14 | $base.$propName = $ext.$propName
15 | }
16 | }
17 | else {
18 | $base | Add-Member -MemberType NoteProperty -Name $propName -Value $ext.$propName
19 | }
20 | }
21 |
22 | return $base
23 | }
24 |
25 | $here = Split-Path -Parent $invocationCommandPath
26 | $appSettings = Get-Content (Join-Path $here "appsettings.json") | ConvertFrom-Json
27 | $appDevelopmentSettingsPath = Join-Path $here "appsettings.development.json"
28 |
29 | if (Test-Path $appDevelopmentSettingsPath) {
30 | $appDevelopmentSettings = Get-Content $appDevelopmentSettingsPath | ConvertFrom-Json
31 | $settings = ExtendJSON $appSettings $appDevelopmentSettings
32 | }
33 | else {
34 | $settings = $appSettings
35 | }
36 |
37 | $tasksFolderPath = Resolve-Path "$here/$($settings.VstsTasksPath)"
38 | $scriptName = (Split-Path -Leaf $invocationCommandPath) -replace '\.Tests\.', '.'
39 | $scriptFolderName = [System.IO.Path]::GetFileNameWithoutExtension($scriptName)
40 | $scriptPath = Resolve-Path "$tasksFolderPath/$scriptFolderName/$scriptName"
41 | $taskLibPath = Resolve-Path "$tasksFolderPath/$scriptFolderName/$($settings.VstsTaskSdkPath)"
42 |
43 | return @{
44 | settings = $settings
45 | tasksFolderPath = $tasksFolderPath
46 | targetScriptName = $scriptFolderName
47 | targetScriptPath = $scriptPath
48 | taskLibPath = $taskLibPath
49 | }
50 | }
51 |
52 | function Add-AzureEndpoint() {
53 | param(
54 | [Parameter(Mandatory=$true)]$config,
55 | [Parameter(Mandatory=$false)][string]$inputName
56 | )
57 |
58 | if (!($inputName)) {
59 | $inputName = "ConnectedServiceName"
60 | }
61 |
62 | $endPointName = [System.Guid]::NewGuid().ToString()
63 |
64 | $auth = @{
65 | scheme = "ServicePrincipal"
66 | parameters = @{
67 | servicePrincipalId = $config.settings.AzureAccount.ServicePrincipalClientId
68 | servicePrincipalKey = $config.settings.AzureAccount.ServicePrincipalKey
69 | tenantId = $config.settings.AzureAccount.TenantId
70 | }
71 | } | ConvertTo-Json
72 |
73 | $data = @{
74 | subscriptionId = $config.settings.AzureAccount.SubscriptionId
75 | subscriptionName = $config.settings.AzureAccount.SubscriptionName
76 | azureSpnRoleAssignmentId = ""
77 | spnObjectId = ""
78 | appObjectId = ""
79 | creationMode = "Manual"
80 | } | ConvertTo-Json
81 |
82 | Add-VstsInput -name $inputName -value $endPointName
83 | Add-VstsEndPoint -name $endPointName -url "https://management.core.windows.net/" `
84 | -auth $auth -data $data
85 | }
86 |
87 | function Add-EnvironmentVariable() {
88 | param(
89 | [Parameter(Mandatory=$true)][string]$name,
90 | [Parameter(Mandatory=$false)][string]$value
91 | )
92 |
93 | $addEnvironmentVariable = "`${env:$name} = '$value'"
94 | Invoke-Expression -Command $addEnvironmentVariable
95 | }
96 |
97 | function Add-VstsInput() {
98 | param(
99 | [Parameter(Mandatory=$true)][string]$name,
100 | [Parameter(Mandatory=$false)][string]$value
101 | )
102 |
103 | Add-EnvironmentVariable -name "INPUT_$name" -value $value
104 | }
105 |
106 | function Add-VstsEndPoint() {
107 | param(
108 | [Parameter(Mandatory=$true)][string]$name,
109 | [Parameter(Mandatory=$true)][string]$url,
110 | [Parameter(Mandatory=$true)][string]$auth,
111 | [Parameter(Mandatory=$true)][string]$data
112 | )
113 |
114 | Add-EnvironmentVariable -name "ENDPOINT_URL_$name" -value $url
115 | Add-EnvironmentVariable -name "ENDPOINT_AUTH_$name" -value $auth
116 | Add-EnvironmentVariable -name "ENDPOINT_DATA_$name" -value $data
117 | }
--------------------------------------------------------------------------------
/Tests/PowerShell3/GeekLearning.VstsTasks.Azure.Tests/Run-Tests.ps1:
--------------------------------------------------------------------------------
1 | param(
2 | [string]$SourceDir = $env:BUILD_SOURCESDIRECTORY,
3 | [string]$TempDir = $env:TEMP
4 | )
5 |
6 | $ErrorActionPreference = "Stop"
7 |
8 | $modulePath = Join-Path $TempDir Pester-master\Pester.psm1
9 |
10 | if (-not(Test-Path $modulePath)) {
11 |
12 | # Note: PSGet and chocolatey are not supported in hosted vsts build agent
13 | $tempFile = Join-Path $TempDir pester.zip
14 | Invoke-WebRequest https://github.com/pester/Pester/archive/master.zip -OutFile $tempFile
15 |
16 | [System.Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem') | Out-Null
17 | [System.IO.Compression.ZipFile]::ExtractToDirectory($tempFile, $tempDir)
18 |
19 | Remove-Item $tempFile
20 | }
21 |
22 | Import-Module $modulePath -DisableNameChecking
23 |
24 | $outputFile = Join-Path $SourceDir "TEST-pester.xml"
25 |
26 | Invoke-Pester -Path $SourceDir -PassThru -OutputFile $outputFile -OutputFormat NUnitXml -EnableExit
--------------------------------------------------------------------------------
/Tests/PowerShell3/GeekLearning.VstsTasks.Azure.Tests/SampleDirectory/SqlMultiDacpacDeployment/1.0.0.0.dacpac:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeklearningio/gl-vsts-tasks-azure/5da85062a3925111f3b87469220fe04ed3e3956c/Tests/PowerShell3/GeekLearning.VstsTasks.Azure.Tests/SampleDirectory/SqlMultiDacpacDeployment/1.0.0.0.dacpac
--------------------------------------------------------------------------------
/Tests/PowerShell3/GeekLearning.VstsTasks.Azure.Tests/SampleDirectory/SqlMultiDacpacDeployment/1.0.0.1.dacpac:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeklearningio/gl-vsts-tasks-azure/5da85062a3925111f3b87469220fe04ed3e3956c/Tests/PowerShell3/GeekLearning.VstsTasks.Azure.Tests/SampleDirectory/SqlMultiDacpacDeployment/1.0.0.1.dacpac
--------------------------------------------------------------------------------
/Tests/PowerShell3/GeekLearning.VstsTasks.Azure.Tests/SampleDirectory/SqlMultiDacpacDeployment/GeekLearning.Tasks.Database.dacpac:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeklearningio/gl-vsts-tasks-azure/5da85062a3925111f3b87469220fe04ed3e3956c/Tests/PowerShell3/GeekLearning.VstsTasks.Azure.Tests/SampleDirectory/SqlMultiDacpacDeployment/GeekLearning.Tasks.Database.dacpac
--------------------------------------------------------------------------------
/Tests/PowerShell3/GeekLearning.VstsTasks.Azure.Tests/SqlMultiDacpacDeployment.Tests.ps1:
--------------------------------------------------------------------------------
1 | $here = Split-Path -Parent $MyInvocation.MyCommand.Path
2 | . "$here/Helpers.ps1"
3 |
4 | $config = Get-TestsConfiguration -invocationCommandPath $MyInvocation.MyCommand.Path
5 |
6 | Import-Module $config.taskLibPath -ArgumentList @{ NonInteractive = $true }
7 |
8 | Describe "SqlMultiDacpacDeployment" {
9 |
10 | Context "With correctly configured Azure Endpoint" {
11 |
12 | Add-AzureEndpoint -config $config
13 | Add-EnvironmentVariable -name "BUILD_SOURCESDIRECTORY" -value $here
14 |
15 | It "Runs" {
16 | Add-VstsInput -name "DacpacFiles" -value $config.settings.SqlMultiDacpacDeployment.DacpacFiles.Replace("`$(Build.SourcesDirectory)", $here)
17 | Add-VstsInput -name "AdditionalArguments" -value $config.settings.SqlMultiDacpacDeployment.AdditionalArguments
18 | Add-VstsInput -name "ServerName" -value $config.settings.SqlMultiDacpacDeployment.ServerName
19 | Add-VstsInput -name "DatabaseName" -value $config.settings.SqlMultiDacpacDeployment.DatabaseName
20 | Add-VstsInput -name "SqlUsername" -value $config.settings.SqlMultiDacpacDeployment.SqlUsername
21 | Add-VstsInput -name "SqlPassword" -value $config.settings.SqlMultiDacpacDeployment.SqlPassword
22 | Add-VstsInput -name "IpDetectionMethod" -value $config.settings.SqlMultiDacpacDeployment.IpDetectionMethod
23 | Add-VstsInput -name "DeleteFirewallRule" -value $config.settings.SqlMultiDacpacDeployment.DeleteFirewallRule.ToString()
24 |
25 | $outputVariable = Invoke-VstsTaskScript -ScriptBlock ([scriptblock]::Create(". $($config.targetScriptPath)")) -Verbose 2>&1 3>&1 4>&1 5>&1 6>&1 | Out-String
26 | $outputVariable | Out-File -FilePath "$here/dump.txt" -Force
27 | Write-VstsAddAttachment -Type "TestLog" -Name "SqlMultiDacpacDeployment-Runs" -Path "$here/dump.txt"
28 |
29 | $outputVariable | Should Not BeLike "*task.logissue type=error*"
30 | }
31 |
32 | It "Runs with only one DACPAC" {
33 | Add-VstsInput -name "DacpacFiles" -value $config.settings.SqlMultiDacpacDeployment.OneDacpacFile.Replace("`$(Build.SourcesDirectory)", $here)
34 | Add-VstsInput -name "AdditionalArguments" -value $config.settings.SqlMultiDacpacDeployment.AdditionalArguments
35 | Add-VstsInput -name "ServerName" -value $config.settings.SqlMultiDacpacDeployment.ServerName
36 | Add-VstsInput -name "DatabaseName" -value $config.settings.SqlMultiDacpacDeployment.DatabaseName
37 | Add-VstsInput -name "SqlUsername" -value $config.settings.SqlMultiDacpacDeployment.SqlUsername
38 | Add-VstsInput -name "SqlPassword" -value $config.settings.SqlMultiDacpacDeployment.SqlPassword
39 | Add-VstsInput -name "IpDetectionMethod" -value $config.settings.SqlMultiDacpacDeployment.IpDetectionMethod
40 | Add-VstsInput -name "DeleteFirewallRule" -value $config.settings.SqlMultiDacpacDeployment.DeleteFirewallRule.ToString()
41 |
42 | $outputVariable = Invoke-VstsTaskScript -ScriptBlock ([scriptblock]::Create(". $($config.targetScriptPath)")) -Verbose 2>&1 3>&1 4>&1 5>&1 6>&1 | Out-String
43 | $outputVariable | Out-File -FilePath "$here/dump.txt" -Force
44 | Write-VstsAddAttachment -Type "TestLog" -Name "SqlMultiDacpacDeployment-Runs" -Path "$here/dump.txt"
45 |
46 | $outputVariable | Should Not BeLike "*task.logissue type=error*"
47 | }
48 |
49 | It "Fails because no DACPAC is found" {
50 | Add-VstsInput -name "DacpacFiles" -value "whatever\\*.any"
51 | Add-VstsInput -name "AdditionalArguments" -value $config.settings.SqlMultiDacpacDeployment.AdditionalArguments
52 | Add-VstsInput -name "ServerName" -value $config.settings.SqlMultiDacpacDeployment.ServerName
53 | Add-VstsInput -name "DatabaseName" -value $config.settings.SqlMultiDacpacDeployment.DatabaseName
54 | Add-VstsInput -name "SqlUsername" -value $config.settings.SqlMultiDacpacDeployment.SqlUsername
55 | Add-VstsInput -name "SqlPassword" -value $config.settings.SqlMultiDacpacDeployment.SqlPassword
56 | Add-VstsInput -name "IpDetectionMethod" -value $config.settings.SqlMultiDacpacDeployment.IpDetectionMethod
57 | Add-VstsInput -name "DeleteFirewallRule" -value $config.settings.SqlMultiDacpacDeployment.DeleteFirewallRule.ToString()
58 |
59 | $outputVariable = Invoke-VstsTaskScript -ScriptBlock ([scriptblock]::Create(". $($config.targetScriptPath)")) -Verbose 2>&1 3>&1 4>&1 5>&1 6>&1 | Out-String
60 | $outputVariable | Out-File -FilePath "$here/dump.txt" -Force
61 | Write-VstsAddAttachment -Type "TestLog" -Name "SqlMultiDacpacDeployment-Fails because no DACPAC is found" -Path "$here/dump.txt"
62 |
63 | $outputVariable | Should BeLike "*task.logissue type=error*"
64 | }
65 | }
66 | }
--------------------------------------------------------------------------------
/Tests/PowerShell3/GeekLearning.VstsTasks.Azure.Tests/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "VstsTaskSdkPath": "node_modules/vsts-task-sdk/VstsTaskSdk",
3 | "VstsTasksPath": "../../../Tasks",
4 | "AzureAccount": {
5 | "ConnectionName": "",
6 | "SubscriptionId": "",
7 | "SubscriptionName": "",
8 | "ServicePrincipalClientId": "",
9 | "ServicePrincipalKey": "",
10 | "TenantId": ""
11 | },
12 | "SqlMultiDacpacDeployment": {
13 | "DacpacFiles": "$(Build.SourcesDirectory)\\SampleDirectory\\SqlMultiDacpacDeployment\\*.dacpac",
14 | "OneDacpacFile": "$(Build.SourcesDirectory)\\SampleDirectory\\SqlMultiDacpacDeployment\\GeekLearning.Tasks.Database.dacpac",
15 | "AdditionalArguments": "/p:DropObjectsNotInSource=True /p:DoNotDropObjectTypes=users /p:ExcludeObjectTypes=RoleMembership;users /p:BlockOnPossibleDataLoss=False",
16 | "ServerName": "",
17 | "DatabaseName": "",
18 | "SqlUsername": "",
19 | "SqlPassword": "",
20 | "IpDetectionMethod": "AutoDetect",
21 | "DeleteFirewallRule": true
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Tests/PowerShell3/global.json:
--------------------------------------------------------------------------------
1 | {
2 | "projects": [ "src", "tests" ],
3 | "sdk": {
4 | "version": "1.0.0-preview2-003121"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/configuration.json:
--------------------------------------------------------------------------------
1 | {
2 | "environments": [
3 | {
4 | "Name": "production",
5 | "VssExtensionIdSuffix": "",
6 | "VssExtensionGalleryFlags": [
7 | "Public"
8 | ],
9 | "DisplayNamesSuffix": "",
10 | "TaskIds": {
11 | "AzCopy" : "d66b2794-5008-46fc-ad96-77d90c2e5615",
12 | "RestoreSqlDatabaseToSqlDatabase": "56EFEADB-7DF6-4DAC-8163-AF8E07298C8B",
13 | "StartWebApp": "DF1611D6-6AEE-40B5-8AF6-143AF94D9F3E",
14 | "StopWebApp": "A3F35BB6-5341-413A-8091-10F93D390BB5",
15 | "SwapSlots": "8698E535-D070-4A41-8C0E-4624D6283F05",
16 | "ExecuteSql": "A93D571D-F32C-4FE7-A63A-3599DDDD5279",
17 | "SqlMultiDacpacDeployment": "fc7c81bb-92a2-4750-a0c9-d0d88c749ac0"
18 | }
19 | },
20 | {
21 | "Name": "preview",
22 | "VssExtensionIdSuffix": "-preview",
23 | "VssExtensionGalleryFlags": [],
24 | "DisplayNamesSuffix": " (Preview)",
25 | "TaskIds": {
26 | "AzCopy" : "0c29237d-1bbb-4172-9d54-8ee559104a82",
27 | "RestoreSqlDatabaseToSqlDatabase": "9FF8A021-58DA-4386-91DB-728B064D11FB",
28 | "StartWebApp": "3543A9E7-FF08-47C5-A8F4-D9FBB5D5F345",
29 | "StopWebApp": "4F59C1AE-AA86-4FAA-8E0C-D632C8CC07A7",
30 | "SwapSlots": "714D2CD7-B76B-4E1D-BE59-B66C4001A89E",
31 | "ExecuteSql": "CF2009AD-2816-4A2B-BBCF-2004C769555B",
32 | "SqlMultiDacpacDeployment": "9b319c14-18ab-4e76-84e9-443f6efd5722"
33 | }
34 | },
35 | {
36 | "Name": "dev",
37 | "VssExtensionIdSuffix": "-dev",
38 | "VssExtensionGalleryFlags": [],
39 | "DisplayNamesSuffix": " (Development)",
40 | "TaskIds": {
41 | "AzCopy" : "c76ec66c-c6ae-4687-a978-b02440bcc8e6",
42 | "RestoreSqlDatabaseToSqlDatabase": "AEE6A733-4997-40A0-AA39-D23EFC10BBBC",
43 | "StartWebApp": "14118FFB-528E-44CC-9F3C-E9078400AC6F",
44 | "StopWebApp": "8E2A112A-F09C-4C9D-A73B-41D94B2389E4",
45 | "SwapSlots": "D5DABE39-CC68-4B5A-B068-A248DF24A754",
46 | "ExecuteSql": "01450B61-71C8-4AE1-B38D-FB7444C5A87F",
47 | "SqlMultiDacpacDeployment": "14d05d66-7359-4996-b54b-0b870c86d22b"
48 | }
49 | }
50 | ]
51 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gl-vsts-tasks-azure",
3 | "version": "0.1.0",
4 | "description": "Visual Studio Team Services Build and Release Management extensions that help you to build and publish your applications on Microsoft Azure",
5 | "main": "gulpfile.js",
6 | "scripts": {
7 | "clean": "vsts-build-tools-clean",
8 | "postinstall": "vsts-build-tools-install",
9 | "prebuild": "vsts-build-tools-prebuild",
10 | "build": "tsc",
11 | "package": "vsts-build-tools-package",
12 | "build:test": "run-s build test",
13 | "test": "jasmine JASMINE_CONFIG_PATH=./Tests/Node/jasmine.json",
14 | "test:chutzpah": "chutzpah.console ./Tests",
15 | "fix:prettier": "prettier Tasks/**/*.ts --write"
16 | },
17 | "repository": {
18 | "type": "git",
19 | "url": "https://github.com/geeklearningio/gl-vsts-tasks-azure"
20 | },
21 | "keywords": [
22 | "VSTS",
23 | "build",
24 | "tasks",
25 | "Azure"
26 | ],
27 | "author": "Geek Learning, Adrien Siffermann, Cyprien Autexier",
28 | "license": "MIT",
29 | "bugs": {
30 | "url": "https://github.com/geeklearningio/gl-vsts-tasks-azure/issues"
31 | },
32 | "homepage": "https://github.com/geeklearningio/gl-vsts-tasks-azure/wiki",
33 | "devDependencies": {
34 | "@types/fs-extra": "^5.0.5",
35 | "@types/ini": "^1.3.30",
36 | "@types/jasmine": "2.8.4",
37 | "@types/node": "^6.14.3",
38 | "@types/q": "^1.5.1",
39 | "@types/xregexp": "^3.0.29",
40 | "@typescript-eslint/eslint-plugin": "^1.9.0",
41 | "@typescript-eslint/parser": "^1.9.0",
42 | "async": "^3.2.0",
43 | "fs-extra": "9.0.1",
44 | "gl-vsts-tasks-build-scripts": "^0.6.0-alpha.0",
45 | "jasmine": "3.5.0",
46 | "lodash": "^4.17.15",
47 | "npm-run-all": "4.1.5",
48 | "eslint": "^5.16.0",
49 | "typescript": "^3.9.5",
50 | "prettier": "2.0.5"
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "moduleResolution": "node",
5 | "noImplicitAny": true,
6 | "removeComments": true,
7 | "preserveConstEnums": true,
8 | "target": "es6",
9 | "sourceMap": false,
10 | "inlineSourceMap": true,
11 | "declaration": true
12 | },
13 | "filesGlob": [
14 | "./Tasks/*.ts",
15 | "./Tests/*.ts",
16 | "./typings/index.d.ts",
17 | "./Commom/Node/*.d.ts"
18 | ],
19 | "exclude": [
20 | "node_modules",
21 | "Tasks/AzCopy/node_modules",
22 | "Common",
23 | "BuildScripts/node_modules",
24 | ".BuildOutput"
25 | ]
26 | }
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "tslint:recommended"
3 | }
--------------------------------------------------------------------------------
/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gl-vsts-tasks-azure",
3 | "dependencies": {},
4 | "globalDependencies": {
5 | "fs-extra": "registry:dt/fs-extra#0.0.0+20160907105211",
6 | "jasmine": "registry:dt/jasmine#2.2.0+20160621224255",
7 | "minimatch": "registry:dt/minimatch#2.0.8+20160317120654",
8 | "node": "registry:dt/node#6.0.0+20160907103612",
9 | "q": "registry:dt/q#0.0.0+20160613154756",
10 | "xregexp": "registry:dt/xregexp#3.0.0+20160317120654"
11 | }
12 | }
--------------------------------------------------------------------------------