From 4d392c5edc00482eab44896ae3f4e52203cfc477 Mon Sep 17 00:00:00 2001 From: Dexter Ajoku Date: Thu, 2 Apr 2026 04:01:15 +0200 Subject: [PATCH 1/3] Add CI and tag-driven NuGet/GitHub release workflows Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/ci.yml | 40 ++++++++++++++ .github/workflows/release.yml | 100 ++++++++++++++++++++++++++++++++++ README.md | 8 ++- 3 files changed, 146 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..00a93e4 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,40 @@ +name: CI + +on: + push: + branches: + - main + pull_request: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ci-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build-test: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 10.0.x + cache: true + + - name: Restore + run: dotnet restore Clockworks.sln + + - name: Build + run: dotnet build Clockworks.sln -c Release --no-restore + + - name: Test + run: dotnet test tests/Clockworks.Tests.csproj -c Release --no-build --nologo diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..1b4834b --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,100 @@ +name: Release + +on: + push: + tags: + - "v*.*.*" + workflow_dispatch: + inputs: + version: + description: "Package/release version (e.g. 1.3.1)" + required: true + type: string + +permissions: + contents: write + +concurrency: + group: release-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: false + +jobs: + publish: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 10.0.x + cache: true + + - name: Resolve version + id: vars + shell: bash + run: | + if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then + VERSION="${{ github.event.inputs.version }}" + TAG="v${VERSION}" + else + TAG="${GITHUB_REF_NAME}" + VERSION="${TAG#v}" + fi + + if [[ ! "${VERSION}" =~ ^[0-9]+\.[0-9]+\.[0-9]+([-+].*)?$ ]]; then + echo "Invalid version: ${VERSION}" + exit 1 + fi + + echo "version=${VERSION}" >> "${GITHUB_OUTPUT}" + echo "tag=${TAG}" >> "${GITHUB_OUTPUT}" + + - name: Ensure tag exists for manual runs + if: github.event_name == 'workflow_dispatch' + shell: bash + run: | + TAG="${{ steps.vars.outputs.tag }}" + git fetch --tags --force + if ! git rev-parse "${TAG}" >/dev/null 2>&1; then + echo "Tag ${TAG} does not exist in repository." + echo "Create and push it first (for example: git tag ${TAG} && git push origin ${TAG})." + exit 1 + fi + + - name: Restore + run: dotnet restore Clockworks.sln + + - name: Build + run: dotnet build Clockworks.sln -c Release --no-restore + + - name: Test + run: dotnet test tests/Clockworks.Tests.csproj -c Release --no-build --nologo + + - name: Pack + run: > + dotnet pack src/Clockworks.csproj + -c Release + --no-build + -p:PackageVersion=${{ steps.vars.outputs.version }} + -o artifacts/packages + + - name: Push package to NuGet + run: > + dotnet nuget push artifacts/packages/*.nupkg + --api-key ${{ secrets.NUGET_API_KEY }} + --source https://api.nuget.org/v3/index.json + --skip-duplicate + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ steps.vars.outputs.tag }} + generate_release_notes: true + files: | + artifacts/packages/*.nupkg + artifacts/packages/*.snupkg diff --git a/README.md b/README.md index f44b3fb..8869a7a 100644 --- a/README.md +++ b/README.md @@ -92,13 +92,13 @@ var header = new VectorClockMessageHeader( clock: clockA, correlationId: Guid.NewGuid() ); -var headerString = header.ToString(); // "1:1;{correlationId}" (example) +var headerString = header.ToString(); // "1:1;{correlationId:N}" (example) ``` ### Hybrid Logical Clock (HLC) propagation In Clockworks, a "remote timestamp" is the `HlcTimestamp` produced on a different node and carried over the wire -via `HlcMessageHeader` (format: `walltime.counter@node`). The receiver should call `BeforeReceive(...)` with that +via `HlcMessageHeader` (format: `walltime.counter@node[;correlationId;causationId]`). The receiver should call `BeforeReceive(...)` with that timestamp to preserve causality. Note: `HlcTimestamp.ToPackedInt64()`/`FromPackedInt64()` is an optimization encoding with a 48-bit wall time and a 4-bit node id (node id is truncated). Use `WriteTo`/`ReadFrom` when you need a full-fidelity representation. @@ -290,6 +290,10 @@ Clockworks follows Semantic Versioning (SemVer). - Package version is defined in `src/Clockworks.csproj`. - Release tags use the format `vX.Y.Z` (example: `v1.2.0`). - See `CHANGELOG.md` for notable changes. +- CI runs on pushes/PRs to `main` via `.github/workflows/ci.yml`. +- Publishing is automated by `.github/workflows/release.yml`: + - Trigger by pushing a tag like `v1.3.1` to publish to NuGet and create a GitHub Release. + - Or run the workflow manually with `version` input (the matching `vX.Y.Z` tag must already exist). Build-wide defaults are centralized in `Directory.Build.props`. From 234058e1739977cc399f29c974823fb7f50712e8 Mon Sep 17 00:00:00 2001 From: Dexter Ajoku Date: Thu, 2 Apr 2026 04:15:50 +0200 Subject: [PATCH 2/3] Remove setup-dotnet lockfile cache requirement --- .github/workflows/ci.yml | 1 - .github/workflows/release.yml | 1 - 2 files changed, 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 00a93e4..df90c05 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,7 +28,6 @@ jobs: uses: actions/setup-dotnet@v4 with: dotnet-version: 10.0.x - cache: true - name: Restore run: dotnet restore Clockworks.sln diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1b4834b..c23189a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -32,7 +32,6 @@ jobs: uses: actions/setup-dotnet@v4 with: dotnet-version: 10.0.x - cache: true - name: Resolve version id: vars From 36e52d5445c86c811ebff133cbbb5c33a08d7101 Mon Sep 17 00:00:00 2001 From: Dexter Ajoku Date: Thu, 2 Apr 2026 04:21:41 +0200 Subject: [PATCH 3/3] Add commit-msg hook to strip auto co-author trailers --- .githooks/commit-msg | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 .githooks/commit-msg diff --git a/.githooks/commit-msg b/.githooks/commit-msg new file mode 100644 index 0000000..cfe0fdc --- /dev/null +++ b/.githooks/commit-msg @@ -0,0 +1,16 @@ +#!/usr/bin/env sh +set -eu + +message_file="$1" +tmp_file="${message_file}.tmp" + +# Remove auto-injected co-author trailers we do not want in commit history. +awk ' +{ + if ($0 ~ /^Co-authored-by:[[:space:]]*Copilot[[:space:]]*<223556219\+Copilot@users\.noreply\.github\.com>[[:space:]]*$/) next + if ($0 ~ /^Co-authored-by:[[:space:]]*dexcompiler([[:space:]]*<[^>]+>)?[[:space:]]*$/) next + print $0 +} +' "$message_file" > "$tmp_file" + +mv "$tmp_file" "$message_file"