Skip to content
Closed
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
18 changes: 18 additions & 0 deletions .github/workflows/dispatch-on-lgtm.yml
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not a fan of calling it "chatops" in file or action name. Please use a more specific name (e.g. dispatch-on-lgtm)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure Thanks

Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: ChatOps Dispatcher
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

due to my lack of knowledge, what does this action do? Is only used to dispatch other jobs when a comment is made?

Copy link
Author

@revit13 revit13 Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes It is a "traffic controller" action that robustly parses slash commands (like /lgtm) from comments, validates user permissions, and dispatches events to trigger specific workflows.

on:
issue_comment:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: shuoldn't this be done on PR comments? (assuming there is such a trigger)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, apparently in GitHub's internal architecture, every Pull Request is an Issue. It has issue-type: pull-request defined later in the yml...

types: [created]

jobs:
dispatch:
runs-on: ubuntu-latest
steps:
- name: Slash Command Dispatch
uses: peter-evans/slash-command-dispatch@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
commands: lgtm
# 1. Basic Security: Only allow users with 'write' access to even trigger this
permission: write
issue-type: pull-request
reactions: false
134 changes: 134 additions & 0 deletions .github/workflows/lgtm-command.yml
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo in file name, missing n

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks will fix it.

Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# ============================================================================
# LGTM Command Worker
# ============================================================================
# Handles /lgtm commands from chatops-dispatcher
#
# Flow:
# 1. User comments /lgtm on PR
# 2. chatops-dispatcher catches it and dispatches here
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how does the dispatcher know which job/action to invoke?
I did not see a reference to lgtm-command in that file.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is an "invisible handshake" done through Events, not file references. When /lgtm is typed, the slash-command-dispatch action fires a Repository Dispatch event. By default, it constructs the event type by adding -command to the slash command.

The Signal: When the dispatcher validates the /lgtm comment, it broadcasts a repository_dispatch event with the custom type lgtm-command.

The Listener: The lgtm-command.yml workflow is explicitly configured to listen for this signal via types: [lgtm-command].

# 3. This workflow:
# - Verifies user is listed under 'reviewers' in OWNERS file
# - Checks if PR is draft
# - Checks for blocking labels (hold)
# - Adds lgtm label
# - Enables auto-merge
# ============================================================================

name: LGTM Command Worker
on:
repository_dispatch:
types: [lgtm-command]

env:
BLOCKING_LABELS: "hold"

jobs:
apply-lgtm:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
issues: write
steps:
- uses: actions/checkout@v4
- uses: tibdex/github-app-token@v1
id: generate-token
with:
app_id: ${{ secrets.VLLMD_BOT_APP_ID }}
private_key: ${{ secrets.VLLMD_BOT_APP_PRIVATE_KEY }}
repository: ${{ github.repository }}

# -----------------------------------------------------------------------
# STEP 1: AUTHORIZATION - Verify user is in OWNERS file
# -----------------------------------------------------------------------
# Only users listed as reviewers in OWNERS can use /lgtm
# This prevents unauthorized users from applying the lgtm label
- name: Check Permissions
env:
ACTOR: ${{ github.event.client_payload.github.actor }}
run: |
# Extract only the reviewers section and check if ACTOR is listed
REVIEWERS=$(sed -n '/^reviewers:/,/^[^ -]/p' OWNERS | grep -v '^reviewers:')
if echo "$REVIEWERS" | grep -q "^\s*-\s*$ACTOR\s*$"; then
echo "User $ACTOR is authorized"
else
echo "::error:: User $ACTOR is not a reviewer."
exit 1
fi

# -----------------------------------------------------------------------
# STEP 2: VALIDATION - Check if PR is in draft mode
# -----------------------------------------------------------------------
# Draft PRs cannot be approved - they must be marked ready for review
# This prevents accidental approval of incomplete work
- name: Check Draft Status
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.client_payload.github.payload.issue.number }}
REPO: ${{ github.repository }}
run: |
IS_DRAFT=$(gh pr view $PR_NUMBER --repo "$REPO" --json isDraft --jq '.isDraft')
if [ "$IS_DRAFT" = "true" ]; then
echo "::error:: Cannot LGTM a Draft PR."
gh issue comment $PR_NUMBER --repo "$REPO" --body "⚠️ **LGTM Failed**: PR is a Draft."
exit 1
fi

