Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 1 addition & 3 deletions .coderabbit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ tone_instructions: >

reviews:
profile: assertive
request_changes_workflow: false
request_changes_workflow: true
# No unsolicited summaries: CodeRabbit summarizes only on `@coderabbitai summary`.
high_level_summary: false
poem: false
Expand All @@ -23,8 +23,6 @@ reviews:
- ".*"
ignore_usernames:
- "dependabot[bot]"
ignore_title_keywords:
- WIP

path_filters:
- "!**/node_modules/**"
Expand Down
53 changes: 53 additions & 0 deletions .github/actions/changed-stacks/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: Changed stacks
description: >
Report whether a pull request touches the C# or Vue stack, so workflows can
skip jobs for the stack it leaves alone. Non-PR events report both as changed.
Needs a checkout with fetch-depth 0.

inputs:
own-paths:
description: The calling workflow's own files or folders, space-separated; a change to any runs both stacks.
required: true

outputs:
csharp:
description: "'true' when C# code or its build/tooling changed"
value: ${{ steps.filter.outputs.csharp }}
vue:
description: "'true' when Vue code or its build/tooling changed"
value: ${{ steps.filter.outputs.vue }}

runs:
using: composite
steps:
- id: filter
shell: bash
env:
BASE_REF: ${{ github.base_ref }}
OWN_PATHS: ${{ inputs.own-paths }}
run: |
if [ -z "$BASE_REF" ]; then
echo "csharp=true" >> "$GITHUB_OUTPUT"
echo "vue=true" >> "$GITHUB_OUTPUT"
exit 0
fi

files=$(git diff --no-renames --name-only "origin/$BASE_REF...HEAD")
echo "Changed files:"
echo "$files"

# Shared tooling runs both stacks; other workflow files run neither
shared="^(package(-lock)?\.json$|scripts/|\.editorconfig$|\.jscpd\.json$|\.npmrc$|\.github/actions/changed-stacks/)"
dot='\.'
for p in $OWN_PATHS; do shared="$shared|^${p//./$dot}"; done
csharp="$shared|^(web/|test/|Viper\.sln|Directory\.Build\.props$|global\.json$|\.globalconfig$|\.config/)"
vue="$shared|^(VueApp/|eslint\.config\.mjs$|\.oxlintrc\.json$|stylelint\.config\.mjs$|\.env)"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved

for stack in csharp vue; do
if grep -qE "${!stack}" <<< "$files"; then
echo "$stack=true" >> "$GITHUB_OUTPUT"
else
echo "$stack=false" >> "$GITHUB_OUTPUT"
fi
done
cat "$GITHUB_OUTPUT"
27 changes: 26 additions & 1 deletion .github/workflows/code-quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ name: Code Quality

on:
pull_request:
branches: [main]

# Detects whether a PR *adds* new dead code or duplication compared to main.
# - fallow covers VueApp (dead code, unused exports, complexity, duplication)
Expand All @@ -13,8 +12,28 @@ on:
# Passes if counts are equal to or lower than main.

