Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .config/dotnet-tools.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"version": 1,
"isRoot": true,
"tools": {
"microsoft.sbom.dotnettool": {
"version": "4.1.5",
"commands": [
"sbom-tool"
],
"rollForward": false
}
}
}
15 changes: 0 additions & 15 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,3 @@ dotnet_diagnostic.CA1062.severity = none

[src/Snaply.App/App.xaml.cs]
dotnet_diagnostic.CA1515.severity = none

[src/Snaply.App/MainWindow.xaml.cs]
dotnet_diagnostic.CA1515.severity = none

[src/Snaply.App/MainPage.xaml.cs]
dotnet_diagnostic.CA1515.severity = none

[src/Snaply.App/ViewModels/MainViewModel.cs]
dotnet_diagnostic.CA1031.severity = none

[src/Snaply.App/ImageExportService.cs]
dotnet_diagnostic.CA1849.severity = none

[src/Snaply.App/ScreenCaptureService.cs]
dotnet_diagnostic.CA2000.severity = none
11 changes: 11 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,17 @@ updates:
commit-message:
prefix: build

- package-ecosystem: nuget
directory: /tests/Snaply.App.Tests
schedule:
interval: weekly
day: monday
groups:
app-tests:
patterns: ["*"]
commit-message:
prefix: build