# -----------------------------------------------------------------------
# STEP 3: BLOCKING LABELS - Check for hold
# -----------------------------------------------------------------------
# If any blocking label exists, fail immediately
# This prevents approving PRs that are explicitly marked as not ready
- name: Check for Blocking Labels
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_URL: ${{ github.event.client_payload.github.payload.issue.html_url }}
run: |
LABELS=$(gh pr view "$PR_URL" --json labels --jq '.labels[].name')
if echo "$LABELS" | grep -Eiq "^($BLOCKING_LABELS)$"; then
echo "::error:: PR is blocked by label."
gh issue comment "$PR_URL" --body " **Merge Blocked**: Please remove the \`hold\` label before merging."
exit 1
fi

# -----------------------------------------------------------------------
# STEP 4: APPLY LGTM - Add label, wait, then enable auto-merge
# -----------------------------------------------------------------------
# 1. Add lgtm label (triggers gatekeeper to validate)
# 2. Enable auto-merge (PR will merge when all checks pass)
- name: Apply or Cancel LGTM
env:
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
PR_NUMBER: ${{ github.event.client_payload.github.payload.issue.number }}
PR_URL: ${{ github.event.client_payload.github.payload.issue.html_url }}
# Extract the full comment body from the dispatcher payload
COMMENT_BODY: ${{ github.event.client_payload.github.payload.comment.body }}
run: |
# Check if the command is a cancellation
if echo "$COMMENT_BODY" | grep -q "/lgtm cancel"; then
echo "🚨 Retracting LGTM status..."

# 1. Remove lgtm label
gh issue edit "$PR_NUMBER" --remove-label "lgtm" || echo "Label already gone"

# 2. Disable Auto-Merge
gh pr merge --disable-auto "$PR_URL" || echo "Auto-merge was not enabled"

# 3. Notify user
gh issue comment "$PR_URL" --body "Retracted: **LGTM** label removed and auto-merge disabled by @$ACTOR."

else
echo "✅ Applying LGTM status..."

# 1. Add lgtm label
gh issue edit "$PR_NUMBER" --add-label "lgtm"

# 2. Enable auto-merge (Squash)
if ! gh pr merge --auto --squash "$PR_URL" 2>&1 | tee merge_output.txt; then
ERROR_MSG=$(cat merge_output.txt)
gh issue comment "$PR_URL" --body "⚠️ **Auto-merge failed**: $ERROR_MSG"
exit 1
fi

gh issue comment "$PR_URL" --body "✅ **LGTM**: auto-merge enabled."
fi
63 changes: 63 additions & 0 deletions .github/workflows/lgtm-gatekeeper.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# ============================================================================
# LGTM Gatekeeper - Required Status Check
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: there seems to be quite a bit of overlap between this file and the previous. Can you explain how they differ and what purpuse they serve.

Copy link
Author

@revit13 revit13 Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I generated a diagram hope it helps to clarify.
output

# ============================================================================
# Rules Enforced:
# 1. PR MUST have the "lgtm" label
# 2. PR MUST have a native GitHub Approved status (via /approve)
# 3. PR MUST NOT have blocking labels (hold)
# ============================================================================

name: LGTM Gatekeeper
on:
pull_request:
types: [opened, labeled, unlabeled, reopened, synchronize]
pull_request_review:
types: [submitted, dismissed]

env:
BLOCKING_LABELS: "hold"

jobs:
validate-pr:
runs-on: ubuntu-latest
steps:
- name: Enforce LGTM, Approvals & Blockers
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Dynamically grab the PR number depending on which event triggered the workflow
PR_NUMBER: ${{ github.event.pull_request.number || github.event.pull_request_review.pull_request.number }}
REPO: ${{ github.repository }}
run: |
# Fetch current labels and review status in a single API call
PR_DATA=$(gh pr view $PR_NUMBER --repo "$REPO" --json labels,reviewDecision)

