Skip to content

Commit c12edce

Browse files
committed
Replace AppVeyor with GitHub Actions and NuGet trusted publishing
- Add a CI workflow (build + test on push/PR to master) and a CD workflow (pack and publish on a v*.*.* tag). Both run on windows-latest because the library targets net40/net45 and the demo targets net48, and restore in locked mode against the committed lock files. - Publish to NuGet with Trusted Publishing (OIDC) via NuGet/login: no long-lived API key, authorized by a trusted-publishing policy on nuget.org that names the cd.yml workflow. The nuget.org account name is provided through the NUGET_USER secret. - Emit a symbol package (snupkg) and attach the package to a generated GitHub Release on tag. - Run tests on Microsoft.Testing.Platform with a TRX report uploaded as a CI artifact (adds the Microsoft.Testing.Extensions.TrxReport extension). - Pin the SDK in global.json so setup-dotnet installs a known version. - Remove the AppVeyor definitions, the now-obsolete empty Version tag, and point the solution folder and README badges at the new workflows.
1 parent 087cc71 commit c12edce

10 files changed

Lines changed: 206 additions & 74 deletions

File tree

.github/workflows/cd.yml

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
name: CD
2+
3+
# Builds, tests and packs the NuGet package on a version tag (v1.2.3) or manual run.
4+
# Publishing to NuGet uses Trusted Publishing (OIDC) and runs only on a v*.*.* tag push; a manual
5+
# run packs and uploads the artifact as a dry run without publishing (see the step comments below).
6+
7+
on:
8+
push:
9+
tags: [ 'v*.*.*' ]
10+
workflow_dispatch:
11+
inputs:
12+
version:
13+
description: 'Package version, e.g. 1.2.3. Defaults to a dev version when omitted.'
14+
required: false
15+
16+
permissions:
17+
contents: read
18+
19+
jobs:
20+
pack-publish:
21+
name: Pack & Publish
22+
# Windows is required: the library multi-targets net40/net45 and the demo targets net48, which
23+
# need the .NET Framework reference assemblies / targeting packs available on the Windows runners.
24+
runs-on: windows-latest
25+
timeout-minutes: 15
26+
permissions:
27+
id-token: write # Required for NuGet Trusted Publishing; without it NuGet/login fails with 403.
28+
contents: write # Required to create the GitHub Release; a job-level block drops inherited defaults.
29+
steps:
30+
- uses: actions/checkout@v6
31+
32+
- name: Setup .NET
33+
uses: actions/setup-dotnet@v5
34+
with:
35+
# Install the exact SDK pinned in global.json; Dependabot's dotnet-sdk updater keeps it current.
36+
global-json-file: global.json
37+
# Cache the restored NuGet packages, keyed on the committed lock files.
38+
cache: true
39+
cache-dependency-path: '**/packages.lock.json'
40+
41+
- name: Resolve version
42+
id: version
43+
shell: bash
44+
# The manual input is read through an env var, not interpolated into the script, so a crafted
45+
# value cannot inject shell. It is then validated as SemVer before anything downstream uses it.
46+
env:
47+
VERSION_INPUT: ${{ github.event.inputs.version }}
48+
run: |
49+
if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then
50+
VERSION="${GITHUB_REF_NAME#v}"
51+
elif [[ -n "${VERSION_INPUT}" ]]; then
52+
VERSION="${VERSION_INPUT}"
53+
if ! [[ "${VERSION}" =~ ^[0-9]+\.[0-9]+\.[0-9]+([-.][0-9A-Za-z.-]+)?$ ]]; then
54+
echo "Invalid version '${VERSION}'; expected SemVer such as 1.2.3 or 1.2.3-rc.1." >&2
55+
exit 1
56+
fi
57+
else
58+
VERSION="0.0.0-dev.${GITHUB_RUN_NUMBER}"
59+
fi
60+
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
61+
echo "Resolved package version: ${VERSION}"
62+
63+
- name: Restore
64+
# Locked-mode restore fails the build if any packages.lock.json is missing or out of date, so the
65+
# restore is reproducible and a forgotten lock-file update cannot slip through.
66+
run: dotnet restore SQLite.CodeFirst.slnx --locked-mode
67+
68+
- name: Build
69+
run: dotnet build SQLite.CodeFirst.slnx -c Release --no-restore -p:Version=${{ steps.version.outputs.version }}
70+
71+
- name: Test
72+
# The test project runs on Microsoft.Testing.Platform (opted in via global.json), so target the
73+
# solution with the native MTP dotnet test syntax.
74+
run: dotnet test --solution SQLite.CodeFirst.slnx -c Release --no-build
75+
76+
- name: Pack
77+
run: >
78+
dotnet pack SQLite.CodeFirst/SQLite.CodeFirst.csproj -c Release --no-build
79+
-p:Version=${{ steps.version.outputs.version }}
80+
-o ${{ github.workspace }}/artifacts
81+
82+
- name: Upload package artifact
83+
uses: actions/upload-artifact@v7
84+
with:
85+
name: nuget-package
86+
path: |
87+
${{ github.workspace }}/artifacts/*.nupkg
88+
${{ github.workspace }}/artifacts/*.snupkg
89+
90+
# --- NuGet publishing via Trusted Publishing (OIDC). ---
91+
# No long-lived API key: NuGet/login swaps the GitHub OIDC token for a short-lived key, authorized
92+
# by the trusted publishing policy on nuget.org (the policy must name this workflow file, cd.yml).
93+
# Gated to tag pushes so a manual run stays a dry run and never pushes the 0.0.0-dev.* version.
94+
# https://learn.microsoft.com/nuget/nuget-org/trusted-publishing
95+
- name: NuGet login (OIDC)
96+
id: nuget-login
97+
if: startsWith(github.ref, 'refs/tags/v')
98+
uses: NuGet/login@v1
99+
with:
100+
user: ${{ secrets.NUGET_USER }} # nuget.org account/profile name, NOT the email address.
101+
102+
- name: Publish to NuGet
103+
if: startsWith(github.ref, 'refs/tags/v')
104+
run: >
105+
dotnet nuget push "${{ github.workspace }}/artifacts/*.nupkg"
106+
--api-key "${{ steps.nuget-login.outputs.NUGET_API_KEY }}"
107+
--source https://api.nuget.org/v3/index.json
108+
--skip-duplicate
109+
110+
# --- GitHub Release. ---
111+
# Created only on tag pushes, after a successful NuGet publish, so the Release reflects what was
112+
# actually shipped. Uses the gh CLI (preinstalled on the runner) rather than a third-party action.
113+
# --generate-notes builds the notes from commits/PRs since the previous tag; --verify-tag guards
114+
# against creating a release for a tag the runner cannot see. The .nupkg/.snupkg are attached so
115+
# the package is downloadable straight from the Release page, not just the workflow run.
116+
- name: Create GitHub Release
117+
if: startsWith(github.ref, 'refs/tags/v')
118+
shell: bash
119+
# The tag is passed through an env var rather than interpolated into the script, matching the
120+
# version step above.
121+
env:
122+
GH_TOKEN: ${{ github.token }}
123+
TAG: ${{ github.ref_name }}
124+
run: |
125+
# SemVer pre-release tags carry a hyphen (e.g. v1.2.3-rc.1); mark those as GitHub pre-releases.
126+
prerelease=""
127+
if [[ "${TAG}" == *-* ]]; then prerelease="--prerelease"; fi
128+
gh release create "${TAG}" \
129+
--title "${TAG}" \
130+
--generate-notes \
131+
--verify-tag \
132+
${prerelease} \
133+
"${GITHUB_WORKSPACE}/artifacts/"*.nupkg \
134+
"${GITHUB_WORKSPACE}/artifacts/"*.snupkg

.github/workflows/ci.yml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [ master ]
6+
pull_request:
7+
branches: [ master ]
8+
9+
jobs:
10+
build-test:
11+
name: Build & Test
12+
# Windows is required: the library multi-targets net40/net45 and the demo targets net48, which
13+
# need the .NET Framework reference assemblies / targeting packs available on the Windows runners.
14+
runs-on: windows-latest
15+
timeout-minutes: 15
16+
steps:
17+
- uses: actions/checkout@v6
18+
19+
- name: Setup .NET
20+
uses: actions/setup-dotnet@v5
21+
with:
22+
# Install the exact SDK pinned in global.json; Dependabot's dotnet-sdk updater keeps it current.
23+
global-json-file: global.json
24+
# Cache the restored NuGet packages, keyed on the committed lock files.
25+
cache: true
26+
cache-dependency-path: '**/packages.lock.json'
27+
28+
- name: Restore
29+
# Locked-mode restore fails the build if any packages.lock.json is missing or out of date, so the
30+
# restore is reproducible and a forgotten lock-file update cannot slip through.
31+
run: dotnet restore SQLite.CodeFirst.slnx --locked-mode
32+
33+
- name: Build
34+
run: dotnet build SQLite.CodeFirst.slnx -c Release --no-restore
35+
36+
- name: Test
37+
# The test project runs on Microsoft.Testing.Platform (opted in via global.json), so this uses the
38+
# native MTP dotnet test syntax: --solution, and the TRX report flags instead of --logger trx.
39+
run: >
40+
dotnet test --solution SQLite.CodeFirst.slnx -c Release --no-build
41+
--report-trx --report-trx-filename test-results.trx
42+
--results-directory ${{ github.workspace }}/TestResults
43+
44+
- name: Upload test results
45+
if: always()
46+
uses: actions/upload-artifact@v7
47+
with:
48+
name: test-results
49+
path: ${{ github.workspace }}/TestResults/*.trx
50+
if-no-files-found: ignore

README.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
# SQLite CodeFirst
22

3-
**Release Build** [![Build status](https://ci.appveyor.com/api/projects/status/2qavdqctw0ehscm6/branch/master?svg=true)](https://ci.appveyor.com/project/msallin/sqlitecodefirst-nv6vn/branch/master)
4-
5-
**CI Build** [![Build status](https://ci.appveyor.com/api/projects/status/oc1miog385h801qe?svg=true)](https://ci.appveyor.com/project/msallin/sqlitecodefirst)
3+
[![CI](https://github.com/msallin/SQLiteCodeFirst/actions/workflows/ci.yml/badge.svg)](https://github.com/msallin/SQLiteCodeFirst/actions/workflows/ci.yml)
4+
[![CD](https://github.com/msallin/SQLiteCodeFirst/actions/workflows/cd.yml/badge.svg)](https://github.com/msallin/SQLiteCodeFirst/actions/workflows/cd.yml)
65

76
Creates a [SQLite Database](https://sqlite.org/) from Code, using [Entity Framework](https://msdn.microsoft.com/en-us/data/ef.aspx) CodeFirst.
87

SQLite.CodeFirst.Test/SQLite.CodeFirst.Test.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
<PackageReference Include="Moq" Version="4.20.72" />
1515
<PackageReference Include="MSTest.TestAdapter" Version="4.2.3" />
1616
<PackageReference Include="MSTest.TestFramework" Version="4.2.3" />
17+
<!-- TRX report extension so the test run can emit a .trx report under Microsoft.Testing.Platform (CI). -->
18+
<PackageReference Include="Microsoft.Testing.Extensions.TrxReport" Version="2.2.3" />
1719
</ItemGroup>
1820
<ItemGroup>
1921
<ProjectReference Include="..\SQLite.CodeFirst.NetCore.Console\SQLite.CodeFirst.NetCore.Console.csproj" />

SQLite.CodeFirst.Test/packages.lock.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,16 @@
22
"version": 1,
33
"dependencies": {
44
"net10.0": {
5+
"Microsoft.Testing.Extensions.TrxReport": {
6+
"type": "Direct",
7+
"requested": "[2.2.3, )",
8+
"resolved": "2.2.3",
9+
"contentHash": "9Hot3ty5ZVWHrW40k2NPfD0dCaPwIxj7j7VjujNYwpYkYw9AdbejPHjGNkL/gvUWorauJf5IkeDoUeIbS7LuUg==",
10+
"dependencies": {
11+
"Microsoft.Testing.Extensions.TrxReport.Abstractions": "2.2.3",
12+
"Microsoft.Testing.Platform": "2.2.3"
13+
}
14+
},
515
"Moq": {
616
"type": "Direct",
717
"requested": "[4.20.72, )",

SQLite.CodeFirst.slnx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Solution>
22
<Folder Name="/Build/">
3-
<File Path="ci_appveyor.yml" />
4-
<File Path="release_appveyor.yml" />
3+
<File Path=".github/workflows/ci.yml" />
4+
<File Path=".github/workflows/cd.yml" />
55
</Folder>
66
<Folder Name="/Shared/">
77
<File Path="README.md" />

SQLite.CodeFirst/SQLite.CodeFirst.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@
44
<TargetFrameworks>net40;net45;netstandard2.1</TargetFrameworks>
55
<Authors>Marc Sallin</Authors>
66
<Company />
7-
<Version /> <!-- This empty tag is necessary to make appveyor csproj version patching work! -->
87
<Description>Creates a SQLite Database from Code, using Entity Framework CodeFirst. This Project ships several IDbInitializer which creates a new SQLite Database, based on your model/code.</Description>
98
<PackageProjectUrl>https://github.com/msallin/SQLiteCodeFirst</PackageProjectUrl>
109
<RepositoryUrl>https://github.com/msallin/SQLiteCodeFirst</RepositoryUrl>
1110
<RepositoryType>GitHub</RepositoryType>
1211
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
12+
<IncludeSymbols>true</IncludeSymbols>
13+
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
1314
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
1415
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
1516
<Copyright>Copyright (C) Marc Sallin</Copyright>

ci_appveyor.yml

Lines changed: 0 additions & 23 deletions
This file was deleted.

global.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
{
2+
"sdk": {
3+
"version": "10.0.300",
4+
"rollForward": "latestMinor"
5+
},
26
"test": {
37
"runner": "Microsoft.Testing.Platform"
48
}

release_appveyor.yml

Lines changed: 0 additions & 45 deletions
This file was deleted.

0 commit comments

Comments
 (0)