Skip to content
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
3 changes: 3 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ jobs:
<<: *defaults
steps:
- checkout
- run:
name: Verify version metadata
command: bash scripts/verify-version.sh
- run:
name: Install dependencies
command: dotnet restore trolley.sln
Expand Down
37 changes: 37 additions & 0 deletions .cursor/rules/version-bump.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
description: Keep SDK version metadata consistent across all release files
globs: trolley/trolley.csproj,trolley/Types/Supporting/SemVer.cs,trolley/Properties/AssemblyInfo.cs,trolley/trolley.nuspec,scripts/**
alwaysApply: false
---

# SDK Version Bumps

When changing the .NET SDK release version, update **every** location below in the same change. Do not bump only `trolley.csproj`.

| File | Field | Example for `2.3.1` |
|------|-------|---------------------|
| `trolley/trolley.csproj` | `<Version>` | `2.3.1` |
| `trolley/trolley.csproj` | `<ApplicationVersion>` | `2.3.1.0` |
| `trolley/Types/Supporting/SemVer.cs` | `MAJOR`, `PATCH`, `MINOR` | `2`, `3`, `1` |
| `trolley/Properties/AssemblyInfo.cs` | `AssemblyFileVersion` | `2.3.1.0` |
| `trolley/Properties/AssemblyInfo.cs` | `AssemblyInformationalVersion` | `2.3.1` |
| `trolley/trolley.nuspec` | `<version>` | `2.3.1` |

Notes:
- `SemVer.cs` uses `MAJOR.PATCH.MINOR` for the `Trolley-Source` header (not standard SemVer naming).
- Leave `AssemblyVersion("2.0.0.0")` unchanged unless there is an explicit assembly-version policy change.

After editing, run:

```bash
scripts/verify-version.sh
scripts/verify-version.sh 2.3.1 # optional explicit target
```

Before publishing, run:

```bash
scripts/cut-release.sh 2.3.1
```

CI runs `scripts/verify-version.sh` on every PR and push to `main`.
2 changes: 2 additions & 0 deletions .github/workflows/dotnet-core.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ jobs:
TROLLEY_API_BASE_URL: ${{ secrets.TROLLEY_API_BASE_URL }}
steps:
- uses: actions/checkout@v4
- name: Verify version metadata
run: scripts/verify-version.sh
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
Expand Down
123 changes: 123 additions & 0 deletions scripts/cut-release.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#!/usr/bin/env bash
set -euo pipefail

usage() {
cat <<'EOF'
Usage: scripts/cut-release.sh <version> [--publish]

Validates a release candidate for the trolleyhq NuGet package.

Examples:
scripts/cut-release.sh 2.3.1
scripts/cut-release.sh 2.3.1 --publish

Options:
--publish Trigger the manual NuGet publish workflow for the current commit.

The --publish option must be run from main after the release PR is merged.
EOF
}

if [[ $# -lt 1 ]]; then
usage
exit 1
fi

version="$1"
publish="false"

shift
while [[ $# -gt 0 ]]; do
case "$1" in
--publish)
publish="true"
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown option: $1" >&2
usage
exit 1
;;
esac
shift
done

if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Version must be SemVer in the form MAJOR.MINOR.PATCH, got: $version" >&2
exit 1
fi

repo_root="$(git rev-parse --show-toplevel)"
cd "$repo_root"

if [[ -n "$(git status --porcelain)" ]]; then
echo "Working tree is not clean. Commit or stash changes before cutting a release." >&2
exit 1
fi

echo "Checking version metadata..."
scripts/verify-version.sh "$version"

package_file="trolley/bin/Release/trolleyhq.${version}.nupkg"

echo "Restoring dependencies..."
dotnet restore trolley.sln

echo "Building release package..."
dotnet build trolley.sln --configuration Release --no-restore

echo "Running local release helper tests..."
dotnet test tests/tests.sln \
--configuration Release \
--no-build \
--filter FullyQualifiedName~ClientRequestTest

if [[ -n "${TROLLEY_ACCESS_KEY:-}" && -n "${TROLLEY_SECRET_KEY:-}" ]]; then
echo "Running integration tests with configured Trolley credentials..."
dotnet test tests/tests.sln --configuration Release --no-build
else
echo "Skipping full integration tests because TROLLEY_ACCESS_KEY/TROLLEY_SECRET_KEY are not set."
fi

if [[ ! -f "$package_file" ]]; then
echo "Expected package was not created: $package_file" >&2
exit 1
fi

status="$(curl -s -o /dev/null -w "%{http_code}" "https://api.nuget.org/v3-flatcontainer/trolleyhq/${version}/trolleyhq.${version}.nupkg")"
if [[ "$status" == "200" ]]; then
echo "trolleyhq $version already exists on NuGet." >&2
exit 1
fi

if [[ "$status" != "404" ]]; then
echo "Unexpected NuGet availability check status: $status" >&2
exit 1
fi

echo "Release candidate $version is ready."

if [[ "$publish" != "true" ]]; then
echo "To publish after merge, run: scripts/cut-release.sh $version --publish"
exit 0
fi

branch="$(git branch --show-current)"
if [[ "$branch" != "main" ]]; then
echo "--publish must be run from main, current branch: $branch" >&2
exit 1
fi

git fetch origin main --quiet
if [[ "$(git rev-parse HEAD)" != "$(git rev-parse origin/main)" ]]; then
echo "Local main is not at origin/main. Pull the latest main before publishing." >&2
exit 1
fi

echo "Triggering NuGet publish workflow..."
gh workflow run publish-netcore.yml --ref main

echo "Publish workflow triggered. Monitor with: gh run list --workflow publish-netcore.yml --limit 1"
91 changes: 91 additions & 0 deletions scripts/verify-version.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#!/usr/bin/env bash
set -euo pipefail

usage() {
cat <<'EOF'
Usage: scripts/verify-version.sh [version]

Verify SDK version metadata is consistent across all release files.

If version is omitted, the canonical version is read from trolley/trolley.csproj.

Checked locations:
- trolley/trolley.csproj (<Version>, <ApplicationVersion>)
- trolley/Types/Supporting/SemVer.cs (MAJOR, PATCH, MINOR -> User-Agent)
- trolley/Properties/AssemblyInfo.cs (AssemblyFileVersion, AssemblyInformationalVersion)
- trolley/trolley.nuspec (<version>)
EOF
}

if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
usage
exit 0
fi

repo_root="$(git rev-parse --show-toplevel)"
cd "$repo_root"

project_file="trolley/trolley.csproj"
semver_file="trolley/Types/Supporting/SemVer.cs"
assembly_info_file="trolley/Properties/AssemblyInfo.cs"
nuspec_file="trolley/trolley.nuspec"

first_match() {
awk 'NF { print; exit }'
}

xml_value() {
local file="$1"
local tag="$2"

sed -nE "s/.*<${tag}>([^<]+)<\\/${tag}>.*/\\1/p" "$file" | first_match
}

