Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build NuGet packages in CI #9

Merged
merged 18 commits into from
Oct 15, 2024
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
5 changes: 4 additions & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
*.verified.txt text eol=lf working-tree-encoding=UTF-8
*.verified.xml text eol=lf working-tree-encoding=UTF-8
*.verified.json text eol=lf working-tree-encoding=UTF-8
*.verified.json text eol=lf working-tree-encoding=UTF-8

# force LF line endings on all shell scripts, even on Windows
*.sh text eol=lf
68 changes: 68 additions & 0 deletions .github/workflows/nuget-ci-cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
name: Build NuGet packages

on:
push:
branches: [ develop, main ]
tags:
- v*
pull_request:
branches: [ develop, main ]

jobs:
build:
permissions:
packages: write
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4
with:
# We use `git describe` to find tags in commit history, so we need complete repo history
fetch-depth: 0

- name: Calculate version number for PR build
if: github.event_name == 'pull_request'
shell: bash
run: src/calculate-version.sh "${{ github.run_number }}" "${{ github.event.number }}"

- name: Calculate version number for non-PR build
if: github.event_name != 'pull_request'
shell: bash
run: src/calculate-version.sh "${{ github.run_number }}"

- name: Install .NET
uses: actions/setup-dotnet@v4

- name: Build & test
run: dotnet test --configuration Release --logger GitHubActions

- name: Pack
shell: bash
run: |
dotnet pack --include-symbols /p:PackageVersion="$PACKAGE_VERSION" /p:AssemblyVersion="$ASSEMBLY_VERSION" /p:FileVersion="$FILE_VERSION"

