Skip to content

Commit

Permalink
Integrate MSI installer generation in azure pipelines (#131)
Browse files Browse the repository at this point in the history
* ci: add new tlk.ps1 build script

* devolutions-gateway: load dotenv file in tlk.ps1

* ci/tlk: start integrating packaging script in parent script

* devolutions-gateway: refactor tlk.ps1 script

* devolutions-gateway: start modifying azure pipeline

* devolutions-gateway: update azure-pipelines.yaml

* devolutions-gateway: update azure-pipelines.yaml

* devolutions-gateway: start defining pipeline variables

* devolutions-gateway: add more variables to control packaging

* devolutions-gateway: fix msi installer version name

Co-authored-by: Marc-André Moreau <mamoreau@devolutions.net>
  • Loading branch information
awakecoding and Marc-André Moreau authored Dec 15, 2020
1 parent a268a4b commit 4a2c58b
Show file tree
Hide file tree
Showing 5 changed files with 311 additions and 72 deletions.
1 change: 1 addition & 0 deletions VERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2020.3.1
37 changes: 29 additions & 8 deletions ci/azure-pipelines.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -261,12 +261,16 @@ stages:
- job: Windows_64_bit
pool:
name: 'Devolutions - Windows containers'

workspace:
clean: all

container: devolutions/waykbuilder:vstools2k19

variables:
TargetPlatform: "windows"
TargetArchitecture: "x86_64"

steps:
- checkout: self
clean: true
Expand All @@ -291,25 +295,42 @@ stages:
$secureString = convertto-securestring "$(WINDOWS_SIGNING_PASSPHRASE)" -asplaintext -force
Import-PfxCertificate -FilePath CodeSigningCertificateUnsecure.pfx -CertStoreLocation Cert:\LocalMachine\My -Password $secureString
Import-PfxCertificate -FilePath CodeSigningCertificateUnsecure.pfx -CertStoreLocation Cert:\CurrentUser\My -Password $secureString
Write-Host "##vso[task.setvariable variable=SignToolName]Devolutions"
displayName: Import signing certificate
- powershell: |
$version = Get-Content $(Agent.BuildDirectory)\version\VERSION
conan install openssl/$(OPENSSL_VERSION)@devolutions/stable -g virtualenv -pr windows-x86_64
$CargoVersion = Get-Content $(Agent.BuildDirectory)\version\VERSION
$TargetOutputPath = "$(Build.StagingDirectory)/$(TargetPlatform)/$(TargetArchitecture)"
Write-Host "##vso[task.setvariable variable=CargoVersion]$CargoVersion"
Write-Host "##vso[task.setvariable variable=TargetOutputPath]$TargetOutputPath"
conan install openssl/$(OPENSSL_VERSION)@devolutions/stable -g virtualenv -pr $(TargetPlatform)-$(TargetArchitecture)
.\activate.ps1
cargo build --release
mkdir $(Build.ArtifactStagingDirectory)/windows/x86_64
cp $(Build.Repository.LocalPath)/target/release/devolutions-gateway.exe $(Build.ArtifactStagingDirectory)/windows/x86_64/DevolutionsGateway_windows_"$version"_x86_64.exe
mkdir $TargetOutputPath
$DGatewayExecutable = "$TargetOutputPath/DevolutionsGateway_$(TargetPlatform)_${CargoVersion}_$(TargetArchitecture).exe"
cp $(Build.Repository.LocalPath)/target/release/devolutions-gateway.exe $DGatewayExecutable
Write-Host "##vso[task.setvariable variable=DGATEWAY_EXECUTABLE]$DGatewayExecutable"
displayName: Building devolutions-gateway
env:
RUSTFLAGS: '-C target-feature=+crt-static'
- powershell: |
$version = Get-Content $(Agent.BuildDirectory)\version\VERSION
signtool sign /fd SHA256 /v /t http://timestamp.verisign.com/scripts/timstamp.dll $(Build.ArtifactStagingDirectory)/windows/x86_64/DevolutionsGateway_windows_"$version"_x86_64.exe
signtool sign /fd SHA256 /v /t http://timestamp.verisign.com/scripts/timstamp.dll $(DGATEWAY_EXECUTABLE)
displayName: Signing binary
- task: PowerShell@2
inputs:
targetType: 'filePath'
filePath: $(System.DefaultWorkingDirectory)\ci\tlk.ps1
arguments: package -Platform $(TargetPlatform) -Architecture $(TargetArchitecture)
env:
TARGET_OUTPUT_PATH: "$(TargetOutputPath)"
DGATEWAY_EXECUTABLE: "$(DGATEWAY_EXECUTABLE)"
DGATEWAY_PACKAGE_FILENAME: "DevolutionsGateway-$(TargetArchitecture)-$(CargoVersion).msi"
SIGNTOOL_NAME: "$(SignToolName)"
displayName: Creating MSI package

- task: PublishBuildArtifacts@1
inputs:
pathToPublish: $(Build.ArtifactStagingDirectory)
pathToPublish: $(Build.StagingDirectory)
artifactName: devolutions-gateway
280 changes: 280 additions & 0 deletions ci/tlk.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,280 @@

# global initialization

if (-Not (Test-Path 'variable:global:IsWindows')) {
$global:IsWindows = $true; # Windows PowerShell 5.1 or earlier
}

if ($IsWindows) {
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12;
}

function Get-DotEnvFile {
param(
[Parameter(Position=0,Mandatory=$true)]
[string] $InputFile
)

$DotEnv = @{}
$InputValue = Get-Content -Path $InputFile -Encoding UTF8 -ErrorAction Stop
$($InputValue | Select-String -AllMatches -Pattern "^(.+)=`"(.+)`"$").Matches | ForEach-Object {
$DotEnv.Add($_.Groups[1].Value, $_.Groups[2].Value)
}
return $DotEnv
}

function Get-TlkPlatform {
param(
[Parameter(Position=0)]
[string] $Platform
)

if (-Not $Platform) {
$Platform = if ($IsWindows) {
'windows'
} elseif ($IsMacOS) {
'macos'
} elseif ($IsLinux) {
'linux'
}
}

$Platform
}

function Get-TlkArchitecture {
param(
[Parameter(Position=0)]
[string] $Architecture
)

if (-Not $Architecture) {
$Architecture = 'x86_64'
}

$Architecture
}

class TlkTarget
{
[string] $Platform
[string] $Architecture

[string] $ExecutableExtension

TlkTarget() {
$this.Init()
}

[void] Init() {
$this.Platform = Get-TlkPlatform
$this.Architecture = Get-TlkArchitecture

if ($this.IsWindows()) {
$this.ExecutableExtension = 'exe'
} else {
$this.ExecutableExtension = ''
}
}

[bool] IsWindows() {
return $this.Platform -eq 'Windows'
}

[bool] IsMacOS() {
return $this.Platform -eq 'macOS'
}

[bool] IsLinux() {
return $this.Platform -eq 'Linux'
}
}

class TlkRecipe
{
[string] $PackageName
[string] $Version
[string] $SourcePath
[bool] $Verbose

[TlkTarget] $Target

TlkRecipe() {
$this.Init()
}

[void] Init() {
$this.SourcePath = $($PSScriptRoot | Get-Item).Parent.FullName
$this.PackageName = "DevolutionsGateway"
$this.Version = $(Get-Content -Path "$($this.SourcePath)/VERSION").Trim()
$this.Verbose = $true

$this.Target = [TlkTarget]::new()
}

[void] Build() {
$OPENSSL_VERSION = '1.1.1b-5'
$ConanPackage = "openssl/${OPENSSL_VERSION}@devolutions/stable"
$ConanProfile = "$($this.Target.Platform)-$($this.Target.Architecture)"

$BuildStagingDirectory = Join-Path $this.SourcePath "artifacts" # Build.StagingDirectory

& 'conan' 'install' $ConanPackage '-g' 'virtualenv' '-pr' $ConanProfile
$dotenv = Get-DotEnvFile ".\environment.sh.env"

Get-ChildItem 'conanbuildinfo.*' | Remove-Item
Get-ChildItem 'environment.*.env' | Remove-Item
Get-ChildItem '*activate.*' | Remove-Item

$OPENSSL_DIR = $dotenv['OPENSSL_DIR']
$Env:OPENSSL_DIR = $OPENSSL_DIR

if ($this.Target.IsWindows()) {
$Env:RUSTFLAGS = "-C target-feature=+crt-static"
}

$OutputPath = "${BuildStagingDirectory}/$($this.Target.Platform)/$($this.Target.Architecture)"
New-Item -Path $OutputPath -ItemType 'Directory' -Force | Out-Null

Push-Location
Set-Location $this.SourcePath
& 'cargo' 'build' '--release'
$DstExecutableName = $SrcExecutableName = 'devolutions-gateway', $this.Target.ExecutableExtension -ne '' -Join '.'
if ($this.Target.IsWindows()) {
$DstExecutableName = "DevolutionsGateway.exe"
}
Copy-Item "$($this.SourcePath)/target/release/${SrcExecutableName}" `
-Destination "${OutputPath}/${DstExecutableName}" -Force
Pop-Location
}

[void] Package() {
$ShortVersion = $this.Version.Substring(2) # msi version
$CargoVersion = "0.14.0" # Cargo.toml version
$TargetArch = if ($this.Target.Architecture -eq 'x86_64') { 'x64' } else { 'x86' }

$ModuleName = "DevolutionsGateway"
$ModuleVersion = $this.Version # both versions should match

Push-Location
Set-Location "$($this.SourcePath)/package/$($this.Target.Platform)"

if (Test-Path Env:DGATEWAY_EXECUTABLE) {
$DGatewayExecutable = $Env:DGATEWAY_EXECUTABLE
} else {
$WebClient = [System.Net.WebClient]::new()
$DownloadUrl = "https://github.com/Devolutions/devolutions-gateway/releases/download/" + `
"v${CargoVersion}/DevolutionsGateway_windows_${CargoVersion}_x86_64.exe"

$OutputFile = "$(Get-Location)/bin/DevolutionsGateway.exe"
New-Item -Path "bin" -ItemType 'Directory' -ErrorAction 'SilentlyContinue' | Out-Null
Remove-Item $OutputFile -ErrorAction 'SilentlyContinue'
$WebClient.DownloadFile($DownloadUrl, $OutputFile)
$DGatewayExecutable = $OutputFile
}

Save-Module -Name $ModuleName -Force -RequiredVersion $ModuleVersion -Repository 'PSGallery' -Path '.'
Remove-Item -Path "${ModuleName}/${ModuleVersion}/PSGetModuleInfo.xml" -ErrorAction 'SilentlyContinue'

$WixExtensions = @('WixUtilExtension', 'WixUIExtension', 'WixFirewallExtension')
$WixExtensions += $(Join-Path $(Get-Location) 'WixUserPrivilegesExtension.dll')

$WixArgs = @($WixExtensions | ForEach-Object { @('-ext', $_) }) + @(
"-dDGatewayPSSourceDir=${ModuleName}/${ModuleVersion}",
"-dDGatewayExecutable=$DGatewayExecutable",
"-dVersion=$ShortVersion", "-v")

$WixFiles = @('DevolutionsGateway', "DevolutionsGateway-$TargetArch")

$HeatArgs = @('dir', "${ModuleName}/${ModuleVersion}",
"-dr", "DGATEWAYPSROOTDIRECTORY",
"-cg", "DGatewayPSComponentGroup",
'-var', 'var.DGatewayPSSourceDir',
'-nologo', '-srd', '-suid', '-scom', '-sreg', '-sfrag', '-gg')

& 'heat.exe' $HeatArgs + @('-t', 'HeatTransform64.xslt', '-o', "$($this.PackageName)-$TargetArch.wxs")

$InputFiles = $WixFiles | ForEach-Object { "$_.wxs" }
$ObjectFiles = $WixFiles | ForEach-Object { "$_.wixobj" }

$Cultures = @('en-US', 'fr-FR')

foreach ($Culture in $Cultures) {
& 'candle.exe' "-nologo" $InputFiles $WixArgs "-dPlatform=$TargetArch" `
"-dWixUILicenseRtf=$($this.PackageName)_EULA_${Culture}.rtf"

$OutputFile = "$($this.PackageName)_${Culture}.msi"

if ($Culture -eq 'en-US') {
$OutputFile = "$($this.PackageName).msi"
}

& 'light.exe' "-v" "-nologo" $ObjectFiles "-cultures:${Culture}" "-loc" "$($this.PackageName)_${Culture}.wxl" `
"-out" $OutputFile $WixArgs "-dPlatform=$TargetArch" "-sice:ICE61"
}

foreach ($Culture in $($Cultures | Select-Object -Skip 1)) {
& 'torch.exe' "-v" "$($this.PackageName).msi" "$($this.PackageName)_${Culture}.msi" "-o" "${Culture}_$TargetArch.mst"
& 'cscript.exe' "/nologo" "WiSubStg.vbs" "$($this.PackageName).msi" "${Culture}_$TargetArch.mst" "1036"
& 'cscript.exe' "/nologo" "WiLangId.vbs" "$($this.PackageName).msi" "Package" "1033,1036"
}

if (Test-Path Env:TARGET_OUTPUT_PATH) {
$TargetOutputPath = $Env:TARGET_OUTPUT_PATH
$PackageFileName = "$($this.PackageName).msi"
if (Test-Path Env:DGATEWAY_PACKAGE_FILENAME) {
$PackageFileName = $Env:DGATEWAY_PACKAGE_FILENAME
}
$TargetPackageFile = $(Join-Path $TargetOutputPath $PackageFileName)
Copy-Item -Path "$($this.PackageName).msi" -Destination $TargetPackageFile

if (Test-Path Env:SIGNTOOL_NAME) {
$SignToolName = $Env:SIGNTOOL_NAME
$TimestampServer = 'http://timestamp.verisign.com/scripts/timstamp.dll'
$SignToolArgs = @(
'sign', '/fd', 'SHA256', '/v',
'/n', $SignToolName,
'/t', $TimestampServer,
$TargetPackageFile
)
& 'signtool' $SignToolArgs
}
}

Pop-Location
}
}

function Invoke-TlkStep {
param(
[Parameter(Position=0,Mandatory=$true)]
[ValidateSet('build','package')]
[string] $TlkVerb,
[ValidateSet('windows','macos','linux')]
[string] $Platform,
[ValidateSet('x86','x86_64','arm64')]
[string] $Architecture
)

if (-Not $Platform) {
$Platform = Get-TlkPlatform
}

if (-Not $Architecture) {
$Architecture = Get-TlkArchitecture
}

$RootPath = Split-Path -Parent $PSScriptRoot

$tlk = [TlkRecipe]::new()
$tlk.SourcePath = $RootPath
$tlk.Target.Platform = $Platform
$tlk.Target.Architecture = $Architecture

switch ($TlkVerb) {
"build" { $tlk.Build() }
"package" {$tlk.Package() }
}
}

Invoke-TlkStep @args
2 changes: 1 addition & 1 deletion package/Windows/DevolutionsGateway.wxs
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@
</DirectoryRef>

<Component Id="cmpDGatewayService" Guid="31eaa967-64e3-469c-b0c9-c9ecea61b7d3" Win64="$(var.Win64)" Directory="INSTALLDIR">
<File Name="DevolutionsGateway.exe" Source="./bin/$(var.ProcessorArchitecture)/DevolutionsGateway.exe" Id="DevolutionsGateway.exe" ProcessorArchitecture="$(var.ProcessorArchitecture)" KeyPath="yes" Vital="yes" DiskId="1">
<File Name="DevolutionsGateway.exe" Source="$(var.DGatewayExecutable)" Id="DevolutionsGateway.exe" ProcessorArchitecture="$(var.ProcessorArchitecture)" KeyPath="yes" Vital="yes" DiskId="1">
<fw:FirewallException Id="DGatewayServiceFirewallExceptionTcp" Name="Wayk Now Service TCP" Description="Wayk Now Service TCP" Protocol="tcp" Profile="all" Scope="any" IgnoreFailure="yes"/>
<fw:FirewallException Id="DGatewayServiceFirewallExceptionUdp" Name="Wayk Now Service UDP" Description="Wayk Now Service UDP" Protocol="udp" Profile="all" Scope="any" IgnoreFailure="yes"/>
</File>
Expand Down
Loading

0 comments on commit 4a2c58b

Please sign in to comment.