chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
# File auto-generated and managed by Devops
|
||||
/.github/ @devolutions/devops @devolutions/architecture-maintainers @GabrielDuf # Gabriel Dufresne
|
||||
/.github/dependabot.yml @devolutions/security-managers
|
||||
@@ -0,0 +1,68 @@
|
||||
name: '🐞 Report a bug or an issue'
|
||||
description: Report issues or unexpected behaviors.
|
||||
title: "[BUG] (Enter your description here)"
|
||||
labels: ["bug"]
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Please confirm these before moving forward
|
||||
description: Please confirm the following before posting your issue.
|
||||
options:
|
||||
- label: I have searched for my issue and have not found a work-in-progress/duplicate/resolved issue.
|
||||
required: true
|
||||
- label: I have tested that this issue has not been fixed in the latest [(beta or stable) release](https://github.com/Devolutions/UniGetUI/releases/).
|
||||
required: true
|
||||
- label: I have checked the [FAQ](https://github.com/Devolutions/UniGetUI#frequently-asked-questions) section for solutions.
|
||||
required: true
|
||||
- label: This issue is about a bug (if it is not, please use the [correct template](https://github.com/Devolutions/UniGetUI/issues/new/choose)).
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: UniGetUI Version
|
||||
placeholder: 'x.y.z (e.g., 3.1.0)'
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: Windows version, edition, and architecture
|
||||
placeholder: Windows 11 Pro 10.0.22000.0 x64
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe your issue
|
||||
placeholder: Explain the issue you are experiencing, providing as many details as possible.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Steps to reproduce the issue
|
||||
placeholder: How can this issue be reproduced? List here, if known, the steps followed before this issue appeared.
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: UniGetUI Log
|
||||
render: "text"
|
||||
placeholder: Paste your UniGetUI logs here. Click the button on the bottom-left corner of UniGetUI -> UniGetUI Log.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Package Managers Logs
|
||||
render: "text"
|
||||
placeholder: Paste your Package Manager logs here. Click the button on the bottom-left corner of UniGetUI -> Package Manager logs.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Relevant information
|
||||
placeholder: Other relevant information about this issue. Perhaps you have some special settings enabled or any other detail that could be related.
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Screenshots and videos
|
||||
placeholder: If applicable, please post here a video or a screenshot of the issue.
|
||||
validations:
|
||||
required: false
|
||||
@@ -0,0 +1,12 @@
|
||||
blank_issues_enabled: false
|
||||
|
||||
contact_links:
|
||||
- name: 📦 ISSUES INSTALLING/UPDATING A PACKAGE
|
||||
url: https://github.com/Devolutions/UniGetUI
|
||||
about: PLEASE READ THIS BEFORE CREATING AN ISSUE RELATED TO A SPECIFIC PACKAGE
|
||||
- name: 🔒 Security issue or vulnerability
|
||||
url: https://devolutions.net/security/
|
||||
about: Found a security issue? Please report it via the Devolutions security page
|
||||
- name: 📧 Contact us directly, in private
|
||||
url: https://devolutions.net/contact/
|
||||
about: Please use only for private inquiries that should not be posted publicly
|
||||
@@ -0,0 +1,28 @@
|
||||
name: '🚧 Suggest an improvement for an existing feature'
|
||||
description: Propose an improvement to UniGetUI.
|
||||
title: "[IMPROVEMENT] (Enter your description here)"
|
||||
labels: ["enhancement"]
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Please confirm these before moving forward.
|
||||
description: Please confirm the following before posting your issue.
|
||||
options:
|
||||
- label: I have searched for my feature proposal and have not found a work-in-progress/duplicate/resolved/discarded issue.
|
||||
required: true
|
||||
- label: This improvement refers to an existing feature. If you want to suggest a new feature, please use [this template](https://github.com/Devolutions/UniGetUI/issues/new?labels=new-feature&projects=&template=feature-request.yml&title=%5BFEATURE+REQUEST%5D+%28Enter+your+description+here%29).
|
||||
required: true
|
||||
- label: This improvement is not a bug. If you want to report a bug, please use [this template](https://github.com/Devolutions/UniGetUI/issues/new?labels=bug&projects=&template=bug-issue.yml&title=%5BBUG%5D+%28Enter+your+description+here%29).
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe the improvement
|
||||
placeholder: Explain how you see this enhancement, providing as many details as possible.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe how this improvement could help users
|
||||
placeholder: For what would it be useful?
|
||||
validations:
|
||||
required: true
|
||||
@@ -0,0 +1,26 @@
|
||||
name: '💡 Propose a new feature'
|
||||
description: Propose a new feature that could be useful in UniGetUI.
|
||||
title: "[FEATURE REQUEST] (Enter your description here)"
|
||||
labels: ["new-feature"]
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Please confirm these before moving forward.
|
||||
description: Please confirm the following before posting your issue.
|
||||
options:
|
||||
- label: I have searched for my feature proposal and have not found a work-in-progress/duplicate/resolved/discarded issue.
|
||||
required: true
|
||||
- label: This proposal is a completely new feature. If you want to suggest an improvement or an enhancement, please use [this template](https://github.com/Devolutions/UniGetUI/issues/new?labels=enhancement&projects=&template=enhancement-improvement.yml&title=%5BENHANCEMENT%5D+%28Enter+your+description+here%29).
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe the new feature
|
||||
placeholder: Explain how you see this new feature, providing as many details as possible.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe how this new feature could help users
|
||||
placeholder: For what would it be useful?
|
||||
validations:
|
||||
required: true
|
||||
@@ -0,0 +1,35 @@
|
||||
name: '🚑 Report a crash or a hang'
|
||||
description: UniGetUI is not launching, is hard-crashing, or is hanging at some point.
|
||||
title: "[CRASH] (Enter your description here)"
|
||||
labels: ["bug", "important"]
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Please confirm these before moving forward.
|
||||
description: Please confirm the following before posting your issue.
|
||||
options:
|
||||
- label: I have tried deleting a folder named `UniGetUI` under `%UserProfile%\AppData\Local\UniGetUI`.
|
||||
required: true
|
||||
- label: I have tried reinstalling UniGetUI.
|
||||
required: true
|
||||
- label: I have tested that this issue has not been fixed in the latest [(beta or stable) release](https://github.com/Devolutions/UniGetUI/releases/).
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe your crash
|
||||
placeholder: What were you doing when this happened?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Logs (if possible)
|
||||
placeholder: If you get an error report or a message, please post it here.
|
||||
render: "text"
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: More details
|
||||
placeholder: Do you have any other valuable information about this issue?
|
||||
validations:
|
||||
required: false
|
||||
@@ -0,0 +1,74 @@
|
||||
name: '🧩 Report an issue with Widgets for UniGetUI'
|
||||
description: Report issues or unexpected behaviors with Widgets for UniGetUI.
|
||||
title: "[WIDGETS BUG] (Enter your description here)"
|
||||
labels: ["bug", "widgets-for-unigetui"]
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Please confirm these before moving forward
|
||||
description: Please confirm the following before posting your issue.
|
||||
options:
|
||||
- label: I have searched for my issue and have not found a work-in-progress/duplicate/resolved issue.
|
||||
required: true
|
||||
- label: I have tested that this issue has not been fixed in the latest [(beta or stable) release](https://github.com/Devolutions/UniGetUI/releases/).
|
||||
required: true
|
||||
- label: I have checked the [FAQ](https://github.com/Devolutions/UniGetUI#frequently-asked-questions) section for solutions.
|
||||
required: true
|
||||
- label: This issue is about a bug (if it is not, please use the [correct template](https://github.com/Devolutions/UniGetUI/issues/new/choose)).
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: UniGetUI Version
|
||||
placeholder: 'x.y.z (e.g., 3.1.0)'
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: Widgets for UniGetUI Version
|
||||
placeholder: 'x.y.z.w (e.g., 0.6.1.0)'
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: Windows version, edition, and architecture
|
||||
placeholder: Windows 11 Pro 10.0.22000.0 x64
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe your issue
|
||||
placeholder: Explain the issue you are experiencing, providing as many details as possible.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Steps to reproduce the issue
|
||||
placeholder: How can this issue be reproduced? List here, if known, the steps followed before this issue appeared.
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: UniGetUI Log
|
||||
render: "text"
|
||||
placeholder: Paste your UniGetUI logs here. Click the button on the bottom-left corner of UniGetUI -> UniGetUI Log.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Package Managers Logs
|
||||
render: "text"
|
||||
placeholder: Paste your Package Manager logs here. Click the button on the bottom-left corner of UniGetUI -> Package Manager logs.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Relevant information
|
||||
placeholder: Other relevant information about this issue. Perhaps you have some special settings enabled or any other detail that could be related.
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Screenshots and videos
|
||||
placeholder: If applicable, please post a video or a screenshot of the issue here.
|
||||
validations:
|
||||
required: false
|
||||
@@ -0,0 +1,14 @@
|
||||
<!-- Provide a general summary of your changes in the title above -->
|
||||
- [ ] **I have read the [contributing guidelines](https://github.com/Devolutions/UniGetUI/blob/main/CONTRIBUTING.md#coding), and I agree with the [Code of Conduct](https://github.com/Devolutions/UniGetUI/blob/main/CODE_OF_CONDUCT.md)**.
|
||||
- [ ] **Have you checked that there aren't other open [pull requests](https://github.com/Devolutions/UniGetUI/pulls) for the same changes?**
|
||||
- [ ] **Have you tested that the committed code can be executed without errors?**
|
||||
- [ ] **Have you confirmed that this issue is caused by UniGetUI itself, and not by the package manager or the package involved?**
|
||||
If the same issue can be reproduced outside UniGetUI with the relevant package manager or with the package itself, please report it there first. UniGetUI should only be used to track issues that are specific to UniGetUI's behavior or integration.
|
||||
-----
|
||||
|
||||
<!-- optionally, explain here about the committed code -->
|
||||
-----
|
||||
<!-- insert below the issue number (if applicable, do not create a new issue to justify a PR) -->
|
||||
Closes #XXXX
|
||||
<!-- and/or -->
|
||||
Relates to #XXXX
|
||||
@@ -0,0 +1,10 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
groups:
|
||||
actions-deps:
|
||||
patterns:
|
||||
- "*"
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"config:recommended"
|
||||
],
|
||||
"enabledManagers": [
|
||||
"nuget"
|
||||
],
|
||||
"dependencyDashboard": true
|
||||
}
|
||||
@@ -0,0 +1,896 @@
|
||||
name: Build and Release
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: 'Release version (required, e.g. 2026.1.0)'
|
||||
required: true
|
||||
draft-release:
|
||||
description: 'Create the GitHub Release as a draft'
|
||||
required: true
|
||||
type: boolean
|
||||
default: false
|
||||
skip-publish:
|
||||
description: 'Skip publishing to GitHub Releases'
|
||||
required: true
|
||||
type: boolean
|
||||
default: false
|
||||
dry-run:
|
||||
description: 'Dry run (simulate without publishing)'
|
||||
required: true
|
||||
type: boolean
|
||||
default: true
|
||||
|
||||
jobs:
|
||||
preflight:
|
||||
name: Preflight
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
package-env: ${{ steps.info.outputs.package-env }}
|
||||
package-version: ${{ steps.info.outputs.package-version }}
|
||||
onedrive-version: ${{ steps.info.outputs.onedrive-version }}
|
||||
draft-release: ${{ steps.info.outputs.draft-release }}
|
||||
skip-publish: ${{ steps.info.outputs.skip-publish }}
|
||||
dry-run: ${{ steps.info.outputs.dry-run }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Resolve build parameters
|
||||
id: info
|
||||
shell: pwsh
|
||||
run: |
|
||||
$IsProductionBranch = @('main', 'master') -contains '${{ github.ref_name }}'
|
||||
|
||||
try { $DraftRelease = [System.Boolean]::Parse('${{ inputs.draft-release }}') } catch { $DraftRelease = $false }
|
||||
try { $SkipPublish = [System.Boolean]::Parse('${{ inputs.skip-publish }}') } catch { $SkipPublish = $false }
|
||||
try { $DryRun = [System.Boolean]::Parse('${{ inputs.dry-run }}') } catch { $DryRun = $true }
|
||||
|
||||
$PackageEnv = if ($IsProductionBranch) {
|
||||
"publish-prod"
|
||||
} else {
|
||||
"publish-test"
|
||||
}
|
||||
|
||||
if (-Not $IsProductionBranch) {
|
||||
$DryRun = $true # force dry run when not on main/master branch
|
||||
}
|
||||
|
||||
if (-Not $SkipPublish -And $PackageEnv -ne 'publish-prod') {
|
||||
$DryRun = $true # force dry run when publishing outside production environment
|
||||
}
|
||||
|
||||
$PackageVersion = '${{ inputs.version }}'
|
||||
if ([string]::IsNullOrWhiteSpace($PackageVersion)) {
|
||||
throw "The workflow_dispatch version input is required."
|
||||
}
|
||||
|
||||
echo "package-env=$PackageEnv" >> $Env:GITHUB_OUTPUT
|
||||
$OneDriveVersion = "$PackageVersion.0"
|
||||
|
||||
echo "package-version=$PackageVersion" >> $Env:GITHUB_OUTPUT
|
||||
echo "onedrive-version=$OneDriveVersion" >> $Env:GITHUB_OUTPUT
|
||||
echo "draft-release=$($DraftRelease.ToString().ToLower())" >> $Env:GITHUB_OUTPUT
|
||||
echo "skip-publish=$($SkipPublish.ToString().ToLower())" >> $Env:GITHUB_OUTPUT
|
||||
echo "dry-run=$($DryRun.ToString().ToLower())" >> $Env:GITHUB_OUTPUT
|
||||
|
||||
echo "::notice::Environment: $PackageEnv"
|
||||
echo "::notice::Version: $PackageVersion"
|
||||
echo "::notice::DraftRelease: $DraftRelease"
|
||||
echo "::notice::DryRun: $DryRun"
|
||||
|
||||
build:
|
||||
name: Build & Sign (${{ matrix.platform }})
|
||||
runs-on: windows-latest
|
||||
needs: [preflight]
|
||||
environment: ${{ needs.preflight.outputs.package-env }}
|
||||
permissions:
|
||||
contents: read
|
||||
env:
|
||||
UNIGETUI_GITHUB_CLIENT_ID: ${{ secrets.UNIGETUI_GITHUB_CLIENT_ID }}
|
||||
UNIGETUI_GITHUB_CLIENT_SECRET: ${{ secrets.UNIGETUI_GITHUB_CLIENT_SECRET }}
|
||||
UNIGETUI_OPENSEARCH_USERNAME: ${{ secrets.UNIGETUI_OPENSEARCH_USERNAME }}
|
||||
UNIGETUI_OPENSEARCH_PASSWORD: ${{ secrets.UNIGETUI_OPENSEARCH_PASSWORD }}
|
||||
NUGET_PACKAGES: ${{ github.workspace }}\.nuget\packages
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [x64, arm64]
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Validate GitHub OAuth secrets
|
||||
shell: pwsh
|
||||
run: |
|
||||
if ([string]::IsNullOrWhiteSpace($env:UNIGETUI_GITHUB_CLIENT_ID)) {
|
||||
throw "UNIGETUI_GITHUB_CLIENT_ID is not configured for this build environment."
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($env:UNIGETUI_GITHUB_CLIENT_SECRET)) {
|
||||
throw "UNIGETUI_GITHUB_CLIENT_SECRET is not configured for this build environment."
|
||||
}
|
||||
|
||||
Write-Host "::notice::GitHub OAuth secrets are configured for this build."
|
||||
|
||||
- name: Install .NET
|
||||
uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
- name: Cache NuGet packages
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ${{ env.NUGET_PACKAGES }}
|
||||
key: ${{ runner.os }}-nuget-${{ hashFiles('global.json', 'src/**/*.csproj', 'src/**/*.props', 'src/**/*.targets', 'src/**/*.sln', 'src/**/*.slnx') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-nuget-
|
||||
|
||||
- name: Install Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
- name: Install Inno Setup
|
||||
shell: pwsh
|
||||
run: |
|
||||
choco install innosetup -y --no-progress
|
||||
echo "C:\Program Files (x86)\Inno Setup 6" >> $Env:GITHUB_PATH
|
||||
|
||||
- name: Install code-signing tools
|
||||
shell: pwsh
|
||||
run: |
|
||||
dotnet tool install --global AzureSignTool
|
||||
Install-Module -Name Devolutions.Authenticode -Force
|
||||
|
||||
# Trust test code-signing CA
|
||||
$TestCertsUrl = "https://raw.githubusercontent.com/Devolutions/devolutions-authenticode/master/data/certs"
|
||||
Invoke-WebRequest -Uri "$TestCertsUrl/authenticode-test-ca.crt" -OutFile ".\authenticode-test-ca.crt"
|
||||
Import-Certificate -FilePath ".\authenticode-test-ca.crt" -CertStoreLocation "cert:\LocalMachine\Root"
|
||||
Remove-Item ".\authenticode-test-ca.crt" -ErrorAction SilentlyContinue | Out-Null
|
||||
|
||||
- name: Set version
|
||||
shell: pwsh
|
||||
run: |
|
||||
$PackageVersion = '${{ needs.preflight.outputs.package-version }}'
|
||||
.\scripts\set-version.ps1 -Version $PackageVersion
|
||||
|
||||
- name: Restore dependencies
|
||||
working-directory: src
|
||||
run: dotnet restore UniGetUI.Windows.slnx
|
||||
|
||||
- name: Run tests
|
||||
working-directory: src
|
||||
shell: pwsh
|
||||
run: |
|
||||
dotnet build-server shutdown
|
||||
# Retry once to handle flaky tests (e.g. TaskRecyclerTests uses Random)
|
||||
dotnet test UniGetUI.Windows.slnx --no-restore --verbosity q --nologo /p:Platform=x64 /p:UseSharedCompilation=false /m:1
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "::warning::First test run failed, retrying..."
|
||||
dotnet build-server shutdown
|
||||
dotnet test UniGetUI.Windows.slnx --no-restore --verbosity q --nologo /p:Platform=x64 /p:UseSharedCompilation=false /m:1
|
||||
if ($LASTEXITCODE -ne 0) { exit 1 }
|
||||
}
|
||||
|
||||
- name: Publish
|
||||
shell: pwsh
|
||||
run: |
|
||||
$Platform = '${{ matrix.platform }}'
|
||||
$TargetFramework = (
|
||||
dotnet msbuild src/UniGetUI.Avalonia/UniGetUI.Avalonia.csproj `
|
||||
/nologo `
|
||||
-getProperty:TargetFramework `
|
||||
/p:Configuration=Release `
|
||||
/p:Platform=$Platform `
|
||||
/p:RuntimeIdentifier=win-$Platform |
|
||||
Select-Object -Last 1
|
||||
).Trim()
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($TargetFramework)) {
|
||||
throw "Could not resolve the Avalonia target framework from MSBuild"
|
||||
}
|
||||
|
||||
dotnet publish src/UniGetUI.Avalonia/UniGetUI.Avalonia.csproj `
|
||||
/noLogo `
|
||||
/p:Configuration=Release `
|
||||
/p:Platform=$Platform `
|
||||
/p:RuntimeIdentifier=win-$Platform `
|
||||
/p:PublishProfile=Win-$Platform-NativeAot `
|
||||
/p:UseSharedCompilation=false `
|
||||
/p:BuildInParallel=false `
|
||||
/m:1 `
|
||||
-v m
|
||||
if ($LASTEXITCODE -ne 0) { throw "dotnet publish Avalonia failed" }
|
||||
|
||||
# Stage binaries
|
||||
$PublishDir = "src/UniGetUI.Avalonia/bin/$Platform/Release/$TargetFramework/win-$Platform/publish"
|
||||
if (Test-Path "unigetui_bin") { Remove-Item "unigetui_bin" -Recurse -Force }
|
||||
New-Item "unigetui_bin" -ItemType Directory | Out-Null
|
||||
Get-ChildItem $PublishDir | Move-Item -Destination "unigetui_bin" -Force
|
||||
|
||||
if (-not (Test-Path "unigetui_bin/UniGetUI.exe")) {
|
||||
throw "Windows app host was not produced at unigetui_bin/UniGetUI.exe"
|
||||
}
|
||||
|
||||
$MaxShippedPdbSizeBytes = 1MB
|
||||
$PdbsToRemove = Get-ChildItem "unigetui_bin" -Filter "*.pdb" -File -Recurse | Where-Object {
|
||||
$_.Length -gt $MaxShippedPdbSizeBytes
|
||||
}
|
||||
|
||||
if ($PdbsToRemove.Count -gt 0) {
|
||||
$RemovedPdbBytes = ($PdbsToRemove | Measure-Object -Property Length -Sum).Sum
|
||||
$PdbsToRemove | Remove-Item -Force
|
||||
Write-Host ("Removed {0} oversized PDBs above {1:N2} MiB ({2:N2} MiB total)." -f $PdbsToRemove.Count, ($MaxShippedPdbSizeBytes / 1MB), ($RemovedPdbBytes / 1MB))
|
||||
}
|
||||
|
||||
- name: Code-sign binaries
|
||||
if: ${{ fromJSON(needs.preflight.outputs.dry-run) == false }}
|
||||
shell: pwsh
|
||||
run: |
|
||||
$ListPath = Join-Path $PWD "signing-files.txt"
|
||||
$files = Get-ChildItem "unigetui_bin" -Recurse -Include "*.exe", "*.dll" | Where-Object {
|
||||
(Get-AuthenticodeSignature $_.FullName).Status -eq "NotSigned"
|
||||
}
|
||||
$files.FullName | Set-Content $ListPath
|
||||
Write-Host "Signing list contains $($files.Count) files."
|
||||
|
||||
.\scripts\sign.ps1 `
|
||||
-FileListPath $ListPath `
|
||||
-AzureTenantId '${{ secrets.AZURE_TENANT_ID }}' `
|
||||
-KeyVaultUrl '${{ secrets.CODE_SIGNING_KEYVAULT_URL }}' `
|
||||
-ClientId '${{ secrets.CODE_SIGNING_CLIENT_ID }}' `
|
||||
-ClientSecret '${{ secrets.CODE_SIGNING_CLIENT_SECRET }}' `
|
||||
-CertificateName '${{ secrets.CODE_SIGNING_CERTIFICATE_NAME }}' `
|
||||
-TimestampServer '${{ vars.CODE_SIGNING_TIMESTAMP_SERVER }}'
|
||||
|
||||
- name: Build installer
|
||||
shell: pwsh
|
||||
run: |
|
||||
$Platform = '${{ matrix.platform }}'
|
||||
$OutputDir = Join-Path $PWD "output"
|
||||
New-Item $OutputDir -ItemType Directory -ErrorAction SilentlyContinue | Out-Null
|
||||
|
||||
.\scripts\refresh-integrity-tree.ps1 -Path $PWD/unigetui_bin -FailOnUnexpectedFiles
|
||||
|
||||
# Configure Inno Setup to use AzureSignTool
|
||||
$IssPath = "UniGetUI.iss"
|
||||
|
||||
# Build the installer (signing of the installer itself happens in the next step)
|
||||
# Temporarily remove SignTool line so ISCC doesn't try to sign during build
|
||||
$issContent = Get-Content $IssPath -Raw
|
||||
|
||||
try {
|
||||
$issContentNoSign = $issContent -Replace '(?m)^SignTool=.*$', '; SignTool=azsign (disabled for CI, signed separately)'
|
||||
$issContentNoSign = $issContentNoSign -Replace '(?m)^SignedUninstaller=yes', 'SignedUninstaller=no'
|
||||
Set-Content $IssPath $issContentNoSign -NoNewline
|
||||
|
||||
$InstallerBaseName = "UniGetUI.Installer.$Platform"
|
||||
$IsccArgs = @($IssPath, "/F$InstallerBaseName", "/O$OutputDir")
|
||||
if ([System.Boolean]::Parse('${{ needs.preflight.outputs.dry-run }}') -eq $false) {
|
||||
Write-Host "Using lzma/ultra64 installer compression for release build."
|
||||
$IsccArgs = @('/DInstallerCompression=lzma/ultra64') + $IsccArgs
|
||||
}
|
||||
|
||||
& ISCC.exe @IsccArgs
|
||||
if ($LASTEXITCODE -ne 0) { throw "Inno Setup failed with exit code $LASTEXITCODE" }
|
||||
}
|
||||
finally {
|
||||
Set-Content $IssPath $issContent -NoNewline
|
||||
}
|
||||
|
||||
- name: Stage output
|
||||
shell: pwsh
|
||||
run: |
|
||||
$Platform = '${{ matrix.platform }}'
|
||||
New-Item "output" -ItemType Directory -ErrorAction SilentlyContinue | Out-Null
|
||||
|
||||
.\scripts\refresh-integrity-tree.ps1 -Path $PWD/unigetui_bin -FailOnUnexpectedFiles
|
||||
|
||||
# Zip
|
||||
Compress-Archive -Path "unigetui_bin/*" -DestinationPath "output/UniGetUI.$Platform.zip" -CompressionLevel Optimal
|
||||
|
||||
# Installer is created in output during the previous step
|
||||
|
||||
- name: Capture artifact sizes
|
||||
shell: pwsh
|
||||
run: |
|
||||
$Platform = '${{ matrix.platform }}'
|
||||
$SizesFile = "output/sizes.$Platform.json"
|
||||
$UncompressedSize = (Get-ChildItem "unigetui_bin" -Recurse -File | Measure-Object -Property Length -Sum).Sum
|
||||
$Artifacts = Get-ChildItem "output" -File | Where-Object { $_.Name -ne "sizes.$Platform.json" } | ForEach-Object {
|
||||
@{ Name = $_.Name; SizeBytes = $_.Length }
|
||||
}
|
||||
$Report = @{
|
||||
Platform = $Platform
|
||||
RuntimeIdentifier = "win-$Platform"
|
||||
UncompressedSizeBytes = $UncompressedSize
|
||||
Artifacts = $Artifacts
|
||||
Timestamp = [DateTimeOffset]::UtcNow.ToString("o")
|
||||
}
|
||||
$Report | ConvertTo-Json -Depth 4 | Set-Content $SizesFile -Encoding UTF8
|
||||
Write-Host "Artifact sizes saved to $SizesFile"
|
||||
Get-Content $SizesFile
|
||||
|
||||
- name: Code-sign installer
|
||||
if: ${{ fromJSON(needs.preflight.outputs.dry-run) == false }}
|
||||
shell: pwsh
|
||||
run: |
|
||||
$Platform = '${{ matrix.platform }}'
|
||||
.\scripts\sign.ps1 `
|
||||
-InstallerPath "output/UniGetUI.Installer.$Platform.exe" `
|
||||
-AzureTenantId '${{ secrets.AZURE_TENANT_ID }}' `
|
||||
-KeyVaultUrl '${{ secrets.CODE_SIGNING_KEYVAULT_URL }}' `
|
||||
-ClientId '${{ secrets.CODE_SIGNING_CLIENT_ID }}' `
|
||||
-ClientSecret '${{ secrets.CODE_SIGNING_CLIENT_SECRET }}' `
|
||||
-CertificateName '${{ secrets.CODE_SIGNING_CERTIFICATE_NAME }}' `
|
||||
-TimestampServer '${{ vars.CODE_SIGNING_TIMESTAMP_SERVER }}'
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: UniGetUI-release-${{ matrix.platform }}
|
||||
path: output/*
|
||||
|
||||
- name: Cleanup
|
||||
if: always()
|
||||
shell: pwsh
|
||||
run: |
|
||||
Remove-Item "unigetui_bin" -Recurse -Force -ErrorAction SilentlyContinue
|
||||
|
||||
build-avalonia:
|
||||
name: Build (${{ matrix.name }})
|
||||
runs-on: ${{ matrix.os }}
|
||||
needs: [preflight]
|
||||
environment: ${{ needs.preflight.outputs.package-env }}
|
||||
permissions:
|
||||
contents: read
|
||||
env:
|
||||
UNIGETUI_GITHUB_CLIENT_ID: ${{ secrets.UNIGETUI_GITHUB_CLIENT_ID }}
|
||||
UNIGETUI_GITHUB_CLIENT_SECRET: ${{ secrets.UNIGETUI_GITHUB_CLIENT_SECRET }}
|
||||
UNIGETUI_OPENSEARCH_USERNAME: ${{ secrets.UNIGETUI_OPENSEARCH_USERNAME }}
|
||||
UNIGETUI_OPENSEARCH_PASSWORD: ${{ secrets.UNIGETUI_OPENSEARCH_PASSWORD }}
|
||||
NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages
|
||||
SIGNING_IDENTITY: 'Developer ID Application: Devolutions inc.'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: macos-latest
|
||||
name: macos-arm64
|
||||
runtime: osx-arm64
|
||||
publish_profile: osx-arm64-NativeAot
|
||||
- os: macos-latest
|
||||
name: macos-x64
|
||||
runtime: osx-x64
|
||||
publish_profile: osx-x64-NativeAot
|
||||
- os: ubuntu-latest
|
||||
name: linux-x64
|
||||
runtime: linux-x64
|
||||
publish_profile: linux-x64-NativeAot
|
||||
- os: ubuntu-latest
|
||||
name: linux-arm64
|
||||
runtime: linux-arm64
|
||||
publish_profile: linux-arm64-NativeAot
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Install .NET
|
||||
uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
- name: Cache NuGet packages
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ${{ env.NUGET_PACKAGES }}
|
||||
key: ${{ runner.os }}-nuget-${{ hashFiles('global.json', 'src/**/*.csproj', 'src/**/*.props', 'src/**/*.targets', 'src/**/*.sln', 'src/**/*.slnx') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-nuget-
|
||||
|
||||
- name: Install Linux arm64 NativeAOT toolchain
|
||||
if: matrix.runtime == 'linux-arm64'
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
. /etc/os-release
|
||||
sudo dpkg --add-architecture arm64
|
||||
|
||||
# Keep the runner's default Ubuntu feeds bound to amd64, then add the
|
||||
# Ubuntu Ports arm64 feed that provides the target CRT and zlib objects.
|
||||
if compgen -G "/etc/apt/sources.list.d/*.sources" > /dev/null; then
|
||||
for source in /etc/apt/sources.list.d/*.sources; do
|
||||
if ! grep -q '^Architectures:' "$source"; then
|
||||
sudo sed -i '/^Types: deb$/a Architectures: amd64' "$source"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [ -f /etc/apt/sources.list ]; then
|
||||
sudo sed -i -E '/^deb /s/^deb /deb [arch=amd64] /' /etc/apt/sources.list
|
||||
fi
|
||||
|
||||
sudo tee /etc/apt/sources.list.d/ubuntu-arm64.sources >/dev/null <<EOF
|
||||
Types: deb
|
||||
URIs: http://ports.ubuntu.com/ubuntu-ports/
|
||||
Suites: ${VERSION_CODENAME} ${VERSION_CODENAME}-updates ${VERSION_CODENAME}-backports
|
||||
Components: main restricted universe multiverse
|
||||
Architectures: arm64
|
||||
Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg
|
||||
|
||||
Types: deb
|
||||
URIs: http://ports.ubuntu.com/ubuntu-ports/
|
||||
Suites: ${VERSION_CODENAME}-security
|
||||
Components: main restricted universe multiverse
|
||||
Architectures: arm64
|
||||
Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg
|
||||
EOF
|
||||
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
clang \
|
||||
llvm \
|
||||
binutils-aarch64-linux-gnu \
|
||||
gcc-aarch64-linux-gnu \
|
||||
zlib1g-dev:arm64
|
||||
|
||||
- name: Set version
|
||||
shell: pwsh
|
||||
run: |
|
||||
$PackageVersion = '${{ needs.preflight.outputs.package-version }}'
|
||||
./scripts/set-version.ps1 -Version $PackageVersion
|
||||
|
||||
- name: Restore dependencies
|
||||
working-directory: src
|
||||
run: dotnet restore UniGetUI.Avalonia/UniGetUI.Avalonia.csproj --runtime ${{ matrix.runtime }}
|
||||
|
||||
- name: Publish
|
||||
working-directory: src
|
||||
shell: pwsh
|
||||
run: |
|
||||
$PublishProfile = '${{ matrix.publish_profile }}'
|
||||
$PublishArgs = @(
|
||||
'publish',
|
||||
'UniGetUI.Avalonia/UniGetUI.Avalonia.csproj',
|
||||
'--configuration', 'Release',
|
||||
'--runtime', '${{ matrix.runtime }}',
|
||||
'--self-contained', 'true',
|
||||
'--output', '../bin/${{ matrix.name }}'
|
||||
)
|
||||
if ($PublishProfile) {
|
||||
$PublishArgs += "/p:PublishProfile=$PublishProfile"
|
||||
}
|
||||
dotnet @PublishArgs
|
||||
|
||||
- name: Remove oversized Linux debug symbols
|
||||
if: runner.os == 'Linux'
|
||||
shell: pwsh
|
||||
run: |
|
||||
$PublishDir = "bin/${{ matrix.name }}"
|
||||
$MaxDebugSymbolSizeBytes = 1MB
|
||||
$DebugSymbolsToRemove = @(Get-ChildItem $PublishDir -Include "*.dbg", "*.pdb" -File -Recurse | Where-Object {
|
||||
$_.Length -gt $MaxDebugSymbolSizeBytes
|
||||
})
|
||||
|
||||
if ($DebugSymbolsToRemove.Count -gt 0) {
|
||||
$RemovedDebugSymbolBytes = ($DebugSymbolsToRemove | Measure-Object -Property Length -Sum).Sum
|
||||
$DebugSymbolsToRemove | Remove-Item -Force
|
||||
Write-Host ("Removed {0} oversized Linux debug symbols above {1:N2} MiB ({2:N2} MiB total)." -f $DebugSymbolsToRemove.Count, ($MaxDebugSymbolSizeBytes / 1MB), ($RemovedDebugSymbolBytes / 1MB))
|
||||
}
|
||||
|
||||
- name: Install macOS packaging tools
|
||||
if: runner.os == 'macOS'
|
||||
run: brew install create-dmg
|
||||
|
||||
- name: Check out Devolutions/actions
|
||||
if: ${{ runner.os == 'macOS' && fromJSON(needs.preflight.outputs.dry-run) == false }}
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
repository: Devolutions/actions
|
||||
ref: v1
|
||||
token: ${{ secrets.DEVOLUTIONSBOT_TOKEN }}
|
||||
path: ./.github/workflows
|
||||
|
||||
- name: Import Developer ID certificate
|
||||
if: ${{ runner.os == 'macOS' && fromJSON(needs.preflight.outputs.dry-run) == false }}
|
||||
uses: ./.github/workflows/macos-code-sign-setup
|
||||
with:
|
||||
base64_certificate: ${{ secrets.APPLE_APP_DEV_ID_APP_CERTIFICATE }}
|
||||
certificate_password: ${{ secrets.APPLE_APP_DEV_ID_APP_CERTIFICATE_PASSWORD }}
|
||||
|
||||
- name: Package (macOS)
|
||||
if: ${{ runner.os == 'macOS' }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
VERSION='${{ needs.preflight.outputs.package-version }}'
|
||||
APP_BUNDLE="UniGetUI.app"
|
||||
APP_EXECUTABLE="UniGetUI"
|
||||
DRY_RUN='${{ needs.preflight.outputs.dry-run }}'
|
||||
|
||||
rm -rf "${APP_BUNDLE}" output
|
||||
mkdir -p output
|
||||
mkdir -p "${APP_BUNDLE}/Contents/MacOS"
|
||||
mkdir -p "${APP_BUNDLE}/Contents/Resources"
|
||||
|
||||
cp -R "bin/${{ matrix.name }}/." "${APP_BUNDLE}/Contents/MacOS/"
|
||||
find "${APP_BUNDLE}/Contents/MacOS" -name "*.pdb" -type f -delete
|
||||
chmod +x "${APP_BUNDLE}/Contents/MacOS/${APP_EXECUTABLE}"
|
||||
sed "s|@VERSION@|${VERSION}|g" \
|
||||
scripts/macos/Info.plist \
|
||||
> "${APP_BUNDLE}/Contents/Info.plist"
|
||||
# Compile the appearance-aware app icon (Default/Dark/Tinted/Clear) from the Icon Composer
|
||||
# .icon into the bundle: produces Assets.car + AppIcon.icns. Info.plist already declares
|
||||
# CFBundleIconName=AppIcon, so macOS renders the appearance styles itself (incl. when closed).
|
||||
xcrun actool scripts/macos/AppIcon.icon \
|
||||
--compile "${APP_BUNDLE}/Contents/Resources" \
|
||||
--app-icon AppIcon \
|
||||
--output-partial-info-plist "$(mktemp).plist" \
|
||||
--platform macosx \
|
||||
--minimum-deployment-target 12.0 \
|
||||
--errors --warnings
|
||||
# Static .icns fallback for macOS < 26 (CFBundleIconFile) and the dmg volume icon.
|
||||
cp scripts/macos/UniGetUI.icns "${APP_BUNDLE}/Contents/Resources/"
|
||||
|
||||
if [ "$DRY_RUN" = "false" ]; then
|
||||
ENTITLEMENTS="scripts/macos/Entitlements.plist"
|
||||
find "${APP_BUNDLE}/Contents/MacOS" -type f \! -name "${APP_EXECUTABLE}" -print0 \
|
||||
| while IFS= read -r -d '' f; do
|
||||
codesign --force --timestamp --options runtime \
|
||||
--entitlements "$ENTITLEMENTS" \
|
||||
--sign "$SIGNING_IDENTITY" "$f"
|
||||
done
|
||||
codesign --force --timestamp --options runtime \
|
||||
--entitlements "$ENTITLEMENTS" \
|
||||
--sign "$SIGNING_IDENTITY" "${APP_BUNDLE}"
|
||||
codesign --verify --verbose=2 "${APP_BUNDLE}"
|
||||
else
|
||||
find "${APP_BUNDLE}/Contents/MacOS" -type f | while IFS= read -r f; do
|
||||
codesign --force --sign - "$f" 2>/dev/null || true
|
||||
done
|
||||
codesign --force --sign - "${APP_BUNDLE}"
|
||||
fi
|
||||
|
||||
COPYFILE_DISABLE=1 tar -czf "output/UniGetUI.${{ matrix.name }}.tar.gz" "${APP_BUNDLE}"
|
||||
|
||||
create-dmg \
|
||||
--volname "UniGetUI" \
|
||||
--volicon "scripts/macos/UniGetUI.icns" \
|
||||
--window-pos 200 120 \
|
||||
--window-size 600 400 \
|
||||
--icon-size 128 \
|
||||
--icon "UniGetUI.app" 150 185 \
|
||||
--hide-extension "UniGetUI.app" \
|
||||
--app-drop-link 450 185 \
|
||||
"output/UniGetUI.${{ matrix.name }}.dmg" \
|
||||
"${APP_BUNDLE}"
|
||||
|
||||
test -f "output/UniGetUI.${{ matrix.name }}.tar.gz"
|
||||
test -f "output/UniGetUI.${{ matrix.name }}.dmg"
|
||||
|
||||
- name: Sign DMG
|
||||
if: ${{ runner.os == 'macOS' && fromJSON(needs.preflight.outputs.dry-run) == false }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
DMG="output/UniGetUI.${{ matrix.name }}.dmg"
|
||||
codesign --force --timestamp --sign "$SIGNING_IDENTITY" "$DMG"
|
||||
codesign --verify --verbose=2 "$DMG"
|
||||
|
||||
- name: Notarize DMG
|
||||
if: ${{ runner.os == 'macOS' && fromJSON(needs.preflight.outputs.dry-run) == false }}
|
||||
uses: ./.github/workflows/macos-notarize
|
||||
timeout-minutes: 15
|
||||
with:
|
||||
apple_password: ${{ secrets.APPLE_BOT_PASSWORD }}
|
||||
package_path: output/UniGetUI.${{ matrix.name }}.dmg
|
||||
|
||||
- name: Install Linux packaging tools
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y rpm
|
||||
|
||||
- name: Package (Linux)
|
||||
if: runner.os == 'Linux'
|
||||
shell: pwsh
|
||||
run: |
|
||||
$Version = '${{ needs.preflight.outputs.package-version }}'
|
||||
$Parts = $Version -split '-', 2
|
||||
$BaseVersion = $Parts[0]
|
||||
$Prerelease = if ($Parts.Count -gt 1) { $Parts[1] } else { $null }
|
||||
|
||||
# deb: use tilde notation for pre-releases (Ubuntu 18.04+ compatible)
|
||||
$DebVersion = if ($Prerelease) { "${BaseVersion}~${Prerelease}" } else { $Version }
|
||||
# rpm: pre-release encoded in Release/Iteration field (RHEL 8+ / RPM 4.14+)
|
||||
$RpmVersion = $BaseVersion
|
||||
$RpmIteration = if ($Prerelease) { "0.${Prerelease}" } else { '1' }
|
||||
|
||||
# Map .NET RID -> package arch names
|
||||
$DebArch, $RpmArch = switch ('${{ matrix.runtime }}') {
|
||||
'linux-arm64' { 'arm64', 'aarch64' }
|
||||
default { 'amd64', 'x86_64' }
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Force -Path output | Out-Null
|
||||
|
||||
# .tar.gz
|
||||
& tar -czf "output/UniGetUI.${{ matrix.name }}.tar.gz" -C "bin/${{ matrix.name }}" .
|
||||
if ($LASTEXITCODE -ne 0) { exit 1 }
|
||||
|
||||
# .deb — Ubuntu 18.04+ (glibc 2.27, Debian policy 3.9.6)
|
||||
& ./scripts/package-linux.ps1 `
|
||||
-PackageType deb `
|
||||
-SourceDir "bin/${{ matrix.name }}" `
|
||||
-OutputPath "output/UniGetUI.${{ matrix.name }}.deb" `
|
||||
-Version $DebVersion `
|
||||
-Architecture $DebArch
|
||||
|
||||
# .rpm — RHEL 8+ (RPM 4.14, glibc 2.28)
|
||||
& ./scripts/package-linux.ps1 `
|
||||
-PackageType rpm `
|
||||
-SourceDir "bin/${{ matrix.name }}" `
|
||||
-OutputPath "output/UniGetUI.${{ matrix.name }}.rpm" `
|
||||
-Version $RpmVersion `
|
||||
-Iteration $RpmIteration `
|
||||
-Architecture $RpmArch
|
||||
|
||||
- name: Capture artifact sizes
|
||||
shell: pwsh
|
||||
run: |
|
||||
$Name = '${{ matrix.name }}'
|
||||
$Runtime = '${{ matrix.runtime }}'
|
||||
$SizesFile = "output/sizes.$Name.json"
|
||||
$SourceDir = if ('${{ runner.os }}' -eq 'macOS') { "UniGetUI.app/Contents/MacOS" } else { "bin/$Name" }
|
||||
$UncompressedSize = (Get-ChildItem $SourceDir -Recurse -File -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum).Sum
|
||||
$Artifacts = Get-ChildItem "output" -File -ErrorAction SilentlyContinue | Where-Object { $_.Name -ne "sizes.$Name.json" } | ForEach-Object {
|
||||
@{ Name = $_.Name; SizeBytes = $_.Length }
|
||||
}
|
||||
$Report = @{
|
||||
Platform = $Name
|
||||
RuntimeIdentifier = $Runtime
|
||||
UncompressedSizeBytes = $UncompressedSize
|
||||
Artifacts = $Artifacts
|
||||
Timestamp = [DateTimeOffset]::UtcNow.ToString("o")
|
||||
}
|
||||
$Report | ConvertTo-Json -Depth 4 | Set-Content $SizesFile -Encoding UTF8
|
||||
Write-Host "Artifact sizes saved to $SizesFile"
|
||||
Get-Content $SizesFile
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: UniGetUI-${{ matrix.name }}
|
||||
path: output/*
|
||||
|
||||
publish:
|
||||
name: Publish GitHub Release
|
||||
runs-on: ubuntu-latest
|
||||
needs: [preflight, build, build-avalonia]
|
||||
if: ${{ fromJSON(needs.preflight.outputs.skip-publish) == false }}
|
||||
environment: ${{ needs.preflight.outputs.package-env }}
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
path: output
|
||||
|
||||
- name: Add legacy installer filename
|
||||
shell: pwsh
|
||||
working-directory: output
|
||||
run: |
|
||||
$InstallerFiles = Get-ChildItem -Path . -Recurse -File -Filter "UniGetUI.Installer.x64.exe"
|
||||
if (-not $InstallerFiles) {
|
||||
throw "Could not find UniGetUI.Installer.x64.exe in downloaded artifacts"
|
||||
}
|
||||
|
||||
$InstallerFiles | ForEach-Object {
|
||||
$LegacyInstallerPath = Join-Path $_.DirectoryName "UniGetUI.Installer.exe"
|
||||
Copy-Item -Path $_.FullName -Destination $LegacyInstallerPath -Force
|
||||
Write-Host "Created legacy installer alias: $LegacyInstallerPath"
|
||||
}
|
||||
|
||||
- name: Generate consolidated checksums
|
||||
shell: pwsh
|
||||
working-directory: output
|
||||
run: |
|
||||
$ChecksumFile = Join-Path $PWD "checksums.txt"
|
||||
$ChecksumLines = Get-ChildItem -Path . -Recurse -File | Where-Object {
|
||||
$_.Name -notmatch '^checksums(\..+)?\.txt$'
|
||||
} | Sort-Object Name | ForEach-Object {
|
||||
$hash = (Get-FileHash $_.FullName -Algorithm SHA256).Hash
|
||||
"$hash $($_.Name)"
|
||||
}
|
||||
|
||||
Set-Content -Path $ChecksumFile -Value $ChecksumLines -Encoding utf8NoBOM
|
||||
|
||||
echo "::group::checksums"
|
||||
Get-Content $ChecksumFile
|
||||
echo "::endgroup::"
|
||||
|
||||
- name: Generate consolidated size report
|
||||
shell: pwsh
|
||||
working-directory: output
|
||||
run: |
|
||||
$SizeFiles = Get-ChildItem -Path . -Recurse -File -Filter "sizes.*.json" | Sort-Object Name
|
||||
if (-not $SizeFiles) {
|
||||
Write-Host "No size files found."
|
||||
return
|
||||
}
|
||||
|
||||
$Rows = foreach ($file in $SizeFiles) {
|
||||
$data = Get-Content $file.FullName -Raw | ConvertFrom-Json
|
||||
$uncompressedMiB = [math]::Round($data.UncompressedSizeBytes / 1MB, 2)
|
||||
foreach ($artifact in $data.Artifacts) {
|
||||
[PSCustomObject]@{
|
||||
Platform = $data.Platform
|
||||
RID = $data.RuntimeIdentifier
|
||||
Artifact = $artifact.Name
|
||||
CompressedMiB = [math]::Round($artifact.SizeBytes / 1MB, 2)
|
||||
UncompressedMiB = $uncompressedMiB
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$SizeReportFile = Join-Path $PWD "sizes.md"
|
||||
$Lines = @("# UniGetUI Release Artifact Sizes", "")
|
||||
$Lines += $Rows | Format-Table -AutoSize | Out-String -Stream | Where-Object { $_.Trim() -ne '' }
|
||||
Set-Content -Path $SizeReportFile -Value $Lines -Encoding utf8NoBOM
|
||||
|
||||
echo "::group::sizes"
|
||||
Get-Content $SizeReportFile
|
||||
echo "::endgroup::"
|
||||
|
||||
- name: Create GitHub Release
|
||||
shell: pwsh
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
working-directory: output
|
||||
run: |
|
||||
$PackageVersion = '${{ needs.preflight.outputs.package-version }}'
|
||||
$DraftRelease = [System.Boolean]::Parse('${{ needs.preflight.outputs.draft-release }}')
|
||||
$DryRun = [System.Boolean]::Parse('${{ needs.preflight.outputs.dry-run }}')
|
||||
|
||||
echo "::group::checksums"
|
||||
Get-Content "./checksums.txt"
|
||||
echo "::endgroup::"
|
||||
|
||||
$ReleaseTag = "v$PackageVersion"
|
||||
$ReleaseTitle = "UniGetUI v${PackageVersion}"
|
||||
$Repository = $Env:GITHUB_REPOSITORY
|
||||
$DraftArg = if ($DraftRelease) { '--draft' } else { $null }
|
||||
|
||||
$Files = Get-ChildItem -Path . -Recurse -File | Where-Object {
|
||||
$_.Name -eq 'checksums.txt' -or $_.Name -notmatch '^checksums\..+\.txt$'
|
||||
}
|
||||
|
||||
if ($DryRun) {
|
||||
Write-Host "Dry Run: skipping GitHub release creation!"
|
||||
Write-Host "Would create release $ReleaseTag with title '$ReleaseTitle' (draft=$DraftRelease)"
|
||||
$Files | ForEach-Object { Write-Host " - $($_.FullName)" }
|
||||
} else {
|
||||
if ($DraftArg) {
|
||||
& gh release create $ReleaseTag --repo $Repository --title $ReleaseTitle $DraftArg $Files.FullName
|
||||
} else {
|
||||
& gh release create $ReleaseTag --repo $Repository --title $ReleaseTitle $Files.FullName
|
||||
}
|
||||
}
|
||||
|
||||
- name: Check out Devolutions/actions
|
||||
if: ${{ fromJSON(needs.preflight.outputs.dry-run) == false }}
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
repository: Devolutions/actions
|
||||
ref: v1
|
||||
token: ${{ secrets.DEVOLUTIONSBOT_TOKEN }}
|
||||
path: ./.github/workflows
|
||||
|
||||
- name: Install Devolutions Toolbox
|
||||
if: ${{ fromJSON(needs.preflight.outputs.dry-run) == false }}
|
||||
uses: ./.github/workflows/toolbox-install
|
||||
with:
|
||||
github_token: ${{ secrets.DEVOLUTIONSBOT_TOKEN }}
|
||||
|
||||
- name: Stage files for OneDrive upload
|
||||
if: ${{ fromJSON(needs.preflight.outputs.dry-run) == false }}
|
||||
shell: pwsh
|
||||
run: |
|
||||
$PackageVersion = '${{ needs.preflight.outputs.package-version }}'
|
||||
New-Item -Path "onedrive-staging" -ItemType Directory -Force | Out-Null
|
||||
|
||||
$OneDriveVersion = '${{ needs.preflight.outputs.onedrive-version }}'
|
||||
|
||||
$Mappings = @{
|
||||
"output/UniGetUI-release-x64/UniGetUI.Installer.x64.exe" = "Devolutions.UniGetUI.win-x64.$OneDriveVersion.exe"
|
||||
"output/UniGetUI-release-arm64/UniGetUI.Installer.arm64.exe" = "Devolutions.UniGetUI.win-arm64.$OneDriveVersion.exe"
|
||||
"output/UniGetUI-release-x64/UniGetUI.x64.zip" = "Devolutions.UniGetUI.win-x64.$OneDriveVersion.zip"
|
||||
"output/UniGetUI-release-arm64/UniGetUI.arm64.zip" = "Devolutions.UniGetUI.win-arm64.$OneDriveVersion.zip"
|
||||
"output/UniGetUI-macos-x64/UniGetUI.macos-x64.dmg" = "Devolutions.UniGetUI.macos-x64.$OneDriveVersion.dmg"
|
||||
"output/UniGetUI-macos-arm64/UniGetUI.macos-arm64.dmg" = "Devolutions.UniGetUI.macos-arm64.$OneDriveVersion.dmg"
|
||||
"output/UniGetUI-macos-x64/UniGetUI.macos-x64.tar.gz" = "Devolutions.UniGetUI.macos-x64.$OneDriveVersion.tar.gz"
|
||||
"output/UniGetUI-macos-arm64/UniGetUI.macos-arm64.tar.gz" = "Devolutions.UniGetUI.macos-arm64.$OneDriveVersion.tar.gz"
|
||||
"output/UniGetUI-linux-x64/UniGetUI.linux-x64.deb" = "Devolutions.UniGetUI.linux-x64.$OneDriveVersion.deb"
|
||||
"output/UniGetUI-linux-arm64/UniGetUI.linux-arm64.deb" = "Devolutions.UniGetUI.linux-arm64.$OneDriveVersion.deb"
|
||||
"output/UniGetUI-linux-x64/UniGetUI.linux-x64.rpm" = "Devolutions.UniGetUI.linux-x64.$OneDriveVersion.rpm"
|
||||
"output/UniGetUI-linux-arm64/UniGetUI.linux-arm64.rpm" = "Devolutions.UniGetUI.linux-arm64.$OneDriveVersion.rpm"
|
||||
"output/UniGetUI-linux-x64/UniGetUI.linux-x64.tar.gz" = "Devolutions.UniGetUI.linux-x64.$OneDriveVersion.tar.gz"
|
||||
"output/UniGetUI-linux-arm64/UniGetUI.linux-arm64.tar.gz" = "Devolutions.UniGetUI.linux-arm64.$OneDriveVersion.tar.gz"
|
||||
}
|
||||
|
||||
foreach ($entry in $Mappings.GetEnumerator()) {
|
||||
if (-not (Test-Path $entry.Key)) {
|
||||
throw "File not found: $($entry.Key)"
|
||||
}
|
||||
Copy-Item -Path $entry.Key -Destination "onedrive-staging/$($entry.Value)"
|
||||
Write-Host "Staged: $($entry.Key) -> $($entry.Value)"
|
||||
}
|
||||
|
||||
- name: Upload to OneDrive
|
||||
if: ${{ fromJSON(needs.preflight.outputs.dry-run) == false }}
|
||||
uses: ./.github/workflows/onedrive-upload
|
||||
with:
|
||||
azure_client_id: ${{ secrets.ONEDRIVE_AUTOMATION_CLIENT_ID }}
|
||||
azure_client_secret: ${{ secrets.ONEDRIVE_AUTOMATION_CLIENT_SECRET }}
|
||||
conflict_behavior: replace
|
||||
destination_path: /UniGetUI/${{ needs.preflight.outputs.onedrive-version }}
|
||||
remote: releases
|
||||
source_path: Devolutions.UniGetUI.*
|
||||
working_directory: onedrive-staging
|
||||
|
||||
size-report:
|
||||
name: Consolidated Size Report
|
||||
runs-on: ubuntu-latest
|
||||
needs: [preflight, build, build-avalonia]
|
||||
if: always() && needs.build.result != 'cancelled' && needs.build-avalonia.result != 'cancelled'
|
||||
|
||||
steps:
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
path: output
|
||||
|
||||
- name: Generate consolidated size report
|
||||
shell: pwsh
|
||||
working-directory: output
|
||||
run: |
|
||||
$SizeFiles = Get-ChildItem -Path . -Recurse -File -Filter "sizes.*.json" | Sort-Object Name
|
||||
if (-not $SizeFiles) {
|
||||
Write-Host "No size files found."
|
||||
return
|
||||
}
|
||||
|
||||
$Rows = foreach ($file in $SizeFiles) {
|
||||
$data = Get-Content $file.FullName -Raw | ConvertFrom-Json
|
||||
$uncompressedMiB = [math]::Round($data.UncompressedSizeBytes / 1MB, 2)
|
||||
foreach ($artifact in $data.Artifacts) {
|
||||
[PSCustomObject]@{
|
||||
Platform = $data.Platform
|
||||
RID = $data.RuntimeIdentifier
|
||||
Artifact = $artifact.Name
|
||||
CompressedMiB = [math]::Round($artifact.SizeBytes / 1MB, 2)
|
||||
UncompressedMiB = $uncompressedMiB
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$SizeReportFile = Join-Path $PWD "sizes.md"
|
||||
$Lines = @("# UniGetUI Release Artifact Sizes", "")
|
||||
$Lines += $Rows | Format-Table -AutoSize | Out-String -Stream | Where-Object { $_.Trim() -ne '' }
|
||||
Set-Content -Path $SizeReportFile -Value $Lines -Encoding utf8NoBOM
|
||||
|
||||
echo "::group::sizes"
|
||||
Get-Content $SizeReportFile
|
||||
echo "::endgroup::"
|
||||
|
||||
- name: Upload size report
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: UniGetUI-size-report
|
||||
path: output/sizes.md
|
||||
@@ -0,0 +1,179 @@
|
||||
name: CLI Headless E2E
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
paths:
|
||||
- 'src/**/*.cs'
|
||||
- 'src/**/*.csproj'
|
||||
- 'src/**/*.props'
|
||||
- 'src/**/*.targets'
|
||||
- 'src/**/*.sln'
|
||||
- 'src/**/*.slnx'
|
||||
- 'testing/automation/**'
|
||||
- '.github/workflows/cli-headless-e2e.yml'
|
||||
- 'global.json'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
cli-headless-e2e:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- name: Windows (Avalonia)
|
||||
os: windows-latest
|
||||
solution: UniGetUI.Windows.slnx
|
||||
daemon_project: UniGetUI.Avalonia/UniGetUI.Avalonia.csproj
|
||||
daemon_build_args: '-p:Platform=x64'
|
||||
manifest: testing/automation/cli-e2e.manifest.windows.json
|
||||
- name: Windows (NativeAOT)
|
||||
os: windows-latest
|
||||
solution: UniGetUI.Windows.slnx
|
||||
daemon_project: UniGetUI.Avalonia/UniGetUI.Avalonia.csproj
|
||||
daemon_publish_profile: Win-x64-NativeAot
|
||||
daemon_build_args: '-p:Platform=x64'
|
||||
manifest: testing/automation/cli-e2e.manifest.windows.json
|
||||
- name: Linux (Avalonia)
|
||||
os: ubuntu-latest
|
||||
solution: UniGetUI.Avalonia.slnx
|
||||
daemon_project: UniGetUI.Avalonia/UniGetUI.Avalonia.csproj
|
||||
daemon_build_args: ''
|
||||
manifest: testing/automation/cli-e2e.manifest.linux.json
|
||||
- name: Linux (NativeAOT)
|
||||
os: ubuntu-latest
|
||||
solution: UniGetUI.Avalonia.slnx
|
||||
daemon_project: UniGetUI.Avalonia/UniGetUI.Avalonia.csproj
|
||||
daemon_publish_profile: linux-x64-NativeAot
|
||||
daemon_build_args: ''
|
||||
manifest: testing/automation/cli-e2e.manifest.linux-nativeaot.json
|
||||
|
||||
name: ${{ matrix.name }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
CONFIGURATION: Release
|
||||
NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Setup .NET SDK
|
||||
uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.12'
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: '24'
|
||||
|
||||
- name: Cache NuGet packages
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ${{ env.NUGET_PACKAGES }}
|
||||
key: ${{ runner.os }}-nuget-e2e-${{ hashFiles('global.json', 'src/**/*.csproj', 'src/**/*.props', 'src/**/*.targets', 'src/**/*.sln', 'src/**/*.slnx') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-nuget-e2e-
|
||||
|
||||
- name: Restore solution
|
||||
working-directory: src
|
||||
shell: pwsh
|
||||
run: dotnet restore ${{ matrix.solution }}
|
||||
|
||||
- name: Build headless daemon
|
||||
working-directory: src
|
||||
shell: pwsh
|
||||
run: |
|
||||
$PublishProfile = '${{ matrix.daemon_publish_profile }}'
|
||||
$BuildArgs = '${{ matrix.daemon_build_args }}'
|
||||
|
||||
dotnet build-server shutdown
|
||||
|
||||
if ($PublishProfile) {
|
||||
$RuntimeIdentifier = $PublishProfile -replace '-NativeAot$', '' -replace '^Win-', 'win-' -replace '^linux-', 'linux-' -replace '^osx-', 'osx-'
|
||||
$OutputPath = Join-Path (Resolve-Path '..') "artifacts/e2e-nativeaot/$RuntimeIdentifier"
|
||||
New-Item -ItemType Directory -Force -Path $OutputPath | Out-Null
|
||||
|
||||
$args = @(
|
||||
'publish',
|
||||
'${{ matrix.daemon_project }}',
|
||||
'--no-restore',
|
||||
'--configuration',
|
||||
'${{ env.CONFIGURATION }}',
|
||||
'--runtime',
|
||||
$RuntimeIdentifier,
|
||||
'--self-contained',
|
||||
'true',
|
||||
'--output',
|
||||
$OutputPath,
|
||||
'--verbosity',
|
||||
'minimal',
|
||||
'/p:UseSharedCompilation=false',
|
||||
'/m:1',
|
||||
"/p:PublishProfile=$PublishProfile"
|
||||
)
|
||||
if ($BuildArgs) {
|
||||
$args += $BuildArgs
|
||||
}
|
||||
dotnet @args
|
||||
|
||||
$exeName = if ('${{ runner.os }}' -eq 'Windows') { 'UniGetUI.exe' } else { 'UniGetUI' }
|
||||
$daemonExe = Join-Path $OutputPath $exeName
|
||||
if (-not (Test-Path $daemonExe)) {
|
||||
throw "NativeAOT daemon executable was not produced at $daemonExe"
|
||||
}
|
||||
if ('${{ runner.os }}' -ne 'Windows') {
|
||||
chmod +x $daemonExe
|
||||
}
|
||||
echo "UNIGETUI_DAEMON_EXE=$daemonExe" >> $Env:GITHUB_ENV
|
||||
}
|
||||
else {
|
||||
$args = @(
|
||||
'build',
|
||||
'${{ matrix.daemon_project }}',
|
||||
'--no-restore',
|
||||
'--configuration',
|
||||
'${{ env.CONFIGURATION }}',
|
||||
'--verbosity',
|
||||
'minimal',
|
||||
'/p:UseSharedCompilation=false',
|
||||
'/m:1'
|
||||
)
|
||||
if ($BuildArgs) {
|
||||
$args += $BuildArgs
|
||||
}
|
||||
dotnet @args
|
||||
}
|
||||
|
||||
- name: Upgrade pip tooling
|
||||
shell: pwsh
|
||||
run: python -m pip install --upgrade pip setuptools wheel
|
||||
|
||||
- name: Show package-manager inventory
|
||||
shell: pwsh
|
||||
run: |
|
||||
dotnet --version
|
||||
python --version
|
||||
python -m pip --version
|
||||
npm --version
|
||||
|
||||
- name: Run headless CLI E2E
|
||||
shell: pwsh
|
||||
env:
|
||||
UNIGETUI_CLI_E2E_MANIFEST: ${{ matrix.manifest }}
|
||||
UNIGETUI_CLI_E2E_ARTIFACTS: ${{ github.workspace }}/artifacts/cli-headless-e2e/${{ runner.os }}
|
||||
run: ./testing/automation/run-cli-e2e.ps1
|
||||
|
||||
- name: Upload CLI E2E artifacts
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: cli-headless-e2e-${{ matrix.name }}
|
||||
path: artifacts/cli-headless-e2e/${{ runner.os }}
|
||||
if-no-files-found: warn
|
||||
@@ -0,0 +1,90 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * 1'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze (${{ matrix.language }})
|
||||
# Runner size impacts CodeQL analysis time. To learn more, please see:
|
||||
# - https://gh.io/recommended-hardware-resources-for-running-codeql
|
||||
# - https://gh.io/supported-runners-and-hardware-resources
|
||||
# - https://gh.io/using-larger-runners (GitHub.com only)
|
||||
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
|
||||
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
|
||||
timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
|
||||
permissions:
|
||||
# required for all workflows
|
||||
security-events: write
|
||||
|
||||
# required to fetch internal or private CodeQL packs
|
||||
packages: read
|
||||
|
||||
# only required for workflows in private repositories
|
||||
actions: read
|
||||
contents: read
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- language: csharp
|
||||
build-mode: none
|
||||
# CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift'
|
||||
# Use `c-cpp` to analyze code written in C, C++ or both
|
||||
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
|
||||
# Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
|
||||
# To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
|
||||
# see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
|
||||
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
|
||||
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v4
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
build-mode: ${{ matrix.build-mode }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
|
||||
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||
# queries: security-extended,security-and-quality
|
||||
|
||||
# If the analyze step fails for one of the languages you are analyzing with
|
||||
# "We were unable to automatically build your code", modify the matrix above
|
||||
# to set the build mode to "manual" for that language. Then modify this step
|
||||
# to build your code.
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
- if: matrix.build-mode == 'manual'
|
||||
shell: bash
|
||||
run: |
|
||||
echo 'If you are using a "manual" build mode for one or more of the' \
|
||||
'languages you are analyzing, replace this with the commands to build' \
|
||||
'your code, for example:'
|
||||
echo ' make bootstrap'
|
||||
echo ' make release'
|
||||
exit 1
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v4
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
@@ -0,0 +1,115 @@
|
||||
name: .NET Tests
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
paths:
|
||||
- 'global.json'
|
||||
- '**.cs'
|
||||
- '**.axaml'
|
||||
- '**.csproj'
|
||||
- '**.props'
|
||||
- '**.targets'
|
||||
- '**.sln'
|
||||
- '**.slnx'
|
||||
- 'src/.editorconfig'
|
||||
- '.github/workflows/dotnet-test.yml'
|
||||
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
paths:
|
||||
- 'global.json'
|
||||
- '**.cs'
|
||||
- '**.axaml'
|
||||
- '**.csproj'
|
||||
- '**.props'
|
||||
- '**.targets'
|
||||
- '**.sln'
|
||||
- '**.slnx'
|
||||
- 'src/.editorconfig'
|
||||
- '.github/workflows/dotnet-test.yml'
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
test-codebase:
|
||||
runs-on: windows-latest
|
||||
env:
|
||||
NUGET_PACKAGES: ${{ github.workspace }}\.nuget\packages
|
||||
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install .NET SDK
|
||||
uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
- name: Cache NuGet packages
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ${{ env.NUGET_PACKAGES }}
|
||||
key: ${{ runner.os }}-nuget-${{ hashFiles('global.json', 'src/**/*.csproj', 'src/**/*.props', 'src/**/*.targets', 'src/**/*.sln', 'src/**/*.slnx') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-nuget-
|
||||
|
||||
- name: Install dependencies
|
||||
working-directory: src
|
||||
run: dotnet restore UniGetUI.Windows.slnx
|
||||
|
||||
- name: Check whitespace formatting
|
||||
run: dotnet format whitespace src --folder --verify-no-changes --verbosity minimal
|
||||
|
||||
- name: Check code style formatting (Avalonia Windows solution)
|
||||
working-directory: src
|
||||
run: dotnet format style UniGetUI.Windows.slnx --no-restore --verify-no-changes --verbosity minimal
|
||||
|
||||
- name: Build Avalonia Windows solution
|
||||
working-directory: src
|
||||
run: |
|
||||
dotnet build-server shutdown
|
||||
dotnet build UniGetUI.Windows.slnx --no-restore --verbosity minimal /p:Platform=x64 /p:UseSharedCompilation=false /m:1
|
||||
|
||||
- name: Run Tests
|
||||
working-directory: src
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
run: dotnet test UniGetUI.Windows.slnx --no-restore --verbosity q --nologo /p:Platform=x64 /p:UseSharedCompilation=false /m:1
|
||||
|
||||
- name: Report full-trim publish warnings
|
||||
working-directory: src
|
||||
shell: pwsh
|
||||
continue-on-error: true
|
||||
run: |
|
||||
dotnet build-server shutdown
|
||||
dotnet publish UniGetUI.Avalonia/UniGetUI.Avalonia.csproj `
|
||||
--no-restore `
|
||||
--configuration Release `
|
||||
--runtime win-x64 `
|
||||
--self-contained true `
|
||||
--output "${{ runner.temp }}\unigetui-full-trim-publish" `
|
||||
/p:Platform=x64 `
|
||||
/p:TrimMode=full `
|
||||
/p:TrimmerSingleWarn=false `
|
||||
/p:UseSharedCompilation=false `
|
||||
--verbosity minimal
|
||||
|
||||
- name: Report NativeAOT publish warnings
|
||||
working-directory: src
|
||||
shell: pwsh
|
||||
run: |
|
||||
dotnet build-server shutdown
|
||||
dotnet publish UniGetUI.Avalonia/UniGetUI.Avalonia.csproj `
|
||||
--no-restore `
|
||||
--configuration Release `
|
||||
--runtime win-x64 `
|
||||
--self-contained true `
|
||||
--output "${{ runner.temp }}\unigetui-nativeaot-publish" `
|
||||
/m:1 `
|
||||
/p:Platform=x64 `
|
||||
/p:PublishProfile=Win-x64-NativeAot `
|
||||
/p:TrimmerSingleWarn=false `
|
||||
/p:UseSharedCompilation=false `
|
||||
--verbosity minimal
|
||||
@@ -0,0 +1,44 @@
|
||||
name: Translation Validation
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
paths:
|
||||
- 'scripts/translation/**'
|
||||
- '.agents/skills/translation-*/scripts/**'
|
||||
- 'src/Languages/**'
|
||||
- 'src/Languages/Data/LanguagesReference.json'
|
||||
- 'src/Languages/Data/TranslatedPercentages.json'
|
||||
- 'src/Languages/Data/Translators.json'
|
||||
- 'src/UniGetUI.Core.Data/Assets/Data/Contributors.list'
|
||||
- '.github/workflows/translation-validation.yml'
|
||||
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
paths:
|
||||
- 'scripts/translation/**'
|
||||
- '.agents/skills/translation-*/scripts/**'
|
||||
- 'src/Languages/**'
|
||||
- 'src/Languages/Data/LanguagesReference.json'
|
||||
- 'src/Languages/Data/TranslatedPercentages.json'
|
||||
- 'src/Languages/Data/Translators.json'
|
||||
- 'src/UniGetUI.Core.Data/Assets/Data/Contributors.list'
|
||||
- '.github/workflows/translation-validation.yml'
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
validate-translations:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Validate translation file structure
|
||||
shell: pwsh
|
||||
run: pwsh ./scripts/translation/Verify-Translations.ps1
|
||||
|
||||
- name: Validate boundary alignment
|
||||
shell: pwsh
|
||||
run: pwsh ./scripts/translation/Set-TranslationBoundaryOrder.ps1 -CheckOnly
|
||||
Reference in New Issue
Block a user