diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index f9287da..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: Build - -on: - pull_request: - branches: [develop] - -permissions: read-all - -concurrency: - group: ${{ github.ref }}-${{ github.workflow }} - cancel-in-progress: true - -jobs: - build: - name: Build - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v6 - - - name: .NET - uses: actions/setup-dotnet@v5 - - name: Run - run: dotnet run - - name: Output - uses: actions/upload-artifact@v5 - with: - name: Generated Site - path: output/ - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..9b29731 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,61 @@ +name: CI + +on: + push: + branches: [develop] + workflow_dispatch: + +permissions: {} + +concurrency: + group: ${{ github.ref }}-${{ github.workflow }} + cancel-in-progress: true + +jobs: + deploy: + name: Deploy + runs-on: ubuntu-latest + permissions: + contents: write + pages: write + + steps: + - name: Check out repository + uses: actions/checkout@v6 + + - name: Set up .NET SDK + uses: actions/setup-dotnet@v5 + + - name: Deploy + run: dotnet run -- deploy + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + scan: + name: Scan + runs-on: ubuntu-latest + permissions: + security-events: write + + strategy: + fail-fast: false + matrix: + language: ["csharp"] + + steps: + - name: Check out repository + uses: actions/checkout@v6 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v4 + with: + languages: ${{ matrix.language }} + + - name: Set up .NET SDK + uses: actions/setup-dotnet@v5 + + - name: Autobuild + uses: github/codeql-action/autobuild@v4 + + - name: Analyze + uses: github/codeql-action/analyze@v4 diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index 88ebaff..0000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: Deploy - -on: - push: - branches: [develop] - -permissions: read-all - -jobs: - deploy: - name: Deploy - runs-on: ubuntu-latest - permissions: - contents: write - pages: write - - steps: - - name: Checkout - uses: actions/checkout@v6 - - - name: .NET - uses: actions/setup-dotnet@v5 - - run: dotnet run -- deploy - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml deleted file mode 100644 index 014d3c1..0000000 --- a/.github/workflows/lint.yml +++ /dev/null @@ -1,72 +0,0 @@ -name: Lint - -on: - pull_request: - branches: [develop] - -permissions: read-all - -env: - APPLY_FIXES: all - APPLY_FIXES_EVENT: pull_request - APPLY_FIXES_MODE: commit - -concurrency: - group: ${{ github.ref }}-${{ github.workflow }} - cancel-in-progress: true - -jobs: - lint: - name: Lint - runs-on: ubuntu-latest - permissions: - checks: write - contents: write - pull-requests: write - - steps: - - name: Checkout - uses: actions/checkout@v6 - with: - token: ${{ secrets.PAT || secrets.GITHUB_TOKEN }} - fetch-depth: 0 - - - name: Lint - id: ml - uses: oxsecurity/megalinter/flavors/dotnetweb@v9 - env: - VALIDATE_ALL_CODEBASE: ${{ github.event_name == 'push' && github.ref == 'refs/heads/develop' }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Report - if: always() - uses: actions/upload-artifact@v5 - with: - name: Lint Report - path: | - megalinter-reports - mega-linter.log - - - name: Fix - id: cpr - if: steps.ml.outputs.has_updated_sources == 1 && (env.APPLY_FIXES_EVENT == 'all' || env.APPLY_FIXES_EVENT == github.event_name) && env.APPLY_FIXES_MODE == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository && !contains(github.event.head_commit.message, 'skip fix') - uses: peter-evans/create-pull-request@v7 - with: - token: ${{ secrets.PAT || secrets.GITHUB_TOKEN }} - commit-message: "Apply lint fixes" - title: "Apply lint fixes" - labels: bot - - name: Output - if: steps.ml.outputs.has_updated_sources == 1 && (env.APPLY_FIXES_EVENT == 'all' || env.APPLY_FIXES_EVENT == github.event_name) && env.APPLY_FIXES_MODE == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository && !contains(github.event.head_commit.message, 'skip fix') - run: | - echo "PR: ${{ steps.cpr.outputs.pull-request-number }}" - echo "PR URL: ${{ steps.cpr.outputs.pull-request-url }}" - - name: Prepare - if: steps.ml.outputs.has_updated_sources == 1 && (env.APPLY_FIXES_EVENT == 'all' || env.APPLY_FIXES_EVENT == github.event_name) && env.APPLY_FIXES_MODE == 'commit' && github.ref != 'refs/heads/develop' && github.event.pull_request.head.repo.full_name == github.repository && !contains(github.event.head_commit.message, 'skip fix') - run: sudo chown -Rc $UID .git/ - - name: Commit - if: steps.ml.outputs.has_updated_sources == 1 && (env.APPLY_FIXES_EVENT == 'all' || env.APPLY_FIXES_EVENT == github.event_name) && env.APPLY_FIXES_MODE == 'commit' && github.ref != 'refs/heads/develop' && github.event.pull_request.head.repo.full_name == github.repository && !contains(github.event.head_commit.message, 'skip fix') - uses: stefanzweifel/git-auto-commit-action@v7 - with: - branch: ${{ github.event.pull_request.head.ref || github.head_ref || github.ref }} - commit_message: "Apply lint fixes" diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml new file mode 100644 index 0000000..92a8bcb --- /dev/null +++ b/.github/workflows/pr.yml @@ -0,0 +1,173 @@ +name: PR Validation + +on: + pull_request: + branches: [develop] + workflow_dispatch: # checkov:skip=CKV_GHA_7:Input only used to select PR for validation, does not affect build output + inputs: + pull_request_number: + description: "Pull Request Number" + required: true + type: number + +permissions: {} + +concurrency: + group: ${{ github.ref }}-${{ github.workflow }} + cancel-in-progress: true + +jobs: + lint: + name: Lint + runs-on: ubuntu-latest + permissions: + checks: write + contents: write + pull-requests: write + + steps: + - name: Get PR details + id: pr-details + run: | + if [ "$EVENT_NAME" = "workflow_dispatch" ]; then + echo "Fetching details for PR #$PR_NUMBER" + + PR_DATA=$(gh pr view "$PR_NUMBER" --repo "$REPO" --json headRefName,headRepository,author) + HEAD_REF=$(echo "$PR_DATA" | jq -r '.headRefName') + AUTHOR_LOGIN=$(echo "$PR_DATA" | jq -r '.author.login') + HEAD_REPO=$(echo "$PR_DATA" | jq -r '.headRepository.nameWithOwner') + + { + echo "head_ref=$HEAD_REF" + echo "author_login=$AUTHOR_LOGIN" + echo "head_repo=$HEAD_REPO" + } >> "$GITHUB_OUTPUT" + else + { + echo "head_ref=$PR_HEAD_REF" + echo "author_login=$PR_AUTHOR_LOGIN" + echo "head_repo=$PR_HEAD_REPO" + } >> "$GITHUB_OUTPUT" + fi + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + EVENT_NAME: ${{ github.event_name }} + PR_NUMBER: ${{ inputs.pull_request_number }} + REPO: ${{ github.repository }} + PR_HEAD_REF: ${{ github.event.pull_request.head.ref }} + PR_AUTHOR_LOGIN: ${{ github.event.pull_request.user.login }} + PR_HEAD_REPO: ${{ github.event.pull_request.head.repo.full_name }} + + - name: Check out repository + uses: actions/checkout@v6 + with: + ref: ${{ steps.pr-details.outputs.head_ref }} + token: ${{ secrets.PAT || secrets.GITHUB_TOKEN }} + fetch-depth: 0 + + - name: Run MegaLinter + id: ml + uses: oxsecurity/megalinter/flavors/dotnetweb@v9 + env: + VALIDATE_ALL_CODEBASE: false + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + LLM_ADVISOR_ENABLED: >- + ${{ + steps.pr-details.outputs.author_login != 'dependabot[bot]' && + steps.pr-details.outputs.author_login != 'github-actions[bot]' && + !startsWith(steps.pr-details.outputs.author_login, 'dependabot') + }} + + - name: Upload lint reports + if: always() + uses: actions/upload-artifact@v5 + with: + name: Lint Report + path: | + megalinter-reports + mega-linter.log + + - name: Prepare git directory + if: >- + steps.ml.outputs.has_updated_sources == 1 && + steps.pr-details.outputs.head_repo == github.repository + run: sudo chown -Rc $UID .git/ + + - name: Commit and push MegaLinter fixes + if: >- + steps.ml.outputs.has_updated_sources == 1 && + steps.pr-details.outputs.head_repo == github.repository + run: | + git config user.name "megalinter-bot" + git config user.email "129584137+megalinter-bot@users.noreply.github.com" + + if [[ -n $(git status -s) ]]; then + git add . + git commit -m "Apply lint fixes" + + for i in {1..4}; do + if git push; then + echo "✅ MegaLinter fixes pushed successfully" + break + else + if [[ "$i" -lt 4 ]]; then + WAIT_TIME=$((2 ** i)) + echo "⚠️ Push failed, retrying in ${WAIT_TIME}s..." + sleep "$WAIT_TIME" + else + echo "❌ Push failed after 4 attempts" + exit 1 + fi + fi + done + else + echo "ℹ️ No MegaLinter changes to commit" + fi + + build: + name: Build + runs-on: ubuntu-latest + permissions: + checks: write + contents: write + pull-requests: write + + steps: + - name: Get PR details + id: pr-details + run: | + if [ "$EVENT_NAME" = "workflow_dispatch" ]; then + echo "Fetching details for PR #$PR_NUMBER" + + PR_DATA=$(gh pr view "$PR_NUMBER" --repo "$REPO" --json headRefName) + HEAD_REF=$(echo "$PR_DATA" | jq -r '.headRefName') + + echo "head_ref=$HEAD_REF" >> "$GITHUB_OUTPUT" + else + echo "head_ref=$PR_HEAD_REF" >> "$GITHUB_OUTPUT" + fi + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + EVENT_NAME: ${{ github.event_name }} + PR_NUMBER: ${{ inputs.pull_request_number }} + REPO: ${{ github.repository }} + PR_HEAD_REF: ${{ github.event.pull_request.head.ref }} + + - name: Check out repository + uses: actions/checkout@v6 + with: + ref: ${{ steps.pr-details.outputs.head_ref }} + + - name: Set up .NET SDK + uses: actions/setup-dotnet@v5 + + - name: Run build + run: dotnet run + + - name: Upload output + uses: actions/upload-artifact@v5 + with: + name: Generated Site + path: output/ + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml deleted file mode 100644 index c930982..0000000 --- a/.github/workflows/scan.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: "Scan" - -on: - push: - branches: [develop] - pull_request: - branches: [develop] - schedule: - - cron: "0 4 * * 5" - -permissions: read-all - -jobs: - scan: - name: Scan - runs-on: ubuntu-latest - permissions: - security-events: write - - strategy: - fail-fast: false - matrix: - language: ["csharp"] - - steps: - - name: Checkout - uses: actions/checkout@v6 - - - name: Initialize - uses: github/codeql-action/init@v4 - with: - languages: ${{ matrix.language }} - - - name: .NET - uses: actions/setup-dotnet@v5 - - - name: Autobuild - uses: github/codeql-action/autobuild@v4 - - - name: Analyze - uses: github/codeql-action/analyze@v4