[Azure DevOps] 使用 Inno Setup 製作桌面軟件安裝包

1. 桌面應用程序的 CI/CD

桌面應用程序的 CI/CD 過程和網站有一些不同,畢竟桌面應用程序的“部署”只是將安裝包分發到目標位置,連應用商店都不用上,根據公司的管理流程可以很複雜,也可以很簡單。在簡單的情況下,Azure Pipelines 中一個桌面應用(WPF)的 CI/CD 過程如下:

  1. 觸發器啓動 Pipeline
  2. 構建 WPF 應用程序
  3. 啓動單元測試以確保構建質量
  4. 創建安裝包
  5. 將安裝包複製到目標位置
  6. 通知用戶新安裝包已經可以獲取

使用 Azure Pipelines 實現 CI 這篇文章中,我講解了如何實現第 1、2、3、5 步。至於第 6 步,可以在 Project SettingsNotifications 頁面中設置使用郵件通知團隊成員,也可以參考 使用連接器接收Azure DevOps的通知 這篇文章通過 Teams 發送構建的結果。

現在我們還缺少第 4 步“創建安裝包”,這篇文章將講解如何在 Azure Pipelines 中使用 Inno Setup 創建安裝包。

2. 使用 Inno Setup 創建安裝包

假設我們已經根據 使用 Azure Pipelines 實現 CI 的做法發佈了一個 WPF 應用程序,發佈到 Artifacts 的文件將會如上圖所示,可以以 Zip 的方式將所有輸出文件下載到本地,基本相當於綠色版軟件。但我們不能將這個 Zip 包直接發給客戶,我們至少還要包括開始菜單和修改註冊表什麼的一大堆東西,所以需要將 Release 的文件打包到一個安裝包中。我的公司通常使用 Inno Setup 製作安裝包,在 Azure Pipelines 中使用 Inno Setup 也十分簡單,於是這篇文章將使用 Inno Setup 作爲製作安裝包的例子。

首先我們需要一個 iss 腳本。在 install 目錄下創建一個簡單的名爲 SetupScript.iss 的腳本文件,大部分保留了默認值(懶得修改公司名之類的了),它只是將 Release 目錄的內容全部打包起來,內容如下:

; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!

#define MyAppName "My Program"
#define MyAppPublisher "My Company, Inc."
#define MyAppURL "https://www.example.com/"
#define MyAppExeName "wpf.exe"
#define VersionSourceAssemblyName     MyAppExeName
#define BuildOutputFolder  "..\wpf\bin\Release\"
#define MyAppFileVersion              GetFileVersion(AddBackslash(BuildOutputFolder) + VersionSourceAssemblyName)
#define MyAppCustomerVersion          GetStringFileInfo(AddBackslash(BuildOutputFolder) + VersionSourceAssemblyName, "ProductVersion")
[Setup]
; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{0B50DAF7-728E-48C7-984F-5E6FDB924490}
AppName={#MyAppName}
AppVersion={#MyAppCustomerVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={autopf}\{#MyAppName}
DisableProgramGroupPage=yes
; Uncomment the following line to run in non administrative install mode (install for current user only.)
;PrivilegesRequired=lowest
OutputBaseFilename=mysetup {#MyAppCustomerVersion}
Compression=lzma
SolidCompression=yes
WizardStyle=modern

VersionInfoCompany={#MyAppPublisher}
VersionInfoVersion={#MyAppFileVersion}
VersionInfoProductName={#MyAppName}
VersionInfoProductTextVersion={#MyAppCustomerVersion}

[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"

[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked

[Files]
Source: "{#BuildOutputFolder}{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#BuildOutputFolder}*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs; 
; NOTE: Don't use "Flags: ignoreversion" on any shared system files

[Icons]
Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon

[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent

用 Inno Setup 運行一下這個腳本文件確保它正確運行(如果成功的話會在 Installer\Output 目錄下生成一個安裝程序)。

3. 在 Azure Pipelines 上運行 Inno Setup

SetupScript.iss 推送到 Azure Repos 上,然後修改對應的 Pipeline。Pipeline 中需要添加兩個任務:

  • 一個負責使用 Chocolatey 下載並安裝 Inno Setup 的任務
  • 一個調用 Inno Setup 運行 SetupScript.iss 的任務

然後修改 CopyFiles 任務,將 Installer\output 目錄中的安裝包複製到 $(build.artifactstagingdirectory)。修改後的 YAML 文件如下(其中兩個 PowerShell 任務即爲新增的兩個任務):

trigger:
- master
pool:
   vmImage: 'windows-latest'
variables:
  solution: '**/*.sln'
  buildPlatform: 'Any CPU'
  buildConfiguration: 'Release'
steps:
- task: NuGetToolInstaller@1

- task: PowerShell@2
  displayName: 'Inno setup download'
  inputs:
    targetType: 'inline'
    script: 'choco install innosetup'
- task: NuGetCommand@2
  inputs:
    restoreSolution: '$(solution)'
- task: VSBuild@1
  inputs:
    solution: '$(solution)'
    platform: '$(buildPlatform)'
    configuration: '$(buildConfiguration)'
- task: PowerShell@2
  displayName: 'Execute Inno Setup script'
  inputs:
    targetType: 'inline'
    script: 'iscc.exe Installer\\SetupScript.iss'
    
- task: CopyFiles@2
  inputs:
    SourceFolder: 'Installer\\output'
    Contents: '*.exe'
    TargetFolder: '$(build.artifactstagingdirectory)'
- task: PublishBuildArtifacts@1
  inputs:
    PathtoPublish: '$(Build.ArtifactStagingDirectory)'
    ArtifactName: 'drop'
    publishLocation: 'Container'

4. 最後

現在,一個桌面應用程序的 CI/CD 已經基本完成了。當然實際應用中 iss 腳本和 PowerShell 都可以更復雜以便完成更多任務,例如程序簽名、檢查並安裝 .Net Framework 等,這些操作都超出了這篇文章的範疇,如有需要可以參考下面這些鏈接:

Azure Pipelines 文檔

Inno Setup - a free installer for Windows programs

Chocolatey Software - The package manager for Windows

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章