diff --git a/.github/workflows/proposal-numbering.yml b/.github/workflows/proposal-numbering.yml new file mode 100644 index 0000000..5de7e9c --- /dev/null +++ b/.github/workflows/proposal-numbering.yml @@ -0,0 +1,209 @@ +# +# Copyright Kroxylicious Authors. +# +# Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0 +# + +# Automatically checks that proposal files follow the PR-number naming convention (e.g., proposals/092-my-proposal.md for PR #92). +# When a proposal file doesn't match its PR number, this workflow updates the PR description with instructions to rename it. +# Once the author fixes the naming, the warning is automatically removed from the PR description. + +name: Check Proposal Numbering + +on: + pull_request: + types: [opened, synchronize, reopened] + +permissions: + pull-requests: write + contents: read + +jobs: + check-numbering: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + fetch-depth: 0 + + - name: Check proposal file numbering + id: check + env: + PR_NUMBER: ${{ github.event.pull_request.number }} + run: | + # Find all .md files directly in proposals directory (not subdirectories) + # Include both Added (A) and Renamed (R) files + ALL_PROPOSAL_FILES=$(git diff --name-only --diff-filter=AR origin/${{ github.base_ref }}...HEAD | grep '^proposals/[^/]*\.md$' || true) + + # Filter out non-proposal files (README.md and template) + PROPOSAL_FILES="" + for file in $ALL_PROPOSAL_FILES; do + # Skip README.md and the template + if [[ "$file" == "proposals/README.md" ]] || [[ "$file" == "proposals/000-template.md" ]]; then + continue + fi + PROPOSAL_FILES="$PROPOSAL_FILES $file" + done + + if [ -z "$PROPOSAL_FILES" ]; then + echo "No proposal files found in this PR" + echo "has_proposal=false" >> $GITHUB_OUTPUT + exit 0 + fi + + echo "has_proposal=true" >> $GITHUB_OUTPUT + + # Expected filename pattern: proposals/0{PR_NUMBER}-*.md + EXPECTED_PREFIX=$(printf "proposals/%03d-" $PR_NUMBER) + + INCORRECT_FILES="" + INCORRECT_TITLES="" + for file in $PROPOSAL_FILES; do + # Check filename + if [[ ! "$file" =~ ^${EXPECTED_PREFIX} ]]; then + if [ -z "$INCORRECT_FILES" ]; then + INCORRECT_FILES="$file" + else + INCORRECT_FILES="$INCORRECT_FILES,$file" + fi + fi + + # Check title format (should be: # - ) + EXPECTED_TITLE_PREFIX="# $PR_NUMBER -" + if ! grep -q "^${EXPECTED_TITLE_PREFIX}" "$file"; then + if [ -z "$INCORRECT_TITLES" ]; then + INCORRECT_TITLES="$file" + else + INCORRECT_TITLES="$INCORRECT_TITLES,$file" + fi + fi + done + + if [ -n "$INCORRECT_FILES" ] || [ -n "$INCORRECT_TITLES" ]; then + echo "incorrect=true" >> $GITHUB_OUTPUT + echo "files=$INCORRECT_FILES" >> $GITHUB_OUTPUT + echo "titles=$INCORRECT_TITLES" >> $GITHUB_OUTPUT + echo "expected_prefix=$EXPECTED_PREFIX" >> $GITHUB_OUTPUT + else + echo "incorrect=false" >> $GITHUB_OUTPUT + fi + + - name: Update PR description if numbering is incorrect + if: steps.check.outputs.incorrect == 'true' + uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7 + with: + script: | + const prNumber = context.payload.pull_request.number; + const expectedPrefix = '${{ steps.check.outputs.expected_prefix }}'; + const incorrectFilesRaw = '${{ steps.check.outputs.files }}'; + const incorrectTitlesRaw = '${{ steps.check.outputs.titles }}'; + + const warnings = []; + + // Check filename issues + if (incorrectFilesRaw) { + const filesList = incorrectFilesRaw.split(',').map(f => `- <code>${f}</code>`).join('\n'); + warnings.push( + '**Incorrect filename:**', + '', + filesList, + '', + `**Expected naming:** <code>${expectedPrefix}<descriptive-name>.md</code>`, + '', + `Rename your proposal file to use PR #${prNumber}:`, + '', + '```bash', + `git mv proposals/000-<name>.md ${expectedPrefix}<name>.md`, + '```' + ); + } + + // Check title issues + if (incorrectTitlesRaw) { + const titlesList = incorrectTitlesRaw.split(',').map(f => `- <code>${f}</code>`).join('\n'); + if (warnings.length > 0) warnings.push('', '---', ''); + warnings.push( + '**Incorrect title format:**', + '', + titlesList, + '', + `**Expected title format:** <code># ${prNumber} - <Your Title></code>`, + '', + `Update the H1 heading in your proposal to include the PR number:`, + '', + '```markdown', + `# ${prNumber} - My Feature Title`, + '```' + ); + } + + const warningSection = [ + '---', + '', + '## ⚠️ Proposal Numbering', + '', + 'This PR contains proposal files that don\'t follow the expected format:', + '', + ...warnings, + '', + 'See [proposals/README.md](https://github.com/kroxylicious/design/blob/main/proposals/README.md) for the complete workflow.', + '', + '<!-- proposal-numbering-check -->' + ].join('\n'); + + // Get current PR + const { data: pr } = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: prNumber, + }); + + let currentBody = pr.body || ''; + + // Remove existing warning section if present + const markerRegex = /---\s*\n\s*##\s*⚠️\s*Proposal (File )?Numbering[\s\S]*?<!-- proposal-numbering-check -->/; + currentBody = currentBody.replace(markerRegex, '').trim(); + + // Append new warning section + const newBody = currentBody + '\n' + warningSection; + + await github.rest.pulls.update({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: prNumber, + body: newBody + }); + + - name: Remove warning from PR description if numbering is correct + if: steps.check.outputs.has_proposal == 'true' && steps.check.outputs.incorrect == 'false' + uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7 + with: + script: | + const prNumber = context.payload.pull_request.number; + + // Get current PR + const { data: pr } = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: prNumber, + }); + + let currentBody = pr.body || ''; + + // Check if warning section exists + const markerRegex = /---\s*\n\s*##\s*⚠️\s*Proposal (File )?Numbering[\s\S]*?<!-- proposal-numbering-check -->/; + + if (markerRegex.test(currentBody)) { + // Remove warning section + const newBody = currentBody.replace(markerRegex, '').trim(); + + await github.rest.pulls.update({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: prNumber, + body: newBody + }); + + console.log('Removed numbering warning from PR description - file is now correctly named'); + } diff --git a/notify-open-prs.sh b/notify-open-prs.sh new file mode 100755 index 0000000..d6a1af5 --- /dev/null +++ b/notify-open-prs.sh @@ -0,0 +1,45 @@ +#!/bin/bash +# +# Copyright Kroxylicious Authors. +# +# Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0 +# + +# Script to notify authors of open proposal PRs to rebase on main +# Once they rebase, the workflow will automatically check their proposal numbering + +set -e + +OPEN_PRS=(70 82 83 85 88 93 94 96 98 99 100 101 103) + +COMMENT_BODY="Hi! We've updated the proposal numbering system to use PR numbers as proposal identifiers. + +**Action required:** Please rebase your PR on \`main\`. + +Once you push, the GitHub workflow will automatically check your proposal file naming and update this PR description with specific instructions if your file needs to be renamed. + +See [proposals/README.md](https://github.com/kroxylicious/design/blob/main/proposals/README.md) for the updated workflow." + +echo "This script will comment on ${#OPEN_PRS[@]} open proposal PRs" +echo "" +read -p "Continue? (y/N) " -n 1 -r +echo +if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo "Aborted" + exit 1 +fi + +for pr in "${OPEN_PRS[@]}"; do + echo "Commenting on PR #$pr..." + gh pr comment "$pr" --body "$COMMENT_BODY" + echo "✓ PR #$pr notified" + sleep 2 # Be nice to the API +done + +echo "" +echo "✓ All open proposal PRs have been notified" +echo "" +echo "Once authors rebase, the workflow will automatically:" +echo " 1. Detect if their proposal file naming is incorrect" +echo " 2. Update their PR description with the exact command to fix it" +echo " 3. Remove the warning once they fix the naming" diff --git a/proposals/000-template.md b/proposals/000-template.md index 538db1e..7b4e99e 100644 --- a/proposals/000-template.md +++ b/proposals/000-template.md @@ -1,6 +1,19 @@ -<!-- This template is provided as an example with sections you may wish to comment on with respect to your proposal. Add or remove sections as required to best articulate the proposal. --> - -# <Title> +<!-- +PROPOSAL WORKFLOW: +1. Copy this template to: proposals/000-<descriptive-name>.md +2. Fill in your proposal content +3. Open a PR on GitHub +4. Rename the file to use your PR number: proposals/<PR#>-<descriptive-name>.md + Example: git mv proposals/000-my-feature.md proposals/105-my-feature.md +5. Update the heading below to include your PR number: # <PR#> - <Title> +6. Push the rename and updated title to your PR + +See proposals/README.md for complete instructions. + +This template is provided as an example with sections you may wish to comment on with respect to your proposal. Add or remove sections as required to best articulate the proposal. +--> + +# <PR-NUMBER> - <Title> Provide a brief summary of the feature you are proposing to add to Kroxylicious. diff --git a/proposals/README.md b/proposals/README.md new file mode 100644 index 0000000..1b596f4 --- /dev/null +++ b/proposals/README.md @@ -0,0 +1,39 @@ +# Kroxylicious Proposals + +This directory contains proposals for the Kroxylicious project. + +## Creating a New Proposal + +1. **Create your proposal file** using a placeholder name based on the [template](./000-template.md): + ``` + cp proposals/000-template.md proposals/000-<descriptive-name>.md + ``` + +2. **Commit and open a Pull Request**: + - Push your branch and open a PR on GitHub + - Note your PR number (e.g., #105) + +3. **Rename the file and update the title** to use your PR number (three-digit zero-padded): + ```bash + git mv proposals/000-<descriptive-name>.md proposals/105-<descriptive-name>.md + # Edit the file to update the title to: # 105 - <Your Title> + git commit -m "Rename proposal to use PR number" + git push + ``` + +4. **Announce** your proposal on the [mailing list](https://kroxylicious.io/join-us/mailing-lists/) + +5. **Discussion and approval**: The proposal will be discussed by the community + +6. **Merge**: Once approved, your proposal PR is merged to main. The proposal number remains the same as the PR number. + +## Finding Proposals + +- **Merged proposals:** Browse the directory listing above +- **Open proposals:** [View open proposal PRs](https://github.com/kroxylicious/design/pulls?q=is%3Apr+is%3Aopen) + +## Numbering + +Proposal numbers match PR numbers, using three-digit zero-padding (e.g., `092-`, `105-`). + +Proposals 001-019 predate this system and retain their original numbers.