-
Notifications
You must be signed in to change notification settings - Fork 0
Docfx/context7 chat #18
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| [ ] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,133 @@ | ||
| #!/usr/bin/env python3 | ||
| """ | ||
| Simplified package bumping for Codebelt service updates (Option B). | ||
|
|
||
| Only updates packages published by the triggering source repo. | ||
| Does NOT update Microsoft.Extensions.*, BenchmarkDotNet, or other third-party packages. | ||
| Does NOT parse TFM conditions - only bumps Codebelt/Cuemon/Savvyio packages to the triggering version. | ||
|
|
||
| Usage: | ||
| TRIGGER_SOURCE=cuemon TRIGGER_VERSION=10.3.0 python3 bump-nuget.py | ||
|
|
||
| Behavior: | ||
| - If TRIGGER_SOURCE is "cuemon" and TRIGGER_VERSION is "10.3.0": | ||
| - Cuemon.Core: 10.2.1 → 10.3.0 | ||
| - Cuemon.Extensions.IO: 10.2.1 → 10.3.0 | ||
| - Microsoft.Extensions.Hosting: 9.0.13 → UNCHANGED (not a Codebelt package) | ||
| - BenchmarkDotNet: 0.15.8 → UNCHANGED (not a Codebelt package) | ||
| """ | ||
|
|
||
| import re | ||
| import os | ||
| import sys | ||
| from typing import Dict, List | ||
|
|
||
| TRIGGER_SOURCE = os.environ.get("TRIGGER_SOURCE", "") | ||
| TRIGGER_VERSION = os.environ.get("TRIGGER_VERSION", "") | ||
|
|
||
| # Map of source repos to their package ID prefixes | ||
| SOURCE_PACKAGE_MAP: Dict[str, List[str]] = { | ||
| "cuemon": ["Cuemon."], | ||
| "xunit": ["Codebelt.Extensions.Xunit"], | ||
| "benchmarkdotnet": ["Codebelt.Extensions.BenchmarkDotNet"], | ||
| "bootstrapper": ["Codebelt.Bootstrapper"], | ||
| "newtonsoft-json": [ | ||
| "Codebelt.Extensions.Newtonsoft.Json", | ||
| "Codebelt.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft", | ||
| ], | ||
| "aws-signature-v4": ["Codebelt.Extensions.AspNetCore.Authentication.AwsSignature"], | ||
| "unitify": ["Codebelt.Unitify"], | ||
| "yamldotnet": [ | ||
| "Codebelt.Extensions.YamlDotNet", | ||
| "Codebelt.Extensions.AspNetCore.Mvc.Formatters.Text.Yaml", | ||
| ], | ||
| "globalization": ["Codebelt.Extensions.Globalization"], | ||
| "asp-versioning": ["Codebelt.Extensions.Asp.Versioning"], | ||
| "swashbuckle-aspnetcore": ["Codebelt.Extensions.Swashbuckle"], | ||
| "savvyio": ["Savvyio."], | ||
| "shared-kernel": [], | ||
| } | ||
|
|
||
|
|
||
| def is_triggered_package(package_name: str) -> bool: | ||
| """Check if package is published by the triggering source repo.""" | ||
| if not TRIGGER_SOURCE: | ||
| return False | ||
| prefixes = SOURCE_PACKAGE_MAP.get(TRIGGER_SOURCE, []) | ||
| return any(package_name.startswith(prefix) for prefix in prefixes) | ||
|
|
||
|
|
||
| def main(): | ||
| if not TRIGGER_SOURCE or not TRIGGER_VERSION: | ||
| print( | ||
| "Error: TRIGGER_SOURCE and TRIGGER_VERSION environment variables required" | ||
| ) | ||
| print(f" TRIGGER_SOURCE={TRIGGER_SOURCE}") | ||
|
Comment on lines
+61
to
+65
|
||
| print(f" TRIGGER_VERSION={TRIGGER_VERSION}") | ||
| sys.exit(1) | ||
|
|
||
| # Strip 'v' prefix if present in version | ||
| target_version = TRIGGER_VERSION.lstrip("v") | ||
|
|
||
| print(f"Trigger: {TRIGGER_SOURCE} @ {target_version}") | ||
| print(f"Only updating packages from: {TRIGGER_SOURCE}") | ||
| print() | ||
|
|
||
| try: | ||
| with open("Directory.Packages.props", "r") as f: | ||
| content = f.read() | ||
| except FileNotFoundError: | ||
| print("Error: Directory.Packages.props not found") | ||
| sys.exit(1) | ||
|
|
||
| changes = [] | ||
| skipped_third_party = [] | ||
|
|
||
| def replace_version(m: re.Match) -> str: | ||
| pkg = m.group(1) | ||
| current = m.group(2) | ||
|
|
||
| if not is_triggered_package(pkg): | ||
| skipped_third_party.append(f" {pkg} (skipped - not from {TRIGGER_SOURCE})") | ||
| return m.group(0) | ||
|
|
||
| if target_version != current: | ||
| changes.append(f" {pkg}: {current} → {target_version}") | ||
| return m.group(0).replace( | ||
| f'Version="{current}"', f'Version="{target_version}"' | ||
| ) | ||
|
|
||
| return m.group(0) | ||
|
|
||
| # Match PackageVersion elements (handles multiline) | ||
| pattern = re.compile( | ||
| r"<PackageVersion\b" | ||
| r'(?=[^>]*\bInclude="([^"]+)")' | ||
| r'(?=[^>]*\bVersion="([^"]+)")' | ||
| r"[^>]*>", | ||
| re.DOTALL, | ||
| ) | ||
| new_content = pattern.sub(replace_version, content) | ||
|
|
||
| # Show results | ||
| if changes: | ||
| print(f"Updated {len(changes)} package(s) from {TRIGGER_SOURCE}:") | ||
| print("\n".join(changes)) | ||
| else: | ||
| print(f"No packages from {TRIGGER_SOURCE} needed updating.") | ||
|
|
||
| if skipped_third_party: | ||
| print() | ||
| print(f"Skipped {len(skipped_third_party)} third-party package(s):") | ||
| print("\n".join(skipped_third_party[:5])) # Show first 5 | ||
|
Comment on lines
+119
to
+122
|
||
| if len(skipped_third_party) > 5: | ||
| print(f" ... and {len(skipped_third_party) - 5} more") | ||
|
|
||
| with open("Directory.Packages.props", "w") as f: | ||
| f.write(new_content) | ||
|
|
||
| return 0 if changes else 0 # Return 0 even if no changes (not an error) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| sys.exit(main()) | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,139 @@ | ||||||||||||||||||||||||||||||||||||||||||||||
| name: Service Update | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| on: | ||||||||||||||||||||||||||||||||||||||||||||||
| repository_dispatch: | ||||||||||||||||||||||||||||||||||||||||||||||
| types: [codebelt-service-update] | ||||||||||||||||||||||||||||||||||||||||||||||
| workflow_dispatch: | ||||||||||||||||||||||||||||||||||||||||||||||
| inputs: | ||||||||||||||||||||||||||||||||||||||||||||||
| source_repo: | ||||||||||||||||||||||||||||||||||||||||||||||
| description: 'Triggering source repo name (e.g. cuemon)' | ||||||||||||||||||||||||||||||||||||||||||||||
| required: false | ||||||||||||||||||||||||||||||||||||||||||||||
| default: '' | ||||||||||||||||||||||||||||||||||||||||||||||
| source_version: | ||||||||||||||||||||||||||||||||||||||||||||||
| description: 'Version released by source (e.g. 10.3.0)' | ||||||||||||||||||||||||||||||||||||||||||||||
| required: false | ||||||||||||||||||||||||||||||||||||||||||||||
| default: '' | ||||||||||||||||||||||||||||||||||||||||||||||
| dry_run: | ||||||||||||||||||||||||||||||||||||||||||||||
| type: boolean | ||||||||||||||||||||||||||||||||||||||||||||||
| description: 'Dry run — show changes but do not commit or open PR' | ||||||||||||||||||||||||||||||||||||||||||||||
| default: false | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| permissions: | ||||||||||||||||||||||||||||||||||||||||||||||
| contents: write | ||||||||||||||||||||||||||||||||||||||||||||||
| pull-requests: write | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| jobs: | ||||||||||||||||||||||||||||||||||||||||||||||
| service-update: | ||||||||||||||||||||||||||||||||||||||||||||||
| runs-on: ubuntu-24.04 | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| steps: | ||||||||||||||||||||||||||||||||||||||||||||||
| - name: Checkout | ||||||||||||||||||||||||||||||||||||||||||||||
| uses: actions/checkout@v4 | ||||||||||||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||||||||||||
| fetch-depth: 0 | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| - name: Resolve trigger inputs | ||||||||||||||||||||||||||||||||||||||||||||||
| id: trigger | ||||||||||||||||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||||||||||||||||
| SOURCE="${{ github.event.client_payload.source_repo || github.event.inputs.source_repo }}" | ||||||||||||||||||||||||||||||||||||||||||||||
| VERSION="${{ github.event.client_payload.source_version || github.event.inputs.source_version }}" | ||||||||||||||||||||||||||||||||||||||||||||||
| echo "source=$SOURCE" >> $GITHUB_OUTPUT | ||||||||||||||||||||||||||||||||||||||||||||||
| echo "version=$VERSION" >> $GITHUB_OUTPUT | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| - name: Determine new version for this repo | ||||||||||||||||||||||||||||||||||||||||||||||
| id: newver | ||||||||||||||||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||||||||||||||||
| CURRENT=$(grep -oP '(?<=## \[)[\d.]+(?=\])' CHANGELOG.md | head -1) | ||||||||||||||||||||||||||||||||||||||||||||||
| NEW=$(echo "$CURRENT" | awk -F. '{printf "%s.%s.%d", $1, $2, $3+1}') | ||||||||||||||||||||||||||||||||||||||||||||||
| BRANCH="v${NEW}/service-update" | ||||||||||||||||||||||||||||||||||||||||||||||
| echo "current=$CURRENT" >> $GITHUB_OUTPUT | ||||||||||||||||||||||||||||||||||||||||||||||
| echo "new=$NEW" >> $GITHUB_OUTPUT | ||||||||||||||||||||||||||||||||||||||||||||||
| echo "branch=$BRANCH" >> $GITHUB_OUTPUT | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| - name: Generate codebelt-aicia token | ||||||||||||||||||||||||||||||||||||||||||||||
| id: app-token | ||||||||||||||||||||||||||||||||||||||||||||||
| uses: actions/create-github-app-token@v1 | ||||||||||||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||||||||||||
| app-id: ${{ vars.CODEBELT_AICIA_APP_ID }} | ||||||||||||||||||||||||||||||||||||||||||||||
| private-key: ${{ secrets.CODEBELT_AICIA_PRIVATE_KEY }} | ||||||||||||||||||||||||||||||||||||||||||||||
| owner: codebeltnet | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| - name: Bump NuGet packages | ||||||||||||||||||||||||||||||||||||||||||||||
| run: python3 .github/scripts/bump-nuget.py | ||||||||||||||||||||||||||||||||||||||||||||||
| env: | ||||||||||||||||||||||||||||||||||||||||||||||
| TRIGGER_SOURCE: ${{ steps.trigger.outputs.source }} | ||||||||||||||||||||||||||||||||||||||||||||||
| TRIGGER_VERSION: ${{ steps.trigger.outputs.version }} | ||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+61
to
+65
|
||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| - name: Update PackageReleaseNotes.txt | ||||||||||||||||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||||||||||||||||
| NEW="${{ steps.newver.outputs.new }}" | ||||||||||||||||||||||||||||||||||||||||||||||
| for f in .nuget/*/PackageReleaseNotes.txt; do | ||||||||||||||||||||||||||||||||||||||||||||||
| [ -f "$f" ] || continue | ||||||||||||||||||||||||||||||||||||||||||||||
| TFM=$(grep -m1 "^Availability:" "$f" | sed 's/Availability: //' || echo ".NET 10, .NET 9 and .NET Standard 2.0") | ||||||||||||||||||||||||||||||||||||||||||||||
| ENTRY="Version: ${NEW}\nAvailability: ${TFM}\n \n# ALM\n- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)\n \n" | ||||||||||||||||||||||||||||||||||||||||||||||
| { printf "$ENTRY"; cat "$f"; } > "$f.tmp" && mv "$f.tmp" "$f" | ||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+72
to
+74
|
||||||||||||||||||||||||||||||||||||||||||||||
| TFM=$(grep -m1 "^Availability:" "$f" | sed 's/Availability: //' || echo ".NET 10, .NET 9 and .NET Standard 2.0") | |
| ENTRY="Version: ${NEW}\nAvailability: ${TFM}\n \n# ALM\n- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)\n \n" | |
| { printf "$ENTRY"; cat "$f"; } > "$f.tmp" && mv "$f.tmp" "$f" | |
| AVAIL_LINE=$(grep -m1 "^Availability:" "$f" || true) | |
| if [ -n "$AVAIL_LINE" ]; then | |
| TFM="${AVAIL_LINE#Availability: }" | |
| else | |
| TFM=".NET 10, .NET 9 and .NET Standard 2.0" | |
| fi | |
| ENTRY="Version: ${NEW}\nAvailability: ${TFM}\n \n# ALM\n- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)\n \n" | |
| { printf '%b' "$ENTRY"; cat "$f"; } > "$f.tmp" && mv "$f.tmp" "$f" |
Copilot
AI
Feb 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PackageReleaseNotes.txt currently starts with a UTF-8 BOM; prepending content via { printf ...; cat "$f"; } will push the BOM into the middle of the file (as part of the old first line), which can show up as a stray character in some consumers. Consider preserving/removing the BOM explicitly (e.g., rewrite using a tool that keeps BOM at the beginning, or strip it before concatenation).
| { printf "$ENTRY"; cat "$f"; } > "$f.tmp" && mv "$f.tmp" "$f" | |
| { | |
| printf "$ENTRY" | |
| python3 - << 'EOF' < "$f" | |
| import sys | |
| data = sys.stdin.read() | |
| if data.startswith('\ufeff'): | |
| data = data[1:] | |
| sys.stdout.write(data) | |
| EOF | |
| } > "$f.tmp" && mv "$f.tmp" "$f" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| name: Trigger Downstream Service Updates | ||
|
|
||
| on: | ||
| release: | ||
| types: [published] | ||
|
|
||
| jobs: | ||
| dispatch: | ||
| if: github.event.release.prerelease == false | ||
| runs-on: ubuntu-24.04 | ||
| permissions: | ||
| contents: read | ||
|
|
||
| steps: | ||
| - name: Checkout (to read dispatch-targets.json) | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Check for dispatch targets | ||
| id: check | ||
| run: | | ||
| if [ ! -f .github/dispatch-targets.json ]; then | ||
| echo "No dispatch-targets.json found, skipping." | ||
| echo "has_targets=false" >> $GITHUB_OUTPUT | ||
| exit 0 | ||
| fi | ||
| COUNT=$(python3 -c "import json; print(len(json.load(open('.github/dispatch-targets.json'))))") | ||
| echo "has_targets=$([ $COUNT -gt 0 ] && echo true || echo false)" >> $GITHUB_OUTPUT | ||
|
|
||
| - name: Extract version from release tag | ||
| if: steps.check.outputs.has_targets == 'true' | ||
| id: version | ||
| run: | | ||
| VERSION="${{ github.event.release.tag_name }}" | ||
| VERSION="${VERSION#v}" | ||
| echo "version=$VERSION" >> $GITHUB_OUTPUT | ||
|
|
||
| - name: Generate codebelt-aicia token | ||
| if: steps.check.outputs.has_targets == 'true' | ||
| id: app-token | ||
| uses: actions/create-github-app-token@v1 | ||
| with: | ||
| app-id: ${{ vars.CODEBELT_AICIA_APP_ID }} | ||
| private-key: ${{ secrets.CODEBELT_AICIA_PRIVATE_KEY }} | ||
| owner: codebeltnet | ||
|
|
||
| - name: Dispatch to downstream repos | ||
| if: steps.check.outputs.has_targets == 'true' | ||
| run: | | ||
| python3 - <<'EOF' | ||
| import json, urllib.request, os, sys | ||
|
|
||
| targets = json.load(open('.github/dispatch-targets.json')) | ||
| token = os.environ['GH_TOKEN'] | ||
| version = os.environ['VERSION'] | ||
| source = os.environ['SOURCE_REPO'] | ||
|
|
||
| for repo in targets: | ||
| url = f'https://api.github.com/repos/codebeltnet/{repo}/dispatches' | ||
| payload = json.dumps({ | ||
| 'event_type': 'codebelt-service-update', | ||
| 'client_payload': { | ||
| 'source_repo': source, | ||
| 'source_version': version | ||
| } | ||
| }).encode() | ||
| req = urllib.request.Request(url, data=payload, method='POST', headers={ | ||
| 'Authorization': f'Bearer {token}', | ||
| 'Accept': 'application/vnd.github+json', | ||
| 'Content-Type': 'application/json', | ||
| 'X-GitHub-Api-Version': '2022-11-28' | ||
| }) | ||
|
Comment on lines
+66
to
+71
|
||
| with urllib.request.urlopen(req) as r: | ||
| print(f'✓ Dispatched to {repo}: HTTP {r.status}') | ||
| EOF | ||
| env: | ||
| GH_TOKEN: ${{ steps.app-token.outputs.token }} | ||
| VERSION: ${{ steps.version.outputs.version }} | ||
| SOURCE_REPO: ${{ github.event.repository.name }} | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The footer now injects a third-party script from
https://context7.com/widget.jsinto the generated docs. This increases supply-chain/XSS risk for the published site; consider hosting/pinning the script (or adding Subresource Integrity + a documented allowlist/CSP) so the build output isn’t executing unpinned remote code.