From 9a79a2671d144bc5503332ebb045cd49b37e91e8 Mon Sep 17 00:00:00 2001 From: coderrob Date: Thu, 20 Feb 2025 21:15:44 -0600 Subject: [PATCH 1/4] Initial commit --- LICENSE | 366 +++++++++++++++++++++--------------------- README.md | 1 + action.yml | 37 +++++ scripts/entrypoint.sh | 108 +++++++++++++ 4 files changed, 329 insertions(+), 183 deletions(-) create mode 100644 action.yml create mode 100755 scripts/entrypoint.sh diff --git a/LICENSE b/LICENSE index 261eeb9..5f073f9 100644 --- a/LICENSE +++ b/LICENSE @@ -2,180 +2,180 @@ Version 2.0, January 2004 http://www.apache.org/licenses/ - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" @@ -186,16 +186,16 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] +Copyright 2005 Robert Lindley - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/README.md b/README.md index 07240b9..09a6f2b 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,3 @@ # github-rate-limit-check + GitHub Action to get current GitHub rate limit summary. diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..66773fe --- /dev/null +++ b/action.yml @@ -0,0 +1,37 @@ +# +# Copyright 2025 Robert Lindley +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +--- +name: GitHub API Rate Limit Check +description: Checks the GitHub API rate limit, formats the output, and provides warnings/errors. +author: "Robert Lindley (coderrob)" + +branding: + icon: "bar-chart" + color: "blue" + +inputs: + github-token: + default: ${{ github.token }} + description: GitHub Token for API authentication + required: true + +runs: + using: composite + steps: + - name: Call GitHub Rate Limit API + id: github-rate-limit-api + shell: bash + run: bash "${{ github.action_path }}/scripts/entrypoint.sh" "${{ inputs.github-token }}" diff --git a/scripts/entrypoint.sh b/scripts/entrypoint.sh new file mode 100755 index 0000000..04044fc --- /dev/null +++ b/scripts/entrypoint.sh @@ -0,0 +1,108 @@ +#!/bin/bash + +# +# Copyright 2025 Robert Lindley +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +set -e # Exit on error + +GITHUB_TOKEN=$1 +API_URL="https://api.github.com/rate_limit" + +echo "Calling GitHub Rate Limit API..." +RESPONSE=$(curl -s -H "Authorization: Bearer $GITHUB_TOKEN" $API_URL) + +if [ -z "$RESPONSE" ]; then + echo "::error::Failed to retrieve rate limit data from GitHub API." + exit 1 +fi + +echo "$RESPONSE" >rate_limit.json + +parse_safe() { + local value=$(jq -r "$1 // empty" rate_limit.json) + echo "${value:-0}" # Default to 0 if empty/null +} + +format_time() { + if [ "$1" -gt 0 ]; then + date -u -d "@$1" "+%Y-%m-%d %H:%M:%S UTC" + else + echo "N/A" + fi +} + +RATE_LIMIT=$(parse_safe '.rate.limit') +RATE_REMAINING=$(parse_safe '.rate.remaining') +RATE_RESET=$(parse_safe '.rate.reset') +GRAPHQL_LIMIT=$(parse_safe '.graphql.limit') +GRAPHQL_REMAINING=$(parse_safe '.graphql.remaining') +GRAPHQL_RESET=$(parse_safe '.graphql.reset') +SEARCH_LIMIT=$(parse_safe '.search.limit') +SEARCH_REMAINING=$(parse_safe '.search.remaining') +SEARCH_RESET=$(parse_safe '.search.reset') + +RESET_TIME=$(format_time "$RATE_RESET") +GRAPHQL_RESET_TIME=$(format_time "$GRAPHQL_RESET") +SEARCH_RESET_TIME=$(format_time "$SEARCH_RESET") + +echo "GitHub API Rate Limit Status:" +echo "--------------------------------------------" +echo " Core API: $RATE_REMAINING / $RATE_LIMIT (Resets at $RESET_TIME)" +echo " GraphQL: $GRAPHQL_REMAINING / $GRAPHQL_LIMIT (Resets at $GRAPHQL_RESET_TIME)" +echo " Search: $SEARCH_REMAINING / $SEARCH_LIMIT (Resets at $SEARCH_RESET_TIME)" +echo "--------------------------------------------" + +if [ "$RATE_REMAINING" -le 0 ]; then + echo "::error::❌ GitHub API Rate Limit has been fully exhausted!" + exit 1 +elif [ "$RATE_REMAINING" -lt 100 ]; then + echo "::warning::⚠️ GitHub API Rate Limit is low ($RATE_REMAINING remaining)!" +fi + +if [ "$GRAPHQL_REMAINING" -le 0 ]; then + echo "::error::❌ GitHub GraphQL API Rate Limit has been fully exhausted!" + exit 1 +elif [ "$GRAPHQL_REMAINING" -lt 100 ]; then + echo "::warning::⚠️ GitHub GraphQL API Rate Limit is low ($GRAPHQL_REMAINING remaining)!" +fi + +if [ "$SEARCH_REMAINING" -le 0 ]; then + echo "::error::❌ GitHub Search API Rate Limit has been fully exhausted!" + exit 1 +elif [ "$SEARCH_REMAINING" -lt 100 ]; then + echo "::warning::⚠️ GitHub Search API Rate Limit is low ($SEARCH_REMAINING remaining)!" +fi + +echo "# :bar_chart: GitHub API Rate Limit Summary" >>$GITHUB_STEP_SUMMARY +echo "" >>$GITHUB_STEP_SUMMARY +echo "| API Type | Remaining | Limit | Reset Time (UTC) |" >>$GITHUB_STEP_SUMMARY +echo "|-----------|----------|-------|------------------|" >>$GITHUB_STEP_SUMMARY +echo "| Core API | $RATE_REMAINING | $RATE_LIMIT | $RESET_TIME |" >>$GITHUB_STEP_SUMMARY +echo "| GraphQL | $GRAPHQL_REMAINING | $GRAPHQL_LIMIT | $GRAPHQL_RESET_TIME |" >>$GITHUB_STEP_SUMMARY +echo "| Search | $SEARCH_REMAINING | $SEARCH_LIMIT | $SEARCH_RESET_TIME |" >>$GITHUB_STEP_SUMMARY +echo "" >>$GITHUB_STEP_SUMMARY + +if [ "$RATE_REMAINING" -lt 100 ]; then + echo "⚠️ **Warning:** GitHub API rate limit is low ($RATE_REMAINING remaining)." >>$GITHUB_STEP_SUMMARY +fi +if [ "$GRAPHQL_REMAINING" -lt 100 ]; then + echo "⚠️ **Warning:** GitHub GraphQL API rate limit is low ($GRAPHQL_REMAINING remaining)." >>$GITHUB_STEP_SUMMARY +fi +if [ "$SEARCH_REMAINING" -lt 100 ]; then + echo "⚠️ **Warning:** GitHub Search API rate limit is low ($SEARCH_REMAINING remaining)." >>$GITHUB_STEP_SUMMARY +fi + +echo "⏳ API limits reset periodically. Plan requests accordingly." >>$GITHUB_STEP_SUMMARY From 3106cce336bad4f2ccd71ade674d75ffae6eec03 Mon Sep 17 00:00:00 2001 From: coderrob Date: Thu, 20 Feb 2025 21:32:05 -0600 Subject: [PATCH 2/4] chore: add DS_STORE to gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index c6bba59..2043986 100644 --- a/.gitignore +++ b/.gitignore @@ -128,3 +128,6 @@ dist .yarn/build-state.yml .yarn/install-state.gz .pnp.* + +# mac +.DS_STORE From e919d05f6c04995c30473352e900fb1222acb48c Mon Sep 17 00:00:00 2001 From: coderrob Date: Thu, 20 Feb 2025 21:43:43 -0600 Subject: [PATCH 3/4] chore: patch failure on 0 limits --- scripts/entrypoint.sh | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/scripts/entrypoint.sh b/scripts/entrypoint.sh index 04044fc..14efdda 100755 --- a/scripts/entrypoint.sh +++ b/scripts/entrypoint.sh @@ -36,24 +36,26 @@ parse_safe() { echo "${value:-0}" # Default to 0 if empty/null } -format_time() { - if [ "$1" -gt 0 ]; then - date -u -d "@$1" "+%Y-%m-%d %H:%M:%S UTC" - else - echo "N/A" - fi -} - RATE_LIMIT=$(parse_safe '.rate.limit') RATE_REMAINING=$(parse_safe '.rate.remaining') RATE_RESET=$(parse_safe '.rate.reset') + GRAPHQL_LIMIT=$(parse_safe '.graphql.limit') GRAPHQL_REMAINING=$(parse_safe '.graphql.remaining') GRAPHQL_RESET=$(parse_safe '.graphql.reset') + SEARCH_LIMIT=$(parse_safe '.search.limit') SEARCH_REMAINING=$(parse_safe '.search.remaining') SEARCH_RESET=$(parse_safe '.search.reset') +format_time() { + if [ "$1" -gt 0 ]; then + date -u -d "@$1" "+%Y-%m-%d %H:%M:%S UTC" + else + echo "N/A" + fi +} + RESET_TIME=$(format_time "$RATE_RESET") GRAPHQL_RESET_TIME=$(format_time "$GRAPHQL_RESET") SEARCH_RESET_TIME=$(format_time "$SEARCH_RESET") @@ -65,27 +67,31 @@ echo " GraphQL: $GRAPHQL_REMAINING / $GRAPHQL_LIMIT (Resets at $GRAPHQL_RESET echo " Search: $SEARCH_REMAINING / $SEARCH_LIMIT (Resets at $SEARCH_RESET_TIME)" echo "--------------------------------------------" -if [ "$RATE_REMAINING" -le 0 ]; then +# Core API Limits +if [ "$RATE_LIMIT" -gt 0 ] && [ "$RATE_REMAINING" -le 0 ]; then echo "::error::❌ GitHub API Rate Limit has been fully exhausted!" exit 1 -elif [ "$RATE_REMAINING" -lt 100 ]; then +elif [ "$RATE_LIMIT" -gt 0 ] && [ "$RATE_REMAINING" -lt 100 ]; then echo "::warning::⚠️ GitHub API Rate Limit is low ($RATE_REMAINING remaining)!" fi -if [ "$GRAPHQL_REMAINING" -le 0 ]; then +# GraphQL Limits +if [ "$GRAPHQL_LIMIT" -gt 0 ] && [ "$GRAPHQL_REMAINING" -le 0 ]; then echo "::error::❌ GitHub GraphQL API Rate Limit has been fully exhausted!" exit 1 -elif [ "$GRAPHQL_REMAINING" -lt 100 ]; then +elif [ "$GRAPHQL_LIMIT" -gt 0 ] && [ "$GRAPHQL_REMAINING" -lt 100 ]; then echo "::warning::⚠️ GitHub GraphQL API Rate Limit is low ($GRAPHQL_REMAINING remaining)!" fi -if [ "$SEARCH_REMAINING" -le 0 ]; then +# Search Limits +if [ "$SEARCH_LIMIT" -gt 0 ] && [ "$SEARCH_REMAINING" -le 0 ]; then echo "::error::❌ GitHub Search API Rate Limit has been fully exhausted!" exit 1 -elif [ "$SEARCH_REMAINING" -lt 100 ]; then +elif [ "$SEARCH_LIMIT" -gt 0 ] && [ "$SEARCH_REMAINING" -lt 100 ]; then echo "::warning::⚠️ GitHub Search API Rate Limit is low ($SEARCH_REMAINING remaining)!" fi +# GitHub Step Summary echo "# :bar_chart: GitHub API Rate Limit Summary" >>$GITHUB_STEP_SUMMARY echo "" >>$GITHUB_STEP_SUMMARY echo "| API Type | Remaining | Limit | Reset Time (UTC) |" >>$GITHUB_STEP_SUMMARY @@ -95,13 +101,13 @@ echo "| GraphQL | $GRAPHQL_REMAINING | $GRAPHQL_LIMIT | $GRAPHQL_RESET_TIME |" echo "| Search | $SEARCH_REMAINING | $SEARCH_LIMIT | $SEARCH_RESET_TIME |" >>$GITHUB_STEP_SUMMARY echo "" >>$GITHUB_STEP_SUMMARY -if [ "$RATE_REMAINING" -lt 100 ]; then +if [ "$RATE_LIMIT" -gt 0 ] && [ "$RATE_REMAINING" -lt 100 ]; then echo "⚠️ **Warning:** GitHub API rate limit is low ($RATE_REMAINING remaining)." >>$GITHUB_STEP_SUMMARY fi -if [ "$GRAPHQL_REMAINING" -lt 100 ]; then +if [ "$GRAPHQL_LIMIT" -gt 0 ] && [ "$GRAPHQL_REMAINING" -lt 100 ]; then echo "⚠️ **Warning:** GitHub GraphQL API rate limit is low ($GRAPHQL_REMAINING remaining)." >>$GITHUB_STEP_SUMMARY fi -if [ "$SEARCH_REMAINING" -lt 100 ]; then +if [ "$SEARCH_LIMIT" -gt 0 ] && [ "$SEARCH_REMAINING" -lt 100 ]; then echo "⚠️ **Warning:** GitHub Search API rate limit is low ($SEARCH_REMAINING remaining)." >>$GITHUB_STEP_SUMMARY fi From 598bbf0d6d66a470512c002d3737074a4f84af4c Mon Sep 17 00:00:00 2001 From: coderrob Date: Thu, 20 Feb 2025 22:17:44 -0600 Subject: [PATCH 4/4] chore: add copyright and cleanups and documentation --- .github/workflows/check-api-limit.yml | 18 ++++ README.md | 124 +++++++++++++++++++++++- action.yml | 10 +- scripts/entrypoint.sh | 2 +- scripts/release.sh | 133 ++++++++++++++++++++++++++ 5 files changed, 281 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/check-api-limit.yml create mode 100644 scripts/release.sh diff --git a/.github/workflows/check-api-limit.yml b/.github/workflows/check-api-limit.yml new file mode 100644 index 0000000..0dd8bc4 --- /dev/null +++ b/.github/workflows/check-api-limit.yml @@ -0,0 +1,18 @@ +name: "Check GitHub API Rate Limit" + +on: + workflow_dispatch: {} + +jobs: + check-rate-limit: + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + id: checkout-repo + uses: actions/checkout@v4 + + - name: Run GitHub API Rate Limit Check + id: check-rate-limit + uses: ./ + with: + github-token: ${{ github.token }} diff --git a/README.md b/README.md index 09a6f2b..993f26b 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,123 @@ -# github-rate-limit-check +# 📊 GitHub API Rate Limit Check -GitHub Action to get current GitHub rate limit summary. +## **Description** + +This GitHub Action provides an **automated, real-time check** of your repository’s GitHub API rate limits, giving you **instant visibility** into your API consumption. With detailed reporting and proactive alerts, you can **prevent unexpected disruptions** and **optimize API usage** in your workflows. + +Designed for **reliability and clarity**, this composite action: + +- Calls the **GitHub Rate Limit API** and extracts real-time usage metrics. +- Formats and logs the results professionally in both **workflow logs** and **GitHub Step Summary**. +- **Warns** when remaining API requests fall below a threshold (default: `100`). +- **Fails fast** when limits are exhausted to avoid unexpected workflow failures. +- **Handles missing data gracefully**, preventing false alarms from disabled or unavailable API endpoints. + +Whether you're running frequent automation, managing API-driven integrations, or monitoring GitHub resources, this action ensures you **stay informed and in control** of your API quota. + +--- + +## 🚀 **Why Use This Action?** + +✔️ **Prevents Workflow Failures** – Stops workflows from running when API limits are exceeded. +✔️ **Proactive Warnings** – Get alerts when remaining requests drop below a safe threshold. +✔️ **Clear, Professional Reporting** – View a **clean summary table** in GitHub Actions for quick insights. +✔️ **Safe and Robust Handling** – Avoids errors due to missing or unavailable API data. +✔️ **Simple Integration** – Plug it into any workflow with minimal setup. + +--- + +## 📦 **Usage** + +### **Workflow Example** + +Add the following to your **GitHub Actions workflow** to monitor API usage before running rate-limited tasks. + +```yaml +jobs: + check-rate-limit: + name: Check GitHub API Rate Limit + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + id: checkout-repo + uses: actions/checkout@v4 + + - name: Run GitHub API Rate Limit Check + id: check-rate-limit + uses: coderrob/github-api-rate-limit-check@v1 + with: + github-token: ${{ github.token }} +``` + +--- + +## 📜 **How It Works** + +1. **Fetches Rate Limit Data** → Calls the `https://api.github.com/rate_limit` endpoint. +2. **Parses and Processes Data** → Extracts core, GraphQL, and search API quotas. +3. **Logs Results** → Displays a structured **table** in `GITHUB_STEP_SUMMARY` and console logs. +4. **Triggers Alerts**: + - **Warning** (`⚠️`) if remaining API requests **drop below 100**. + - **Error** (`❌`) if limits are **fully exhausted** (only if that API type is enabled). +5. **Fails the Workflow (if needed)** → Prevents unintended execution when API access is unavailable. + +--- + +## 📊 **Example Output** + +### **Console Logs** + +```bash +GitHub API Rate Limit Status: +-------------------------------------------- + Core API: 85 / 5000 (Resets at 2025-02-20 15:00:00 UTC) + GraphQL: 4500 / 5000 (Resets at 2025-02-20 15:00:00 UTC) + Search: 0 / 30 (Resets at 2025-02-20 15:00:00 UTC) +-------------------------------------------- +⚠️ GitHub API Rate Limit is low (85 remaining)! +❌ GitHub Search API Rate Limit has been fully exhausted! +``` + +--- + +### 📊 **GitHub API Rate Limit Summary** + +| API Type | Remaining | Limit | Reset Time (UTC) | +| ------------ | --------- | ----- | ------------------- | +| **Core API** | **85** | 5000 | 2025-02-20 15:00:00 | +| **GraphQL** | **4500** | 5000 | 2025-02-20 15:00:00 | +| **Search** | **0** | 30 | 2025-02-20 15:00:00 | + +⚠️ **Warning:** GitHub API rate limit is low (85 remaining). +❌ **Error:** GitHub Search API rate limit has been fully exhausted. + +⏳ API limits reset periodically. Plan requests accordingly. + +--- + +## 🛠 **Inputs** + +| Name | Required | Description | +| -------------- | -------- | ------------------------------------------------------------ | +| `github-token` | ✅ Yes | GitHub token used for authentication (`${{ github.token }}`) | + +--- + +## 🎯 **Best Use Cases** + +- **Before running API-heavy workflows** (e.g., fetching issue data, triggering GitHub Actions via API). +- **Monitoring CI/CD jobs that rely on GitHub API calls** to avoid failures mid-run. +- **Logging and auditing API usage** across your organization’s GitHub actions. + +--- + +## 🏆 **Take Control of Your GitHub API Usage** + +This action gives you the **power to monitor, manage, and prevent API failures before they happen**. Whether you're a solo developer or running large-scale automation, **stay ahead of rate limits and keep your workflows running smoothly**. 🚀 + +--- + +### **🔗 Related Resources** + +- [GitHub API Rate Limits Docs](https://docs.github.com/en/rest/rate-limit) +- [GitHub Actions Documentation](https://docs.github.com/en/actions) diff --git a/action.yml b/action.yml index 66773fe..2f8b4fa 100644 --- a/action.yml +++ b/action.yml @@ -14,9 +14,13 @@ # limitations under the License. # --- -name: GitHub API Rate Limit Check -description: Checks the GitHub API rate limit, formats the output, and provides warnings/errors. author: "Robert Lindley (coderrob)" +name: GitHub API Rate Limit Check +description: This GitHub Action provides an automated, real-time check of your + repository's GitHub API rate limits, giving you instant visibility + into your API consumption. With detailed reporting and proactive + alerts, you can prevent unexpected disruptions and optimize API + usage in your workflows. branding: icon: "bar-chart" @@ -26,7 +30,7 @@ inputs: github-token: default: ${{ github.token }} description: GitHub Token for API authentication - required: true + required: false runs: using: composite diff --git a/scripts/entrypoint.sh b/scripts/entrypoint.sh index 14efdda..ff72d2c 100755 --- a/scripts/entrypoint.sh +++ b/scripts/entrypoint.sh @@ -111,4 +111,4 @@ if [ "$SEARCH_LIMIT" -gt 0 ] && [ "$SEARCH_REMAINING" -lt 100 ]; then echo "⚠️ **Warning:** GitHub Search API rate limit is low ($SEARCH_REMAINING remaining)." >>$GITHUB_STEP_SUMMARY fi -echo "⏳ API limits reset periodically. Plan requests accordingly." >>$GITHUB_STEP_SUMMARY +echo "⏳ API limits reset hourly. Plan requests accordingly." >>$GITHUB_STEP_SUMMARY diff --git a/scripts/release.sh b/scripts/release.sh new file mode 100644 index 0000000..a2daa58 --- /dev/null +++ b/scripts/release.sh @@ -0,0 +1,133 @@ +#!/bin/bash + +# Exit early +# See: https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#The-Set-Builtin +set -e + +# About: +# +# This is a helper script to tag and push a new release. GitHub Actions use +# release tags to allow users to select a specific version of the action to use. +# +# See: https://github.com/actions/typescript-action#publishing-a-new-release +# See: https://github.com/actions/toolkit/blob/master/docs/action-versioning.md#recommendations +# +# This script will do the following: +# +# 1. Retrieve the latest release tag +# 2. Display the latest release tag +# 3. Prompt the user for a new release tag +# 4. Validate the new release tag +# 5. Remind user to update the version field in package.json +# 6. Tag a new release +# 7. Set 'is_major_release' variable +# 8. Point separate major release tag (e.g. v1, v2) to the new release +# 9. Push the new tags (with commits, if any) to remote +# 10. If this is a major release, create a 'releases/v#' branch and push +# +# Usage: +# +# script/release + +# Variables +semver_tag_regex='v[0-9]+\.[0-9]+\.[0-9]+$' +semver_tag_glob='v[0-9].[0-9].[0-9]*' +git_remote='origin' +major_semver_tag_regex='\(v[0-9]*\)' + +# Terminal colors +OFF='\033[0m' +BOLD_RED='\033[1;31m' +BOLD_GREEN='\033[1;32m' +BOLD_BLUE='\033[1;34m' +BOLD_PURPLE='\033[1;35m' +BOLD_UNDERLINED='\033[1;4m' +BOLD='\033[1m' + +# 1. Retrieve the latest release tag +if ! latest_tag=$(git describe --abbrev=0 --match="$semver_tag_glob"); then + # There are no existing release tags + echo -e "No tags found (yet) - Continue to create and push your first tag" + latest_tag="[unknown]" +fi + +# 2. Display the latest release tag +echo -e "The latest release tag is: ${BOLD_BLUE}${latest_tag}${OFF}" + +# 3. Prompt the user for a new release tag +read -r -p 'Enter a new release tag (vX.X.X format): ' new_tag + +# 4. Validate the new release tag +if echo "$new_tag" | grep -q -E "$semver_tag_regex"; then + # Release tag is valid + echo -e "Tag: ${BOLD_BLUE}$new_tag${OFF} is valid syntax" +else + # Release tag is not in `vX.X.X` format + echo -e "Tag: ${BOLD_BLUE}$new_tag${OFF} is ${BOLD_RED}not valid${OFF} (must be in ${BOLD}vX.X.X${OFF} format)" + exit 1 +fi + +# 5. Remind user to update the version field in package.json +echo -e -n "Make sure the version field in package.json is ${BOLD_BLUE}$new_tag${OFF}. Yes? [Y/${BOLD_UNDERLINED}n${OFF}] " +read -r YN + +if [[ ! ($YN == "y" || $YN == "Y") ]]; then + # Package.json version field is not up to date + echo -e "Please update the package.json version to ${BOLD_PURPLE}$new_tag${OFF} and commit your changes" + exit 1 +fi + +# 6. Tag a new release +git tag "$new_tag" --annotate --message "$new_tag Release" +echo -e "Tagged: ${BOLD_GREEN}$new_tag${OFF}" + +# 7. Set 'is_major_release' variable +new_major_release_tag=$(expr "$new_tag" : "$major_semver_tag_regex") + +if [[ "$latest_tag" = "[unknown]" ]]; then + # This is the first major release + is_major_release='yes' +else + # Compare the major version of the latest tag with the new tag + latest_major_release_tag=$(expr "$latest_tag" : "$major_semver_tag_regex") + + if ! [[ "$new_major_release_tag" = "$latest_major_release_tag" ]]; then + is_major_release='yes' + else + is_major_release='no' + fi +fi + +# 8. Point separate major release tag (e.g. v1, v2) to the new release +if [ $is_major_release = 'yes' ]; then + # Create a new major version tag and point it to this release + git tag "$new_major_release_tag" --annotate --message "$new_major_release_tag Release" + echo -e "New major version tag: ${BOLD_GREEN}$new_major_release_tag${OFF}" +else + # Update the major version tag to point it to this release + git tag "$latest_major_release_tag" --force --annotate --message "Sync $latest_major_release_tag tag with $new_tag" + echo -e "Synced ${BOLD_GREEN}$latest_major_release_tag${OFF} with ${BOLD_GREEN}$new_tag${OFF}" +fi + +# 9. Push the new tags (with commits, if any) to remote +git push --follow-tags + +if [ $is_major_release = 'yes' ]; then + # New major version tag is pushed with the '--follow-tags' flags + echo -e "Tags: ${BOLD_GREEN}$new_major_release_tag${OFF} and ${BOLD_GREEN}$new_tag${OFF} pushed to remote" +else + # Force push the updated major version tag + git push $git_remote "$latest_major_release_tag" --force + echo -e "Tags: ${BOLD_GREEN}$latest_major_release_tag${OFF} and ${BOLD_GREEN}$new_tag${OFF} pushed to remote" +fi + +# 10. If this is a major release, create a 'releases/v#' branch and push +if [ $is_major_release = 'yes' ]; then + git branch "releases/$new_major_release_tag" "$new_major_release_tag" + echo -e "Branch: ${BOLD_BLUE}releases/$new_major_release_tag${OFF} created from ${BOLD_BLUE}$new_major_release_tag${OFF} tag" + git push --set-upstream $git_remote "releases/$new_major_release_tag" + echo -e "Branch: ${BOLD_GREEN}releases/$new_major_release_tag${OFF} pushed to remote" +fi + +# Completed +echo -e "${BOLD_GREEN}Done!${OFF}"