Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
69df3e8
Release: v1.0 = core rewrite, CI/CD, docs, and test suite overhaul (#…
github-actions[bot] Apr 4, 2026
41e4701
fixes for 1.0 (#171)
petesramek Apr 4, 2026
daa0569
FIX: workflows (#173)
petesramek Apr 4, 2026
7119c0c
version-snapshot guides alongside API reference, fix index.md links, …
petesramek Apr 4, 2026
5c2263a
minor updates to code and docs generation (#180)
petesramek Apr 4, 2026
12f6503
Fix version switcher URL bug and improve docs navigation/landing page…
petesramek Apr 4, 2026
8a6bf93
backtracking (#189)
petesramek Apr 4, 2026
b688f8b
backtracking (#195)
petesramek Apr 4, 2026
25325de
backtracking 2 (#198)
petesramek Apr 4, 2026
31ecf2d
Preview/1.0 (#202)
petesramek Apr 4, 2026
a24f4e7
Promote preview/1.0 to release/1.0 (#208)
github-actions[bot] Apr 4, 2026
81d350f
Promote preview/1.0 to release/1.0 (#211)
github-actions[bot] Apr 4, 2026
155b8c8
Promote preview/1.0 to release/1.0 (#215)
github-actions[bot] Apr 4, 2026
2da0dad
resolved conflicts
petesramek Apr 5, 2026
0ea3e5a
Promote preview/1.0 to release/1.0 (#245)
github-actions[bot] Oct 29, 2026
f490792
Fixed release workflow issues (#276)
petesramek Oct 29, 2026
599a063
Fixed unshipedd.txt update (#279)
petesramek Oct 29, 2026
9aae2c1
Fixed release promotion of unshipped to shipped api (#282)
petesramek Oct 29, 2026
f5b25ab
Fix release API promotion: use rulesets instead of branch protection …
petesramek Oct 29, 2026
7f15533
Promote PublicAPI.Unshipped.txt into PublicAPI.Shipped.txt for release
petesramek Oct 29, 2026
fbc2a02
Fix skipped release job condition, reverted package versioning (#288)
petesramek Oct 29, 2026
40d0033
Minor changes to docs and pipelines. (#295)
petesramek Oct 29, 2026
e48ae2f
Docs removed version 0.0, fixed build action (#300)
petesramek Oct 29, 2026
c8798ae
Refactor implementation, update benchmarks, and improve project struc…
petesramek Oct 29, 2026
bc26a0f
Fix release CHANGELOG push blocked by branch rules- #306 (#308)
petesramek Oct 29, 2026
6a8e390
Update CHANGELOG.md for 1.0.88.25
petesramek Oct 29, 2026
794a530
Release main sync (#311)
petesramek Oct 29, 2026
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 .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -274,3 +274,6 @@ dotnet_naming_style.underscore_camel_case.capitalization = camel_case
# Public API analyzer

dotnet_public_api_analyzer.require_api_files = true

# RS0017: Symbol removed from public API - error severity (IDE guidance; build enforcement via WarningsAsErrors in .csproj)
dotnet_diagnostic.RS0017.severity = error
5 changes: 5 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
* @petesramek

.github/ @petesramek
src/ @petesramek
tests/ @petesramek
32 changes: 13 additions & 19 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
title: '[Bug]: '
labels: 'bug'
assignees: ''

---
Expand All @@ -11,28 +11,22 @@ assignees: ''
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
Minimal code snippet that reproduces the issue:

```csharp
// paste reproduction code here
```

**Expected behavior**
A clear and concise description of what you expected to happen.

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Actual behavior**
A clear and concise description of what actually happens (include exception messages/stack traces if applicable).

**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Environment**
- Package version: [e.g. 2.1.0]
- .NET version: [e.g. net8.0]
- OS: [e.g. Windows 11, Ubuntu 24.04]

**Additional context**
Add any other context about the problem here.
5 changes: 5 additions & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Ask a question
url: https://github.com/petesramek/polyline-algorithm-csharp/discussions
about: Use GitHub Discussions for questions, ideas, or general feedback.
4 changes: 2 additions & 2 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
title: '[Feature]: '
labels: 'enhancement'
assignees: ''

---
Expand Down
19 changes: 19 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
## Summary

<!-- Briefly describe what this PR does and why. -->

## Type of change

- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation / samples only

## Checklist

- [ ] Unit tests added or updated (`/tests`)
- [ ] Benchmarks added or updated (`/benchmarks`) — if performance-impacting
- [ ] XML doc comments updated for all public API changes
- [ ] `dotnet format` run with no issues
- [ ] README and `/samples` updated — if public API changed
- [ ] PR label added (`breaking` / `feat` / `fix` / `docs`) — for changelog categorization
12 changes: 12 additions & 0 deletions .github/actions/git/configure-identity/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: 'Configure git identity'
author: 'Pete Sramek'
description: 'Configures git user name and email from the last commit.'

runs:
using: composite
steps:
- name: 'Configure git identity'
shell: bash
run: |
git config user.name "$(git log -n 1 --pretty=format:%an)"
git config user.email "$(git log -n 1 --pretty=format:%ae)"
6 changes: 4 additions & 2 deletions .github/actions/git/push-changes/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,14 @@ runs:
set -e
working-directory: ${{ inputs.working-directory }}

- name: Configure git identity
if: ${{ fromJSON(steps.validate.outputs.has-changes) == '1' }}
uses: './.github/actions/git/configure-identity'

- name: Push changes to ${{ github.head_ref || github.ref }}
if: ${{ fromJSON(steps.validate.outputs.has-changes) == '1' }}
shell: bash
run: |
git config user.name "$(git log -n 1 --pretty=format:%an)"
git config user.email "$(git log -n 1 --pretty=format:%ae)"
git commit -m '${{ inputs.commit-message }}'
git pull --rebase origin ${{ github.head_ref || github.ref }}
git push
Expand Down
79 changes: 21 additions & 58 deletions .github/actions/github/branch-protection/lock/action.yml
Original file line number Diff line number Diff line change
@@ -1,37 +1,16 @@
name: 'Lock branch'
author: 'Pete Sramek'
description: 'Apply branch protection to prevent direct pushes. Requires PRs with configurable approval count; admins can optionally bypass all restrictions.'
description: 'Restore ruleset protection for a branch previously unlocked by the unlock action (removes it from each ruleset exclude list).'
inputs:
branch:
description: 'Branch name to lock.'
required: true
token:
description: 'GitHub token with administration:write (repo admin) permission. Use a PAT; GITHUB_TOKEN cannot call the branch protection API.'
description: 'GitHub token with administration:write (repo admin) permission. Use a PAT; GITHUB_TOKEN cannot modify rulesets.'
required: true
ruleset-ids:
description: 'Space-separated ruleset IDs, as output by the unlock action.'
required: true
lock-branch:
description: 'When true, sets lock_branch to prevent even PR merges (use during automated operations). When false (default), only direct pushes are blocked; PRs can still be merged.'
required: false
default: 'false'
required-approving-review-count:
description: 'Number of approving reviews required before a PR can be merged. Set to 0 to require PRs without requiring approvals.'
required: false
default: '1'
dismiss-stale-reviews:
description: 'When true, approved reviews are dismissed when new commits are pushed to the branch.'
required: false
default: 'true'
bypass-admins:
description: 'When true, repository admins are exempt from all branch protection rules (enforce_admins is disabled). When false (default), admins are also subject to the rules.'
required: false
default: 'false'
skip-pull-request-reviews:
description: 'When true, sets required_pull_request_reviews to null (removes PR review requirement). Use temporarily before automated merges so the merge API is not blocked. When false (default), PR reviews are required as configured.'
required: false
default: 'false'
required-linear-history:
description: 'When true, enforces linear history (no merge commits). When false (default), merge commits are allowed. Set to false before automated merges that create merge commits.'
required: false
default: 'false'

runs:
using: composite
Expand All @@ -40,36 +19,20 @@ runs:
shell: bash
env:
GH_TOKEN: ${{ inputs.token }}
BRANCH: ${{ inputs.branch }}
REPOSITORY: ${{ github.repository }}
RULESET_IDS: ${{ inputs.ruleset-ids }}
run: |
ENFORCE_ADMINS=true
if [ '${{ inputs.bypass-admins }}' = 'true' ]; then
ENFORCE_ADMINS=false
fi

PAYLOAD=$(jq -n \
--argjson review_count '${{ inputs.required-approving-review-count }}' \
--argjson dismiss_stale '${{ inputs.dismiss-stale-reviews }}' \
--argjson enforce_admins "$ENFORCE_ADMINS" \
--argjson lock_branch '${{ inputs.lock-branch }}' \
--argjson skip_reviews '${{ inputs.skip-pull-request-reviews }}' \
--argjson required_linear_history '${{ inputs.required-linear-history }}' \
'{
"required_status_checks": null,
"enforce_admins": $enforce_admins,
"required_pull_request_reviews": (if $skip_reviews then null else {
"dismiss_stale_reviews": $dismiss_stale,
"require_code_owner_reviews": false,
"required_approving_review_count": $review_count
} end),
"restrictions": null,
"allow_force_pushes": false,
"allow_deletions": false,
"lock_branch": $lock_branch,
"required_linear_history": $required_linear_history
}')

if ! echo "$PAYLOAD" | gh api --method PUT /repos/${{ github.repository }}/branches/${{ inputs.branch }}/protection --input -; then
echo "::error::Failed to apply branch protection to '${{ inputs.branch }}'. Ensure the token has 'administration: write' permission and the branch exists."
exit 1
fi
echo "🔒 Branch '${{ inputs.branch }}' is now protected." >> $GITHUB_STEP_SUMMARY
ref="refs/heads/$BRANCH"
failed=0
for id in $RULESET_IDS; do
endpoint="/repos/$REPOSITORY/rulesets/$id"
if ! gh api "$endpoint" \
| jq -c --arg ref "$ref" '{conditions: (.conditions | .ref_name.exclude -= [$ref])}' \
| gh api --method PUT "$endpoint" --input - > /dev/null; then
echo "::error::Failed to restore ruleset $id for '$BRANCH'."
failed=1
fi
done
[ "$failed" = 0 ] || exit 1
echo "🔒 Branch '$BRANCH' is protected again." >> $GITHUB_STEP_SUMMARY
60 changes: 51 additions & 9 deletions .github/actions/github/branch-protection/unlock/action.yml
Original file line number Diff line number Diff line change
@@ -1,29 +1,71 @@
name: 'Unlock branch'
author: 'Pete Sramek'
description: 'Remove branch protection to allow a workflow to push directly. Always re-lock after the operation.'
description: 'Temporarily exempt a branch from the repository rulesets that apply to it (adds it to each ruleset exclude list) so a workflow can push directly. Always restore afterwards.'
inputs:
branch:
description: 'Branch name to unlock.'
required: true
token:
description: 'GitHub token with administration:write (repo admin) permission. Use a PAT; GITHUB_TOKEN cannot call the branch protection API.'
description: 'GitHub token with administration:write (repo admin) permission. Use a PAT; GITHUB_TOKEN cannot modify rulesets.'
required: true
fail-on-error:
description: 'When true, the step fails if branch protection cannot be removed. When false (default), errors are silently ignored.'
description: 'When true, the step fails if the rulesets cannot be updated. When false (default), errors are ignored.'
required: false
default: 'false'
outputs:
ruleset-ids:
description: 'Space-separated IDs of the rulesets the branch was excluded from, for restoring them later.'
value: ${{ steps.unlock.outputs.ruleset-ids }}

runs:
using: composite
steps:
- name: 'Unlock branch ${{ inputs.branch }}'
id: unlock
shell: bash
env:
GH_TOKEN: ${{ inputs.token }}
BRANCH: ${{ inputs.branch }}
REPOSITORY: ${{ github.repository }}
FAIL_ON_ERROR: ${{ inputs.fail-on-error }}
run: |
if [ '${{ inputs.fail-on-error }}' = 'true' ]; then
gh api --method DELETE /repos/${{ github.repository }}/branches/${{ inputs.branch }}/protection
else
gh api --method DELETE /repos/${{ github.repository }}/branches/${{ inputs.branch }}/protection || true
fi
echo "🔓 Branch protection removed from '${{ inputs.branch }}'." >> $GITHUB_STEP_SUMMARY
fail() {
if [ "$FAIL_ON_ERROR" = 'true' ]; then
echo "::error::$1"
exit 1
fi
exit 0
}

branch_path=$(jq -rn --arg branch "$BRANCH" '$branch | @uri')
ref="refs/heads/$BRANCH"

rules=$(gh api "/repos/$REPOSITORY/rules/branches/$branch_path") \
|| fail "Failed to read rules applying to '$BRANCH'."

# Only repository-level rulesets can be edited through the repository endpoint.
ids=$(echo "$rules" | jq -r '[.[] | select(.ruleset_source_type == "Repository") | .ruleset_id] | unique | .[]')

changed=""
for id in $ids; do
endpoint="/repos/$REPOSITORY/rulesets/$id"
ruleset=$(gh api "$endpoint") || fail "Failed to read ruleset $id."
payload=$(echo "$ruleset" | jq -c --arg ref "$ref" \
'{conditions: (.conditions | .ref_name.exclude = ((.ref_name.exclude // []) + [$ref] | unique))}')
if echo "$payload" | gh api --method PUT "$endpoint" --input - > /dev/null; then
changed="$changed $id"
else
echo "::error::Failed to exclude '$BRANCH' from ruleset $id."
# Roll back what was already changed so protection is not left weakened.
for done_id in $changed; do
gh api "/repos/$REPOSITORY/rulesets/$done_id" | jq -c --arg ref "$ref" \
'{conditions: (.conditions | .ref_name.exclude -= [$ref])}' \
| gh api --method PUT "/repos/$REPOSITORY/rulesets/$done_id" --input - > /dev/null || true
done
fail "Failed to unlock '$BRANCH'."
fi
done

changed=$(echo $changed)
echo "ruleset-ids=$changed" >> "$GITHUB_OUTPUT"
echo "🔓 Branch '$BRANCH' excluded from rulesets: ${changed:-none}." >> $GITHUB_STEP_SUMMARY
13 changes: 8 additions & 5 deletions .github/actions/github/create-release/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,21 @@ runs:
echo "is-preview=${{ inputs.is-preview }}"
echo "preview-argument=${{ inputs.is-preview == 'true' && '--prerelease' || '' }}"
echo "notes-start-tag=${{ inputs.notes-start-tag }}"
echo "notes-start-tag-argument="${{ inputs.notes-start-tag != '' && '--notes-start-tag $(inputs.notes-start-tag)' || '' }}"
echo "notes-start-tag-argument=${{ inputs.notes-start-tag != '' && format('--notes-start-tag {0}', inputs.notes-start-tag) || '' }}"
shell: bash
- name: 'Create git tag ${{ env.release-version }}'
- name: 'Configure git identity'
uses: './.github/actions/git/configure-identity'
- name: 'Create git tag ${{ inputs.release-version }}'
shell: bash
run: |
git tag -a ${{ env.release-version }} -m "${{ env.release-version }}"
- name: 'Create GitHub release PolylineAlgorithm ${{ env.release-version }}'
git tag -a ${{ inputs.release-version }} -m "${{ inputs.release-version }}"
git push origin ${{ inputs.release-version }}
- name: 'Create GitHub release PolylineAlgorithm ${{ inputs.release-version }}'
shell: bash
env:
GH_TOKEN: ${{ github.token }}
release-version: ${{ inputs.release-version }}
preview-argument: "${{ inputs.is-preview == 'true' && '--prerelease' || '' }}"
notes-start-tag-argument: "${{ inputs.notes-start-tag != '' && '--notes-start-tag $(inputs.notes-start-tag)' || '' }}"
notes-start-tag-argument: "${{ inputs.notes-start-tag != '' && format('--notes-start-tag {0}', inputs.notes-start-tag) || '' }}"
run: |
gh release create ${{ env.release-version }} --generate-notes --discussion-category "General" ${{ env.preview-argument }} ${{ env.notes-start-tag-argument }}
2 changes: 1 addition & 1 deletion .github/actions/source/compile/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ inputs:
file-version:
description: 'Assembly file version.'
required: true
treat-warnins-as-error:
treat-warnings-as-error:
description: 'Treat warnings as errors.'
required: true
project-path:
Expand Down
12 changes: 12 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,23 @@ updates:
directory: "/"
schedule:
interval: "weekly"
labels:
- "dependencies"
assignees:
- "petesramek"
- package-ecosystem: "nuget"
directory: "/"
schedule:
interval: "weekly"
labels:
- "dependencies"
assignees:
- "petesramek"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
labels:
- "dependencies"
assignees:
- "petesramek"
23 changes: 23 additions & 0 deletions .github/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
changelog:
exclude:
labels:
- ignore-for-release
categories:
- title: Breaking Changes
labels:
- breaking
- title: New Features
labels:
- feat
- enhancement
- title: Bug Fixes
labels:
- fix
- bug
- title: Documentation
labels:
- docs
- documentation
- title: Other Changes
labels:
- '*'
Loading
Loading