diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..2c93b88 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,114 @@ +name: CI + +on: + push: + tags-ignore: + - 'v*' + pull_request: + workflow_dispatch: + +permissions: + contents: read + +env: + DOTNET_NOLOGO: true + CARGO_TERM_COLOR: always + +jobs: + rust-lint: + name: Rust Lint + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Setup Rust + shell: bash + run: | + rustup toolchain install stable --profile minimal + rustup component add rustfmt clippy --toolchain stable + rustup default stable + + - name: Check formatting + run: cargo fmt --manifest-path rust/Cargo.toml --all --check + + - name: Run clippy + run: cargo clippy -q --manifest-path rust/Cargo.toml --workspace --tests -- -D warnings + + rust-build: + name: Rust Build (${{ matrix.os }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: + - ubuntu-latest + - windows-latest + + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Setup Rust on Linux + if: runner.os != 'Windows' + shell: bash + run: | + rustup toolchain install stable --profile minimal + rustup default stable + + - name: Setup Rust on Windows + if: runner.os == 'Windows' + shell: pwsh + run: | + rustup toolchain install stable --profile minimal + rustup default stable + + - name: Test pinget-core + run: cargo test -p pinget-core --manifest-path rust/Cargo.toml + + - name: Test pinget-cli + run: cargo test -p pinget-cli --manifest-path rust/Cargo.toml + + - name: Build pinget-cli + run: cargo build -p pinget-cli --manifest-path rust/Cargo.toml + + dotnet: + name: Dotnet Build + runs-on: windows-latest + + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Setup .NET + uses: actions/setup-dotnet@v5 + with: + dotnet-version: 10.0.x + + - name: Install Pester + shell: pwsh + run: | + Set-PSRepository PSGallery -InstallationPolicy Trusted + Install-Module Pester -Scope CurrentUser -Force -SkipPublisherCheck + + - name: Restore solution + run: dotnet restore dotnet/Devolutions.Pinget.slnx + + - name: Build solution + run: dotnet build dotnet/Devolutions.Pinget.slnx -c Release --no-restore + + - name: Run core tests + run: dotnet test dotnet/src/Devolutions.Pinget.Core.Tests/Devolutions.Pinget.Core.Tests.csproj -c Release --no-build + + - name: Run PowerShell tests + shell: pwsh + run: pwsh -NoLogo -NoProfile -File (Resolve-Path 'dotnet/tests/RunTests.ps1') + + - name: Validate NuGet packing + shell: pwsh + run: | + New-Item -Path artifacts/ci-nuget -ItemType Directory -Force | Out-Null + dotnet pack dotnet/src/Devolutions.Pinget.Core/Devolutions.Pinget.Core.csproj -c Release --no-build -o artifacts/ci-nuget + dotnet pack dotnet/src/Devolutions.Pinget.PowerShell.Engine/Devolutions.Pinget.PowerShell.Engine.csproj -c Release --no-build -o artifacts/ci-nuget + dotnet pack dotnet/src/Devolutions.Pinget.PowerShell.Cmdlets/Devolutions.Pinget.PowerShell.Cmdlets.csproj -c Release --no-build -o artifacts/ci-nuget \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..6d8308f --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,394 @@ +name: Release + +on: + push: + branches: + - master + workflow_dispatch: + inputs: + version: + description: Package version to release. Defaults to the version detected from source files. + required: false + type: string + dry-run: + description: Build and package only; skip tag creation, GitHub release, and NuGet publication. + required: false + default: true + type: boolean + publish-nuget: + description: Publish packages to NuGet.org during a manual release. + required: false + default: false + type: boolean + +permissions: + contents: write + +env: + DOTNET_NOLOGO: true + CARGO_TERM_COLOR: always + +jobs: + preflight: + name: Preflight + runs-on: ubuntu-latest + outputs: + version: ${{ steps.info.outputs.version }} + tag-name: ${{ steps.info.outputs.tag-name }} + dry-run: ${{ steps.info.outputs.dry-run }} + publish-nuget: ${{ steps.info.outputs.publish-nuget }} + + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Package information + id: info + shell: pwsh + run: | + $IsMasterBranch = ('${{ github.ref_name }}' -eq 'master') + $IsWorkflowDispatch = ('${{ github.event_name }}' -eq 'workflow_dispatch') + + $DryRun = $false + $PublishNuget = $true + + if ($IsWorkflowDispatch) { + try { $DryRun = [System.Boolean]::Parse('${{ inputs['dry-run'] }}') } catch { $DryRun = $true } + try { $PublishNuget = [System.Boolean]::Parse('${{ inputs['publish-nuget'] }}') } catch { $PublishNuget = $false } + } + + if (-not $IsMasterBranch) { + $DryRun = $true + $PublishNuget = $false + } + + if ($DryRun) { + $PublishNuget = $false + } + + $Version = '${{ inputs.version }}' + if ([string]::IsNullOrWhiteSpace($Version)) { + $coreVersion = Select-String -Path 'rust/crates/pinget-core/Cargo.toml' -Pattern '^version = "([^"]+)"$' | Select-Object -First 1 + $cliVersion = Select-String -Path 'rust/crates/pinget-cli/Cargo.toml' -Pattern '^version = "([^"]+)"$' | Select-Object -First 1 + $dotnetVersion = Select-String -Path 'dotnet/src/Devolutions.Pinget.Cli/Program.cs' -Pattern '^const string Version = "([^"]+)";$' | Select-Object -First 1 + + if (($null -eq $coreVersion) -or ($null -eq $cliVersion) -or ($null -eq $dotnetVersion)) { + throw 'Unable to detect version from source files' + } + + $coreVersionValue = $coreVersion.Matches[0].Groups[1].Value + $cliVersionValue = $cliVersion.Matches[0].Groups[1].Value + $dotnetVersionValue = $dotnetVersion.Matches[0].Groups[1].Value + + if (($coreVersionValue -ne $cliVersionValue) -or ($coreVersionValue -ne $dotnetVersionValue)) { + throw "Version mismatch detected: pinget-core=$coreVersionValue pinget-cli=$cliVersionValue dotnet=$dotnetVersionValue" + } + + $Version = $coreVersionValue + } + + if ([string]::IsNullOrWhiteSpace($Version)) { + throw 'Package version is empty' + } + + $TagName = "v$Version" + + "version=$Version" >> $Env:GITHUB_OUTPUT + "tag-name=$TagName" >> $Env:GITHUB_OUTPUT + "dry-run=$($DryRun.ToString().ToLower())" >> $Env:GITHUB_OUTPUT + "publish-nuget=$($PublishNuget.ToString().ToLower())" >> $Env:GITHUB_OUTPUT + + Write-Host "::notice::Version: $Version" + Write-Host "::notice::Tag: $TagName" + Write-Host "::notice::DryRun: $DryRun" + Write-Host "::notice::PublishNuget: $PublishNuget" + + rust-artifacts: + name: Rust Artifacts (${{ matrix.name }}) + runs-on: ${{ matrix.os }} + needs: preflight + strategy: + fail-fast: false + matrix: + include: + - name: linux-x64 + os: ubuntu-latest + target: x86_64-unknown-linux-gnu + archive_name: pinget-linux-x64.zip + binary_name: pinget + - name: linux-arm64 + os: ubuntu-latest + target: aarch64-unknown-linux-gnu + archive_name: pinget-linux-arm64.zip + binary_name: pinget + - name: windows-x64 + os: windows-latest + target: x86_64-pc-windows-msvc + archive_name: pinget-windows-x64.zip + binary_name: pinget.exe + - name: windows-arm64 + os: windows-latest + target: aarch64-pc-windows-msvc + archive_name: pinget-windows-arm64.zip + binary_name: pinget.exe + - name: macos-x64 + os: macos-14 + target: x86_64-apple-darwin + archive_name: pinget-macos-x64.zip + binary_name: pinget + - name: macos-arm64 + os: macos-14 + target: aarch64-apple-darwin + archive_name: pinget-macos-arm64.zip + binary_name: pinget + + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Install Rust toolchain + shell: pwsh + run: | + rustup toolchain install stable --profile minimal --target "${{ matrix.target }}" + rustup default stable + + - name: Install Linux ARM64 linker + if: matrix.target == 'aarch64-unknown-linux-gnu' + shell: bash + run: | + sudo apt-get update + sudo apt-get install -y gcc-aarch64-linux-gnu + + - name: Configure static MSVC runtime + if: contains(matrix.target, 'windows-msvc') + shell: pwsh + run: | + "RUSTFLAGS=-C target-feature=+crt-static" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + + - name: Build release binary + shell: pwsh + env: + CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc + run: | + cargo build --release --package pinget-cli --bin pinget --manifest-path rust/Cargo.toml --target "${{ matrix.target }}" + + - name: Package artifacts + shell: pwsh + env: + TARGET: ${{ matrix.target }} + PINGET_BIN_NAME: ${{ matrix.binary_name }} + PINGET_ARCHIVE_NAME: ${{ matrix.archive_name }} + run: | + Add-Type -AssemblyName System.IO.Compression.FileSystem + + $target = $env:TARGET + $binaryName = $env:PINGET_BIN_NAME + $archiveName = $env:PINGET_ARCHIVE_NAME + $binaryPath = [System.IO.Path]::Combine('rust', 'target', $target, 'release', $binaryName) + + if (-not (Test-Path -Path $binaryPath)) { + throw "Binary not found: $binaryPath" + } + + if (Test-Path -Path $archiveName) { + Remove-Item -Path $archiveName -Force + } + + $archive = [System.IO.Compression.ZipFile]::Open($archiveName, [System.IO.Compression.ZipArchiveMode]::Create) + try { + [System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile( + $archive, + $binaryPath, + $binaryName, + [System.IO.Compression.CompressionLevel]::Optimal + ) | Out-Null + } + finally { + $archive.Dispose() + } + + Write-Host "Created $archiveName" + + - name: Upload Rust artifact + uses: actions/upload-artifact@v7 + with: + name: ${{ matrix.archive_name }} + path: ${{ matrix.archive_name }} + if-no-files-found: error + + csharp-packages: + name: C# Packages + runs-on: windows-latest + needs: preflight + + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Setup .NET + uses: actions/setup-dotnet@v5 + with: + dotnet-version: 10.0.x + + - name: Install Pester + shell: pwsh + run: | + Set-PSRepository PSGallery -InstallationPolicy Trusted + Install-Module Pester -Scope CurrentUser -Force -SkipPublisherCheck + + - name: Restore solution + run: dotnet restore dotnet/Devolutions.Pinget.slnx + + - name: Build solution + run: dotnet build dotnet/Devolutions.Pinget.slnx -c Release --no-restore + + - name: Run core tests + run: dotnet test dotnet/src/Devolutions.Pinget.Core.Tests/Devolutions.Pinget.Core.Tests.csproj -c Release --no-build + + - name: Run PowerShell tests + shell: pwsh + run: pwsh -NoLogo -NoProfile -File (Resolve-Path 'dotnet/tests/RunTests.ps1') + + - name: Pack NuGet packages + shell: pwsh + env: + PACKAGE_VERSION: ${{ needs.preflight.outputs.version }} + run: | + New-Item -Path dist/nuget -ItemType Directory -Force | Out-Null + $packArgs = @('-c', 'Release', '--no-build', '-p:ContinuousIntegrationBuild=true', "-p:Version=$env:PACKAGE_VERSION", '-p:IncludeSymbols=true', '-p:SymbolPackageFormat=snupkg', '-o', 'dist/nuget') + dotnet pack dotnet/src/Devolutions.Pinget.Core/Devolutions.Pinget.Core.csproj @packArgs + dotnet pack dotnet/src/Devolutions.Pinget.PowerShell.Engine/Devolutions.Pinget.PowerShell.Engine.csproj @packArgs + dotnet pack dotnet/src/Devolutions.Pinget.PowerShell.Cmdlets/Devolutions.Pinget.PowerShell.Cmdlets.csproj @packArgs + + - name: Package PowerShell module + shell: pwsh + env: + PACKAGE_VERSION: ${{ needs.preflight.outputs.version }} + run: | + Add-Type -AssemblyName System.IO.Compression.FileSystem + + $moduleName = 'Pinget' + $moduleVersion = $env:PACKAGE_VERSION + $moduleOutput = Join-Path 'dotnet/src/Devolutions.Pinget.PowerShell.Cmdlets/bin/Release' 'net8.0' + $stagingRoot = Join-Path 'dist' 'powershell-module' + $moduleRoot = Join-Path $stagingRoot $moduleName + $archivePath = Join-Path 'dist' ("pinget-powershell-module-$moduleVersion.zip") + + if (-not (Test-Path -Path (Join-Path $moduleOutput 'Pinget.psd1'))) { + throw "PowerShell module manifest not found in $moduleOutput" + } + + if (Test-Path -Path $stagingRoot) { + Remove-Item -Path $stagingRoot -Recurse -Force + } + + if (Test-Path -Path $archivePath) { + Remove-Item -Path $archivePath -Force + } + + New-Item -Path $moduleRoot -ItemType Directory -Force | Out-Null + Copy-Item -Path (Join-Path $moduleOutput '*') -Destination $moduleRoot -Recurse -Force + [System.IO.Compression.ZipFile]::CreateFromDirectory($stagingRoot, $archivePath, [System.IO.Compression.CompressionLevel]::Optimal, $false) + + Write-Host "Created $archivePath" + + - name: Upload package artifacts + uses: actions/upload-artifact@v7 + with: + name: csharp-nuget + path: | + dist/nuget/*.nupkg + dist/nuget/*.snupkg + if-no-files-found: error + + - name: Upload PowerShell module artifact + uses: actions/upload-artifact@v7 + with: + name: powershell-module + path: dist/pinget-powershell-module-*.zip + if-no-files-found: error + + create-tag: + name: Create Tag + runs-on: ubuntu-latest + needs: + - preflight + - rust-artifacts + - csharp-packages + if: ${{ fromJSON(needs.preflight.outputs.dry-run) == false }} + + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Ensure tag does not already exist + shell: bash + run: | + if git ls-remote --exit-code --tags origin "refs/tags/${{ needs.preflight.outputs.tag-name }}" >/dev/null 2>&1; then + echo "Tag ${{ needs.preflight.outputs.tag-name }} already exists on origin" >&2 + exit 1 + fi + + - name: Create and push tag + shell: bash + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git tag -a "${{ needs.preflight.outputs.tag-name }}" "${GITHUB_SHA}" -m "Release ${{ needs.preflight.outputs.tag-name }}" + git push origin "${{ needs.preflight.outputs.tag-name }}" + + github-release: + name: GitHub Release + runs-on: ubuntu-latest + needs: + - preflight + - create-tag + - rust-artifacts + - csharp-packages + if: ${{ fromJSON(needs.preflight.outputs.dry-run) == false }} + + steps: + - name: Download all artifacts + uses: actions/download-artifact@v8 + with: + path: dist/release + merge-multiple: true + + - name: Create GitHub release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh release create "${{ needs.preflight.outputs.tag-name }}" dist/release/*.zip dist/release/*.nupkg dist/release/*.snupkg --generate-notes + + publish-nuget: + name: Publish NuGet + runs-on: ubuntu-latest + needs: + - preflight + - csharp-packages + - create-tag + - github-release + if: ${{ fromJSON(needs.preflight.outputs.dry-run) == false && fromJSON(needs.preflight.outputs.publish-nuget) == true }} + + steps: + - name: Setup .NET + uses: actions/setup-dotnet@v5 + with: + dotnet-version: 10.0.x + + - name: Download package artifacts + uses: actions/download-artifact@v8 + with: + name: csharp-nuget + path: dist/nuget + + - name: Push packages to NuGet.org + if: env.NUGET_API_KEY != '' + shell: bash + env: + NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} + run: | + dotnet nuget push dist/nuget/*.nupkg --api-key "$NUGET_API_KEY" --source https://api.nuget.org/v3/index.json --skip-duplicate + dotnet nuget push dist/nuget/*.snupkg --api-key "$NUGET_API_KEY" --source https://api.nuget.org/v3/index.json --skip-duplicate \ No newline at end of file diff --git a/dotnet/Directory.Build.props b/dotnet/Directory.Build.props new file mode 100644 index 0000000..6d59fcf --- /dev/null +++ b/dotnet/Directory.Build.props @@ -0,0 +1,15 @@ + + + Devolutions + Devolutions Inc. + MIT + https://github.com/Devolutions/pinget + https://github.com/Devolutions/pinget.git + git + true + false + pinget;winget;package-manager;powershell;dotnet + See the repository changelog and release notes for details. + Copyright 2021-2026 Devolutions Inc. + + \ No newline at end of file diff --git a/dotnet/src/Devolutions.Pinget.Core/Devolutions.Pinget.Core.csproj b/dotnet/src/Devolutions.Pinget.Core/Devolutions.Pinget.Core.csproj index 418431a..62a8689 100644 --- a/dotnet/src/Devolutions.Pinget.Core/Devolutions.Pinget.Core.csproj +++ b/dotnet/src/Devolutions.Pinget.Core/Devolutions.Pinget.Core.csproj @@ -1,7 +1,7 @@ - net10.0 + net8.0;net10.0 enable enable true diff --git a/dotnet/src/Devolutions.Pinget.Core/Repository.cs b/dotnet/src/Devolutions.Pinget.Core/Repository.cs index d4c2ebe..c91199a 100644 --- a/dotnet/src/Devolutions.Pinget.Core/Repository.cs +++ b/dotnet/src/Devolutions.Pinget.Core/Repository.cs @@ -2019,7 +2019,7 @@ private static bool SearchMatchHasUnknownVersion(SearchMatch match) => private static string Sha256Hex(byte[] data) { var hash = SHA256.HashData(data); - return Convert.ToHexStringLower(hash); + return Convert.ToHexString(hash).ToLowerInvariant(); } private class VersionComparer : IComparer diff --git a/dotnet/src/Devolutions.Pinget.PowerShell.Cmdlets/Devolutions.Pinget.PowerShell.Cmdlets.csproj b/dotnet/src/Devolutions.Pinget.PowerShell.Cmdlets/Devolutions.Pinget.PowerShell.Cmdlets.csproj index d404b77..cb24ffd 100644 --- a/dotnet/src/Devolutions.Pinget.PowerShell.Cmdlets/Devolutions.Pinget.PowerShell.Cmdlets.csproj +++ b/dotnet/src/Devolutions.Pinget.PowerShell.Cmdlets/Devolutions.Pinget.PowerShell.Cmdlets.csproj @@ -8,17 +8,26 @@ - net10.0 + net8.0;net10.0 enable enable true true + $(TargetsForTfmSpecificContentInPackage);AddPowerShellModuleFilesToPackage Devolutions.Pinget.PowerShell.Cmdlets Devolutions.Pinget.PowerShell.Cmdlets Devolutions.Pinget.PowerShell.Cmdlets PowerShell cmdlets for Pinget. + + + + lib\$(TargetFramework)\%(RecursiveDir)%(Filename)%(Extension) + + + + diff --git a/dotnet/src/Devolutions.Pinget.PowerShell.Engine/Devolutions.Pinget.PowerShell.Engine.csproj b/dotnet/src/Devolutions.Pinget.PowerShell.Engine/Devolutions.Pinget.PowerShell.Engine.csproj index 7c17438..9edeba9 100644 --- a/dotnet/src/Devolutions.Pinget.PowerShell.Engine/Devolutions.Pinget.PowerShell.Engine.csproj +++ b/dotnet/src/Devolutions.Pinget.PowerShell.Engine/Devolutions.Pinget.PowerShell.Engine.csproj @@ -4,7 +4,7 @@ - net10.0 + net8.0;net10.0 enable enable true diff --git a/dotnet/tests/RunTests.ps1 b/dotnet/tests/RunTests.ps1 index 8dc787d..601dafe 100644 --- a/dotnet/tests/RunTests.ps1 +++ b/dotnet/tests/RunTests.ps1 @@ -1,6 +1,6 @@ [CmdletBinding()] param( - [string]$ModulePath = (Join-Path $PSScriptRoot '..\src\Devolutions.Pinget.PowerShell.Cmdlets\bin\Release\net10.0\Pinget.psd1'), + [string]$ModulePath = (Join-Path $PSScriptRoot '..\src\Devolutions.Pinget.PowerShell.Cmdlets\bin\Release\net8.0\Pinget.psd1'), [string]$SourceArgument = 'https://api.winget.pro/4259fd23-6fcd-46bf-9287-be8833cfbdd5' ) diff --git a/rust/crates/pinget-cli/Cargo.toml b/rust/crates/pinget-cli/Cargo.toml index 24063c6..e23a013 100644 --- a/rust/crates/pinget-cli/Cargo.toml +++ b/rust/crates/pinget-cli/Cargo.toml @@ -17,7 +17,7 @@ pinget-core = { version = "0.1.0", path = "../pinget-core" } chrono = "0.4.44" dirs = "6.0" jsonschema = "0.30" -reqwest = { version = "0.12", features = ["blocking"] } +reqwest = { version = "0.12", default-features = false, features = ["blocking", "rustls-tls"] } rusqlite = { version = "0.39", features = ["bundled"] } serde = { version = "1", features = ["derive"] } serde_json = "1.0.149" diff --git a/rust/crates/pinget-core/src/lib.rs b/rust/crates/pinget-core/src/lib.rs index 045432b..10bb561 100644 --- a/rust/crates/pinget-core/src/lib.rs +++ b/rust/crates/pinget-core/src/lib.rs @@ -2022,7 +2022,7 @@ impl Repository { .headers() .get("x-ms-meta-sourceversion") .and_then(|value| value.to_str().ok()) - .map(str::to_string); + .map(str::to_owned); let bytes = response.bytes().context("failed to read preindexed package bytes")?; let payload = bytes.to_vec(); let index_bytes = extract_zip_member(&payload, "Public/index.db") @@ -2055,7 +2055,7 @@ impl Repository { source.identifier = info.source_identifier.clone(); } source.last_update = Some(Utc::now()); - source.source_version = choose_contract(&info.server_supported_versions).map(str::to_string); + source.source_version = choose_contract(&info.server_supported_versions).map(str::to_owned); Ok("refreshed information cache".to_owned()) } @@ -4467,7 +4467,7 @@ fn yaml_scalar_string(value: &YamlValue) -> Option { fn yaml_string_list(root: &YamlMapping, key: &str) -> Vec { root.get(YamlValue::from(key)) .and_then(YamlValue::as_sequence) - .map(|items| items.iter().filter_map(YamlValue::as_str).map(str::to_string).collect()) + .map(|items| items.iter().filter_map(YamlValue::as_str).map(str::to_owned).collect()) .unwrap_or_default() } @@ -4523,14 +4523,14 @@ fn yaml_package_dependencies(root: &YamlMapping) -> Vec { } fn json_string(value: &JsonValue, key: &str) -> Option { - value.get(key).and_then(JsonValue::as_str).map(str::to_string) + value.get(key).and_then(JsonValue::as_str).map(str::to_owned) } fn json_string_list(value: &JsonValue, key: &str) -> Vec { value .get(key) .and_then(JsonValue::as_array) - .map(|items| items.iter().filter_map(JsonValue::as_str).map(str::to_string).collect()) + .map(|items| items.iter().filter_map(JsonValue::as_str).map(str::to_owned).collect()) .unwrap_or_default() } @@ -4595,7 +4595,7 @@ fn json_installer_switches(value: &JsonValue) -> InstallerSwitches { switches .and_then(|switches| switches.get(key)) .and_then(JsonValue::as_str) - .map(str::to_string) + .map(str::to_owned) }; InstallerSwitches { @@ -6199,13 +6199,8 @@ Installers: #[test] fn parses_fixture_manifest() { let root = Path::new(env!("CARGO_MANIFEST_DIR")) - .join("..") - .join("..") - .join("..") - .join("..") - .join("src") - .join("AppInstallerCLITests") - .join("TestData") + .join("tests") + .join("fixtures") .join("ManifestV1_28-Singleton.yaml"); let bytes = fs::read(root).expect("fixture bytes"); let manifest = parse_yaml_manifest(&bytes).expect("manifest"); diff --git a/rust/crates/pinget-core/tests/fixtures/ManifestV1_28-Singleton.yaml b/rust/crates/pinget-core/tests/fixtures/ManifestV1_28-Singleton.yaml new file mode 100644 index 0000000..24d2cba --- /dev/null +++ b/rust/crates/pinget-core/tests/fixtures/ManifestV1_28-Singleton.yaml @@ -0,0 +1,13 @@ +PackageIdentifier: microsoft.msixsdk +PackageVersion: 1.7.32 +PackageLocale: en-US +PackageName: MSIX SDK +Publisher: Microsoft +ShortDescription: Test fixture manifest for pinget-core parsing. +ManifestType: singleton +ManifestVersion: 1.10.0 +Installers: + - Architecture: x64 + InstallerType: exe + InstallerUrl: https://example.test/msixsdk-x64.exe + InstallerSha256: 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF \ No newline at end of file