diff --git a/.github/workflows/update-maintainers.yml b/.github/workflows/update-maintainers.yml new file mode 100644 index 00000000..b679f158 --- /dev/null +++ b/.github/workflows/update-maintainers.yml @@ -0,0 +1,254 @@ +name: Update maintainers list + +on: + push: + branches: + - main + paths: + - lib/maintainers.nix + schedule: + # Update every Monday at 9 AM UTC + - cron: "0 9 * * 1" + workflow_dispatch: + inputs: + create_pr: + description: "Create PR even if no changes" + required: false + default: false + type: boolean + +jobs: + update-maintainers: + runs-on: ubuntu-latest + if: github.repository_owner == 'nix-community' || github.event_name == 'workflow_dispatch' + # Permissions required for workflow + # `contents`: to update maintainers file + # `pull-requests`: to create pr + # `issues`: to label pr + permissions: + contents: write + pull-requests: write + issues: write + env: + pr_branch: update/maintainers-${{ github.ref_name }} + steps: + - name: Create GitHub App token + uses: actions/create-github-app-token@v2 + if: vars.CI_APP_ID + id: app-token + with: + app-id: ${{ vars.CI_APP_ID }} + private-key: ${{ secrets.CI_APP_PRIVATE_KEY }} + permission-contents: write + permission-pull-requests: write + permission-issues: write + + - name: Get GitHub App user info + id: user-info + if: vars.CI_APP_ID + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + slug: ${{ steps.app-token.outputs.app-slug }} + run: | + name="$slug[bot]" + id=$(gh api "/users/$name" --jq .id) + { + echo "id=$id" + echo "name=$name" + echo "email=$id+$name@users.noreply.github.com" + } >> "$GITHUB_OUTPUT" + + - name: Checkout repository + uses: actions/checkout@v4 + with: + token: ${{ steps.app-token.outputs.token || github.token }} + + - name: Install Nix + uses: cachix/install-nix-action@v31 + with: + github_access_token: ${{ steps.app-token.outputs.token || github.token }} + extra_nix_config: | + allow-import-from-derivation = false + + - name: Setup Git + env: + name: ${{ steps.user-info.outputs.name || 'github-actions[bot]' }} + email: ${{ steps.user-info.outputs.email || '41898282+github-actions[bot]@users.noreply.github.com' }} + run: | + git config user.name "$name" + git config user.email "$email" + + - name: Generate updated maintainers list + run: | + echo "::group::📋 Generating updated generated/all-maintainers.nix..." + nix run .#generate-all-maintainers -- --root . --output generated/all-maintainers.nix + echo "::endgroup::" + echo "::group::🎨 Formatting with nixfmt..." + nix fmt generated/all-maintainers.nix + echo "::endgroup::" + + - name: Check for changes + id: check-changes + run: | + if git diff --quiet generated/all-maintainers.nix; then + echo "No changes to generated/all-maintainers.nix" + echo "has_changes=false" >> "$GITHUB_OUTPUT" + else + echo "Changes detected in generated/all-maintainers.nix" + echo "has_changes=true" >> "$GITHUB_OUTPUT" + added=$(git diff --numstat generated/all-maintainers.nix | cut -f1) + removed=$(git diff --numstat generated/all-maintainers.nix | cut -f2) + echo "changes_summary=+$added -$removed lines" >> "$GITHUB_OUTPUT" + fi + + - name: Validate generated file + if: steps.check-changes.outputs.has_changes == 'true' + run: | + echo "🔍 Validating generated generated/all-maintainers.nix..." + if nix-instantiate --eval generated/all-maintainers.nix --strict > /dev/null; then + echo "✅ Generated file has valid Nix syntax" + else + echo "❌ Generated file has invalid Nix syntax" + exit 1 + fi + + - name: Create update branch + run: | + git branch -D "$pr_branch" || echo "Nothing to delete" + git switch -c "$pr_branch" + + - name: Get info on the current PR + id: open_pr_info + env: + GH_TOKEN: ${{ steps.app-token.outputs.token || github.token }} + run: | + # Query for info about the already open update PR + info=$( + gh api graphql -F owner='{owner}' -F repo='{repo}' -F branch="$pr_branch" -f query=' + query($owner:String!, $repo:String!, $branch:String!) { + repository(owner: $owner, name: $repo) { + pullRequests(first: 1, states: OPEN, headRefName: $branch) { + nodes { + number + url + } + } + } + } + ' | jq --raw-output ' + .data.repository.pullRequests.nodes[] + | to_entries[] + | "\(.key)=\(.value)" + ' + ) + if [[ -n "$info" ]]; then + echo "PR info:" + echo "$info" + echo "$info" >> $GITHUB_OUTPUT + else + echo "No PR is currently open" + fi + + - name: Fetch current PR's branch + if: steps.open_pr_info.outputs.number + run: | + git fetch origin "$pr_branch" + git branch --set-upstream-to "origin/$pr_branch" + + - name: Create Pull Request + id: create-pr + if: steps.check-changes.outputs.has_changes == 'true' || github.event.inputs.create_pr == 'true' + env: + GH_TOKEN: ${{ steps.app-token.outputs.token || github.token }} + title: "maintainers: update generated/all-maintainers.nix" + commit_body: | + Automated update of the master maintainers list combining: + - Nixvim specific maintainers from lib/maintainers.nix + - Nixpkgs maintainers referenced in Nixvim modules + + Changes: ${{ steps.check-changes.outputs.changes_summary || 'No content changes' }} + + Generated by: flake/dev/generate-all-maintainers/generate-all-maintainers.py + pr_url: ${{ steps.open_pr_info.outputs.url }} + pr_num: ${{ steps.open_pr_info.outputs.number }} + pr_body: | + ## 📋 Summary + + This PR updates the master maintainers list (`generated/all-maintainers.nix`) which combines: + - **Nixvim specific maintainers** from `lib/maintainers.nix` + - **Nixpkgs maintainers** referenced in Nixvim modules + + ## 🔄 Changes + + **Statistics:** ${{ steps.check-changes.outputs.changes_summary || 'No content changes (format/comment updates only)' }} + + The updated list includes all maintainers needed for review assignments across the Nixvim project. + + ## 🤖 Automation + + - **Generated by:** `flake/dev/generate-all-maintainers/generate-all-maintainers.py` + - **Trigger:** ${{ github.event_name == 'schedule' && 'Scheduled weekly update' || 'Manual workflow dispatch' }} + - **Validation:** File syntax verified with `nix-instantiate --eval` + + ## 📚 Usage + + This file can be imported and used for maintainer lookups: + ```nix + let allMaintainers = import ./generated/all-maintainers.nix; in + # Access any maintainer by name: allMaintainers.username + ``` + + --- + 🤖 *This PR was automatically created by the [update-maintainers workflow](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})* + run: | + git add generated/all-maintainers.nix + git commit -m "$title" -m "$commit_body" + + echo "Pushing to remote branch $pr_branch" + git push --force --set-upstream origin "$pr_branch" + + if [ -z "$pr_num" ]; then + echo "Creating new pull request." + PR_URL=$( + gh pr create \ + --title "$title" \ + --body "$pr_body" + ) + else + PR_URL=$pr_url + echo "Pull request already exists: $PR_URL" + gh pr edit "$pr_num" --body "$pr_body" + fi + + echo "pr_url=$PR_URL" >> "$GITHUB_OUTPUT" + + - name: Summary + env: + has_changes: ${{ steps.check-changes.outputs.has_changes }} + changes: ${{ steps.check-changes.outputs.changes_summary }} + pr_url: ${{ steps.create-pr.outputs.pr_url}} + pr_num: ${{ steps.open_pr_info.outputs.number }} + run: | + if [[ "$has_changes" == "true" ]]; then + if [[ -n "$pr_num" ]]; then + echo "✅ Successfully updated PR with new changes." + echo "$changes" + echo "🔗 PR URL: $pr_url" + echo "### ✅ PR Updated" >> $GITHUB_STEP_SUMMARY + echo "[$pr_url]($pr_url)" >> $GITHUB_STEP_SUMMARY + elif [[ -n "$pr_url" ]]; then + echo "✅ Successfully created PR with maintainer updates." + echo "$changes" + echo "🔗 PR URL: $pr_url" + echo "### ✅ PR Created" >> $GITHUB_STEP_SUMMARY + echo "[$pr_url]($pr_url)" >> $GITHUB_STEP_SUMMARY + else + echo "❌ Failed to create or update pull request." + echo "### ❌ PR Operation Failed" >> $GITHUB_STEP_SUMMARY + echo "A pull request was intended but the URL was not captured. Please check the logs." >> $GITHUB_STEP_SUMMARY + fi + else + echo "â„šī¸ No changes detected - maintainers list is up to date." + echo "### â„šī¸ No Changes" >> $GITHUB_STEP_SUMMARY + echo "The maintainers list is up-to-date. No PR was created." >> $GITHUB_STEP_SUMMARY + fi