ci: build Windows Store release artifacts
56
packaging/windows/AppxManifest.xml
Normal file
@@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Package
|
||||
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||
xmlns:uap10="http://schemas.microsoft.com/appx/manifest/uap/windows10/10"
|
||||
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||
IgnorableNamespaces="uap uap10 rescap">
|
||||
<Identity
|
||||
Name="SudosyLabs.Vnidrop"
|
||||
Publisher="CN=6456DC8E-2C31-44BD-AACC-2E6813C833CB"
|
||||
Version="__VERSION__"
|
||||
ProcessorArchitecture="x64" />
|
||||
<Properties>
|
||||
<DisplayName>Vnidrop</DisplayName>
|
||||
<PublisherDisplayName>Sudosy Labs</PublisherDisplayName>
|
||||
<Description>Send files directly across your devices.</Description>
|
||||
<Logo>Assets\StoreLogo.png</Logo>
|
||||
</Properties>
|
||||
<Resources>
|
||||
<Resource Language="en-US" />
|
||||
</Resources>
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily
|
||||
Name="Windows.Desktop"
|
||||
MinVersion="10.0.19041.0"
|
||||
MaxVersionTested="10.0.26100.0" />
|
||||
</Dependencies>
|
||||
<Capabilities>
|
||||
<rescap:Capability Name="runFullTrust" />
|
||||
</Capabilities>
|
||||
<Applications>
|
||||
<Application
|
||||
Id="VniDrop"
|
||||
Executable="VniDrop.exe"
|
||||
uap10:RuntimeBehavior="packagedClassicApp"
|
||||
uap10:TrustLevel="mediumIL">
|
||||
<uap:VisualElements
|
||||
DisplayName="Vnidrop"
|
||||
Description="Send files directly across your devices."
|
||||
Square150x150Logo="Assets\Square150x150Logo.png"
|
||||
Square44x44Logo="Assets\Square44x44Logo.png"
|
||||
BackgroundColor="transparent" />
|
||||
<Extensions>
|
||||
<uap:Extension Category="windows.fileTypeAssociation">
|
||||
<uap:FileTypeAssociation Name="vnidropinvitation">
|
||||
<uap:DisplayName>VniDrop Invitation</uap:DisplayName>
|
||||
<uap:Logo>Assets\Square44x44Logo.png</uap:Logo>
|
||||
<uap:SupportedFileTypes>
|
||||
<uap:FileType>.vnd</uap:FileType>
|
||||
</uap:SupportedFileTypes>
|
||||
</uap:FileTypeAssociation>
|
||||
</uap:Extension>
|
||||
</Extensions>
|
||||
</Application>
|
||||
</Applications>
|
||||
</Package>
|
||||
BIN
packaging/windows/Assets/Square150x150Logo.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
packaging/windows/Assets/Square44x44Logo.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
BIN
packaging/windows/Assets/StoreLogo.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
105
packaging/windows/README.md
Normal file
@@ -0,0 +1,105 @@
|
||||
# Windows Microsoft Store packaging
|
||||
|
||||
This directory turns the Compose Desktop Windows app image into the unsigned
|
||||
MSIX artifacts accepted by Partner Center. Microsoft signs the package after
|
||||
certification, so this build does not use a PFX, certificate, HSM, or signing
|
||||
secret.
|
||||
|
||||
## Product identity
|
||||
|
||||
These values came from the Partner Center Product identity page and are
|
||||
case-sensitive:
|
||||
|
||||
| Field | Value |
|
||||
| --- | --- |
|
||||
| Package identity name | SudosyLabs.Vnidrop |
|
||||
| Publisher | CN=6456DC8E-2C31-44BD-AACC-2E6813C833CB |
|
||||
| Publisher display name | Sudosy Labs |
|
||||
| Reserved Store name | Vnidrop |
|
||||
| Application ID | VniDrop |
|
||||
| Store ID | 9NJ5Q0FG7TGL |
|
||||
|
||||
The package identity name, publisher, and Application ID must remain stable
|
||||
after the first release. The manifest display name uses the exact reserved Store
|
||||
name; the product's in-app branding and launcher remain `VniDrop`.
|
||||
|
||||
The initial package targets Windows Desktop x64, Windows 10 version 2004
|
||||
(build 19041) or later. The fourth MSIX version component is reserved by the
|
||||
Store, so app version 1.2.3 becomes package version 1.2.3.0.
|
||||
|
||||
## GitHub Actions
|
||||
|
||||
The Windows Store package workflow runs automatically for relevant pull
|
||||
requests, for release tags matching vMAJOR.MINOR.PATCH, and by manual dispatch.
|
||||
Pull requests build and validate without retaining an artifact. Tags and manual
|
||||
runs retain:
|
||||
|
||||
- VniDrop_VERSION_x64.msix
|
||||
- VniDrop_VERSION_x64.msixupload
|
||||
- build metadata
|
||||
- SHA-256 checksums
|
||||
|
||||
The preferred Partner Center upload is the msixupload file. It is an upload
|
||||
envelope containing the x64 MSIX. The MSIX is intentionally unsigned and is not
|
||||
a public sideloading artifact. Do not attach it to a public GitHub Release
|
||||
unless an independent production-signing path is added.
|
||||
|
||||
The workflow explicitly selects Gobley's release Rust variant and rejects a
|
||||
package containing the debug native JAR. It also verifies the bundled JVM,
|
||||
vnidrop.dll, app version, manifest identity, architecture, and launcher after
|
||||
MakeAppx unpacks the finished package.
|
||||
|
||||
## First Store release
|
||||
|
||||
Microsoft's current GitHub Actions publishing flow is for updates to an
|
||||
already-live free product. For the first release:
|
||||
|
||||
1. Run this workflow from a release tag or by manual dispatch.
|
||||
2. Download the retained artifact.
|
||||
3. Test that exact build on an interactive Windows VM. Local installation needs
|
||||
an ephemeral development signature trusted only by that VM; this is not a
|
||||
production signing key.
|
||||
4. Upload the msixupload file to the current Partner Center draft.
|
||||
5. Confirm that Partner Center parses the expected identity, version, x64
|
||||
architecture, Windows.Desktop target, en-US language, and runFullTrust
|
||||
capability.
|
||||
6. Complete listing, screenshots, certification notes, and submit.
|
||||
|
||||
Use this restricted-capability justification in Submission options:
|
||||
|
||||
> VniDrop is a classic JVM desktop application that loads its bundled native
|
||||
> Rust and JVM libraries and needs normal user-level filesystem and network
|
||||
> access to transfer user-selected files directly between devices.
|
||||
|
||||
After the first release is certified and live, Store publication can be added
|
||||
as a separate protected job. Keep its Partner Center credentials in a GitHub
|
||||
Environment, not in this build job:
|
||||
|
||||
- AZURE_AD_TENANT_ID
|
||||
- AZURE_AD_APPLICATION_CLIENT_ID
|
||||
- AZURE_AD_APPLICATION_SECRET
|
||||
- SELLER_ID
|
||||
|
||||
The Store ID is a non-secret variable.
|
||||
|
||||
## Manual build on Windows
|
||||
|
||||
From the repository root:
|
||||
|
||||
~~~powershell
|
||||
.\gradlew.bat :shared:jvmTest :desktopApp:createReleaseDistributable -Pvnidrop.version=1.0.0 -Pvnidrop.desktop.rustVariant=release -Pvnidrop.diagnostics.included=false --no-daemon --no-configuration-cache --stacktrace
|
||||
|
||||
.\packaging\windows\build-msix.ps1 -Version 1.0.0 -AppImage .\desktopApp\build\compose\binaries\main-release\app\VniDrop -OutputDirectory .\build\release\windows
|
||||
~~~
|
||||
|
||||
The packaging script requires Windows SDK 10.0.26100.0. It uses MakePri to
|
||||
index the scale-qualified visual assets, then MakeAppx with SHA-256 block maps
|
||||
and manifest validation enabled.
|
||||
|
||||
Microsoft references:
|
||||
|
||||
- [MSIX Store package requirements](https://learn.microsoft.com/en-us/windows/apps/publish/publish-your-app/msix/app-package-requirements)
|
||||
- [Manual desktop MSIX packaging](https://learn.microsoft.com/en-us/windows/msix/desktop/desktop-to-uwp-manual-conversion)
|
||||
- [MakeAppx](https://learn.microsoft.com/en-us/windows/msix/package/create-app-package-with-makeappx-tool)
|
||||
- [Uploading MSIX packages](https://learn.microsoft.com/en-us/windows/apps/publish/publish-your-app/msix/upload-app-packages)
|
||||
- [GitHub Actions Store updates](https://learn.microsoft.com/en-us/windows/apps/publish/msstore-dev-cli/github-actions)
|
||||
280
packaging/windows/build-msix.ps1
Normal file
@@ -0,0 +1,280 @@
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[string] $Version,
|
||||
|
||||
[Parameter(Mandatory)]
|
||||
[string] $AppImage,
|
||||
|
||||
[Parameter(Mandatory)]
|
||||
[string] $OutputDirectory,
|
||||
|
||||
[string] $WindowsSdkVersion = "10.0.26100.0"
|
||||
)
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = "Stop"
|
||||
$ProgressPreference = "SilentlyContinue"
|
||||
|
||||
function Assert-Condition {
|
||||
param(
|
||||
[bool] $Condition,
|
||||
[string] $Message
|
||||
)
|
||||
|
||||
if (-not $Condition) {
|
||||
throw $Message
|
||||
}
|
||||
}
|
||||
|
||||
function Invoke-Checked {
|
||||
param(
|
||||
[string] $FilePath,
|
||||
[string[]] $Arguments
|
||||
)
|
||||
|
||||
& $FilePath @Arguments
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "$FilePath failed with exit code $LASTEXITCODE"
|
||||
}
|
||||
}
|
||||
|
||||
function Read-ZipEntry {
|
||||
param(
|
||||
[string] $ArchivePath,
|
||||
[string] $EntryPath
|
||||
)
|
||||
|
||||
$archive = [System.IO.Compression.ZipFile]::OpenRead($ArchivePath)
|
||||
try {
|
||||
$entry = $archive.GetEntry($EntryPath)
|
||||
if ($null -eq $entry) {
|
||||
throw "$ArchivePath does not contain $EntryPath"
|
||||
}
|
||||
$reader = [System.IO.StreamReader]::new($entry.Open())
|
||||
try {
|
||||
return $reader.ReadToEnd()
|
||||
}
|
||||
finally {
|
||||
$reader.Dispose()
|
||||
}
|
||||
}
|
||||
finally {
|
||||
$archive.Dispose()
|
||||
}
|
||||
}
|
||||
|
||||
function Get-ZipEntryLength {
|
||||
param(
|
||||
[string] $ArchivePath,
|
||||
[string] $EntryPath
|
||||
)
|
||||
|
||||
$archive = [System.IO.Compression.ZipFile]::OpenRead($ArchivePath)
|
||||
try {
|
||||
$entry = $archive.GetEntry($EntryPath)
|
||||
if ($null -eq $entry) {
|
||||
throw "$ArchivePath does not contain $EntryPath"
|
||||
}
|
||||
return $entry.Length
|
||||
}
|
||||
finally {
|
||||
$archive.Dispose()
|
||||
}
|
||||
}
|
||||
|
||||
if ([System.Environment]::OSVersion.Platform -ne [System.PlatformID]::Win32NT) {
|
||||
throw "MSIX packaging must run on Windows"
|
||||
}
|
||||
|
||||
$versionParts = $Version.Split(".")
|
||||
Assert-Condition ($versionParts.Count -eq 3) "Version must use MAJOR.MINOR.PATCH"
|
||||
for ($index = 0; $index -lt $versionParts.Count; $index++) {
|
||||
$part = $versionParts[$index]
|
||||
$number = 0
|
||||
Assert-Condition ([int]::TryParse($part, [ref] $number)) "Version components must be integers"
|
||||
Assert-Condition ($number.ToString() -eq $part) "Version components must not contain leading zeroes"
|
||||
Assert-Condition ($number -ge $(if ($index -eq 0) { 1 } else { 0 }) -and $number -le 65535) "Version components must be between 0 and 65535, with a non-zero major"
|
||||
}
|
||||
$packageVersion = "$Version.0"
|
||||
|
||||
$appImagePath = (Resolve-Path -LiteralPath $AppImage).Path
|
||||
Assert-Condition (Test-Path -LiteralPath $appImagePath -PathType Container) "App image not found: $AppImage"
|
||||
Assert-Condition (Test-Path -LiteralPath (Join-Path $appImagePath "VniDrop.exe") -PathType Leaf) "The app image does not contain VniDrop.exe"
|
||||
Assert-Condition (Test-Path -LiteralPath (Join-Path $appImagePath "runtime\bin\server\jvm.dll") -PathType Leaf) "The app image does not contain its bundled JVM"
|
||||
|
||||
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
||||
$appFiles = @(Get-ChildItem -LiteralPath $appImagePath -Recurse -File)
|
||||
$debugRustJars = @($appFiles | Where-Object { $_.Name -match "^shared-win32-x86-64-debug-.+\.jar$" })
|
||||
Assert-Condition ($debugRustJars.Count -eq 0) "The app image contains a debug Rust runtime JAR"
|
||||
$releaseRustJars = @($appFiles | Where-Object { $_.Name -match "^shared-win32-x86-64-(?!debug-).+\.jar$" })
|
||||
Assert-Condition ($releaseRustJars.Count -eq 1) "Expected exactly one release Rust runtime JAR"
|
||||
$nativeDllLength = Get-ZipEntryLength -ArchivePath $releaseRustJars[0].FullName -EntryPath "win32-x86-64/vnidrop.dll"
|
||||
Assert-Condition ($nativeDllLength -gt 0) "The release Rust runtime JAR contains an empty vnidrop.dll"
|
||||
|
||||
$sharedJars = @($appFiles | Where-Object { $_.Name -match "^shared-jvm-.+\.jar$" })
|
||||
Assert-Condition ($sharedJars.Count -eq 1) "Expected exactly one shared JVM JAR"
|
||||
$sharedManifest = Read-ZipEntry -ArchivePath $sharedJars[0].FullName -EntryPath "META-INF/MANIFEST.MF"
|
||||
Assert-Condition ($sharedManifest -match "(?m)^Implementation-Version: $([regex]::Escape($Version))\r?$") "The packaged app version does not match $Version"
|
||||
|
||||
$programFilesX86 = [System.Environment]::GetFolderPath([System.Environment+SpecialFolder]::ProgramFilesX86)
|
||||
$makeAppxPath = Join-Path $programFilesX86 "Windows Kits\10\bin\$WindowsSdkVersion\x64\MakeAppx.exe"
|
||||
$makePriPath = Join-Path $programFilesX86 "Windows Kits\10\bin\$WindowsSdkVersion\x64\MakePri.exe"
|
||||
Assert-Condition (Test-Path -LiteralPath $makeAppxPath -PathType Leaf) "MakeAppx.exe from Windows SDK $WindowsSdkVersion was not found"
|
||||
Assert-Condition (Test-Path -LiteralPath $makePriPath -PathType Leaf) "MakePri.exe from Windows SDK $WindowsSdkVersion was not found"
|
||||
|
||||
$outputPath = [System.IO.Path]::GetFullPath($OutputDirectory)
|
||||
[System.IO.Directory]::CreateDirectory($outputPath) | Out-Null
|
||||
$artifactBaseName = "VniDrop_" + $Version + "_x64"
|
||||
$msixPath = Join-Path $outputPath "$artifactBaseName.msix"
|
||||
$uploadPath = Join-Path $outputPath "$artifactBaseName.msixupload"
|
||||
$buildInfoPath = Join-Path $outputPath "$artifactBaseName.build-info.json"
|
||||
$checksumsPath = Join-Path $outputPath "SHA256SUMS"
|
||||
@($msixPath, $uploadPath, $buildInfoPath, $checksumsPath) |
|
||||
Where-Object { Test-Path -LiteralPath $_ } |
|
||||
ForEach-Object { Remove-Item -LiteralPath $_ -Force }
|
||||
|
||||
$stageRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("vnidrop-msix-" + [System.Guid]::NewGuid().ToString("N"))
|
||||
$packageRoot = Join-Path $stageRoot "package"
|
||||
$unpackedRoot = Join-Path $stageRoot "unpacked"
|
||||
$priConfigPath = Join-Path $stageRoot "priconfig.xml"
|
||||
[System.IO.Directory]::CreateDirectory($packageRoot) | Out-Null
|
||||
|
||||
try {
|
||||
Get-ChildItem -LiteralPath $appImagePath -Force | Copy-Item -Destination $packageRoot -Recurse -Force
|
||||
Copy-Item -LiteralPath (Join-Path $PSScriptRoot "Assets") -Destination $packageRoot -Recurse -Force
|
||||
|
||||
$manifestTemplate = Get-Content -LiteralPath (Join-Path $PSScriptRoot "AppxManifest.xml") -Raw
|
||||
Assert-Condition (([regex]::Matches($manifestTemplate, "__VERSION__")).Count -eq 1) "AppxManifest.xml must contain exactly one __VERSION__ placeholder"
|
||||
$manifestText = $manifestTemplate.Replace("__VERSION__", $packageVersion)
|
||||
[System.IO.File]::WriteAllText(
|
||||
(Join-Path $packageRoot "AppxManifest.xml"),
|
||||
$manifestText,
|
||||
[System.Text.UTF8Encoding]::new($false)
|
||||
)
|
||||
|
||||
Invoke-Checked -FilePath $makePriPath -Arguments @(
|
||||
"createconfig",
|
||||
"/cf", $priConfigPath,
|
||||
"/dq", "en-US",
|
||||
"/o"
|
||||
)
|
||||
Invoke-Checked -FilePath $makePriPath -Arguments @(
|
||||
"new",
|
||||
"/pr", $packageRoot,
|
||||
"/cf", $priConfigPath,
|
||||
"/mn", (Join-Path $packageRoot "AppxManifest.xml"),
|
||||
"/of", (Join-Path $packageRoot "resources.pri"),
|
||||
"/o"
|
||||
)
|
||||
Assert-Condition ((Get-Item -LiteralPath (Join-Path $packageRoot "resources.pri")).Length -gt 0) "MakePri created an empty resources.pri"
|
||||
|
||||
Invoke-Checked -FilePath $makeAppxPath -Arguments @(
|
||||
"pack",
|
||||
"/v",
|
||||
"/h", "SHA256",
|
||||
"/d", $packageRoot,
|
||||
"/p", $msixPath,
|
||||
"/o"
|
||||
)
|
||||
Invoke-Checked -FilePath $makeAppxPath -Arguments @(
|
||||
"unpack",
|
||||
"/v",
|
||||
"/p", $msixPath,
|
||||
"/d", $unpackedRoot,
|
||||
"/o"
|
||||
)
|
||||
|
||||
[xml] $manifest = Get-Content -LiteralPath (Join-Path $unpackedRoot "AppxManifest.xml") -Raw
|
||||
$namespaces = [System.Xml.XmlNamespaceManager]::new($manifest.NameTable)
|
||||
$namespaces.AddNamespace("f", "http://schemas.microsoft.com/appx/manifest/foundation/windows10")
|
||||
$namespaces.AddNamespace("uap", "http://schemas.microsoft.com/appx/manifest/uap/windows10")
|
||||
$namespaces.AddNamespace("uap10", "http://schemas.microsoft.com/appx/manifest/uap/windows10/10")
|
||||
$namespaces.AddNamespace("rescap", "http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities")
|
||||
$identity = $manifest.SelectSingleNode("/f:Package/f:Identity", $namespaces)
|
||||
Assert-Condition ($null -ne $identity) "The packed manifest has no Identity"
|
||||
Assert-Condition ($identity.GetAttribute("Name") -eq "SudosyLabs.Vnidrop") "The packed package identity name is incorrect"
|
||||
Assert-Condition ($identity.GetAttribute("Publisher") -eq "CN=6456DC8E-2C31-44BD-AACC-2E6813C833CB") "The packed publisher identity is incorrect"
|
||||
Assert-Condition ($identity.GetAttribute("Version") -eq $packageVersion) "The packed package version is incorrect"
|
||||
Assert-Condition ($identity.GetAttribute("ProcessorArchitecture") -eq "x64") "The packed package architecture is not x64"
|
||||
Assert-Condition ($manifest.SelectSingleNode("/f:Package/f:Properties/f:DisplayName", $namespaces).InnerText -eq "Vnidrop") "The packed display name does not match the reserved Store name"
|
||||
Assert-Condition ($manifest.SelectSingleNode("/f:Package/f:Properties/f:PublisherDisplayName", $namespaces).InnerText -eq "Sudosy Labs") "The packed publisher display name is incorrect"
|
||||
$targetFamily = $manifest.SelectSingleNode("/f:Package/f:Dependencies/f:TargetDeviceFamily", $namespaces)
|
||||
Assert-Condition ($null -ne $targetFamily) "The packed manifest has no target device family"
|
||||
Assert-Condition ($targetFamily.GetAttribute("Name") -eq "Windows.Desktop") "The packed package does not target Windows.Desktop"
|
||||
Assert-Condition ($null -ne $manifest.SelectSingleNode("/f:Package/f:Capabilities/rescap:Capability[@Name='runFullTrust']", $namespaces)) "The packed package does not declare runFullTrust"
|
||||
|
||||
$application = $manifest.SelectSingleNode("/f:Package/f:Applications/f:Application", $namespaces)
|
||||
Assert-Condition ($null -ne $application) "The packed manifest has no Application"
|
||||
Assert-Condition ($application.GetAttribute("Id") -eq "VniDrop") "The packed application ID is incorrect"
|
||||
$executable = $application.GetAttribute("Executable")
|
||||
Assert-Condition ($executable -eq "VniDrop.exe") "The packed manifest executable is incorrect"
|
||||
Assert-Condition ($application.GetAttribute("RuntimeBehavior", "http://schemas.microsoft.com/appx/manifest/uap/windows10/10") -eq "packagedClassicApp") "The packed runtime behavior is incorrect"
|
||||
Assert-Condition ($application.GetAttribute("TrustLevel", "http://schemas.microsoft.com/appx/manifest/uap/windows10/10") -eq "mediumIL") "The packed trust level is incorrect"
|
||||
Assert-Condition ($manifest.SelectSingleNode("/f:Package/f:Applications/f:Application/f:Extensions/uap:Extension/uap:FileTypeAssociation/uap:SupportedFileTypes/uap:FileType[text()='.vnd']", $namespaces) -ne $null) "The packed package is missing the .vnd file association"
|
||||
Assert-Condition (Test-Path -LiteralPath (Join-Path $unpackedRoot $executable) -PathType Leaf) "The packed executable is missing"
|
||||
Assert-Condition (Test-Path -LiteralPath (Join-Path $unpackedRoot "resources.pri") -PathType Leaf) "The packed resource index is missing"
|
||||
}
|
||||
finally {
|
||||
if (Test-Path -LiteralPath $stageRoot) {
|
||||
Remove-Item -LiteralPath $stageRoot -Recurse -Force
|
||||
}
|
||||
}
|
||||
|
||||
$temporaryZip = Join-Path $outputPath "$artifactBaseName.zip"
|
||||
if (Test-Path -LiteralPath $temporaryZip) {
|
||||
Remove-Item -LiteralPath $temporaryZip -Force
|
||||
}
|
||||
Compress-Archive -LiteralPath $msixPath -DestinationPath $temporaryZip -CompressionLevel Optimal
|
||||
Move-Item -LiteralPath $temporaryZip -Destination $uploadPath
|
||||
|
||||
$repoRoot = (Resolve-Path -LiteralPath (Join-Path $PSScriptRoot "..\..")).Path
|
||||
$wrapperProperties = Get-Content -LiteralPath (Join-Path $repoRoot "gradle\wrapper\gradle-wrapper.properties")
|
||||
$gradleDistribution = $wrapperProperties | Where-Object { $_.StartsWith("distributionUrl=") } | Select-Object -First 1
|
||||
$sourceCommit = [System.Environment]::GetEnvironmentVariable("GITHUB_SHA")
|
||||
if ([string]::IsNullOrWhiteSpace($sourceCommit)) {
|
||||
$sourceCommit = "local"
|
||||
}
|
||||
$sourceRef = [System.Environment]::GetEnvironmentVariable("GITHUB_REF")
|
||||
if ([string]::IsNullOrWhiteSpace($sourceRef)) {
|
||||
$sourceRef = "local"
|
||||
}
|
||||
|
||||
$buildInfo = [ordered] @{
|
||||
appVersion = $Version
|
||||
packageVersion = $packageVersion
|
||||
architecture = "x64"
|
||||
identityName = "SudosyLabs.Vnidrop"
|
||||
publisher = "CN=6456DC8E-2C31-44BD-AACC-2E6813C833CB"
|
||||
storeId = "9NJ5Q0FG7TGL"
|
||||
sourceCommit = $sourceCommit
|
||||
sourceRef = $sourceRef
|
||||
runnerImage = [System.Environment]::GetEnvironmentVariable("ImageOS")
|
||||
runnerImageVersion = [System.Environment]::GetEnvironmentVariable("ImageVersion")
|
||||
javaVersion = ((& java --version | Select-Object -First 1) | Out-String).Trim()
|
||||
rustVersion = ((& rustc --version) | Out-String).Trim()
|
||||
cargoVersion = ((& cargo --version) | Out-String).Trim()
|
||||
gradleDistribution = $gradleDistribution
|
||||
windowsSdkVersion = $WindowsSdkVersion
|
||||
makeAppxVersion = (Get-Item -LiteralPath $makeAppxPath).VersionInfo.FileVersion
|
||||
makePriVersion = (Get-Item -LiteralPath $makePriPath).VersionInfo.FileVersion
|
||||
unsignedForMicrosoftStore = $true
|
||||
builtAtUtc = [System.DateTimeOffset]::UtcNow.ToString("O")
|
||||
}
|
||||
[System.IO.File]::WriteAllText(
|
||||
$buildInfoPath,
|
||||
($buildInfo | ConvertTo-Json -Depth 4),
|
||||
[System.Text.UTF8Encoding]::new($false)
|
||||
)
|
||||
|
||||
$checksumTargets = @($msixPath, $uploadPath, $buildInfoPath)
|
||||
[string[]] $checksumLines = $checksumTargets | ForEach-Object {
|
||||
$hash = Get-FileHash -LiteralPath $_ -Algorithm SHA256
|
||||
$hash.Hash.ToLowerInvariant() + " " + [System.IO.Path]::GetFileName($_)
|
||||
}
|
||||
[System.IO.File]::WriteAllLines($checksumsPath, $checksumLines, [System.Text.Encoding]::ASCII)
|
||||
|
||||
Write-Host "Created unsigned Microsoft Store artifacts:"
|
||||
Write-Host " $msixPath"
|
||||
Write-Host " $uploadPath"
|
||||
Write-Host " $checksumsPath"
|
||||