jobs:
changes:
name: Detect changed stacks
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
csharp: ${{ steps.stacks.outputs.csharp }}
vue: ${{ steps.stacks.outputs.vue }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
persist-credentials: false
- id: stacks
uses: ./.github/actions/changed-stacks
with:
own-paths: .github/workflows/code-quality.yml

fallow-regression:
name: Fallow regression (VueApp)
needs: changes
if: needs.changes.outputs.vue == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout PR head
Expand Down Expand Up @@ -64,6 +83,8 @@ jobs:

jscpd-regression-csharp:
name: JSCPD regression (C#/Razor)
needs: changes
if: needs.changes.outputs.csharp == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout PR head
Expand Down Expand Up @@ -100,6 +121,8 @@ jobs:

jscpd-regression-vue:
name: JSCPD regression (Vue/TS)
needs: changes
if: needs.changes.outputs.vue == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout PR head
Expand Down Expand Up @@ -133,6 +156,8 @@ jobs:

resharper-pr-gate:
name: ReSharper PR-scoped gate (C#)
needs: changes
if: needs.changes.outputs.csharp == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout PR head
Expand Down
26 changes: 26 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,31 @@ on:
- cron: '32 18 * * 6'

jobs:
changes:
name: Detect changed stacks
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
csharp: ${{ steps.stacks.outputs.csharp }}
vue: ${{ steps.stacks.outputs.vue }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false
- id: stacks
uses: ./.github/actions/changed-stacks
with:
own-paths: .github/workflows/codeql.yml .github/codeql/

analyze:
name: Analyze
needs: changes
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
# Job-level `if` can't read the matrix; web/ holds plain JS, so a C# change runs both
env:
RUN_ANALYSIS: ${{ needs.changes.outputs.csharp == 'true' || (matrix.language == 'javascript' && needs.changes.outputs.vue == 'true') }}
permissions:
actions: read
contents: read
Expand All @@ -40,10 +62,12 @@ jobs:

steps:
- name: Checkout repository
if: env.RUN_ANALYSIS == 'true'
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
if: env.RUN_ANALYSIS == 'true'
uses: github/codeql-action/init@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4.39.1
with:
languages: ${{ matrix.language }}
Expand All @@ -52,6 +76,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
if: env.RUN_ANALYSIS == 'true'
uses: github/codeql-action/autobuild@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4.39.1

# ℹ️ Command-line programs to run using the OS shell.
Expand All @@ -65,6 +90,7 @@ jobs:
# ./location_of_script_within_repo/buildscript.sh

- name: Perform CodeQL Analysis
if: env.RUN_ANALYSIS == 'true'
uses: github/codeql-action/analyze@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4.39.1
with:
category: "/language:${{matrix.language}}"
90 changes: 90 additions & 0 deletions .github/workflows/coderabbit-gate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
name: CodeRabbit Gate

# Passes when CodeRabbit's check run succeeded on the head commit and none of
# its threads are unresolved. A clean incremental review posts no PR review at
# all, so the job waits for CodeRabbit's check run instead of a review event.
# A declined finding passes once its thread is resolved and this check is re-run.

on:
pull_request:
types: [opened, reopened, synchronize, ready_for_review]
pull_request_review:
types: [submitted, dismissed]
# Catches a CodeRabbit review that finishes after the gate stopped polling.
# check_run only fires from the default branch's copy of this workflow.
check_run:
types: [completed]

permissions:
pull-requests: read # read CodeRabbit's review threads
checks: read # read CodeRabbit's check run on the head commit

concurrency:
# check_run fires for every check, so its runs must not cancel each other
group: coderabbit-gate-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true

jobs:
coderabbit-gate:
name: CodeRabbit approval
# CodeRabbit skips drafts and Dependabot PRs, so there is no verdict to wait for
if: ${{ github.event_name != 'check_run' && !github.event.pull_request.draft && github.event.pull_request.user.login != 'dependabot[bot]' }}
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- name: Check CodeRabbit's review of the head commit
env:
GH_TOKEN: ${{ github.token }}
PR: ${{ github.event.pull_request.number }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
set -o pipefail
for _ in $(seq 40); do
run=$(gh api "repos/$GITHUB_REPOSITORY/commits/$HEAD_SHA/check-runs?check_name=CodeRabbit" \
--jq '.check_runs | sort_by(.id) | last | select(.) | "\(.status) \(.conclusion)"')
[[ "$run" == completed* ]] && break
sleep 30
Comment thread
rlorenzo marked this conversation as resolved.
Resolved
done
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
if [ "$run" != "completed success" ]; then
echo "::error::CodeRabbit has not reviewed the latest commit (${run:-no run}). If it was rate limited or skipped, comment '@coderabbitai review'."
exit 1
fi

# Findings outside the diff have no thread, so only threaded findings block
unresolved=$(gh api graphql --paginate --slurp -F pr="$PR" -f owner="${GITHUB_REPOSITORY%/*}" -f repo="${GITHUB_REPOSITORY#*/}" -f query='
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
query($owner:String!, $repo:String!, $pr:Int!, $endCursor:String) {
repository(owner:$owner, name:$repo) { pullRequest(number:$pr) {
reviewThreads(first:100, after:$endCursor) {
pageInfo { hasNextPage endCursor }
nodes { isResolved comments(first:1) { nodes { author { login } } } }
}
} }
}' | jq '[.[].data.repository.pullRequest.reviewThreads.nodes[]
| select(.isResolved == false and .comments.nodes[0].author.login == "coderabbitai")] | length')
if [ "$unresolved" -gt 0 ]; then
echo "::error::$unresolved CodeRabbit thread(s) unresolved. Address or resolve them, then re-run this check."
exit 1
fi
echo "CodeRabbit's review of the latest commit is clean."

rerun-after-coderabbit:
name: Re-run gate after CodeRabbit finishes
if: ${{ github.event_name == 'check_run' && github.event.check_run.name == 'CodeRabbit' }}
runs-on: ubuntu-latest
permissions:
actions: write # list and re-run this workflow's gate runs
steps:
- name: Re-run the commit's failed gate run
env:
GH_TOKEN: ${{ github.token }}
HEAD_SHA: ${{ github.event.check_run.head_sha }}
# This run reports on the default branch, so re-run the PR's own gate run instead
run: |
run=$(gh run list -R "$GITHUB_REPOSITORY" --workflow coderabbit-gate.yml --commit "$HEAD_SHA" -L 20 \
--json databaseId,event,status,conclusion \
--jq '[.[] | select(.event != "check_run")][0] | select(.status == "completed" and .conclusion == "failure") | .databaseId')
if [ -n "$run" ]; then
gh run rerun "$run" -R "$GITHUB_REPOSITORY"
Comment thread
rlorenzo marked this conversation as resolved.
Resolved
else
echo "No failed gate run to refresh for $HEAD_SHA."
fi
4 changes: 2 additions & 2 deletions .github/workflows/development-merge-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ name: Development Merge Check
on:
pull_request:
types: [opened, reopened, synchronize, ready_for_review]
Comment thread
rlorenzo marked this conversation as resolved.
Resolved
branches: [main]
branches-ignore: [Development]
push:
branches: [Development]
workflow_dispatch:
Expand Down Expand Up @@ -95,7 +95,7 @@ jobs:
// in Development without a new PR commit. Re-run each still-red PR's
// check so its verdict refreshes against the updated Development.
const prs = await github.paginate(github.rest.pulls.list, {
owner, repo, state: 'open', base: 'main', per_page: 100,
owner, repo, state: 'open', per_page: 100,
});
const runs = await github.paginate(github.rest.actions.listWorkflowRuns, {
owner, repo, workflow_id: WORKFLOW, event: 'pull_request', per_page: 100,
Expand Down
23 changes: 22 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,30 @@ on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
changes:
name: Detect changed stacks
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
csharp: ${{ steps.stacks.outputs.csharp }}
vue: ${{ steps.stacks.outputs.vue }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false
- id: stacks
uses: ./.github/actions/changed-stacks
with:
own-paths: .github/workflows/tests.yml

frontend:
name: Frontend Tests
needs: changes
if: needs.changes.outputs.vue == 'true'
runs-on: ubuntu-latest
env:
HAS_CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN != '' }}
Expand Down Expand Up @@ -54,6 +73,8 @@ jobs:

backend:
name: Backend Tests
needs: changes
if: needs.changes.outputs.csharp == 'true'
runs-on: ubuntu-latest
env:
HAS_CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN != '' }}
Expand Down
Loading