Skip to content

Build and Package MSI & Portable Installer #397

Build and Package MSI & Portable Installer

Build and Package MSI & Portable Installer #397

name: Build and Package MSI & Portable Installer
on:
workflow_dispatch:
inputs:
uploadAsLatest:
type: string
default: "False"
required: false
description: 'Also upload the msi installer to storage account as latest'
version:
type: string
default: ""
required: false
description: 'Version of promptflow to install (optional). Will build locally if not specified.'
set_msi_private_version:
type: string
default: ""
required: false
description: 'Set the version of the private msi installer'
permissions:
id-token: write
contents: read
env:
packageSetupType: promptflow_with_extra
testWorkingDirectory: src/promptflow
jobs:
build_msi_installer:
runs-on: windows-latest
name: Build Windows MSI
environment:
internal
steps:
- name: Check input parameters
run: |
echo "uploadAsLatest: ${{ inputs.uploadAsLatest }}"
echo "version: ${{ inputs.version }}"
echo "set_msi_private_version: ${{ inputs.set_msi_private_version }}"
- name: Checkout Repo
uses: actions/checkout@v3
with:
submodules: true
- name: Add msbuild to PATH
uses: microsoft/[email protected]
- name: Install WIX Toolset
shell: pwsh
working-directory: ${{ github.workspace }}/scripts/installer/windows
run: |
Invoke-WebRequest -Uri 'https://azurecliprod.blob.core.windows.net/msi/wix310-binaries-mirror.zip' -OutFile 'wix-archive.zip'
Expand-Archive -Path 'wix-archive.zip' -DestinationPath 'wix'
Remove-Item -Path 'wix-archive.zip'
- name: Python Setup
uses: "./.github/actions/step_create_python_environment"
- name: Install stable promptflow
if: ${{ github.event.inputs.version != null && github.event.inputs.version != '' }}
run: |
pip install "promptflow[azure,executable,azureml-serving,executor-service]==$env:INPUT_VERSION" promptflow-tools
echo "There's no promptflow-evals in pypi, we need to install it from source for now"
pip install ${{ github.workspace }}/src/promptflow-evals
env:
INPUT_VERSION: ${{ github.event.inputs.version }}
shell: pwsh
- name: Get promptflow version
id: get-version
# Convert string to int since the version tuple used in "version_info" can't start with 0.
run: |
if ($env:INPUT_VERSION) {
$version=$env:INPUT_VERSION
$run_version=$(python -c "import promptflow; print(promptflow.__version__)")
if ($version -ne $run_version) {
throw "Version input does not match the version in promptflow package. Version input: $version, version in promptflow package: $run_version"
}
}
elseif ($env:MSI_PRIVATE_VERSION) {
$version=$env:MSI_PRIVATE_VERSION
}
else {
$prefix = 0
$year = [int](Get-Date -Format "yy")
$monthday = [int](Get-Date -Format "MMdd")
$hourminutesecond = [int](Get-Date -Format "HHmmss")
$version="$prefix.$year.$monthday.$hourminutesecond"
}
echo "::set-output name=version::$version"
env:
INPUT_VERSION: ${{ github.event.inputs.version }}
MSI_PRIVATE_VERSION: ${{ github.event.inputs.set_msi_private_version }}
shell: pwsh
- name: Update promptflow package version when set msi private version
if: ${{ github.event.inputs.set_msi_private_version != null && github.event.inputs.set_msi_private_version != '' }}
run: |
$override_version = 'VERSION = "{0}"' -f $env:MSI_PRIVATE_VERSION
Write-Host "'$override_version' as version"
$override_version | Out-File -FilePath "./src/promptflow/promptflow/_version.py" -Encoding ASCII
shell: pwsh
env:
MSI_PRIVATE_VERSION: ${{ github.event.inputs.set_msi_private_version }}
- name: Setup and Install dev promptflow
if: ${{ github.event.inputs.version == null || github.event.inputs.version == '' }}
uses: "./.github/actions/step_sdk_setup"
with:
setupType: promptflow_with_extra
scriptPath: ${{ env.testWorkingDirectory }}
- name: Setup and Install separate dev promptflow
if: ${{ github.event.inputs.version == null || github.event.inputs.version == '' }}
shell: pwsh
run: |
Set-PSDebug -Trace 1
pip install -r ${{ github.workspace }}/src/promptflow/dev_requirements.txt
pip install ${{ github.workspace }}/src/promptflow-tracing
pip install ${{ github.workspace }}/src/promptflow-core[executor-service,azureml-serving]
pip install ${{ github.workspace }}/src/promptflow-devkit[pyarrow,executable]
pip install ${{ github.workspace }}/src/promptflow-azure
pip install ${{ github.workspace }}/src/promptflow-evals
echo "Should fix this after pf-core could install this dependency"
pip install azureml-ai-monitoring
pip freeze
- name: Generate promptflow spec file to config pyinstaller
working-directory: ${{ github.workspace }}/scripts/installer/windows/scripts
run: |
python generate_dependency.py
Get-Content promptflow.spec
- name: Build Pyinstaller project
working-directory: ${{ github.workspace }}/scripts/installer/windows/scripts
run: |
echo 'Version from promptflow: ${{ steps.get-version.outputs.version }}'
$text = Get-Content "version_info.txt" -Raw
$versionString = '${{ steps.get-version.outputs.version }}'
$versionArray = $versionString.Split('.')
if ($versionArray.Count -ge 4) {
$versionArray = $versionArray[0..3]
} else {
$remainingLength = 4 - $versionArray.Count
$zerosToAppend = @(0) * $remainingLength
$versionArray += $zerosToAppend
}
$versionTuple = [string]::Join(', ', $versionArray)
$text = $text -replace '\$\((env\.FILE_VERSION)\)', $versionTuple
$text = $text -replace '\$\((env\.CLI_VERSION)\)', '${{ steps.get-version.outputs.version }}'
$text | Out-File -FilePath "version_info.txt" -Encoding utf8
pyinstaller promptflow.spec
shell: pwsh
- name: Generate portable promptflow
run: |
Compress-Archive -Path ${{ github.workspace }}/scripts/installer/windows/scripts/dist/promptflow -DestinationPath promptflow-${{ steps.get-version.outputs.version }}.zip
shell: pwsh
- name: Build WIX project
working-directory: ${{ github.workspace }}/scripts/installer/windows
run: |
$text = Get-Content "promptflow.wixproj" -Raw
$text = $text -replace '\$\((env\.CLI_VERSION)\)', '${{ steps.get-version.outputs.version }}'
$text | Out-File -FilePath "promptflow.wixproj" -Encoding utf8
$text = Get-Content "product.wxs" -Raw
$text = $text -replace '\$\((env\.CLI_VERSION)\)', '${{ steps.get-version.outputs.version }}'
$text | Out-File -FilePath "product.wxs" -Encoding utf8
msbuild /t:rebuild /p:Configuration=Release /p:Platform=x64 promptflow.wixproj
shell: pwsh
- uses: azure/login@v1
with:
subscription-id: ${{secrets.AZURE_SUBSCRIPTION_ID}}
tenant-id: ${{secrets.AZURE_TENANT_ID}}
client-id: ${{secrets.AZURE_CLIENT_ID}}
- name: Download JSON file from Azure Blob Storage
id: download-json
run: |
az storage blob download --account-name promptflowartifact --container-name msi-installer --name latest_version.json --file downloaded_version.json
$downloaded_version = (Get-Content downloaded_version.json | ConvertFrom-Json).promptflow
echo "::set-output name=downloaded_version::$downloaded_version"
- name: Check if version input is valid and upload JSON file
run: |
$version = "${{ steps.get-version.outputs.version }}"
$downloaded_version = "${{ steps.download-json.outputs.downloaded_version }}"
$uploadAsLatest = "${{ github.event.inputs.uploadAsLatest }}"
if ($uploadAsLatest -ieq 'True' -and $version -like '1.*' -and [Version]$version -gt [Version]$downloaded_version){
$jsonContent = @{
"promptflow" = $version
} | ConvertTo-Json -Depth 100
$jsonContent | Out-File -FilePath latest_version.json -Encoding UTF8
Write-Output "Created latest_version.json with version: $version"
az storage blob upload --account-name promptflowartifact --container-name msi-installer --file "latest_version.json" --name "latest_version.json" --overwrite
} else {
Write-Output "skip uploading since version input isn't greater than latest version or does not start with '1.'"
}
- name: Upload to Azure Storage
run: |
$msi_files = Get-ChildItem -Path 'scripts/installer/windows/out/' -Filter *.msi
foreach ($msi_file in $msi_files) {
if ($env:INPUT_UPLOADASLATEST -ieq 'True') {
az storage blob upload --account-name promptflowartifact --container-name msi-installer --file "scripts/installer/windows/out/$($msi_file.Name)" --name "promptflow.msi" --overwrite
az storage blob copy start --account-name promptflowartifact --destination-container msi-installer --destination-blob "$($msi_file.Name)" --source-container msi-installer --source-blob "promptflow.msi"
} else {
az storage blob upload --account-name promptflowartifact --container-name msi-installer --file "scripts/installer/windows/out/$($msi_file.Name)" --name "$($msi_file.Name)" --overwrite
}
}
# Upload zip file
if ($env:INPUT_UPLOADASLATEST -ieq 'True') {
az storage blob upload --account-name promptflowartifact --container-name portable-installer --file "promptflow-${{ steps.get-version.outputs.version }}.zip" --name "promptflow.zip" --overwrite
az storage blob copy start --account-name promptflowartifact --destination-container portable-installer --destination-blob "promptflow-${{ steps.get-version.outputs.version }}.zip" --source-container portable-installer --source-blob "promptflow.zip"
} else {
az storage blob upload --account-name promptflowartifact --container-name portable-installer --file "promptflow-${{ steps.get-version.outputs.version }}.zip" --name "promptflow-${{ steps.get-version.outputs.version }}.zip" --overwrite
}
env:
INPUT_UPLOADASLATEST: ${{ github.event.inputs.uploadAsLatest }}
shell: pwsh