semver_part() {
local name="$1"

sed -nE "s/.*public[[:space:]]+static[[:space:]]+int[[:space:]]+${name}[[:space:]]*=[[:space:]]*([0-9]+).*/\\1/p" "$semver_file" | first_match
}

assembly_attribute() {
local name="$1"

sed -nE "s/.*${name}\\(\"([^\"]+)\"\\).*/\\1/p" "$assembly_info_file" | first_match
}

project_version="$(xml_value "$project_file" "Version")"
application_version="$(xml_value "$project_file" "ApplicationVersion")"
semver_version="$(semver_part "MAJOR").$(semver_part "PATCH").$(semver_part "MINOR")"
file_version="$(assembly_attribute "AssemblyFileVersion")"
info_version="$(assembly_attribute "AssemblyInformationalVersion")"
nuspec_version="$(xml_value "$nuspec_file" "version")"
expected="${1:-$project_version}"

errors=()

check() {
local label="$1"
local actual="$2"
local want="$3"

if [[ "$actual" != "$want" ]]; then
errors+=("${label}: expected '${want}', found '${actual}'")
fi
}

check "trolley/trolley.csproj <Version>" "$project_version" "$expected"
check "trolley/trolley.csproj <ApplicationVersion>" "$application_version" "${expected}.0"
check "trolley/Types/Supporting/SemVer.cs" "$semver_version" "$expected"
check "trolley/Properties/AssemblyInfo.cs AssemblyFileVersion" "$file_version" "${expected}.0"
check "trolley/Properties/AssemblyInfo.cs AssemblyInformationalVersion" "$info_version" "$expected"
check "trolley/trolley.nuspec <version>" "$nuspec_version" "$expected"

if (( ${#errors[@]} > 0 )); then
echo "Version metadata mismatch:" >&2
printf ' - %s\n' "${errors[@]}" >&2
echo >&2
echo "Update every location above when bumping the SDK version." >&2
exit 1
fi

echo "Version metadata is consistent at ${expected}."
4 changes: 2 additions & 2 deletions trolley/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,5 @@
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("2.0.0.0")]
[assembly: AssemblyFileVersion("2.3.0.0")]
[assembly: AssemblyInformationalVersion("2.3.0")]
[assembly: AssemblyFileVersion("2.3.1.0")]
[assembly: AssemblyInformationalVersion("2.3.1")]
2 changes: 1 addition & 1 deletion trolley/trolley.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
<PackageDescription>The official Trolley .NET SDK to interface with the Trolley API (https://www.trolley.com/)</PackageDescription>
<PackageReadmeFile>README.md</PackageReadmeFile>
<Copyright>Copyright 2020</Copyright>
<Authors>Jesse Tremblay, Jesse Silber, Joshua Cunningham, Aman Aalam</Authors>
<Authors>Jesse Tremblay, Jesse Silber, Joshua Cunningham, Aman Aalam, Barnett Klane</Authors>
<PackageTags>Trolley net sdk PaymentRails</PackageTags>
<RepositoryUrl>https://github.com/Trolley/dotnet-sdk/</RepositoryUrl>
<RepositoryType>Git</RepositoryType>
Expand Down
4 changes: 2 additions & 2 deletions trolley/trolley.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
<package >
<metadata>
<id>trolleyhq</id>
<version>2.3.0</version>
<version>2.3.1</version>
<title>$title$</title>
<authors>Jesse Tremblay, Jesse Silber, Joshua Cunningham, Aman Aalam</authors>
<authors>Jesse Tremblay, Jesse Silber, Joshua Cunningham, Aman Aalam, Barnett Klane</authors>
<owners>aman.trolley, trolley-developers, PaymentRailsJesse, joshuapr</owners>
<projectUrl>https://github.com/Trolley/dotnet-sdk</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
Expand Down
Loading