Skip to content

Publish Netbird to Winget #12

Publish Netbird to Winget

Publish Netbird to Winget #12

name: Publish Netbird to Winget
on:
release:
types: [published]
workflow_dispatch:
inputs:
version:
description: 'Netbird version to publish (e.g., 0.59.9)'
required: true
type: string
jobs:
publish-winget:
runs-on: windows-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up WingetCreate
shell: pwsh
run: Invoke-WebRequest https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe
- name: Determine version
id: version
shell: pwsh
run: |
if ("${{ github.event_name }}" -eq "workflow_dispatch") {
$version = "${{ github.event.inputs.version }}"
} else {
$version = "${{ github.event.release.tag_name }}".TrimStart('v')
}
"VERSION=$version" >> $env:GITHUB_ENV
"version=$version" >> $env:GITHUB_OUTPUT
- name: Fetch release info & collect installer URLs
id: release_info
shell: pwsh
env:
GH_API: https://api.github.com
WINGET_PAT: ${{ secrets.WINGET_PAT }}
run: |
$ErrorActionPreference = 'Stop'
$headers = @{
Authorization = "Bearer $env:WINGET_PAT"
"User-Agent" = "netbird-winget-action"
Accept = "application/vnd.github+json"
"X-GitHub-Api-Version" = "2022-11-28"
}
if ("${{ github.event_name }}" -eq "workflow_dispatch") {
$release = Invoke-RestMethod -Headers $headers -Uri "$env:GH_API/repos/netbirdio/netbird/releases/tags/v${{ env.VERSION }}"
} else {
$release = Invoke-RestMethod -Headers $headers -Uri "${{ github.event.release.url }}"
}
$assets = $release.assets
if (-not $assets) { throw "Release v${{ env.VERSION }} has no assets." }
$msi_x64 = $assets | Where-Object { $_.name -like "*windows_amd64.msi" } | Select-Object -ExpandProperty browser_download_url -First 1
$exe_x64 = $assets | Where-Object { $_.name -like "*windows_amd64.exe" } | Select-Object -ExpandProperty browser_download_url -First 1
$msi_arm = $assets | Where-Object { $_.name -like "*windows_arm64.msi" } | Select-Object -ExpandProperty browser_download_url -First 1
$exe_arm = $assets | Where-Object { $_.name -like "*windows_arm64.exe" } | Select-Object -ExpandProperty browser_download_url -First 1
$any = @($msi_x64, $exe_x64, $msi_arm, $exe_arm) | Where-Object { $_ }
if (-not $any) { throw "No Windows installers (MSI/EXE) found in v${{ env.VERSION }}." }
$qualified = @()
if ($msi_x64) { $qualified += "$msi_x64|x64" }
if ($exe_x64) { $qualified += "$exe_x64|x64" }
if ($msi_arm) { $qualified += "$msi_arm|arm64" }
if ($exe_arm) { $qualified += "$exe_arm|arm64" }
Set-Content -Path installer_urls.txt -Value ($qualified -join "`n")
"installer_urls_file=installer_urls.txt" >> $env:GITHUB_OUTPUT
"installer_url=$($any[0])" >> $env:GITHUB_OUTPUT
# ---------- Fork under PAT user, then sync ----------
- name: Install GitHub CLI
shell: pwsh
run: choco install gh -y
- name: Resolve PAT user (who will own the fork)
id: whoami
shell: pwsh
env:
GH_TOKEN: ${{ secrets.WINGET_PAT }} # <-- set for THIS step
run: |
$login = gh api /user --jq .login
if (-not $login) { throw "Could not determine PAT owner via /user" }
"login=$login" >> $env:GITHUB_OUTPUT
Write-Host "PAT user: $login"
- name: Ensure fork exists under PAT user (create if missing)
shell: pwsh
env:
GH_TOKEN: ${{ secrets.WINGET_PAT }} # <-- set for THIS step
run: |
$login = "${{ steps.whoami.outputs.login }}"
$fork = "$login/winget-pkgs"
Write-Host "Checking fork $fork ..."
$exists = $false
try {
gh repo view $fork --json name -q .name | Out-Null
if ($LASTEXITCODE -eq 0) { $exists = $true }
} catch { $exists = $false }
if (-not $exists) {
Write-Host "Fork not found; creating under $login ..."
gh api --method POST -H "Accept: application/vnd.github+json" /repos/microsoft/winget-pkgs/forks -F default_branch_only=true
# forking is async: poll until it appears
$deadline = (Get-Date).AddSeconds(90)
do {
Start-Sleep -Seconds 3
try {
gh repo view $fork --json defaultBranchRef -q .defaultBranchRef.name | Out-Null
if ($LASTEXITCODE -eq 0) { $exists = $true }
} catch { $exists = $false }
} until ($exists -or (Get-Date) -gt $deadline)
if (-not $exists) { throw "Fork creation did not complete in time for $fork." }
} else {
Write-Host "Fork already exists."
}
- name: Sync fork with upstream
shell: pwsh
env:
GH_TOKEN: ${{ secrets.WINGET_PAT }} # <-- set for THIS step
run: |
$login = "${{ steps.whoami.outputs.login }}"
gh repo sync "$login/winget-pkgs" -b master --force
# ---------- Submit with wingetcreate ----------
- name: Update Winget Manifest
shell: pwsh
env:
WINGET_PAT: ${{ secrets.WINGET_PAT }}
run: |
Write-Host "Updating Winget manifest for Netbird ${{ env.VERSION }}"
$urls = Get-Content "${{ steps.release_info.outputs.installer_urls_file }}" | Where-Object { $_.Trim() }
if (-not $urls) { throw "No installer URLs to submit." }
.\wingetcreate.exe update Netbird.Netbird `
--version $env:VERSION `
--display-version $env:VERSION `
--urls $urls `
--submit `
--token $env:WINGET_PAT
- name: Verify submission
shell: pwsh
run: |
if ($LASTEXITCODE -eq 0) {
Write-Host "✅ Successfully submitted Winget manifest update for Netbird ${{ env.VERSION }}"
} else {
Write-Error "❌ Failed to submit Winget manifest update"
exit 1
}