README Maintainer #353
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: README Maintainer | |
| on: | |
| pull_request_target: | |
| types: [closed] | |
| push: | |
| branches: [main] | |
| schedule: | |
| - cron: '0 0 * * *' # Run daily | |
| workflow_dispatch: # Manual trigger | |
| jobs: | |
| update: | |
| runs-on: ubuntu-latest | |
| if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' || (github.event_name == 'pull_request_target' && github.event.pull_request.merged == true) | |
| permissions: | |
| contents: write | |
| pull-requests: read | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| ref: main | |
| - name: Set up Python | |
| uses: actions/setup-python@v4 | |
| with: | |
| python-version: '3.x' | |
| - name: Install dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install PyGithub | |
| - name: Update README | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| python - <<EOF | |
| import re | |
| import os | |
| import glob | |
| from github import Github | |
| # Hardcoded contributors to always keep | |
| PRESERVED_CONTRIBUTORS = { | |
| 'riteshdavv': ('Ritesh Kumar Singh', 'https://github.com/riteshdavv'), | |
| 'officialasishkumar': ('Asish Kumar', 'https://github.com/officialasishkumar'), | |
| 'JayKapadia389': ('Jay Kapadia', 'https://github.com/JayKapadia389') | |
| } | |
| def get_org_list_from_directories(): | |
| """Get organization list from directories in the repository""" | |
| org_dirs = [] | |
| for dir_path in glob.glob("*"): | |
| if os.path.isdir(dir_path) and not dir_path.startswith('.'): | |
| # Replace underscore with space and capitalize each word for display | |
| org_name = dir_path | |
| org_dirs.append(org_name) | |
| return sorted(org_dirs) | |
| def update_org_list(content): | |
| """Update the organization list based on directories in the repo""" | |
| org_dirs = get_org_list_from_directories() | |
| # Extract the org list section | |
| org_section = re.search(r'(## Org Submission Checklist\s*\n+)((?:- \[.\][^\n]*\n+)*)', content, re.MULTILINE) | |
| if not org_section: | |
| return content | |
| # Create updated checklist with all organizations checked | |
| org_lines = [] | |
| for org in org_dirs: | |
| org_lines.append(f"- [x] {org}") | |
| # Replace section with updated list | |
| new_section = org_section.group(1) + '\n'.join(org_lines) + '\n\n' | |
| return content[:org_section.start()] + new_section + content[org_section.end():] | |
| def count_proposals(): | |
| """Count total number of PDF proposals in the repository""" | |
| return len(glob.glob("**/*.pdf", recursive=True)) | |
| def update_proposal_count(content): | |
| """Update the proposal count in the README""" | |
| count = count_proposals() | |
| count_match = re.search(r'(Total proposals submitted: \*\*)\d+(\*\*)', content) | |
| if count_match: | |
| return content[:count_match.start(1)] + f"Total proposals submitted: **{count}**" + content[count_match.end(2):] | |
| return content | |
| def get_contributors(): | |
| g = Github(os.getenv('GITHUB_TOKEN')) | |
| repo = g.get_repo(os.getenv('GITHUB_REPOSITORY')) | |
| # Start with preserved contributors | |
| contributors = {username: (name, url) for username, (name, url) in PRESERVED_CONTRIBUTORS.items()} | |
| # Get all contributors from GitHub | |
| try: | |
| # Get all contributors, including those who haven't committed recently | |
| for contributor in repo.get_contributors(anon=False): | |
| username = contributor.login.lower() | |
| if not any(bot in username for bot in ['[bot]', 'actions-user', 'dependabot']): | |
| contributors[username] = ( | |
| contributor.name or contributor.login, | |
| f'https://github.com/{contributor.login}' | |
| ) | |
| except Exception as e: | |
| print(f"Error getting contributors: {e}") | |
| # Add PR author if this is a merged PR | |
| if os.getenv('GITHUB_EVENT_NAME') == 'pull_request_target': | |
| try: | |
| with open(os.environ.get('GITHUB_EVENT_PATH')) as f: | |
| import json | |
| event = json.load(f) | |
| if event.get('pull_request', {}).get('user'): | |
| pr_user = event['pull_request']['user'] | |
| username = pr_user['login'].lower() | |
| if not any(bot in username for bot in ['[bot]', 'actions-user', 'dependabot']): | |
| contributors[username] = ( | |
| pr_user.get('name') or pr_user['login'], | |
| f"https://github.com/{pr_user['login']}" | |
| ) | |
| except Exception as e: | |
| print(f"Error processing PR author from event file: {e}") | |
| try: | |
| # Extract PR number from the ref | |
| ref_parts = os.environ.get('GITHUB_REF', '').split('/') | |
| if len(ref_parts) >= 3 and ref_parts[1] == 'pull': | |
| pr_number = int(ref_parts[2]) | |
| if pr_number: | |
| pr = repo.get_pull(pr_number) | |
| if pr.merged and not any(bot in pr.user.login.lower() for bot in ['[bot]', 'actions-user', 'dependabot']): | |
| username = pr.user.login.lower() | |
| contributors[username] = ( | |
| pr.user.name or pr.user.login, | |
| f'https://github.com/{pr.user.login}' | |
| ) | |
| except Exception as e: | |
| print(f"Error processing PR author from ref: {e}") | |
| # Also check for any recent commits that might have been missed | |
| try: | |
| commits = repo.get_commits() | |
| for commit in commits[:50]: # Check last 50 commits | |
| if commit.author and not any(bot in commit.author.login.lower() for bot in ['[bot]', 'actions-user', 'dependabot']): | |
| username = commit.author.login.lower() | |
| contributors[username] = ( | |
| commit.author.name or commit.author.login, | |
| f'https://github.com/{commit.author.login}' | |
| ) | |
| except Exception as e: | |
| print(f"Error checking recent commits: {e}") | |
| return contributors | |
| def update_contributors_section(content, contributors): | |
| # Find contributors section | |
| contrib_match = re.search(r'(## Contributors\s*\n+<!-- Add contributors below -->)(.*?)(\n+##|\Z)', content, re.DOTALL) | |
| if not contrib_match: | |
| return content | |
| # Build new contributors list | |
| contrib_lines = [] | |
| for username, (name, url) in sorted(contributors.items(), key=lambda x: x[1][0].lower()): | |
| contrib_lines.append(f"- [{name}]({url})") | |
| # Build avatar section | |
| avatar_html = "<div align=\"center\">\n" | |
| for username, (_, url) in sorted(contributors.items()): | |
| github_username = url.split('/')[-1] | |
| avatar_html += f' <a href="{url}"><img src="https://github.com/{github_username}.png" width="60px" alt="{github_username}" /></a>\n' | |
| avatar_html += "</div>\n\n" | |
| # Replace section | |
| new_section = ( | |
| contrib_match.group(1) + '\n' + | |
| '\n'.join(contrib_lines) + '\n\n' + | |
| avatar_html | |
| ) | |
| return content[:contrib_match.start()] + new_section + content[contrib_match.end(0):] | |
| # Read current README | |
| with open('README.md', 'r', encoding='utf-8') as f: | |
| content = f.read() | |
| # Update proposal count | |
| content = update_proposal_count(content) | |
| # Update org list from directories | |
| content = update_org_list(content) | |
| # Update contributors | |
| contributors = get_contributors() | |
| content = update_contributors_section(content, contributors) | |
| # Ensure consistent spacing before sections | |
| content = re.sub(r'\n{3,}##', r'\n\n##', content) | |
| # Write updated README | |
| with open('README.md', 'w', encoding='utf-8') as f: | |
| f.write(content) | |
| EOF | |
| - name: Commit changes | |
| run: | | |
| git config --local user.email "[email protected]" | |
| git config --local user.name "GitHub Action" | |
| git add README.md | |
| git diff --quiet && git diff --staged --quiet || ( | |
| if [[ "${{ github.event_name }}" == "pull_request_target" ]]; then | |
| git commit -m "Update README after PR merge - Add new org and contributors" | |
| else | |
| git commit -m "Update README organization list and contributors" | |
| fi | |
| # Pull latest changes before pushing | |
| git pull --rebase origin main | |
| git push | |
| ) |