diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..b6f569a2 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,63 @@ +# If this file is renamed, the incrementing run attempt number will be reset. + +name: CI + +on: + push: + branches: [ "dev", "main" ] + pull_request: + branches: [ "dev", "main" ] + +env: + CI_BUILD_NUMBER_BASE: ${{ github.run_number }} + CI_TARGET_BRANCH: ${{ github.head_ref || github.ref_name }} + CI_PUBLISH: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} + +jobs: + build-windows: + name: Build (Windows) + runs-on: windows-latest + + permissions: + contents: write + + steps: + - uses: actions/checkout@v4 + - name: Setup + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 9.0.x + - name: Build and Publish + env: + DOTNET_CLI_TELEMETRY_OPTOUT: true + NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + shell: pwsh + run: | + ./build/Build.Windows.ps1 + + build-linux: + name: Build (Linux) + runs-on: ubuntu-22.04 + + permissions: + contents: write + + steps: + - uses: actions/checkout@v4 + - name: Setup + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 9.0.x + - name: Configure Docker + run: | + docker run --privileged --rm linuxkit/binfmt:bebbae0c1100ebf7bf2ad4dfb9dfd719cf0ef132 + sudo service docker restart + - name: Build and Publish + env: + DOTNET_CLI_TELEMETRY_OPTOUT: true + DOCKER_USER: ${{ secrets.DOCKER_USER }} + DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }} + shell: pwsh + run: | + ./build/Build.Linux.ps1 diff --git a/Build.Common.ps1 b/Build.Common.ps1 deleted file mode 100644 index 87f2d499..00000000 --- a/Build.Common.ps1 +++ /dev/null @@ -1,12 +0,0 @@ -function Get-SemVer($shortver) -{ - # This script originally (c) 2016 Serilog Contributors - license Apache 2.0 - $branch = @{ $true = $env:APPVEYOR_REPO_BRANCH; $false = $(git symbolic-ref --short -q HEAD) }[$env:APPVEYOR_REPO_BRANCH -ne $NULL]; - $suffix = @{ $true = ""; $false = ($branch.Substring(0, [math]::Min(10,$branch.Length)) -replace '[\/\+]','-').Trim("-")}[$branch -eq "main"] - - if ($suffix) { - $shortver + "-" + $suffix - } else { - $shortver - } -} diff --git a/Setup.ps1 b/Setup.ps1 deleted file mode 100644 index 2cef90f3..00000000 --- a/Setup.ps1 +++ /dev/null @@ -1,11 +0,0 @@ -$ErrorActionPreference = "Stop" - -$RequiredDotnetVersion = $(cat ./ci.global.json | convertfrom-json).sdk.version - -New-Item -ItemType Directory -Force "./build/" | Out-Null - -Invoke-WebRequest "https://dot.net/v1/dotnet-install.ps1" -OutFile "./build/installcli.ps1" -& ./build/installcli.ps1 -InstallDir "$pwd/.dotnetcli" -NoPath -Version $RequiredDotnetVersion -if ($LASTEXITCODE) { throw ".NET install failed" } - -$env:Path = "$pwd/.dotnetcli;$env:Path" diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index c0f95e9e..00000000 --- a/appveyor.yml +++ /dev/null @@ -1,56 +0,0 @@ -version: 2025.1.{build} -skip_tags: true -image: -- Visual Studio 2022 -- Ubuntu2004 -environment: - DOCKER_TOKEN: - secure: QKr2YEuliXdFKe3jN7w97w== - DOCKER_USER: - 'datalustbuild' -test: off -artifacts: -- path: artifacts/seqcli-*.zip -- path: artifacts/seqcli-*.tar.gz -- path: artifacts/seqcli.*.nupkg -- path: artifacts/seqcli-*.md - -for: -- - matrix: - only: - - image: Visual Studio 2022 - - install: - - pwsh: ./Setup.ps1 - - build_script: - - pwsh: ./Build.ps1 - - deploy: - - - provider: NuGet - api_key: - secure: 8gHaCWoeZrbMxRKH09E/cwYxYVvkiJ9P/GXC8H4oNxoYZ2pQgeWzBGkOT9noYrBU - skip_symbols: true - artifact: /seqcli\..*\.nupkg/ - on: - branch: main - - - provider: GitHub - auth_token: - secure: Bo3ypKpKFxinjR9ShkNekNvkob2iklHJU+UlYyfHtcFFIAa58SV2TkEd0xWxz633 - artifact: /seqcli-.*\.(nupkg|zip|tar\.gz)/ - tag: v$(appveyor_build_version) - on: - branch: main -- - matrix: - only: - - image: Ubuntu2004 - - install: - - pwsh: ./setup.sh - - build_script: - - pwsh: $env:PATH = "$env:HOME/.dotnetcli:$env:PATH"; ./Build.Docker.ps1 diff --git a/baseversion b/baseversion new file mode 100644 index 00000000..103ea540 --- /dev/null +++ b/baseversion @@ -0,0 +1 @@ +2025.1 \ No newline at end of file diff --git a/build/Build.Common.ps1 b/build/Build.Common.ps1 new file mode 100644 index 00000000..711462c1 --- /dev/null +++ b/build/Build.Common.ps1 @@ -0,0 +1,16 @@ +function Get-SemVer() +{ + $branch = @{ $true = $env:CI_TARGET_BRANCH; $false = $(git symbolic-ref --short -q HEAD) }[$NULL -ne $env:CI_TARGET_BRANCH]; + $revision = @{ $true = "{0:00000}" -f $([convert]::ToInt32($env:CI_BUILD_NUMBER_BASE, 10) + 2300); $false = "local" }[$NULL -ne $env:CI_BUILD_NUMBER_BASE] + $suffix = @{ $true = ""; $false = "$($branch.Substring(0, [math]::Min(10,$branch.Length)) -replace '([^a-zA-Z0-9\-]*)', '')-$revision"}[$branch -eq "main" -and $revision -ne "local"] + $commitHash = $(git rev-parse --short HEAD) + $buildSuffix = @{ $true = "$($suffix)-$($commitHash)"; $false = "$($branch)-$($commitHash)" }[$suffix -ne ""] + + $base = $(Get-Content ./baseversion).Trim() + + if ($suffix) { + $base + "." + $revision + "-" + $suffix + } else { + $revision + } +} diff --git a/Build.Docker.ps1 b/build/Build.Linux.ps1 similarity index 70% rename from Build.Docker.ps1 rename to build/Build.Linux.ps1 index e68c4381..aa2c188a 100644 --- a/Build.Docker.ps1 +++ b/build/Build.Linux.ps1 @@ -1,11 +1,9 @@ -Push-Location $PSScriptRoot +Push-Location $PSScriptRoot/../ -. ./Build.Common.ps1 +. ./build/Build.Common.ps1 -$IsCIBuild = $null -ne $env:APPVEYOR_BUILD_NUMBER -$IsPublishedBuild = ($env:APPVEYOR_REPO_BRANCH -eq "main" -or $env:APPVEYOR_REPO_BRANCH -eq "dev") -and $null -eq $env:APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH +$version = Get-SemVer -$version = Get-SemVer(@{ $true = $env:APPVEYOR_BUILD_VERSION; $false = "99.99.99" }[$env:APPVEYOR_BUILD_VERSION -ne $NULL]) $framework = "net9.0" $image = "datalust/seqcli" $archs = @( @@ -13,16 +11,13 @@ $archs = @( @{ rid = "arm64"; platform = "linux/arm64/v8" } ) -$endToEndVersion = "preview" - function Execute-Tests { & dotnet test ./test/SeqCli.Tests/SeqCli.Tests.csproj -c Release -f $framework /p:Configuration=Release /p:VersionPrefix=$version if ($LASTEXITCODE -ne 0) { exit 1 } cd ./test/SeqCli.EndToEnd/ - docker pull "datalust/seq:$endToEndVersion" - docker tag "datalust/seq:$endToEndVersion" datalust/seq:latest + docker pull datalust/seq:latest & dotnet run -f $framework -- --docker-server if ($LASTEXITCODE -ne 0) { @@ -35,6 +30,7 @@ function Execute-Tests function Build-DockerImage($arch) { $rid = "linux-$($arch.rid)" + & dotnet publish src/SeqCli/SeqCli.csproj -c Release -f $framework -r $rid --self-contained /p:VersionPrefix=$version /p:PublishSingleFile=true if($LASTEXITCODE -ne 0) { exit 2 } @@ -42,14 +38,19 @@ function Build-DockerImage($arch) if($LASTEXITCODE -ne 0) { exit 3 } } -function Publish-DockerImage($arch) +function Login-ToDocker() { $ErrorActionPreference = "SilentlyContinue" - if ($IsCIBuild) { - Write-Output "$env:DOCKER_TOKEN" | docker login -u $env:DOCKER_USER --password-stdin - if ($LASTEXITCODE) { exit 3 } - } + Write-Output "$env:DOCKER_TOKEN" | docker login -u $env:DOCKER_USER --password-stdin + if ($LASTEXITCODE) { exit 3 } + + $ErrorActionPreference = "Stop" +} + +function Publish-DockerImage($arch) +{ + $ErrorActionPreference = "SilentlyContinue" & docker push "$image-ci:$version-$($arch.rid)" if($LASTEXITCODE -ne 0) { exit 3 } @@ -76,13 +77,15 @@ Execute-Tests foreach ($arch in $archs) { Build-DockerImage($arch) +} - if ($IsPublishedBuild) { +if ("$($env:DOCKER_TOKEN)" -ne "") { + Login-ToDocker + + foreach ($arch in $archs) { Publish-DockerImage($arch) } -} -if ($IsPublishedBuild) { Publish-DockerManifest($archs) } diff --git a/Build.ps1 b/build/Build.Windows.ps1 similarity index 79% rename from Build.ps1 rename to build/Build.Windows.ps1 index caf8ff60..c36fe1f6 100644 --- a/Build.ps1 +++ b/build/Build.Windows.ps1 @@ -1,10 +1,11 @@ -Push-Location $PSScriptRoot +Push-Location $PSScriptRoot/../ -. ./Build.Common.ps1 +. ./build/Build.Common.ps1 $ErrorActionPreference = 'Stop' -$version = Get-SemVer(@{ $true = $env:APPVEYOR_BUILD_VERSION; $false = "99.99.99" }[$env:APPVEYOR_BUILD_VERSION -ne $NULL]) +$version = Get-SemVer + $framework = 'net9.0' $windowsTfmSuffix = '-windows' @@ -78,6 +79,26 @@ function Publish-Docs($version) if($LASTEXITCODE -ne 0) { throw "Build failed" } } +function Upload-NugetPackages +{ + # GitHub Actions will only supply this to branch builds and not PRs. We publish + # builds from any branch this action targets (i.e. main and dev). + + Write-Output "build: Publishing NuGet packages" + + foreach ($nupkg in Get-ChildItem artifacts/*.nupkg) { + & dotnet nuget push -k $env:NUGET_API_KEY -s https://api.nuget.org/v3/index.json "$nupkg" + if($LASTEXITCODE -ne 0) { throw "Publishing failed" } + } +} + +function Upload-GitHubRelease($version) +{ + Write-Output "build: Creating release for version $version" + + iex "gh release create v$version --title v$version --generate-notes $(get-item ./artifacts/*)" +} + function Remove-GlobalJson { if(Test-Path ./global.json) { rm ./global.json } @@ -104,6 +125,16 @@ Publish-Archives($version) Publish-DotNetTool($version) Execute-Tests($version) Publish-Docs($version) + +if ("$($env:NUGET_API_KEY)" -ne "") +{ + Upload-NugetPackages +} + +if ($env:CI_PUBLISH -eq "True") { + Upload-GitHubRelease($version) +} + Remove-GlobalJson Pop-Location diff --git a/docker-publish.ps1 b/docker-publish.ps1 deleted file mode 100644 index 99399c59..00000000 --- a/docker-publish.ps1 +++ /dev/null @@ -1,59 +0,0 @@ -param ( - [Parameter(Mandatory=$True)] - [string] $version -) - -$ErrorActionPreference = "Stop" - -$versionParts = $version.Split('.') - -$major = $versionParts[0] -$minor = $versionParts[1] -$isPre = $version.endswith("pre") - -$image = "datalust/seqcli" -$archs = @("x64", "arm64") -$publishImages = @() - -foreach ($arch in $archs) { - $ciImage = "$image-ci:$version-$arch" - $publishImage = "$($image):$version-$arch"; - - docker pull $ciImage - if ($LASTEXITCODE) { exit 1 } - - docker tag $ciImage $publishImage - if ($LASTEXITCODE) { exit 1 } - - docker push $publishImage - if ($LASTEXITCODE) { exit 1 } - - $publishImages += $publishImage -} - -$publishManifest = "$($image):$version" - -$pushTags = @($publishManifest) - -if ($isPre -eq $True) { - $pushTags += "$($image):preview" -} else { - $pushTags += "$($image):$major", "$($image):$major.$minor", "$($image):latest" -} - -$choices = "&Yes", "&No" -$decision = $Host.UI.PromptForChoice("Publishing ($publishManifest) as ($pushTags)", "Does this look right?", $choices, 1) -if ($decision -eq 0) { - foreach ($pushTag in $pushTags) { - Write-Host "Publishing $pushTag" - - echo "creating manifest $pushTag from $publishImages" - iex "docker manifest create $pushTag $publishImages" - if ($LASTEXITCODE) { exit 1 } - - docker manifest push $pushTag - if ($LASTEXITCODE) { exit 1 } - } -} else { - Write-Host "Cancelled" -} diff --git a/setup.sh b/setup.sh deleted file mode 100755 index 8477bc42..00000000 --- a/setup.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -# Exit if any command fails -set -e -set -o pipefail - -sudo apt-get update || true -sudo apt-get install -y --no-install-recommends jq - -RequiredDotnetVersion=$(jq -r '.sdk.version' ci.global.json) - -curl https://dot.net/v1/dotnet-install.sh -sSfL --output dotnet-install.sh -chmod +x dotnet-install.sh -./dotnet-install.sh --install-dir $HOME/.dotnetcli --no-path --version $RequiredDotnetVersion -rm dotnet-install.sh - -docker run --privileged --rm linuxkit/binfmt:bebbae0c1100ebf7bf2ad4dfb9dfd719cf0ef132 -sudo service docker restart diff --git a/test/SeqCli.EndToEnd/Support/TestConfiguration.cs b/test/SeqCli.EndToEnd/Support/TestConfiguration.cs index dd715813..1f33b97b 100644 --- a/test/SeqCli.EndToEnd/Support/TestConfiguration.cs +++ b/test/SeqCli.EndToEnd/Support/TestConfiguration.cs @@ -41,7 +41,7 @@ public CaptiveProcess SpawnServerProcess(string storagePath) { var containerName = Guid.NewGuid().ToString("n"); const string containerRuntime = "docker"; - return new CaptiveProcess(containerRuntime, $"run --name {containerName} -it --rm -e ACCEPT_EULA=Y -p {_serverListenPort}:80 datalust/seq:{imageTag}", stopCommandFullExePath: containerRuntime, stopCommandArgs: $"stop {containerName}"); + return new CaptiveProcess(containerRuntime, $"run --name {containerName} -d -e ACCEPT_EULA=Y -p {_serverListenPort}:80 datalust/seq:{imageTag}", stopCommandFullExePath: containerRuntime, stopCommandArgs: $"rm -f {containerName}"); } return new CaptiveProcess("seq", commandWithArgs);