# 1. Extract labels
LABELS=$(echo "$PR_DATA" | jq -r '.labels[].name')

# Check 1: IS IT BLOCKED?
if echo "$LABELS" | grep -Eiq "^($BLOCKING_LABELS)$"; then
echo "::error:: ⛔ FAILED: PR is blocked by a 'hold' label."
exit 1
fi

# Check 2: DOES IT HAVE LGTM?
HAS_LGTM=false
if echo "$LABELS" | grep -Fqx "lgtm"; then
HAS_LGTM=true
fi

# Check 3: IS IT NATIVELY APPROVED?
REVIEW_STATUS=$(echo "$PR_DATA" | jq -r '.reviewDecision')
HAS_APPROVE=false
if [ "$REVIEW_STATUS" = "APPROVED" ]; then
HAS_APPROVE=true
fi

if [ "$HAS_LGTM" = false ] || [ "$HAS_APPROVE" = false ]; then
echo "::error:: ⛔ FAILED: PR requires both the 'lgtm' label and a native GitHub Approval."
echo " - lgtm label present: $HAS_LGTM"
echo " - Native Approval (reviewDecision): $REVIEW_STATUS"
exit 1
fi

echo "✅ PASSED: PR has the lgtm label, is natively approved, and has no blockers."
46 changes: 46 additions & 0 deletions .github/workflows/lgtm-reset.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# ============================================================================
# LGTM Reset - Auto-Remove LGTM on New Commits
# ============================================================================
# Kubernetes Prow behavior: When new commits are pushed, approval is invalidated
#
# What It Does:
# 1. Detects when new commits are pushed to a PR
# 2. Removes the "lgtm" label (if present)
# 3. Disables auto-merge (safety net)
# 4. Posts a comment explaining why
# ============================================================================

name: LGTM Reset
on:
pull_request:
types: [synchronize] # Triggers instantly on new commits

jobs:
reset-lgtm:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- uses: tibdex/github-app-token@v1
id: generate-token
with:
app_id: ${{ secrets.VLLMD_BOT_APP_ID }}
private_key: ${{ secrets.VLLMD_BOT_APP_PRIVATE_KEY }}
repository: ${{ github.repository }}
- name: Invalidate LGTM
env:
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
PR_NUMBER: ${{ github.event.pull_request.number }}
REPO: ${{ github.repository }}
run: |
echo "🚨 New code pushed. Resetting LGTM status..."

# 1. Remove the label (This triggers the Gatekeeper to run again)
gh pr edit $PR_NUMBER --repo "$REPO" --remove-label "lgtm" || true

# 2. Disable Auto-Merge (Safety net)
gh pr merge --disable-auto $PR_NUMBER --repo "$REPO" || true

# 3. Notify user
gh issue comment $PR_NUMBER --repo "$REPO" --body "🔄 **Reset**: New commits pushed. LGTM removed."

3 changes: 1 addition & 2 deletions .github/workflows/prow-github.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
steps:
- uses: jpmcb/prow-github-actions@v2.0.0
with:
github-token: "${{ secrets.GITHUB_TOKEN }}"
github-token: "${{ secrets.BOT_TOKEN }}"
prow-commands: "/assign
/unassign
/approve
Expand All @@ -27,7 +27,6 @@ jobs:
/kind
/priority
/remove
/lgtm
/close
/reopen
/lock
Expand Down
18 changes: 0 additions & 18 deletions .github/workflows/prow-pr-automerge.yml

This file was deleted.

11 changes: 0 additions & 11 deletions .github/workflows/prow-pr-remove-lgtm.yml

This file was deleted.

