Skip to content

Release Stage 4 - Package for Hyper-V - Run 19988212442 - beta-2025-12-06 - beta #98

Release Stage 4 - Package for Hyper-V - Run 19988212442 - beta-2025-12-06 - beta

Release Stage 4 - Package for Hyper-V - Run 19988212442 - beta-2025-12-06 - beta #98

name: Release Stage 4 - Package for Hyper-V Appliance
run-name: Release Stage 4 - Package for Hyper-V - Run ${{ inputs.run_id }} - ${{ inputs.HOMEBRIDGE_VM_IMAGE_VERSION }} - ${{ inputs.release_stream }}
on:
workflow_dispatch:
inputs:
run_id:
description: 'GitHub Run ID of the build workflow that produced the artifacts'
required: true
type: string
release_stream:
description: 'Release stream (stable, beta, alpha)'
required: true
type: choice
options:
- stable
- beta
- alpha
default: beta
HOMEBRIDGE_VM_IMAGE_VERSION:
description: 'Homebridge VM image version aka release tag'
required: true
type: string
concurrency:
group: package-hyperv
cancel-in-progress: false
jobs:
package-for-hyperv:
runs-on: windows-2022
timeout-minutes: 60
strategy:
max-parallel: 1
fail-fast: false
matrix:
arch: [amd64, arm64]
hyperv_version: ['8.0', '10.0']
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Download Artifacts
uses: actions/download-artifact@v6
with:
name: homebridge-image-${{ matrix.arch }}
path: output
run-id: ${{ inputs.run_id }}
merge-multiple: true
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: List Downloaded Artifacts
run: dir output
- name: Install qemu-img
run: |
if (-not (Get-Command qemu-img.exe -ErrorAction SilentlyContinue)) {
choco install qemu -y
}
Write-Host "qemu-img installed."
- name: Convert IMG to VHDX with qemu-img
run: |
$imgPath = (Get-ChildItem -Path output -Filter *.img).FullName
$vhdxPath = "output\homebridge-vm-image-${{ inputs.release_stream }}-${{ matrix.arch }}-hyperv${{ matrix.hyperv_version }}.vhdx"
# Find qemu-img.exe in common install locations
$qemuImgExe = "${env:ProgramFiles}\qemu\qemu-img.exe"
if (!(Test-Path $qemuImgExe)) {
$qemuImgExe = "${env:ProgramData}\chocolatey\bin\qemu-img.exe"
}
if (!(Test-Path $qemuImgExe)) {
throw "qemu-img.exe not found after installation"
}
Write-Host "Converting $imgPath to $vhdxPath using $qemuImgExe..."
& $qemuImgExe convert -f raw -O vhdx $imgPath $vhdxPath
Write-Host "Converted $imgPath to $vhdxPath"
- name: List Downloaded Artifacts
run: dir output
- name: Install Hyper-V PowerShell Module
run: |
Install-WindowsFeature -Name Hyper-V -IncludeManagementTools
Import-Module Hyper-V
- name: Ensure Hyper-V Switch Exists
run: |
$switchName = "Default Switch"
if (-not (Get-VMSwitch -Name $switchName -ErrorAction SilentlyContinue)) {
New-VMSwitch -Name $switchName -SwitchType Internal
}
Write-Host "Using switch: $switchName"
- name: Create Hyper-V VM Version ${{ matrix.hyperv_version }}
run: |
$vmName = "homebridge-vm-image-${{ inputs.release_stream }}-${{ matrix.arch }}-hyperv${{ matrix.hyperv_version }}"
$vhdxPath = "output\homebridge-vm-image-${{ inputs.release_stream }}-${{ matrix.arch }}-hyperv${{ matrix.hyperv_version }}.vhdx"
New-VM -Name $vmName -MemoryStartupBytes 4096MB -Generation 2 -VHDPath $vhdxPath -Version ${{ matrix.hyperv_version }}
Set-VMFirmware -VMName $vmName -EnableSecureBoot Off
Add-VMNetworkAdapter -VMName $vmName -SwitchName "Default Switch"
Write-Host "VM $vmName created and configured."
- name: Set VM Description (Notes)
run: |
$vmName = "homebridge-vm-image-${{ inputs.release_stream }}-${{ matrix.arch }}-hyperv${{ matrix.hyperv_version }}"
$manifestPath = "output\homebridge-vm-image-${{ inputs.release_stream }}-${{ matrix.arch }}.manifest"
if (Test-Path $manifestPath) {
$description = Get-Content $manifestPath | Out-String
Set-VM -Name $vmName -Notes $description
Write-Host "Set VM description from manifest."
} else {
Write-Host "Manifest file not found, skipping VM description."
}
- name: Export Hyper-V VM
run: |
$vmName = "homebridge-vm-image-${{ inputs.release_stream }}-${{ matrix.arch }}-hyperv${{ matrix.hyperv_version }}"
$exportPath = "output\$vmName-export"
Export-VM -Name $vmName -Path $exportPath
Write-Host "Exported VM $vmName to $exportPath"
- name: List Exported Artifacts
run: dir -Recurse output
- name: Zip Hyper-V Export with 7-Zip
run: |
$vmName = "homebridge-vm-image-${{ inputs.release_stream }}-${{ matrix.arch }}-hyperv${{ matrix.hyperv_version }}"
$exportPath = "output\$vmName-export"
$zipPath = "..\$vmName.zip"
if (-not (Test-Path $exportPath)) {
throw "Export path '$exportPath' not found"
}
if (-not (Get-Command 7z.exe -ErrorAction SilentlyContinue)) {
choco install 7zip -y
}
# Change into the export folder and add all files so the archive does NOT include the parent path.
Push-Location $exportPath
try {
pwd
# Use '*' to include everything inside the folder; create zip in the output parent folder.
& 7z a -tzip $zipPath * -r -mx=9
Write-Host "Zipped contents of $exportPath to $zipPath (archive root contains export folder contents only)"
} finally {
Pop-Location
}
- name: List Exported Artifacts
run: dir -Recurse output
- name: Upload Hyper-V Appliance as Artifact
uses: actions/upload-artifact@v5
with:
name: hyperv-appliance-${{ matrix.arch }}-v${{ matrix.hyperv_version }}
path: |
output\homebridge-vm-image-${{ inputs.release_stream }}-${{ matrix.arch }}-hyperv${{ matrix.hyperv_version }}.zip
output\*.manifest
- name: Upload VHDX, ZIP, and HyperV ZIP to GitHub Release
run: |
gh release upload "${{ inputs.HOMEBRIDGE_VM_IMAGE_VERSION }}" `
"output\homebridge-vm-image-${{ inputs.release_stream }}-${{ matrix.arch }}-hyperv${{ matrix.hyperv_version }}.zip" --clobber
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Packaging complete
run: |
echo "::notice::Homebridge VM image version: ${{ inputs.HOMEBRIDGE_VM_IMAGE_VERSION }}"
echo "::notice::Run ID: ${{ inputs.run_id }}"
echo "::notice::Architecture: ${{ matrix.arch }}"
echo "::notice::Release Stream: ${{ inputs.release_stream }}"
echo "::notice::Hyper-V Version: ${{ matrix.hyperv_version }}"