Skip to content

Add configurable color themes (default/light/dark/monochrome) #445

Add configurable color themes (default/light/dark/monochrome)

Add configurable color themes (default/light/dark/monochrome) #445

name: Validate And Package
on:
# Trigger when manually run
workflow_dispatch:
# Trigger on pushes to `main`, `rel/*`, or `dev/**`
push:
branches:
- main
- rel/*
- dev/**
# Trigger on pull requests to `main`, `rel/*`, or `dev/**`
pull_request:
branches:
- main
- rel/*
- dev/**
permissions:
contents: read
env:
BUILD_CONFIGURATION: Release
jobs:
build-test-package:
runs-on: windows-latest
# A push to a branch with an open PR fires both `push` and `pull_request`
# events. Rather than cancelling one of them (a cancelled run reports
# as a failed required check on the PR's head SHA and blocks merge),
# we skip the `pull_request` run for same-repo PRs only when the PR
# head branch is also covered by this workflow's `push.branches`
# filters, because only those branches already get a `push` run in
# this repo. For PRs from forks, or same-repo PRs from other head
# branches such as `feature/*`, we still let `pull_request` run.
if: >-
github.event_name != 'pull_request' ||
github.event.pull_request.head.repo.full_name != github.repository ||
(github.head_ref != 'main' &&
!startsWith(github.head_ref, 'rel/') &&
!startsWith(github.head_ref, 'dev/'))
# Concurrency only dedupes runs for the SAME branch across DIFFERENT
# commits (e.g. rapid pushes during a rebase). The cancelled older run
# is on a stale SHA that is no longer the PR head, so it does not
# block the PR. Push and pull_request events for the same SHA are
# already deduped by the `if` above, so they never collide here.
# For `pull_request` events, scope the group by PR number and head
# repo so that two forks pushing branches with the same name do not
# cancel each other.
concurrency:
group: build-${{ github.workflow }}-${{ github.event_name == 'pull_request' && format('{0}-{1}', github.event.pull_request.head.repo.full_name, github.event.pull_request.number) || github.ref_name }}
cancel-in-progress: true
steps:
- name: Checkout
uses: actions/checkout@v4
with:
# GitVersion needs full history to compute commit counts.
fetch-depth: 0
- name: Setup .NET SDK
uses: actions/setup-dotnet@v4
with:
global-json-file: global.json
cache: true
cache-dependency-path: |
global.json
Directory.Packages.props
**/*.csproj
- name: Restore GitVersion tool
shell: pwsh
run: |
$ErrorActionPreference = 'Stop'
dotnet tool restore
if ($LASTEXITCODE -ne 0) {
throw "Failed to restore the local GitVersion tool."
}
- name: Compute version properties
id: version
shell: pwsh
run: |
$ErrorActionPreference = 'Stop'
# GitVersion.yml supplies Major.Minor via next-version and counts
# commits since it was last bumped. We build the final version
# string ourselves so it follows the Major.Minor.<commits>-preview
# format consistently across pipelines.
$gitVersionJson = dotnet tool run dotnet-gitversion /output json /nofetch /nonormalize
if ($LASTEXITCODE -ne 0) {
throw "Failed to compute version metadata with dotnet-gitversion."
}
$gv = $gitVersionJson | ConvertFrom-Json
$commitsSinceVersionSource = [int]$gv.CommitsSinceVersionSource
if ($commitsSinceVersionSource -gt 65535) {
throw "CommitsSinceVersionSource ($commitsSinceVersionSource) exceeds the maximum .NET assembly version segment value of 65535. Bump next-version before generating assembly and file versions."
}
$assemblyVersion = "$($gv.Major).$($gv.Minor).$commitsSinceVersionSource"
$packageVersion = "$assemblyVersion-preview"
$fileVersion = "$assemblyVersion.0"
$infoVersion = "$packageVersion+${{ github.sha }}"
Write-Host "AssemblyVersion: $assemblyVersion"
Write-Host "PackageVersion: $packageVersion"
"assembly_version=$assemblyVersion" >> $env:GITHUB_OUTPUT
"package_version=$packageVersion" >> $env:GITHUB_OUTPUT
"file_version=$fileVersion" >> $env:GITHUB_OUTPUT
"informational_version=$infoVersion" >> $env:GITHUB_OUTPUT
$branchName = "${{ github.ref_name }}"
$branchLabel = $branchName.ToLowerInvariant()
$branchLabel = $branchLabel -replace '[^0-9a-z-]', '-'
$branchLabel = $branchLabel -replace '-+', '-'
$branchLabel = $branchLabel.Trim('-')
if ([string]::IsNullOrWhiteSpace($branchLabel)) {
$branchLabel = 'branch'
}
if ($branchLabel.Length -gt 40) {
$branchLabel = $branchLabel.Substring(0, 40).Trim('-')
}
"branch_label=$branchLabel" >> $env:GITHUB_OUTPUT
"artifact_suffix=$branchLabel-${{ github.run_number }}" >> $env:GITHUB_OUTPUT
- name: Restore
run: dotnet restore CosmosDBShell.sln
- name: Build solution
run: >-
dotnet build CosmosDBShell.sln
--configuration $env:BUILD_CONFIGURATION
--no-restore
/p:Version=${{ steps.version.outputs.assembly_version }}
/p:FileVersion=${{ steps.version.outputs.file_version }}
/p:InformationalVersion=${{ steps.version.outputs.informational_version }}
shell: pwsh
- name: Test solution
run: >-
dotnet test CosmosDBShell.sln
--configuration $env:BUILD_CONFIGURATION
--no-build
--no-restore
--logger "trx;LogFileName=test-results.trx"
--results-directory TestResults
--collect "Code coverage"
shell: pwsh
- name: Run fuzzer smoke test
working-directory: CosmosDBShell.Fuzzer
run: dotnet run --configuration $env:BUILD_CONFIGURATION --no-build --no-restore -- --all
shell: pwsh
- name: Fail if fuzzer crash findings exist
shell: pwsh
run: |
$crashes = Get-ChildItem -Path CosmosDBShell.Fuzzer/findings -Filter 'crash_*.txt' -ErrorAction SilentlyContinue
if ($crashes -and $crashes.Count -gt 0) {
Write-Error "Fuzzer recorded $($crashes.Count) crash(es). See the 'fuzz-findings' artifact for details."
exit 1
}
- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results
path: TestResults
if-no-files-found: ignore
- name: Upload fuzzer findings
if: always()
uses: actions/upload-artifact@v4
with:
name: fuzz-findings
path: CosmosDBShell.Fuzzer/findings
if-no-files-found: ignore
- name: Publish runtime artifacts
shell: pwsh
run: |
$ErrorActionPreference = 'Stop'
$rids = @('win-x64', 'win-arm64', 'linux-x64', 'linux-arm64', 'osx-x64', 'osx-arm64')
foreach ($rid in $rids) {
dotnet restore CosmosDBShell/CosmosDBShell.csproj `
-r $rid
if ($LASTEXITCODE -ne 0) {
throw "RID restore failed for $rid with exit code $LASTEXITCODE."
}
dotnet publish CosmosDBShell/CosmosDBShell.csproj `
--configuration $env:BUILD_CONFIGURATION `
--no-restore `
-r $rid `
--output "out/$rid" `
/p:Version=${{ steps.version.outputs.assembly_version }} `
/p:FileVersion=${{ steps.version.outputs.file_version }} `
/p:InformationalVersion=${{ steps.version.outputs.informational_version }}
if ($LASTEXITCODE -ne 0) {
throw "RID publish failed for $rid with exit code $LASTEXITCODE."
}
}
- name: Pack NuGet artifacts
shell: pwsh
run: |
New-Item -ItemType Directory -Path out/nupkg -Force | Out-Null
# Restore for all RIDs so pack can build packages for each
dotnet restore CosmosDBShell/CosmosDBShell.csproj
dotnet pack CosmosDBShell/CosmosDBShell.csproj `
--configuration $env:BUILD_CONFIGURATION `
--no-restore `
--output out/nupkg `
/p:PackageVersion=${{ steps.version.outputs.package_version }} `
/p:Version=${{ steps.version.outputs.assembly_version }} `
/p:FileVersion=${{ steps.version.outputs.file_version }} `
/p:InformationalVersion=${{ steps.version.outputs.informational_version }} `
/p:ContinuousIntegrationBuild=true
- name: Validate NuGet package set
shell: pwsh
run: |
$pkgDir = Join-Path $pwd 'out/nupkg'
$ridPatterns = @(
'CosmosDBShell.win-x64.*.nupkg',
'CosmosDBShell.win-arm64.*.nupkg',
'CosmosDBShell.linux-x64.*.nupkg',
'CosmosDBShell.linux-arm64.*.nupkg',
'CosmosDBShell.osx-x64.*.nupkg',
'CosmosDBShell.osx-arm64.*.nupkg'
)
foreach ($pattern in $ridPatterns) {
$matches = Get-ChildItem -Path (Join-Path $pkgDir $pattern) -ErrorAction SilentlyContinue
if (-not $matches -or $matches.Count -eq 0) {
Write-Error "Expected package was not generated: $pattern"
exit 1
}
}
$allPackages = Get-ChildItem -Path (Join-Path $pkgDir 'CosmosDBShell.*.nupkg') -ErrorAction SilentlyContinue
$pointerPackages = $allPackages | Where-Object {
$_.Name -notmatch '^CosmosDBShell\.(win-x64|win-arm64|linux-x64|linux-arm64|osx-x64|osx-arm64)\..+\.nupkg$'
}
if (-not $pointerPackages -or $pointerPackages.Count -ne 1) {
$names = @($pointerPackages | ForEach-Object { $_.Name })
Write-Error "Expected exactly one pointer package (non-RID). Found: $($names -join ', ')"
exit 1
}
$anyMatches = Get-ChildItem -Path (Join-Path $pkgDir 'CosmosDBShell.any.*.nupkg') -ErrorAction SilentlyContinue
if ($anyMatches -and $anyMatches.Count -gt 0) {
$names = $anyMatches | ForEach-Object { $_.Name } | Sort-Object
Write-Error "Unexpected any-RID package(s) found: $($names -join ', ')"
exit 1
}
- name: List packaged NuGet files
shell: pwsh
run: |
Get-ChildItem -Path out/nupkg -Filter *.nupkg -File | Sort-Object Name | ForEach-Object {
Write-Host " - $($_.Name) [$($_.Length) bytes]"
}
- name: Write package install summary
shell: pwsh
run: |
$summary = $env:GITHUB_STEP_SUMMARY
$version = '${{ steps.version.outputs.package_version }}'
$artifactSuffix = '${{ steps.version.outputs.artifact_suffix }}'
$branchName = '${{ github.ref_name }}'
$lines = @(
'## NuGet packages',
'',
('- Branch: `' + $branchName + '`'),
('- Preview version: `' + $version + '`'),
'',
'Artifacts:',
('- `CosmosDBShell-pointer-' + $artifactSuffix + '`'),
('- `CosmosDBShell-win-x64-' + $artifactSuffix + '`'),
('- `CosmosDBShell-win-arm64-' + $artifactSuffix + '`'),
('- `CosmosDBShell-linux-x64-' + $artifactSuffix + '`'),
('- `CosmosDBShell-linux-arm64-' + $artifactSuffix + '`'),
('- `CosmosDBShell-osx-x64-' + $artifactSuffix + '`'),
('- `CosmosDBShell-osx-arm64-' + $artifactSuffix + '`'),
'',
'Download the pointer package artifact and the artifact for your runtime, extract both `.nupkg` files to the same local folder, then install the base package:',
'',
'```powershell',
'dotnet tool install --global CosmosDBShell --add-source C:\path\to\nupkgs --version ' + $version,
'```'
)
$lines -join "`n" | Out-File -FilePath $summary -Encoding utf8 -Append
- name: Upload pointer package
uses: actions/upload-artifact@v4
with:
name: CosmosDBShell-pointer-${{ steps.version.outputs.artifact_suffix }}
path: |
out/nupkg/CosmosDBShell.*.nupkg
!out/nupkg/CosmosDBShell.win-x64.*.nupkg
!out/nupkg/CosmosDBShell.win-arm64.*.nupkg
!out/nupkg/CosmosDBShell.linux-x64.*.nupkg
!out/nupkg/CosmosDBShell.linux-arm64.*.nupkg
!out/nupkg/CosmosDBShell.osx-x64.*.nupkg
!out/nupkg/CosmosDBShell.osx-arm64.*.nupkg
if-no-files-found: error
- name: Upload win-x64 package
uses: actions/upload-artifact@v4
with:
name: CosmosDBShell-win-x64-${{ steps.version.outputs.artifact_suffix }}
path: out/nupkg/CosmosDBShell.win-x64.*.nupkg
if-no-files-found: error
- name: Upload win-arm64 package
uses: actions/upload-artifact@v4
with:
name: CosmosDBShell-win-arm64-${{ steps.version.outputs.artifact_suffix }}
path: out/nupkg/CosmosDBShell.win-arm64.*.nupkg
if-no-files-found: error
- name: Upload linux-x64 package
uses: actions/upload-artifact@v4
with:
name: CosmosDBShell-linux-x64-${{ steps.version.outputs.artifact_suffix }}
path: out/nupkg/CosmosDBShell.linux-x64.*.nupkg
if-no-files-found: error
- name: Upload linux-arm64 package
uses: actions/upload-artifact@v4
with:
name: CosmosDBShell-linux-arm64-${{ steps.version.outputs.artifact_suffix }}
path: out/nupkg/CosmosDBShell.linux-arm64.*.nupkg
if-no-files-found: error
- name: Upload osx-x64 package
uses: actions/upload-artifact@v4
with:
name: CosmosDBShell-osx-x64-${{ steps.version.outputs.artifact_suffix }}
path: out/nupkg/CosmosDBShell.osx-x64.*.nupkg
if-no-files-found: error
- name: Upload osx-arm64 package
uses: actions/upload-artifact@v4
with:
name: CosmosDBShell-osx-arm64-${{ steps.version.outputs.artifact_suffix }}
path: out/nupkg/CosmosDBShell.osx-arm64.*.nupkg
if-no-files-found: error