|
| 1 | +--- |
| 2 | +title: 'GitHub Organization Readme Badge Generator' |
| 3 | +author: Josh Johanning |
| 4 | +date: 2024-08-14 3:30:00 -0500 |
| 5 | +description: A GitHub action to create markdown badges for your GitHub organization's README.md file |
| 6 | +categories: [GitHub, Actions] |
| 7 | +tags: [GitHub, GitHub Actions] |
| 8 | +media_subpath: /assets/screenshots/2024-08-14-github-organization-readme-badge-generator |
| 9 | +image: |
| 10 | + path: markdown-badges-light-header.png |
| 11 | + width: 100% |
| 12 | + height: 100% |
| 13 | + alt: Markdown badges in a GitHub organization's README |
| 14 | +--- |
| 15 | + |
| 16 | +## Overview |
| 17 | + |
| 18 | +In this post, I will show you how to add an Actions workflow to generate markdown badges to spruce up your organization READMEs. Badges are a great way to provide a quick visual representation of data; you might see them often on your favorite open source repository showing the code quality or number of stars. My action will generate badges for the following (right now): |
| 19 | + |
| 20 | +- Number of repositories |
| 21 | +- Number of pull requests open in the last 30 days |
| 22 | +- Number of pull requests merged in the last 30 days |
| 23 | + |
| 24 | +Here's an [example](https://github.com/joshjohanning-org#joshjohanning-org) of this in action: |
| 25 | +{: .shadow }{: .light } |
| 26 | +{: .shadow }{: .dark } |
| 27 | +_Markdown badges in a GitHub organization's README_ |
| 28 | + |
| 29 | +## What is an organization README? |
| 30 | + |
| 31 | +[Organization READMEs](https://github.blog/changelog/2021-09-14-readmes-for-organization-profiles/) are a great way to showcase your organization to the world. Take [GitHub's organization README](https://github.com/github) as an example. There's a fun picture, a description of what's in the organization, how to contribute, and much more. [Member-only READMEs](https://github.blog/changelog/2022-04-20-organization-profile-updates-member-only-readmes-and-pinned-private-repositories/) are also a great extension of this functionality. Instead of providing information to the general public, you can provide information to your organization's members. For example, when I navigate to GitHub's organization page, I see a different README by default with internal information. |
| 32 | + |
| 33 | +It's really easy to create a public and/or member-only organization README. For a public organization README, you just need to create a `.github` repository and add a `profile/README.md`{: .filepath} file. For an organization member-only README, create a `.github-private` repository and add a `profile/README.md`{: .filepath} file. |
| 34 | + |
| 35 | +## The Workflow |
| 36 | + |
| 37 | +My [action](https://github.com/joshjohanning/organization-readme-badge-generator) is fairly generic in the sense that all it does is generate the markdown badges. It's up to you to decide where to put them in your README. Here's an example of me overwriting some placeholder text by using my action and a bash script: |
| 38 | + |
| 39 | +{% raw %} |
| 40 | + |
| 41 | +```yml |
| 42 | +name: update-organization-readme-badges |
| 43 | + |
| 44 | +on: |
| 45 | + schedule: |
| 46 | + - cron: '0 7 * * *' # runs daily at 07:00 |
| 47 | + workflow_dispatch: |
| 48 | + |
| 49 | +permissions: |
| 50 | + contents: write |
| 51 | + |
| 52 | +jobs: |
| 53 | + generate-badges: |
| 54 | + runs-on: ubuntu-latest |
| 55 | + |
| 56 | + steps: |
| 57 | + - uses: actions/checkout@v4 |
| 58 | + |
| 59 | + - uses: actions/create-github-app-token@v1 |
| 60 | + id: app-token |
| 61 | + with: |
| 62 | + app-id: ${{ vars.APP_ID }} |
| 63 | + private-key: ${{ secrets.PRIVATE_KEY }} |
| 64 | + owner: ${{ github.repository_owner }} |
| 65 | + |
| 66 | + - name: organization-readme-badge-generator |
| 67 | + id: organization-readme-badge-generator |
| 68 | + uses: joshjohanning/organization-readme-badge-generator@v1 |
| 69 | + with: |
| 70 | + organization: ${{ github.repository_owner }} |
| 71 | + token: ${{ steps.app-token.outputs.token }} # recommend to use a GitHub App and not a PAT |
| 72 | + |
| 73 | + - name: write to job summary |
| 74 | + run: | |
| 75 | + echo "${{ steps.organization-readme-badge-generator.outputs.badges }}" >> $GITHUB_STEP_SUMMARY |
| 76 | +
|
| 77 | + - name: add to readme |
| 78 | + run: | |
| 79 | + readme=profile/README.md |
| 80 | + |
| 81 | + # get SHA256 before |
| 82 | + beforeHash=$(sha256sum $readme | awk '{ print $1 }') |
| 83 | + |
| 84 | + # Define start and end markers |
| 85 | + startMarker="<!-- start organization badges -->" |
| 86 | + endMarker="<!-- end organization badges -->" |
| 87 | + |
| 88 | + replacement="${{ steps.organization-readme-badge-generator.outputs.badges }}" |
| 89 | + |
| 90 | + # Escape special characters in the replacement text |
| 91 | + replacementEscaped=$(printf '%s\n' "$replacement" | perl -pe 's/([\\\/\$\(\)@])/\\$1/g') |
| 92 | + |
| 93 | + # Use perl to replace the text between the markers |
| 94 | + perl -i -pe "BEGIN{undef $/;} s/\Q$startMarker\E.*?\Q$endMarker\E/$startMarker\n$replacementEscaped\n$endMarker/smg" $readme |
| 95 | + # get SHA256 after |
| 96 | + afterHash=$(sha256sum $readme | awk '{ print $1 }') |
| 97 | + # Compare the hashes and commit if required |
| 98 | + if [ "$afterHash" = "$beforeHash" ]; then |
| 99 | + echo "The hashes are equal - exiting script" |
| 100 | + exit 0 |
| 101 | + else |
| 102 | + git config --global user.name 'github-actions[bot]' |
| 103 | + git config --global user.email 'github-actions[bot]@users.noreply.github.com' |
| 104 | + git add $readme |
| 105 | + git commit -m "docs: update organization readme badges" |
| 106 | + git push |
| 107 | + fi |
| 108 | +``` |
| 109 | +{: file='.github/workflows/update-organization-readme-badges.yml'} |
| 110 | +
|
| 111 | +{% endraw %} |
| 112 | +
|
| 113 | +> I have this [workflow](https://github.com/joshjohanning-org/.github/actions/workflows/update-organization-readme-badges.yml) running in my public `joshjohanning-org/.github` repository for reference. |
| 114 | +{: .prompt-tip } |
| 115 | + |
| 116 | +This workflow runs and generates the badges with my action. Afterwards, it finds placeholder text in the `profile/README.md`{: .filepath} file and updates the markdown badges. The workflow then commits the change and pushes it back to the repository. |
| 117 | + |
| 118 | +Here's an example of the placeholder text in the `profile/README.md`{: .filepath} file that it's expecting (your badges would be dynamically inserted between the tags): |
| 119 | + |
| 120 | +```md |
| 121 | +# my-org-name |
| 122 | +
|
| 123 | +<!-- start organization badges --> |
| 124 | +
|
| 125 | +<!-- end organization badges --> |
| 126 | +``` |
| 127 | +{: file='profile/README.md'} |
| 128 | + |
| 129 | +## Summary |
| 130 | + |
| 131 | +I like the ability to add quick little badges to my organization README to give the public / my members an idea of the status and activity stats for the organization. This action is a great way to do that. |
| 132 | + |
| 133 | +I have this running as a scheduled workflow in both my `.github` and `.github-private` repositories. |
| 134 | + |
| 135 | +I hope you find this useful! Let me know if there are other features or badges that I should add! For example, one of the things I was [envisioning](https://github.com/joshjohanning/organization-readme-badge-generator/issues/4) was number of GitHub Actions workflows ran / successful.. 🚀 |
0 commit comments