- package-ecosystem: github-actions
directory: /
schedule:
Expand Down
4 changes: 1 addition & 3 deletions .github/rulesets/protect-default-branch.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,7 @@
"strict_required_status_checks_policy": true,
"do_not_enforce_on_create": false,
"required_status_checks": [
{ "context": "hygiene" },
{ "context": "quality" },
{ "context": "packaging" },
{ "context": "ci-required" },
{ "context": "dependency-review" },
{ "context": "analyze" },
{ "context": "analyze-actions" }
Expand Down
61 changes: 11 additions & 50 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: raven-actions/actionlint@3d39aea434753780c3b3d4a1a31c854b4dbf49d7 # v2.2.0
- uses: crate-ci/typos@bee27e3a4fd1ea2111cf90ab89cd076c870fce14 # v1.47.2
- uses: fsfe/reuse-action@772649cfa03a64a08c458c7cca9a6a473d74e7f9 # v6
- name: Reject incomplete implementation markers
shell: bash
run: |
Expand All @@ -36,62 +37,17 @@ jobs:

quality:
runs-on: windows-latest
timeout-minutes: 35
timeout-minutes: 60
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
with:
global-json-file: global.json
cache: true
cache-dependency-path: "**/packages.lock.json"
- name: Restore locked dependencies
run: dotnet restore Snaply.slnx --locked-mode
# Clear PathMap for this coverage build only: CI's PathMap (/_/) otherwise breaks
# coverlet's source resolution and makes it report 0% line coverage.
- name: Test imaging
run: >-
dotnet test tests/Snaply.Tests/Snaply.Tests.csproj
-c Release --no-restore
-p:PathMap=
--collect:"XPlat Code Coverage"
--logger "trx;LogFileName=results.trx"
--results-directory artifacts/test
- name: Test filesystem workflows
run: >-
dotnet test tests/Snaply.App.Tests/Snaply.App.Tests.csproj
-c Release --no-restore
--logger "trx;LogFileName=results.trx"
--results-directory artifacts/app-test
- name: Reject skipped tests and low coverage
- name: Verify source, tests, coverage, and portable publishes
shell: pwsh
run: |
[xml]$trx = Get-Content artifacts/test/results.trx -Raw
if ([int]$trx.TestRun.ResultSummary.Counters.notExecuted -ne 0) {
throw "Required tests were skipped."
}
[xml]$coverage = Get-Content (
Get-ChildItem artifacts/test -Recurse -Filter coverage.cobertura.xml |
Select-Object -First 1
).FullName -Raw
if ([double]$coverage.coverage.'line-rate' -lt 0.85) {
throw "Line coverage is below 85%."
}
[xml]$appTrx = Get-Content artifacts/app-test/results.trx -Raw
if ([int]$appTrx.TestRun.ResultSummary.Counters.notExecuted -ne 0) {
throw "Required filesystem tests were skipped."
}
- name: Build x64
run: >-
dotnet build src/Snaply.App/Snaply.App.csproj
-c Release -p:Platform=x64 --no-restore
- name: Build ARM64
run: >-
dotnet build src/Snaply.App/Snaply.App.csproj
-c Release -p:Platform=ARM64 --no-restore
- name: Verify formatting
env:
Configuration: Release
run: dotnet format Snaply.slnx --verify-no-changes --no-restore
run: ./scripts/verify.ps1

packaging:
runs-on: windows-latest
Expand All @@ -100,18 +56,23 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
with:
dotnet-version: 8.0.x
global-json-file: global.json
cache: true
cache-dependency-path: "**/packages.lock.json"
- name: Build and validate unsigned release payloads
shell: pwsh
run: |
[xml]$props = Get-Content Directory.Build.props -Raw
$version = (Get-Content version.txt -Raw).Trim()
./scripts/release.ps1 `
-Action Build `
-Version "$($props.Project.PropertyGroup.Version)" `
-Version $version `
-Publisher CN=Snaply `
-OutputRoot build/package-smoke
./scripts/release.ps1 `
-Action Package `
-Version $version `
-OutputRoot build/package-smoke

# Aggregate gate the branch protection requires (context "ci-required"): green only
# when every CI job above succeeded. Keeps the required-checks list stable as jobs change.
Expand Down
41 changes: 15 additions & 26 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,17 @@ jobs:
version: v0.3.1
# Restore with ReadyToRun on so the crossgen2 runtime pack is fetched here; the
# publish below runs --no-restore, so without it R2R fails (NETSDK1094).
- run: dotnet restore Snaply.slnx --locked-mode -p:PublishReadyToRun=true
- run: >-
dotnet restore Snaply.slnx
--locked-mode
-p:Platform=${{ matrix.platform }}
-p:PublishReadyToRun=true
- run: dotnet test tests/Snaply.Tests/Snaply.Tests.csproj -c Release --no-restore
- if: matrix.architecture == 'x64'
run: dotnet test tests/Snaply.App.Tests/Snaply.App.Tests.csproj -c Release --no-restore
- run: >-
dotnet test tests/Snaply.App.Tests/Snaply.App.Tests.csproj
-c Release
-p:Platform=${{ matrix.platform }}
--no-restore
- name: Publish native portable payload
run: >-
dotnet publish src/Snaply.App/Snaply.App.csproj
Expand All @@ -57,20 +64,7 @@ jobs:
--self-contained true
-o build/native
--no-restore
# UI journeys are x64-only. On windows-11-arm the shell keeps the foreground for
# itself — the image boots with a Microsoft-account sign-in prompt (WWAHost), and
# closing it just hands the foreground to SearchHost — so the capture overlay never
# comes forward and synthetic input never reaches it. Even the AttachThreadInput
# handoff in ui-tests.ps1 loses that fight there, so the journeys measured the
# runner image rather than Snaply. arm64 still builds, unit-tests and publishes.
# One pass, not five. The first pass has never failed across every run of this
# work; a repeat pass fails perhaps half the time, and always the same way: the
# region drag's press lands (the overlay closes) but its moves do not register, so
# the selection is empty, CaptureAsync returns null and no preview appears. Three
# retries do not shake it off. The soak below still covers repetition — 100
# captures against one process — which is what the repeat passes were really for.
- name: Run the UI journeys
if: matrix.architecture == 'x64'
shell: pwsh
run: |
1..1 | ForEach-Object {
Expand All @@ -89,7 +83,6 @@ jobs:
}
}
- name: Run 100-capture soak
if: matrix.architecture == 'x64'
shell: pwsh
run: |
$process = Start-Process build/native/Snaply.exe -PassThru
Expand All @@ -109,10 +102,8 @@ jobs:
Stop-Process -Id $process.Id -Force
}
}
# A UI failure otherwise reports only "element did not appear"; Snaply's own log
# carries the exception behind it, so ship it alongside the results.
- name: Collect app logs
if: always() && matrix.architecture == 'x64'
if: always()
shell: pwsh
run: |
$logs = Join-Path $env:LOCALAPPDATA 'Snaply\Logs'
Expand All @@ -131,21 +122,20 @@ jobs:
}
New-Item -ItemType Directory -Force -Path artifacts/ui/app-logs | Out-Null
Copy-Item "$logs\*" artifacts/ui/app-logs -Recurse -Force
# Only reached when everything gating this architecture passed: on x64 that includes
# the UI journeys and the soak, on arm64 the build and the unit tests.
# Only reached when build, unit tests, UI journeys, and soak passed on the
# native runner for this architecture.
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: nightly-${{ matrix.architecture }}
path: build/native
retention-days: 14
if-no-files-found: error
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: always() && matrix.architecture == 'x64'
if: always()
with:
name: ui-${{ matrix.architecture }}
path: artifacts/ui
if-no-files-found: error