- name: Upload packages to build artifacts
uses: actions/upload-artifact@v4
with:
name: nuget-packages
path: src/artifacts/package/release/*nupkg

# Not using the GitHub package registry right now, since it doesn't allow anonymous access so it's a hassle to use

# - name: Publish package to GitHub
# if: github.event_name == 'pull_request' || (github.event_name == 'push' && startsWith(github.ref, 'refs/heads'))
# shell: bash
# run: |
# dotnet nuget push "src/artifacts/package/release/*.symbols.nupkg" -s https://nuget.pkg.github.com/sillsdev/index.json -k "$NUGET_API_KEY" --skip-duplicate
# env:
# NUGET_API_KEY: ${{ secrets.GITHUB_TOKEN }}

# - name: Publish package to NuGet.org
# if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
# shell: bash
# run: |
# echo Would run the following:
# echo dotnet nuget push "src/artifacts/package/release/*nupkg" --skip-duplicate --api-key "$NUGET_API_KEY" --source https://api.nuget.org/v3/index.json
# env:
# NUGET_API_KEY: ${{ secrets.SILLSDEV_PUBLISH_NUGET_ORG }}
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,3 +175,14 @@ ISyncable remoteModel;
await dataModel.SyncWith(remoteModel);
```
It's that easy. All the heavy lifting is done by the interface which is fairly simple to implement.

## Development

### SemVer commit messages

NuGet package versions are calculated from a combination of tags and commit messages. First, the most recent Git tag matching the pattern `v\d+.\d+.\d+` is located. If that is the commit being built, then that version number is used. If there have been any commits since then, the version number will be bumped by looking for one of the following patterns in the commit messages:

* `+semver: major` or `+semver: breaking` - update major version number, reset others to 0 (so 2.3.1 would become 3.0.0)
* `+semver: minor` or `+semver: feature` - update minor version number, reset patch to 0 (so 2.3.1 would become 2.4.0)
* Anything else, including no `+semver` lines at all - update patch version number (so 2.3.1 would become 2.3.2)
* If you want to include `+semver` lines, then `+semver: patch` or `+semver: fix` are the standard ways to increment a patch version bump, but the patch version will be bumped regardless as long as there is at least one commit since the most recent tag.
9 changes: 9 additions & 0 deletions src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<UseArtifactsOutput>true</UseArtifactsOutput>
<IsPackable Condition=" '$(IsPackable)' == '' ">false</IsPackable>
</PropertyGroup>

<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<AssemblyVersion Condition=" '$(AssemblyVersion)' == '' ">$(ASSEMBLY_VERSION)</AssemblyVersion>
<AssemblyVersion Condition=" '$(AssemblyVersion)' == '' ">0.1.0.0</AssemblyVersion>
<FileVersion Condition=" '$(FileVersion)' == '' ">$(FILE_VERSION)</FileVersion>
<FileVersion Condition=" '$(FileVersion)' == '' ">0.1.0.0</FileVersion>
</PropertyGroup>

<ItemGroup>
Expand Down
1 change: 1 addition & 0 deletions src/SIL.Harmony.Core/SIL.Harmony.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

<PropertyGroup>
<RootNamespace>SIL.Harmony.Core</RootNamespace>
<IsPackable>true</IsPackable>
</PropertyGroup>
<ItemGroup>
<InternalsVisibleTo Include="SIL.Harmony"/>
Expand Down
1 change: 1 addition & 0 deletions src/SIL.Harmony.Linq2db/SIL.Harmony.Linq2db.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

<PropertyGroup>
<RootNamespace>SIL.Harmony.Linq2db</RootNamespace>
<IsPackable>true</IsPackable>
</PropertyGroup>

<ItemGroup>
Expand Down
1 change: 1 addition & 0 deletions src/SIL.Harmony/SIL.Harmony.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

<PropertyGroup>
<RootNamespace>SIL.Harmony</RootNamespace>
<IsPackable>true</IsPackable>
</PropertyGroup>

<ItemGroup>
Expand Down
80 changes: 80 additions & 0 deletions src/calculate-version.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#!/bin/bash

# Pass build number and PR number as command-line params, e.g.:
# calculate-version.sh "${{ github.run_number }}" "${{ github.event.number }}"
# If present, command-line params override env vars

BUILD_NUMBER=$1
PR_NUMBER=$2

if [ -z "$BUILD_NUMBER" ]; then
echo "Required: pass a build number as first parameter"
echo "Optional: pass a PR number as second parameter"
exit 2
fi

# If running in CI, current commit is in GITHUB_REF env var
# If not running in CI, use git rev-parse to calculate it
GITHUB_REF=${GITHUB_REF:-$(git rev-parse --symbolic-full-name HEAD)}

# Find most recent tag
DESCRIBE=$(git describe --long --match "v*")
TAG=$(echo "$DESCRIBE" | grep -E -o '^v[0-9]+\.[0-9]+\.[0-9]+')

# Split version number from tag into major/minor/patch sections
MAJOR=$(echo "$TAG" | sed -E 's/^v([0-9]+)\.([0-9]+)\.([0-9]+)$/\1/')
MINOR=$(echo "$TAG" | sed -E 's/^v([0-9]+)\.([0-9]+)\.([0-9]+)$/\2/')
PATCH=$(echo "$TAG" | sed -E 's/^v([0-9]+)\.([0-9]+)\.([0-9]+)$/\3/')

# Calculate prerelease suffix, if any
SUFFIX=""
if [ -n "$PR_NUMBER" ]; then
SUFFIX="-PR${PR_NUMBER}.${BUILD_NUMBER}"
elif [ "$GITHUB_REF" = "refs/heads/develop" ]; then
SUFFIX="-beta.${BUILD_NUMBER}"
elif [ "$GITHUB_REF" = "refs/heads/main" ]; then
SUFFIX="-rc.${BUILD_NUMBER}"
fi

# Calculate version number bump
# Same logic as GitVersion:
# * "+semver: breaking" or "+semver: major" in commit log will produce major version bump (and reset minor and patch to 0)
# * "+semver: feature" or "+semver: minor" in commit log will produce minor version bump (and reset patch to 0)
# Default is to bump the patch version
# Git log format "%B" is the raw body with no author's email or anything else
COMMIT_COUNT=$(echo "$DESCRIBE" | sed -E 's/^[^-]+-([^-]+)-.*$/\1/')
if [ -n "$COMMIT_COUNT" -a "$COMMIT_COUNT" -gt 0 ]; then
# Calculate bump based on commit messages
RAW_LOG=$(git log --format="%B" "$TAG"..HEAD)
if grep -E '\+semver: (breaking|major)' <<< "$RAW_LOG"; then
MAJOR=$(($MAJOR + 1))
MINOR=0
PATCH=0
elif grep -E '\+semver: (feature|minor)' <<< "$RAW_LOG"; then
MINOR=$(($MINOR + 1))
PATCH=0
else
PATCH=$(($PATCH + 1))
fi
fi

# Set version number variables for MSBuild
export PACKAGE_VERSION=${MAJOR}.${MINOR}.${PATCH}${SUFFIX}
if [ $MAJOR -eq 0 ]; then
export ASSEMBLY_VERSION=0.${MINOR}.0.0
else
export ASSEMBLY_VERSION=${MAJOR}.0.0.0
fi
export FILE_VERSION=${MAJOR}.${MINOR}.${PATCH}.${BUILD_NUMBER}

# Put output variables into GITHUB_ENV if it exists
if [ -n "$GITHUB_ENV" ]; then
echo "PACKAGE_VERSION=${PACKAGE_VERSION}" >> "$GITHUB_ENV"
echo "ASSEMBLY_VERSION=${ASSEMBLY_VERSION}" >> "$GITHUB_ENV"
echo "FILE_VERSION=${FILE_VERSION}" >> "$GITHUB_ENV"
fi

# And show them on the console regardless
echo "PACKAGE_VERSION=${PACKAGE_VERSION}"
echo "ASSEMBLY_VERSION=${ASSEMBLY_VERSION}"
echo "FILE_VERSION=${FILE_VERSION}"