Run an AI-powered, Business Central-specific code review on pull requests. This repository provides a GitHub composite action that:
- Collects the PR unified diff and optional context files (app.json, permission sets, markdowns, linked issues).
- Sends a structured prompt to your chosen LLM provider (Azure OpenAI, OpenAI, OpenRouter.ai).
- Posts a summary review and fine-grained inline comments on the PR.
Demo: https://github.com/skeck/bc-reviewer/pull/11
This action is not a generic code reviewer. It is tailored for Business Central AL projects:
- It only reviews AL and BC app artifacts (
**/*.al,app.json, permission sets, markdown docs) and builds deterministic BC object metadata from the HEAD version of your files. - The review prompt is grounded in AL Guidelines ALGuidelines.dev and standard BC design patterns (event-driven extensibility, AL-Go structure, upgrade codeunits, etc.).
- Feedback is BC domain-aware: posting routines, journals, ledgers, dimensions, VAT/currencies, inventory costing, approvals, permissions, data classification, AppSource vs. Per-Tenant rules, and SaaS/multi-tenant safety are all first-class concerns.
- The reviewer prefers safe, upgrade-friendly, tenant-aware suggestions over "clever" but risky shortcuts, and explicitly calls out high-risk changes (posting, schema/upgrade, security/permissions, public APIs/events).
Combined with the .continue/prompts/review-pr.md prompt and PR Reviewer Rules, this makes the review behavior strongly aligned with real-world BC AL practices rather than a generic LLM code review.
- Opinionated defaults and rules are bundled in the action (default-config.yaml) for sensible behaviour out of the box.
- MODELS_BLOCK enables flexible model/provider selection (OpenAI, Azure Foundry, OpenRouter, ...).
- MODELS_BLOCK (required): a multiline YAML string containing a
models:array. It fully replaces the embeddedmodels:section in default-config.yaml. - Merged config: the action writes a merged YAML to
$RUNNER_TEMP/continue-config.yamland setsCONTINUE_CONFIGto that path before invoking the review scripts. - Secrets: supply via
secrets.*(interpolate directly in MODELS_BLOCK) or use placeholders likeapiKey: "{{AZURE_OPENAI_KEY}}"and set corresponding env vars in the workflow.
name: "BC Code Reviewer"
on:
pull_request:
branches: [ main ]
types: [ opened, reopened, ready_for_review ]
issue_comment:
types: [created]
workflow_dispatch:
permissions:
contents: read
pull-requests: write
jobs:
review:
# Only run if this is a pull_request event or an issue_comment on a PR that includes '/review'
if: >
(github.event_name == 'pull_request') ||
(github.event_name == 'issue_comment' &&
github.event.issue.pull_request != null &&
contains(github.event.comment.body, '/review'))
runs-on: ubuntu-latest
# Optional but recommended to avoid overlapping runs on the same PR
concurrency:
group: ai-review-${{ github.event.pull_request.number || github.event.issue.number }}
cancel-in-progress: true
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Run AI Code Review
uses: ACSG-BizApps/bc-ai-reviewer@main
with:
GITHUB_TOKEN: ${{ github.token }}
MODELS_BLOCK: |
models:
- name: GPT-5 @Azure OpenAI w Responses API
provider: azure
model: gpt-5
apiBase: https://your-azure-resource.openai.azure.com/openai/v1 # use a secret here
apiKey: ${{ secrets.AZURE_OPENAI_KEY }}
roles: [chat, edit, apply]
requestOptions:
extraBodyProperties:
reasoning:
effort: high
# Review configuration
MAX_COMMENTS: 20
AUTO_DETECT_APPS: true
INCLUDE_APP_PERMISSIONS: true
INCLUDE_APP_MARKDOWN: true
INCLUDE_PATTERNS: "**/*.al,**/*.json"
EXCLUDE_PATTERNS: ""
CONTEXT_FILES: ""
ISSUE_COUNT: 0
FETCH_CLOSED_ISSUES: true
BASE_PROMPT_EXTRA: ""
DEBUG_PAYLOAD: true
PROJECT_CONTEXT: |
Repository contains Business Central AppSource Apps, related documentation based on docfx, and a slightly extended version of AL-Go for GitHub.Note: The review can be re-triggered by commenting /review on the pull request (issue_comment event).
These inputs are defined in action.yml (defaults in parentheses).
| Input | Type | Default | Description |
|---|---|---|---|
| GITHUB_TOKEN | string | required | GitHub token with repo scope. Defaults to github.token when not passed explicitly. |
| MODELS_BLOCK | string (YAML) | required | Multiline YAML that fully replaces the default models: section. |
| APPROVE_REVIEWS | boolean | false | When true, the bot uses the model’s suggestedAction to choose APPROVE, REQUEST_CHANGES, or COMMENT for the summary review. |
| MAX_COMMENTS | number | 10 | Maximum inline comments to post (0 = unlimited; GitHub caps at 1000 per PR). |
| PROJECT_CONTEXT | string | "" | Optional architecture / guidelines text injected into the prompt. |
| CONTEXT_FILES | string | "" | Comma-separated globs for extra context files (read from HEAD). |
| INCLUDE_PATTERNS | string | "**/*.al" | Comma-separated globs to include in review. |
| EXCLUDE_PATTERNS | string | "" | Comma-separated globs to exclude from review. |
| ISSUE_COUNT | number | 0 | Max linked issues to fetch (0 = all). |
| FETCH_CLOSED_ISSUES | boolean | true | Include closed issues as context. |
| AUTO_DETECT_APPS | boolean | true | Discover app.json for changed files. |
| INCLUDE_APP_PERMISSIONS | boolean | true | Include *.PermissionSet.al and *.Entitlement.al for each relevant app. |
| INCLUDE_APP_MARKDOWN | boolean | true | Include *.md for each relevant app. |
| BASE_PROMPT_EXTRA | string | "" | Free-form text appended to the base review prompt. |
| DEBUG_PAYLOAD | boolean | false | When true, prints the JSON payload to logs (use sparingly; can be large). |
| SNIPPET_CONTEXT_LINES | number | 12 | Lines of context around each changed line in numbered snippets. |
- Installs Node.js v20,
parse-diff, and the Continue CLI; optionally installsuvfor MCP integration. - Merges continue MODELS_BLOCK into the bundled default-config.yaml at runtime via
.github/actions/continue/merge-config.ps1, writes the merged file to$RUNNER_TEMP, and setsCONTINUE_CONFIG. - Executes
scripts/continue-review.ps1which:- Fetches the PR unified diff and parses it with
scripts/parse-diff.js. - Filters changed files by INCLUDE_PATTERNS/EXCLUDE_PATTERNS.
- Builds numbered snippets with SNIPPET_CONTEXT_LINES of surrounding context.
- Optionally auto-discovers app.json and includes permissions and markdown files.
- Assembles a structured prompt and invokes Continue CLI with
.continue/prompts/review-pr.md. - Posts a summary review and up to MAX_COMMENTS inline comments. If APPROVE_REVIEWS is true, uses the model’s
suggestedActionfor the summary event.
- Fetches the PR unified diff and parses it with
- If the reviewer prints errors about
CONTINUE_CONFIGbeing invalid, ensure the action sets it to the merged config path (the composite action does this automatically). - If the model returns non-JSON or malformed JSON, the scripts attempt sanitisation and retries; inspect the uploaded CLI logs (artifact
.continue-logs/) for raw provider output. - Never commit real API keys or secrets. Use GitHub Secrets. The merged config is written to
$RUNNER_TEMPand is not committed.
action.yml— composite action entry point (wires steps and inputs).scripts/continue-review.ps1— runner script that builds the prompt, calls the Continue CLI and posts GitHub reviews..github/actions/continue/default-config.yaml— bundled template used when merging models..github/actions/continue/merge-config.ps1— runtime merge helper (replacesmodels:and substitutes placeholders).scripts/parse-diff.js— diff parsing helper used by the runner.
- PRs & issues welcome. For major feature requests please open a discussion first.
- Licensed under Apache 2.0. See LICENSE for details.
- This action sends diffs and selected context to third-party LLM providers. Do not include secrets or sensitive PII in your PR diffs or context files.