diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..7010a36 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,25 @@ +# Code Owners for PatternKit +# These users will be automatically requested for review when PRs are opened + +# Global owners +* @jerrettdavis + +# Workflows and CI/CD +/.github/ @jerrettdavis + +# Documentation +/docs/ @jerrettdavis +*.md @jerrettdavis + +# Core library +/src/PatternKit.Core/ @jerrettdavis + +# Generators +/src/PatternKit.Generators/ @jerrettdavis +/src/PatternKit.Generators.Abstractions/ @jerrettdavis + +# Examples +/src/PatternKit.Examples/ @jerrettdavis + +# Tests +/test/ @jerrettdavis diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..4234e4e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,122 @@ +name: Bug Report +description: File a bug report to help us improve PatternKit +title: "[Bug]: " +labels: ["bug", "triage"] +assignees: + - jerrettdavis + +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! + + - type: textarea + id: description + attributes: + label: Description + description: A clear and concise description of what the bug is. + placeholder: Tell us what happened! + validations: + required: true + + - type: textarea + id: reproduce + attributes: + label: Steps to Reproduce + description: Steps to reproduce the behavior + placeholder: | + 1. Create a pattern with '...' + 2. Call method '....' + 3. Pass parameters '....' + 4. See error + validations: + required: true + + - type: textarea + id: expected + attributes: + label: Expected Behavior + description: A clear and concise description of what you expected to happen. + validations: + required: true + + - type: textarea + id: actual + attributes: + label: Actual Behavior + description: What actually happened instead. + validations: + required: true + + - type: dropdown + id: component + attributes: + label: Component + description: Which component is affected? + options: + - Core Library + - Generators + - Source Generation + - Behavioral Patterns + - Creational Patterns + - Structural Patterns + - Documentation + - Examples + - Other + validations: + required: true + + - type: input + id: version + attributes: + label: Version + description: What version of PatternKit are you using? + placeholder: "0.1.0" + validations: + required: true + + - type: dropdown + id: dotnet-version + attributes: + label: .NET Version + description: What version of .NET are you using? + options: + - ".NET 10.0" + - ".NET 9.0" + - Other + validations: + required: true + + - type: input + id: os + attributes: + label: Operating System + description: What operating system are you using? + placeholder: "Windows 11, Ubuntu 22.04, macOS 14" + validations: + required: true + + - type: textarea + id: code-sample + attributes: + label: Code Sample + description: Please provide a minimal code sample that reproduces the issue. + render: csharp + placeholder: | + var strategy = Strategy.Create() + .When(i => i > 0).Then(i => "positive") + .Build(); + + - type: textarea + id: logs + attributes: + label: Logs / Stack Trace + description: Please copy and paste any relevant log output or stack traces. + render: shell + + - type: textarea + id: additional + attributes: + label: Additional Context + description: Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..527904f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,104 @@ +name: Feature Request +description: Suggest an idea for PatternKit +title: "[Feature]: " +labels: ["enhancement", "triage"] +assignees: + - jerrettdavis + +body: + - type: markdown + attributes: + value: | + Thanks for suggesting a new feature! + + - type: textarea + id: problem + attributes: + label: Problem Statement + description: Is your feature request related to a problem? Please describe. + placeholder: I'm always frustrated when... + validations: + required: true + + - type: textarea + id: solution + attributes: + label: Proposed Solution + description: Describe the solution you'd like. + placeholder: A clear and concise description of what you want to happen. + validations: + required: true + + - type: textarea + id: alternatives + attributes: + label: Alternatives Considered + description: Describe alternatives you've considered. + placeholder: A clear and concise description of any alternative solutions or features you've considered. + + - type: dropdown + id: component + attributes: + label: Component + description: Which component would this feature affect? + options: + - Core Library + - Generators + - Source Generation + - New Pattern (Behavioral) + - New Pattern (Creational) + - New Pattern (Structural) + - Documentation + - Examples + - Build/CI + - Other + validations: + required: true + + - type: dropdown + id: priority + attributes: + label: Priority + description: How important is this feature to you? + options: + - Low (Nice to have) + - Medium (Would improve workflow) + - High (Blocking current work) + - Critical (Blocking production use) + validations: + required: true + + - type: checkboxes + id: contribution + attributes: + label: Contribution + description: Are you willing to contribute this feature? + options: + - label: I am willing to submit a PR to implement this feature + - label: I can help test this feature when implemented + + - type: textarea + id: use-case + attributes: + label: Use Case + description: Describe a specific use case for this feature. + placeholder: | + As a [developer type], I want to [action] so that [benefit]. + + - type: textarea + id: code-example + attributes: + label: Example Usage (Optional) + description: If applicable, show how you envision using this feature. + render: csharp + placeholder: | + // Example of how the feature would be used + var pattern = NewPattern.Create() + .Configure(...) + .Build(); + + - type: textarea + id: additional + attributes: + label: Additional Context + description: Add any other context, mockups, or examples about the feature request here. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..5e1fbd6 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,48 @@ +# Description + +Please include a summary of the changes and which issue is fixed. Include relevant motivation and context. + +Fixes # (issue) + +## Type of Change + +Please delete options that are not relevant. + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] Documentation update +- [ ] Performance improvement +- [ ] Code refactoring +- [ ] Build/CI changes + +## How Has This Been Tested? + +Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. + +- [ ] Unit tests +- [ ] Integration tests +- [ ] Manual testing + +**Test Configuration**: +- .NET version: +- OS: + +## Checklist + +- [ ] My code follows the style guidelines of this project +- [ ] I have performed a self-review of my code +- [ ] I have commented my code, particularly in hard-to-understand areas +- [ ] I have made corresponding changes to the documentation +- [ ] My changes generate no new warnings +- [ ] I have added tests that prove my fix is effective or that my feature works +- [ ] New and existing unit tests pass locally with my changes +- [ ] Any dependent changes have been merged and published + +## Screenshots (if applicable) + +Add screenshots to help explain your changes. + +## Additional Context + +Add any other context about the pull request here. diff --git a/.github/QUICK_REFERENCE.md b/.github/QUICK_REFERENCE.md new file mode 100644 index 0000000..78741c9 --- /dev/null +++ b/.github/QUICK_REFERENCE.md @@ -0,0 +1,169 @@ +# PatternKit CI/CD Quick Reference + +## 🔄 Development Workflow + +### 1️⃣ Create Feature Branch + +```bash +git checkout -b feature/my-feature +``` + +### 2️⃣ Make Changes + +```bash +# Write code, add tests +git add . +git commit -m "feat: add my feature" +``` + +### 3️⃣ Push and Create PR + +```bash +git push origin feature/my-feature +# Create PR on GitHub +# Wait for validation +``` + +### 4️⃣ Merge to Main + +```bash +# Use "Squash and Merge" +# Automatic release triggered on merge +``` + +## Automated Workflows + +### On Pull Request + +``` +PR Created/Updated + → Dependency Review (checks for security issues) + → PR Validation (build, test, package) + → Auto Label (labels based on files changed) + → CodeQL Analysis (security scanning) + → Post summary comment + → Upload artifacts +``` + +### On Merge to Main + +``` +Merge to Main + → CI Workflow + → Build & test with coverage + → Create packages + → Analyze commits + → Create tag with GitVersion + → Create GitHub Release + → Publish to NuGet.org + → Publish to GitHub Packages +``` + +## 📦 What Gets Published? + +### NuGet Packages + +- PatternKit.Core +- PatternKit.Generators +- PatternKit.Generators.Abstractions + +## Version Format + +- **Format**: `v{Major}.{Minor}.{Patch}` +- **Examples**: + - `v0.1.0` - Initial release + - `v0.2.0` - Feature added + - `v0.2.1` - Bug fixed + - `v1.0.0` - Breaking change + +## ⚠️ Important Notes + +### DO + +- Wait for PR validation to complete before merging +- Squash merge PRs to keep a clean history +- Review dry-run artifacts in PRs +- Write tests for new features +- Follow existing code style + +### DON'T + +- Force-push to main branch +- Merge PRs with failing checks +- Skip tests +- Introduce breaking changes without discussion + +## Build Commands + +```bash +# Restore dependencies +dotnet restore --use-lock-file +dotnet tool restore + +# Build +dotnet build PatternKit.slnx --configuration Release + +# Test +dotnet test PatternKit.slnx --configuration Release + +# Build documentation +docfx metadata docs/docfx.json +docfx build docs/docfx.json + +# Pack for NuGet +dotnet pack PatternKit.slnx --configuration Release --output ./artifacts +``` + +## Troubleshooting + +### Build Failing + +**Check**: +1. Review CI logs in Actions tab +2. Run tests locally: `dotnet test` +3. Check for dependency issues +4. Ensure .NET 9+ SDK is installed + +### Tests Failing + +**Check**: +1. Run specific test: `dotnet test --filter "FullyQualifiedName~TestName"` +2. Check test output for error details +3. Ensure all dependencies are restored + +### Documentation Build Failing + +**Check**: +1. Ensure DocFX is installed: `dotnet tool update -g docfx` +2. Check `docs/docfx.json` for configuration issues +3. Verify XML documentation comments in code + +## Automated Maintenance + +### Dependabot + +- Runs weekly to check for package updates +- Creates PRs for outdated dependencies +- Groups updates by category (Microsoft, testing, etc.) + +### Update Packages Workflow + +- Runs weekly on Sunday +- Uses `dotnet-outdated` tool +- Creates PR with package updates +- Preserves major version compatibility + +### Stale Issues/PRs + +- Marks issues stale after 60 days of inactivity +- Closes stale issues after 7 more days +- Marks PRs stale after 30 days +- Closes stale PRs after 14 more days +- Exempt labels: pinned, security, bug, enhancement + +## More Information + +- **Workflows**: [.github/workflows/](.github/workflows/) +- **Contributing**: Check README.md for contribution guidelines +- **Issues**: [GitHub Issues](https://github.com/JerrettDavis/PatternKit/issues) +- **Discussions**: [GitHub Discussions](https://github.com/JerrettDavis/PatternKit/discussions) diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..03f6659 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,59 @@ +version: 2 + +updates: + # NuGet package updates + - package-ecosystem: "nuget" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + time: "09:00" + open-pull-requests-limit: 10 + reviewers: + - "jerrettdavis" + labels: + - "dependencies" + - "nuget" + commit-message: + prefix: "deps" + include: "scope" + groups: + microsoft: + patterns: + - "Microsoft.*" + update-types: + - "minor" + - "patch" + testing: + patterns: + - "xunit*" + - "Moq" + - "FluentAssertions" + - "coverlet.*" + update-types: + - "minor" + - "patch" + analyzers: + patterns: + - "*.Analyzers" + - "*.CodeAnalysis" + update-types: + - "minor" + - "patch" + + # GitHub Actions updates + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + time: "09:00" + open-pull-requests-limit: 5 + reviewers: + - "jerrettdavis" + labels: + - "dependencies" + - "github-actions" + commit-message: + prefix: "ci" + include: "scope" diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 0000000..830ac1f --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,41 @@ +# Auto-labeling configuration for pull requests + +'area: core': + - changed-files: + - any-glob-to-any-file: + - 'src/PatternKit.Core/**/*' + +'area: generators': + - changed-files: + - any-glob-to-any-file: + - 'src/PatternKit.Generators/**/*' + - 'src/PatternKit.Generators.Abstractions/**/*' + +'area: examples': + - changed-files: + - any-glob-to-any-file: + - 'src/PatternKit.Examples/**/*' + +'area: documentation': + - changed-files: + - any-glob-to-any-file: + - '**/*.md' + - 'docs/**/*' + +'area: tests': + - changed-files: + - any-glob-to-any-file: + - 'test/**/*' + +'area: ci/cd': + - changed-files: + - any-glob-to-any-file: + - '.github/**/*' + +'dependencies': + - changed-files: + - any-glob-to-any-file: + - '**/packages.lock.json' + - '**/*.csproj' + - 'Directory.Build.props' + - 'Directory.Packages.props' diff --git a/.github/workflows/README.md b/.github/workflows/README.md new file mode 100644 index 0000000..b8e202a --- /dev/null +++ b/.github/workflows/README.md @@ -0,0 +1,60 @@ +# Workflows + +This directory contains GitHub Actions workflows for the PatternKit repository. + +## Workflows + +### CI/CD Workflows + +- **ci.yml** - Main CI/CD pipeline that runs on push to main and pull requests. Handles building, testing, packaging, and releasing. +- **pr-validation.yml** - Comprehensive PR validation including builds, tests, documentation, and dry-run packaging. +- **docs.yml** - Publishes documentation to GitHub Pages. + +### Code Quality + +- **codeql-analysis.yml** - CodeQL security scanning for vulnerability detection. +- **dependency-review.yml** - Reviews dependencies in pull requests for security issues and license compliance. + +### Automation + +- **labeler.yml** - Automatically labels PRs based on changed files. +- **stale.yml** - Marks and closes stale issues and PRs. +- **update-packages.yml** - Weekly check for outdated NuGet packages and creates PRs for updates. + +## Workflow Triggers + +### On Pull Request +- ci.yml (pr-checks job) +- pr-validation.yml +- dependency-review.yml +- labeler.yml +- codeql-analysis.yml + +### On Push to Main +- ci.yml (release job) +- docs.yml +- codeql-analysis.yml + +### Scheduled +- stale.yml (daily at midnight UTC) +- update-packages.yml (weekly on Sunday at midnight UTC) +- codeql-analysis.yml (weekly on Sunday at noon UTC) + +### Manual Trigger (workflow_dispatch) +- stale.yml +- update-packages.yml + +## Configuration Files + +Related configuration files in `.github/`: +- **dependabot.yml** - Dependabot configuration for automated dependency updates +- **labeler.yml** - Configuration for the labeler workflow +- **CODEOWNERS** - Defines code owners for automatic review requests +- **PULL_REQUEST_TEMPLATE.md** - Template for pull request descriptions +- **QUICK_REFERENCE.md** - Quick reference guide for CI/CD workflows + +## Notes + +- All workflows use .NET 9.0 and 10.0 +- Workflows are designed to be compatible with the PatternKit project structure +- Security scanning runs automatically on all pull requests and pushes diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 0000000..2900450 --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,27 @@ +name: Dependency Review + +on: + pull_request: + branches: + - main + +permissions: + contents: read + pull-requests: write + +jobs: + dependency-review: + name: Dependency Review + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Dependency Review + uses: actions/dependency-review-action@v4 + with: + fail-on-severity: moderate + deny-licenses: GPL-2.0, GPL-3.0, AGPL-3.0 + comment-summary-in-pr: always diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml new file mode 100644 index 0000000..4df6ff7 --- /dev/null +++ b/.github/workflows/labeler.yml @@ -0,0 +1,46 @@ +name: Auto Label + +on: + pull_request: + types: [opened, synchronize, reopened] + issues: + types: [opened, reopened] + +permissions: + contents: read + issues: write + pull-requests: write + +jobs: + label-pr: + name: Label Pull Request + if: github.event_name == 'pull_request' + runs-on: ubuntu-latest + timeout-minutes: 5 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Label based on files + uses: actions/labeler@v5 + with: + configuration-path: .github/labeler.yml + repo-token: ${{ secrets.GITHUB_TOKEN }} + + label-size: + name: Label PR Size + if: github.event_name == 'pull_request' + runs-on: ubuntu-latest + timeout-minutes: 5 + + steps: + - name: Label by size + uses: codelytv/pr-size-labeler@v1 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + xs_max_size: '10' + s_max_size: '100' + m_max_size: '500' + l_max_size: '1000' + fail_if_xl: 'false' diff --git a/.github/workflows/pr-validation.yml b/.github/workflows/pr-validation.yml new file mode 100644 index 0000000..a8cad1e --- /dev/null +++ b/.github/workflows/pr-validation.yml @@ -0,0 +1,195 @@ +name: PR Validation + +on: + pull_request: + branches: + - main + paths-ignore: + - '**.md' + - 'docs/**' + - '.vscode/**' + - '.editorconfig' + +env: + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + DOTNET_CLI_TELEMETRY_OPTOUT: true + DOTNET_NOLOGO: true + +permissions: + contents: read + pull-requests: write + checks: write + +jobs: + validate-pr: + name: Validate PR + runs-on: ubuntu-latest + timeout-minutes: 30 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Full history for GitVersion + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: | + 9.0.x + 10.0.x + cache: true + cache-dependency-path: | + **/packages.lock.json + global.json + + - name: Install GitVersion + uses: gittools/actions/gitversion/setup@v1 + with: + versionSpec: '5.x' + + - name: Run GitVersion + id: gitversion + uses: gittools/actions/gitversion/execute@v1 + + - name: Set version + id: version + run: | + VERSION="${{ steps.gitversion.outputs.nuGetVersionV2 }}" + echo "VERSION=$VERSION" >> $GITHUB_OUTPUT + echo "📦 Version: $VERSION" + + - name: Restore dependencies + run: | + dotnet restore --use-lock-file + dotnet tool restore + + - name: Build solution + run: | + dotnet build PatternKit.slnx \ + --configuration Release \ + --no-restore \ + /p:ContinuousIntegrationBuild=true \ + /p:Deterministic=true + + - name: Run tests + run: | + dotnet test PatternKit.slnx \ + --configuration Release \ + --no-build \ + --verbosity normal \ + --logger "trx;LogFileName=test-results.trx" \ + --collect:"XPlat Code Coverage" \ + --results-directory ./TestResults \ + -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=opencover + + - name: Publish test results + uses: EnricoMi/publish-unit-test-result-action@v2 + if: always() + with: + files: | + TestResults/**/*.trx + check_name: Test Results + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v4 + if: always() + with: + files: ./TestResults/**/coverage.opencover.xml + flags: unittests + name: pr-${{ github.event.pull_request.number }} + fail_ci_if_error: false + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + + - name: Build Documentation + run: | + dotnet tool update -g docfx + docfx metadata docs/docfx.json + docfx build docs/docfx.json + + - name: Dry-run NuGet packaging + run: | + echo "📦 Performing dry-run of NuGet packaging..." + + mkdir -p ./dry-run-packages + + # Package all library projects + for project in src/PatternKit.Core \ + src/PatternKit.Generators \ + src/PatternKit.Generators.Abstractions; do + if [ -d "$project" ]; then + echo " Packing $project..." + dotnet pack "$project" \ + --configuration Release \ + --no-build \ + --output ./dry-run-packages \ + /p:PackageVersion=${{ steps.version.outputs.VERSION }} \ + /p:RepositoryUrl=https://github.com/JerrettDavis/PatternKit \ + /p:RepositoryType=git \ + /p:ContinuousIntegrationBuild=true || echo " ⚠️ Failed to pack $project" + fi + done + + echo "" + echo "📊 Dry-run packaging summary:" + ls -lh ./dry-run-packages/*.nupkg 2>/dev/null || echo " No packages created" + + - name: Upload dry-run artifacts + uses: actions/upload-artifact@v4 + if: always() + with: + name: dry-run-artifacts-${{ github.event.pull_request.number }} + path: | + ./dry-run-packages/ + retention-days: 7 + + - name: Create PR comment + uses: actions/github-script@v7 + if: always() + with: + script: | + const body = `## 🔍 PR Validation Results + + **Version:** \`${{ steps.version.outputs.VERSION }}\` + + ### ✅ Validation Steps + - [x] Build solution + - [x] Run tests + - [x] Build documentation + - [x] Dry-run NuGet packaging + + ### 📊 Artifacts + Dry-run artifacts have been uploaded and will be available for 7 days. + + --- + *This comment was automatically generated by the PR validation workflow.* + `; + + // Find existing comment + const { data: comments } = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + }); + + const botComment = comments.find(comment => + comment.user.type === 'Bot' && + comment.body.includes('PR Validation Results') + ); + + if (botComment) { + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: botComment.id, + body: body + }); + } else { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: body + }); + } diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000..d06dd30 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,56 @@ +name: Stale Issues and PRs + +on: + schedule: + - cron: '0 0 * * *' # Daily at midnight UTC + workflow_dispatch: + +permissions: + issues: write + pull-requests: write + +jobs: + stale: + name: Close Stale Issues and PRs + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - name: Stale Issues and PRs + uses: actions/stale@v9 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + + # Stale issue configuration + stale-issue-message: | + This issue has been automatically marked as stale because it has not had recent activity. + It will be closed in 7 days if no further activity occurs. + + If this issue is still relevant, please add a comment to keep it open. + Thank you for your contributions! + close-issue-message: | + This issue was automatically closed due to inactivity. + + If you believe this issue is still relevant, please feel free to reopen it or create a new issue with updated information. + days-before-stale: 60 + days-before-close: 7 + stale-issue-label: 'stale' + exempt-issue-labels: 'pinned,security,bug,enhancement' + + # Stale PR configuration + stale-pr-message: | + This pull request has been automatically marked as stale because it has not had recent activity. + It will be closed in 14 days if no further activity occurs. + + Please rebase and update if you'd like to continue working on this PR. + close-pr-message: | + This pull request was automatically closed due to inactivity. + + If you'd like to continue working on this, please feel free to reopen and update it. + days-before-pr-stale: 30 + days-before-pr-close: 14 + stale-pr-label: 'stale' + exempt-pr-labels: 'pinned,security,work-in-progress' + + # Operations per run + operations-per-run: 30 diff --git a/.github/workflows/update-packages.yml b/.github/workflows/update-packages.yml new file mode 100644 index 0000000..2c35eca --- /dev/null +++ b/.github/workflows/update-packages.yml @@ -0,0 +1,78 @@ +name: Update Packages + +on: + schedule: + - cron: '0 0 * * 0' # Weekly on Sunday at midnight UTC + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +jobs: + update-packages: + name: Update NuGet Packages + runs-on: ubuntu-latest + timeout-minutes: 20 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: | + 9.0.x + 10.0.x + + - name: Install dotnet-outdated + run: dotnet tool install --global dotnet-outdated-tool + + - name: Check for outdated packages + id: check + run: | + echo "Checking for outdated packages..." + dotnet outdated --upgrade --version-lock Major > outdated.txt 2>&1 || true + + if [ -s outdated.txt ]; then + echo "has-updates=true" >> $GITHUB_OUTPUT + echo "Outdated packages found:" + cat outdated.txt + else + echo "has-updates=false" >> $GITHUB_OUTPUT + echo "All packages are up to date!" + fi + + - name: Create Pull Request + if: steps.check.outputs.has-updates == 'true' + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: 'deps: update NuGet packages to latest versions' + title: 'deps: Update NuGet packages to latest versions' + body: | + ## 📦 NuGet Package Updates + + This PR updates NuGet packages to their latest versions while preserving major version compatibility. + + ### Changes + ``` + $(cat outdated.txt) + ``` + + ### Checklist + - [ ] All tests pass + - [ ] No breaking changes introduced + - [ ] Documentation updated (if needed) + + --- + *This PR was automatically generated by the Update Packages workflow.* + branch: deps/update-packages + delete-branch: true + labels: | + dependencies + nuget + automated