mutation:
runs-on: ubuntu-latest
timeout-minutes: 45
Expand Down Expand Up @@ -186,6 +176,5 @@ jobs:
- name: Build twice
shell: pwsh
run: |
[xml]$props = Get-Content Directory.Build.props -Raw
$version = "$($props.Project.PropertyGroup.Version)"
$version = (Get-Content version.txt -Raw).Trim()
./scripts/test-reproducibility.ps1 -Version $version
15 changes: 9 additions & 6 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,13 @@ jobs:
if ($LASTEXITCODE -ne 0) {
throw "The release commit is not in main."
}
[xml]$props = Get-Content Directory.Build.props -Raw
if ("v$($props.Project.PropertyGroup.Version)" -ne $env:TAG) {
$version = (Get-Content version.txt -Raw).Trim()
if ("v$version" -ne $env:TAG) {
throw "The release tag does not match the project version."
}
- uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
with:
dotnet-version: 8.0.x
global-json-file: global.json
cache: true
cache-dependency-path: "**/packages.lock.json"
Expand All @@ -95,15 +96,16 @@ jobs:
- name: Generate SPDX SBOM
shell: pwsh
run: |
dotnet tool install --tool-path build/tools `
Microsoft.Sbom.DotNetTool --version 4.1.5
./build/tools/sbom-tool generate `
dotnet tool restore
dotnet tool run sbom-tool -- generate `
-b build/release `
-bc . `
-pn Snaply `
-pv '${{ inputs.tag_name }}'.TrimStart('v') `
-ps P4suta `
-nsb https://github.com/P4suta/Snaply
-nsb https://github.com/P4suta/Snaply `
-mi SPDX:2.2 `
-cd '--DirectoryExclusionList **/artifacts/** --DirectoryExclusionList **/build/**'
- uses: taiki-e/install-action@7572810d7dd469b651bb7793945692cf78da5dd7 # v2.85.0
with:
tool: osv-scanner@2.3.6
Expand Down Expand Up @@ -297,6 +299,7 @@ jobs:
ref: ${{ env.REF }}
- uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
with:
dotnet-version: 8.0.x
global-json-file: global.json
cache: true
cache-dependency-path: "**/packages.lock.json"
Expand Down
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

- Rebuilt Snaply as a GUI-only WinUI 3 application.
- Added region, window, and complete virtual-desktop capture with mixed-DPI and HDR handling.
- Added automatic randomized beautification, preview, clipboard copy, atomic save, Save As, and Open Folder.
- Added automatic randomized beautification, zoomable preview, clipboard copy, atomic save, and Open Folder.
- Added English, Japanese, and Simplified Chinese resources.
- Added x64/ARM64 portable builds and a signed MSIX bundle release path.

Expand Down
4 changes: 1 addition & 3 deletions CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
# Code of Conduct

This project follows the [Contributor Covenant 2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct/).

Be respectful, constructive, and focused on the work. Report unacceptable behavior privately to the repository maintainers. Maintainers may remove content or participation that violates this standard.
Follow [Contributor Covenant 2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct/). Be respectful and report violations privately to the maintainers.
18 changes: 3 additions & 15 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,9 @@
# Contributing

Use Windows 11 24H2 or later and the .NET SDK pinned by `global.json`.
On Windows 11 24H2+ with the SDK from `global.json`:

```powershell
dotnet restore Snaply.slnx --locked-mode
dotnet build src/Snaply.App/Snaply.App.csproj -c Release -p:Platform=x64 --no-restore
dotnet test tests/Snaply.Tests/Snaply.Tests.csproj -c Release --no-restore
$env:Configuration = 'Release'
dotnet format Snaply.slnx --verify-no-changes --no-restore
./scripts/verify.ps1
```

Before a pull request:

- Keep the product GUI-only and local-only.
- Add no public API, capability, dependency, setting, or abstraction without a current product need.
- Add tests for behavior and non-trivial calculations.
- Keep comments for ABI, ownership, lifetime, security, or non-obvious algorithms only.
- Use Conventional Commits and keep the branch green with no warnings or skipped required tests.

Release packaging and UI automation are documented in [RELEASING.md](RELEASING.md).
Keep changes local-only, warning-free, tested, and limited to the current product contract. Use Conventional Commits.
3 changes: 2 additions & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<Project>
<PropertyGroup>
<Version>0.1.1</Version>
<Version>$([System.IO.File]::ReadAllText('$(MSBuildThisFileDirectory)version.txt').Trim())</Version>
<WindowsSdkPackageVersion>10.0.26100.87</WindowsSdkPackageVersion>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<RestoreLockedMode Condition="'$(ContinuousIntegrationBuild)' == 'true'">true</RestoreLockedMode>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
Expand Down
Loading
Loading