Skip to content
Draft
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
10 changes: 10 additions & 0 deletions .github/labeler-area.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@ A-format:
- "protos/**"
- "docs/src/format/**"

# Drives the format-spec vote gate (.github/workflows/format-vote-gate.yml):
# any change to the proto definitions or the spec docs requires a PMC vote.
# Scoped to *.proto (not e.g. protos/AGENTS.md) since only the IDL and spec are
# the format. A PMC member waives a trivial edit with the `format-waived` label.
format-change:
- changed-files:
- any-glob-to-any-file:
- "protos/**/*.proto"
- "docs/src/format/**"

# Lockfiles are intentionally not excluded: a pure dependency bump gets both
# A-python and A-deps. Over-labeling beats dropping the area signal on PRs that
# touch python code alongside a lockfile.
Expand Down
38 changes: 38 additions & 0 deletions .github/workflows/ci-scripts.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: CI scripts

# Tests for helper scripts under ci/ that aren't covered by the language test
# suites (e.g. the format-spec vote gate logic).

on:
push:
branches:
- main
- release/**
pull_request:
branches:
- main
- release/**
paths:
- ci/format_vote_gate.py
- ci/test_format_vote_gate.py
- .github/workflows/format-vote-gate.yml
- .github/workflows/ci-scripts.yml

permissions:
contents: read

jobs:
format-vote-gate:
name: Format vote gate unit tests
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.12"
- name: Install pytest
run: pip install pytest
- name: Run tests
run: pytest ci/test_format_vote_gate.py
61 changes: 61 additions & 0 deletions .github/workflows/format-vote-gate.yml

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

issue(blocking): do we not filter just for PRs that have no format-change label? I think we should leave those PRs alone.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agreed. The gate now keys off the format-change label only. Labeling moved to the existing path labeler (.github/labeler-area.yml), and the gate leaves unlabeled PRs alone — for non-format PRs it posts just a passing format-spec-vote status and nothing else (needed so the required check never blocks them). Trivial edits are now waived by a PMC applying a format-waived label, rather than removing format-change (the path labeler would otherwise re-add it on the next push).

Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: Format spec vote gate

# Structurally enforces the PMC vote required for Lance format-specification
# changes (see https://lance.org/community/voting/). The path labeler
# (.github/labeler-area.yml) applies the `format-change` label to PRs that touch
# the format spec (`protos/**/*.proto`, `docs/src/format/**`); this gate reads
# that label and blocks merging until the PR has 3 binding +1 votes from PMC
# members (PR approvals, excluding the author), has no outstanding veto (a PMC
# "Request changes" review), and the 1-week voting period has elapsed.
#
# The gate publishes its verdict as the `format-spec-vote` commit status on the
# PR head. To make it a merge blocker, an org admin must add `format-spec-vote`
# as a required status check in the branch protection rules for `main` (and any
# release branches). The status is posted on *every* PR — success immediately
# for non-format PRs — so a required check is never left pending forever.
#
# A PMC member may waive a trivial edit (typo, wording, formatting) by applying
# the `format-waived` label.
#
# Uses pull_request_target so the token can post statuses/comments on fork-based
# PRs. It never checks out or executes PR code: it reads the trusted base
# checkout (for the PMC roster and this script) and queries the API only.

on:
pull_request_target:
types: [opened, reopened, synchronize, labeled, unlabeled]
pull_request_review:
types: [submitted, edited, dismissed]
schedule:
# Re-evaluate open format-change PRs so the voting-period clock is re-checked
# even when no PR event fires (e.g. the 1-week period elapses days after the
# third approval lands).
- cron: "0 */8 * * *"
Comment on lines +29 to +33

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

issue(blocking): how does this trigger find which PRs to look at? IIRC this trigger isn't PR specific, but runs on a schedule globally for the whole repo, am I wrong?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

You're right — the schedule trigger runs repo-wide, with no PR in context. The script handles that by listing all open PRs carrying the format-change label and re-evaluating each (so the voting-period clock advances even if no PR event fires). The PR/review event paths use the PR from the event payload. See the event_name == 'schedule' branch in main().


concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true

permissions:
contents: read
pull-requests: write
issues: write
statuses: write

jobs:
gate:
name: Evaluate format spec vote
runs-on: ubuntu-latest
steps:
- name: Checkout base
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.12"
- name: Install dependencies
run: pip install PyGithub PyYAML
- name: Evaluate vote
run: python ci/format_vote_gate.py
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
63 changes: 0 additions & 63 deletions .github/workflows/pr-title.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,69 +22,6 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
fail_on_error: true
format-vote-reminder:
permissions:
pull-requests: write
name: Remind about format spec vote
runs-on: ubuntu-latest
# Comments on PRs that touch the Lance format specification (*.proto files
# and docs/src/format/**) to remind the author that substantive format
# changes require a PMC vote. Re-checks the full PR diff on every push, so a
# format change introduced by a later commit is still caught; a hidden
# marker keeps it to at most one comment.
steps:
- uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
with:
script: |
const { owner, repo } = context.repo;
const prNumber = context.payload.pull_request.number;
const MARKER = '<!-- format-change-vote-reminder -->';

// The Lance format specification is the proto definitions plus the
// spec docs. Changes to either require a PMC vote.
const isFormatFile = (path) =>
path.endsWith('.proto') || path.startsWith('docs/src/format/');

const files = await github.paginate(github.rest.pulls.listFiles, {
owner, repo, pull_number: prNumber, per_page: 100,
});
const formatFiles = files.map((f) => f.filename).filter(isFormatFile);
if (formatFiles.length === 0) {
core.info('No format specification files changed; nothing to do.');
return;
}

// Best effort to comment only once: skip if our marker is present.
const comments = await github.paginate(github.rest.issues.listComments, {
owner, repo, issue_number: prNumber, per_page: 100,
});
if (comments.some((c) => c.body && c.body.includes(MARKER))) {
core.info('Reminder already posted; skipping.');
return;
}

const body = [
MARKER,
'> [!IMPORTANT]',
'> **This PR touches the Lance format specification.**',
'>',
'> Substantive changes to the format specification — the `.proto` definitions',
'> and the spec docs under `docs/src/format/` — require a PMC vote before merge.',
'> Minor edits such as typo fixes, wording, or formatting are excluded; use your',
'> judgment.',
'>',
'> If this is a meaningful format change:',
'> - Start a vote following the [Lance community voting process](https://lance.org/community/voting/).',
'> Format specification modifications need **3 binding +1 votes** (excluding the',
'> proposer), held on GitHub Discussions, with a minimum voting period of **1 week**.',
'> - Once the vote passes, **link the completed vote in this PR**. It should not be',
'> merged until the vote is linked.',
].join('\n');

await github.rest.issues.createComment({
owner, repo, issue_number: prNumber, body,
});
core.info(`Posted format vote reminder (changed: ${formatFiles.join(', ')}).`);
commitlint:
permissions:
pull-requests: write
Expand Down
Loading
Loading