diff --git a/.github/actions/code-style/action.yml b/.github/actions/code-style/action.yml index 1f963f79..7fe1b0f3 100644 --- a/.github/actions/code-style/action.yml +++ b/.github/actions/code-style/action.yml @@ -12,12 +12,18 @@ inputs: runs: using: "composite" steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - fetch-depth: 0 + - name: Check for existing .NET SDK + id: check-dotnet + shell: bash + run: | + if dotnet --version >/dev/null 2>&1; then + echo "installed=true" >> $GITHUB_OUTPUT + else + echo "installed=false" >> $GITHUB_OUTPUT + fi - name: Setup .NET - uses: actions/setup-dotnet@v3 + if: ${{ steps.check-dotnet.outputs.installed == 'false' }} + uses: actions/setup-dotnet@v4 with: dotnet-version: '7.0.x' - name: Run dotnet-format @@ -34,7 +40,7 @@ runs: - name: Process C# file headers uses: ./.github/actions/code-style/header-fixer with: - mode: ${{ inputs.mode }} + mode: soft-check - name: Process trailing whitespace uses: ./.github/actions/code-style/trailing-whitespace with: @@ -46,7 +52,7 @@ runs: - name: Check namespaces uses: ./.github/actions/code-style/namespace-fixer with: - mode: check + mode: soft-check - name: Commit & push changes if: ${{ inputs.commit }} shell: bash diff --git a/.github/actions/code-style/header-fixer/action.yml b/.github/actions/code-style/header-fixer/action.yml index 51524fc1..c9f08f72 100644 --- a/.github/actions/code-style/header-fixer/action.yml +++ b/.github/actions/code-style/header-fixer/action.yml @@ -2,16 +2,12 @@ name: "Header Fixer" description: "Check or fix C# file headers to match .editorconfig header template" inputs: mode: - description: "Operation mode: fix or check" + description: "Operation mode: fix, check, or soft-check" required: false - default: "check" + default: "soft-check" runs: using: "composite" steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - fetch-depth: 0 - name: Process C# file headers shell: bash env: @@ -45,7 +41,7 @@ runs: HEADER_LINES=$(echo -e "$HEADER" | wc -l) CURRENT_HEADER=$(head -n $HEADER_LINES "$file") - if [ "$(echo -e "$HEADER")" != "$CURRENT_HEADER" ]; then + if [ "$HEADER" != "$CURRENT_HEADER" ]; then if [ "${{ inputs.mode }}" = "fix" ]; then echo "Updating header in $file" # Find namespace line @@ -59,8 +55,13 @@ runs: echo "Warning: Could not find namespace line in $file" fi else - echo "Header mismatch in $file" - ERR=1 + if [ "${{ inputs.mode }}" = "soft-check" ]; then + # emit a non-blocking warning + echo "::warning file=$file::Header mismatch in $file (run with mode=fix to auto-fix)" + else + echo "Header mismatch in $file" + ERR=1 + fi fi fi fi diff --git a/.github/actions/code-style/namespace-fixer/action.yml b/.github/actions/code-style/namespace-fixer/action.yml index dac29911..e0f6da0f 100644 --- a/.github/actions/code-style/namespace-fixer/action.yml +++ b/.github/actions/code-style/namespace-fixer/action.yml @@ -2,16 +2,12 @@ name: "Namespace Fixer" description: "Check or fix C# file namespaces to match file path" inputs: mode: - description: "Operation mode: fix or check" + description: "Operation mode: fix, check, or soft-check" required: false default: "check" runs: using: "composite" steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - fetch-depth: 0 - name: Process C# namespaces if: always() shell: bash @@ -38,8 +34,13 @@ runs: sed -i "s/^namespace .*/namespace $ns/" "$file" echo "WARNING: References to this file may need manual updates." else - echo "Namespace mismatch in $file: expected $ns but found $actual" - ERR=1 + if [ "${{ inputs.mode }}" = "soft-check" ]; then + # emit a non-blocking warning + echo "::warning file=$file::Namespace mismatch in $file (run with mode=fix to auto-fix)" + else + echo "Namespace mismatch in $file: expected $ns but found $actual" + ERR=1 + fi fi fi fi diff --git a/.github/actions/code-style/trailing-whitespace/action.yml b/.github/actions/code-style/trailing-whitespace/action.yml index 765324f6..48e29e4e 100644 --- a/.github/actions/code-style/trailing-whitespace/action.yml +++ b/.github/actions/code-style/trailing-whitespace/action.yml @@ -2,16 +2,12 @@ name: "Trailing Whitespace" description: "Check or fix trailing whitespace and normalize line endings" inputs: mode: - description: "Operation mode: fix or check" + description: "Operation mode: fix, check, or soft-check" required: false default: "check" runs: using: "composite" steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - fetch-depth: 0 - name: Process trailing whitespace shell: bash run: | @@ -25,8 +21,13 @@ runs: sed -i 's/\r$//' "$file" else if grep -qE '[ \t]+$' "$file" || file "$file" | grep -q CRLF; then - echo "Trailing whitespace or CRLF found in $file" - ERR=1 + if [ "${{ inputs.mode }}" = "soft-check" ]; then + # emit a non-blocking warning + echo "::warning file=$file::Trailing whitespace or CRLF found in $file (run with mode=fix to auto-fix)" + else + echo "Trailing whitespace or CRLF found in $file" + ERR=1 + fi fi fi fi diff --git a/.github/actions/code-style/using-sorter/action.yml b/.github/actions/code-style/using-sorter/action.yml index fe3a07c4..63914839 100644 --- a/.github/actions/code-style/using-sorter/action.yml +++ b/.github/actions/code-style/using-sorter/action.yml @@ -2,18 +2,24 @@ name: "Using Sorter" description: "Check or fix C# using directives ordering and remove unused usings" inputs: mode: - description: "Operation mode: fix or check" + description: "Operation mode: fix, check, or soft-check" required: false default: "check" runs: using: "composite" steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - fetch-depth: 0 + - name: Check for existing .NET SDK + id: check-dotnet + shell: bash + run: | + if dotnet --version >/dev/null 2>&1; then + echo "installed=true" >> $GITHUB_OUTPUT + else + echo "installed=false" >> $GITHUB_OUTPUT + fi - name: Setup .NET SDK - uses: actions/setup-dotnet@v3 + if: ${{ steps.check-dotnet.outputs.installed == 'false' }} + uses: actions/setup-dotnet@v4 with: dotnet-version: 7.0.x - name: Run using sorter @@ -25,7 +31,7 @@ runs: export PATH="$HOME/.dotnet/tools:$PATH" for file in $FILES; do if [ -f "$file" ]; then - if [ "${{ inputs.mode }}" = "check" ]; then + if [ "${{ inputs.mode }}" = "check" ] || [ "${{ inputs.mode }}" = "soft-check" ]; then dotnet format "$file" --verify-no-changes --fix-analyzers else dotnet format "$file" --fix-analyzers diff --git a/.github/workflows/ci-dotnet-tests.yml b/.github/workflows/ci-dotnet-tests.yml index f64a73f7..189e0ae8 100644 --- a/.github/workflows/ci-dotnet-tests.yml +++ b/.github/workflows/ci-dotnet-tests.yml @@ -27,8 +27,19 @@ jobs: - name: Checkout code uses: actions/checkout@v3 + - name: Check for existing .NET SDK + id: check-dotnet + shell: bash + run: | + if dotnet --version >/dev/null 2>&1; then + echo "installed=true" >> $GITHUB_OUTPUT + else + echo "installed=false" >> $GITHUB_OUTPUT + fi + - name: Setup .NET - uses: actions/setup-dotnet@v3 + if: ${{ steps.check-dotnet.outputs.installed == 'false' }} + uses: actions/setup-dotnet@v4 with: dotnet-version: '7.0.x' diff --git a/.github/workflows/release-1-milestone.yml b/.github/workflows/release-1-milestone.yml index cfd35ea0..e8c37912 100644 --- a/.github/workflows/release-1-milestone.yml +++ b/.github/workflows/release-1-milestone.yml @@ -10,10 +10,14 @@ name: 🏁 1 Prepare Release on Milestone Close # Permissions: # - contents:write - Required to create GitHub releases # - issues:read - Required to read issue information for release notes -# - pull-requests:read - Required to read PR information for release notes +# - pull-requests:write - Required to create pull requests +# +permissions: + contents: write + issues: read + pull-requests: write on: - workflow_dispatch: milestone: types: [ closed ] @@ -25,42 +29,68 @@ jobs: with: fetch-depth: 0 ref: dev + - name: Set up Git user run: | git config user.name "github-actions" git config user.email "action@github.com" + + - name: Check if release branch exists + id: check-branch + run: | + git ls-remote --heads origin release/${{ github.event.milestone.title }} + if [ $? -eq 0 ]; then + echo "branch_exists=true" >> $GITHUB_OUTPUT + else + echo "branch_exists=false" >> $GITHUB_OUTPUT + fi + + - name: Remove existing release branch if exists + if: steps.check-branch.outputs.branch_exists == 'true' + run: git push origin --delete release/${{ github.event.milestone.title }} + - name: Create release branch run: git checkout -b release/${{ github.event.milestone.title }} + - name: Update version in Solution.props uses: ./.github/actions/versioning/update-version with: new-version: ${{ github.event.milestone.title }} + - name: Include missing issues in changelog uses: ./.github/actions/documentation/update-changelog-issues with: token: ${{ secrets.GITHUB_TOKEN }} days-lookback: 90 + - name: Update changelog section uses: ./.github/actions/documentation/update-changelog with: action: create-release version: ${{ github.event.milestone.title }} - - name: Fix code style - uses: ./.github/actions/code-style - with: - mode: fix - commit: false + + - name: Update README badges + uses: ./.github/actions/documentation/update-badges + id: update-badges + + # - name: Fix code style + # uses: ./.github/actions/code-style + # with: + # mode: fix + # commit: false + - name: Commit and push changes run: | - git add Solution.props CHANGELOG.md + git add Solution.props CHANGELOG.md README.md git commit -m "chore: prepare release ${{ github.event.milestone.title }} with version update and code style fixes" git push origin release/${{ github.event.milestone.title }} + - name: Create Pull Request - uses: peter-evans/create-pull-request@v4 - with: - token: ${{ secrets.GITHUB_TOKEN }} - title: "chore: prepare release ${{ github.event.milestone.title }} with version update and code style fixes" - body: "This PR prepares the release for version ${{ github.event.milestone.title }} with version update and code style fixes:\n\n- Fixed header code style\n- Sorted usings\n- Removed trailing whitespace\n- Updated version in Solution.props\n- Updated changelog with closed-solved issues\n\nMILESTONE DESCRIPTION:\n${{ github.event.milestone.description }}" - base: dev - branch: release/${{ github.event.milestone.title }} - milestone: ${{ github.event.milestone.number }} \ No newline at end of file + run: | + gh pr create \ + --base dev \ + --head release/${{ github.event.milestone.title }} \ + --title "chore: prepare release ${{ github.event.milestone.title }} with version update and code style fixes" \ + --body $'This PR prepares the release for version ${{ github.event.milestone.title }} with version update and code style fixes:\n\n- Fixed header code style\n- Sorted usings\n- Removed trailing whitespace\n- Updated version in Solution.props\n- Updated changelog with closed-solved issues\n- Updated README badges\n\nMILESTONE DESCRIPTION:\n${{ github.event.milestone.description }}' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/release-2-pr-to-dev-closed.yml b/.github/workflows/release-2-pr-to-dev-closed.yml index c72e5aa0..6bc94414 100644 --- a/.github/workflows/release-2-pr-to-dev-closed.yml +++ b/.github/workflows/release-2-pr-to-dev-closed.yml @@ -8,37 +8,51 @@ name: 🏁 2 PR Release to Main from Dev # Permissions: # - contents:write - Required to create GitHub releases # - issues:read - Required to read issue information for release notes -# - pull-requests:read - Required to read PR information for release notes +# - pull-requests:write - Required to create PRs on: - workflow_dispatch: pull_request: types: [ closed ] branches: - dev + workflow_dispatch: + inputs: + pr-title: + required: true + type: string + pr-body: + required: true + type: string jobs: create-pr-dev-to-main: - if: ${{ github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'release/') }} + if: ${{ ( github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'release/')) || github.event_name == 'workflow_dispatch' }} runs-on: ubuntu-latest permissions: contents: write issues: read - pull-requests: read + pull-requests: write steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - ref: dev - - name: Set up Git user + - name: Create PR (on PR closed) + if: ${{ github.event_name == 'pull_request' }} + run: | + gh pr create \ + --repo ${{ github.repository }} \ + --base main \ + --head dev \ + --title "${{ github.event.pull_request.head.ref }}" \ + --body "${{ github.event.pull_request.body }}" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Create PR (manual dispatch) + if: ${{ github.event_name == 'workflow_dispatch' }} run: | - git config user.name "github-actions" - git config user.email "action@github.com" - - name: Create PR - uses: peter-evans/create-pull-request@v4 - with: - token: ${{ secrets.GITHUB_TOKEN }} - title: "${{ github.event.pull_request.head.ref }}" - body: "${{ github.event.pull_request.body }}" - base: main - branch: ${{ github.event.pull_request.base.ref }} + gh pr create \ + --repo ${{ github.repository }} \ + --base main \ + --head dev \ + --title "${{ github.event.inputs['pr-title'] }}" \ + --body "${{ github.event.inputs['pr-body'] }}" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release-3-pr-to-main-closed.yml b/.github/workflows/release-3-pr-to-main-closed.yml index 00251d7a..08dc895c 100644 --- a/.github/workflows/release-3-pr-to-main-closed.yml +++ b/.github/workflows/release-3-pr-to-main-closed.yml @@ -13,15 +13,15 @@ name: 🏁 3 Create Release on Release PR Close # - pull-requests:read - Required to read PR information for release notes on: - workflow_dispatch: pull_request: types: [ closed ] branches: - main + workflow_dispatch: jobs: create-release: - if: ${{ github.event.pull_request.merged == true }} + if: ${{ github.event.pull_request.merged == true || github.event_name == 'workflow_dispatch' }} runs-on: ubuntu-latest permissions: contents: write @@ -34,11 +34,15 @@ jobs: fetch-depth: 0 ref: main # Checkout the main branch - - name: Get Release Info + - name: Get Release Version id: release_info + uses: ./.github/actions/versioning/get-version + with: + branch: main + + - name: Set Release Info run: | - VERSION=$(grep -oPm1 "(?<=)[^<]+" Solution.props) - echo "RELEASE_VERSION=$VERSION" >> $GITHUB_ENV + echo "RELEASE_VERSION=${{ steps.release_info.outputs.version }}" >> $GITHUB_ENV echo "RELEASE_DESCRIPTION<> $GITHUB_ENV echo "${{ github.event.pull_request.body }}" >> $GITHUB_ENV echo "EOF" >> $GITHUB_ENV diff --git a/.github/workflows/release-4-build.yml b/.github/workflows/release-4-build.yml index 29212a46..dd683852 100644 --- a/.github/workflows/release-4-build.yml +++ b/.github/workflows/release-4-build.yml @@ -114,8 +114,19 @@ jobs: Write-Host "This is a draft release. Skipping build and upload." exit 0 - - name: Setup .NET SDK - uses: actions/setup-dotnet@v3 + - name: Check for existing .NET SDK + id: check-dotnet + shell: bash + run: | + if dotnet --version >/dev/null 2>&1; then + echo "installed=true" >> $GITHUB_OUTPUT + else + echo "installed=false" >> $GITHUB_OUTPUT + fi + + - name: Setup .NET + if: ${{ steps.check-dotnet.outputs.installed == 'false' }} + uses: actions/setup-dotnet@v4 with: dotnet-version: '7.0.x'