71 changes: 71 additions & 0 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -356,3 +356,74 @@ helm uninstall kgateway-crds -n kgateway-system
```

For more details, see the Gateway API inference Extension [getting started guide](https://gateway-api-inference-extension.sigs.k8s.io/guides/)

## PR Approval Process

The project uses a Prow-inspired ChatOps system to manage PR review process via comment commands.

### Available Commands

| Command | Policy | Description |
|---------|--------|-------------|
| `/approve` | [OWNERS](./OWNERS) | Approve all the files for the current PR |
| `/approve cancel` | [OWNERS](./OWNERS) | Removes your approval on this pull-request |
| `/lgtm` | [OWNERS](./OWNERS) | Adds the `lgtm` label and enables auto-merge (squash). The PR merges automatically once requirements below are met |
| `/lgtm cancel` | [OWNERS](./OWNERS) | Removes the `lgtm` label and disables auto-merge |
| `/assign [@userA @userB @etc]` | Anyone | Assign other users (or yourself if no one is specified). Target user must be Org Member, Collaborator, or have previously commented |
| `/unassign [@userA @userB @etc]` | Anyone | Unassigns specified people (or yourself if no one is specified). Target must have been already assigned |
| `/cc [@userA @userB @etc]` | Anyone | Request review from specified people (or yourself if no one is specified). Target be an Org Member, Collaborator, or have previously commented |
| `/uncc [@userA @userB @etc]` | Anyone | Dismiss review request for specified people (or yourself if no one is specified). Target must already have had a review requested |
| `/close` | Collaborators | Closes the issue / PR |
| `/reopen` | Collaborators | Reopens a closed issue / PR |
| `/lock [resolved / off-topic / too-heated / spam]` | Collaborators | Locks the issue / PR with the specified reason |
| `/milestone milestone-name` | Collaborators | Adds issue / PR to an existing milestone |
| `/retitle some new title` | Collaborators | Renames the issue / PR |
| `/hold` | Anyone | Adds the `hold` label to prevent the PR from merging |
| `/hold cancel` | Anyone | Removes the `hold` label |
| `/area [label1 label2 ...]` | Anyone | Adds an area/<> label(s) if it's defined in the `.prowlabels.yaml` file |
| `/kind [label1 label2 ...]` | Anyone | Adds a kind/<> label(s) if it's defined in the `.prowlabels.yaml` file |
| `/priority [label1 label2 ...]` | Anyone | Adds a priority/<> label(s) if it's defined in the `.prowlabels.yaml` file |
| `/remove [label1 label2 ...]` | Collaborators | Removes a specified label(s) on an issue / PR |

### Merge Requirements

For a PR to be merged, it must have:
- ✅ **The `lgtm` label AND a native GitHub Approval** - Triggered by authorized users via the `/lgtm` and `/approve` commands in the comments.
- ✅ **No blocking labels** - The `hold` label must not be present.
- ✅ **Signed and verified commits** - All commits must include a DCO sign-off.
- ✅ **All required status checks passing** - CI/CD pipelines and gatekeeper checks must succeed.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please Signed verified commits

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated Developer.md: Added documentation noting that signed commits can be enforced as a pre-merge check via branch rulesets

The gatekeeper workflow enforces these requirements as a required status check.

*Note: The label and approval requirements are enforced by the custom LGTM Gatekeeper workflow, while commit signatures are enforced natively by the repository's branch rulesets.*

### Approval Reset on New Commits

When new commits are pushed to an approved PR, the `lgtm` label is automatically removed and auto-merge is disabled. This ensures approvals always reflect the latest code. The author must request a new `/lgtm` after pushing changes.

**Note:** The `approve` label is NOT automatically removed on new commits. If significant changes are made, reviewers should use `/approve cancel` to remove their approval.

## OWNERS

A simplified version of [Prow's OWNERS](https://go.k8s.io/owners) file is supported. When an OWNERS file is present at the root of the repository, it is used to authorize the /lgtm and /approve commands.

The `reviewers` role grants access to the /lgtm command and the approvers role grants access to the /approve command.

The `approvers` role does not grant the reviewers role, a user must be in both roles to use /lgtm and /approve.

The OWNERS file must be in YAML format. All entries are expected to be GitHub usernames; teams are not supported.

```yaml
# List of usernames who may use /lgtm
reviewers:
- user1
- user2
- user3

# List of usernames who may use /approve
approvers:
- user1
- user2
- admin1
```