From 1d8f8b2ac2f0982101293d820faef9a9250d2e61 Mon Sep 17 00:00:00 2001 From: Zack Koppert Date: Thu, 18 May 2023 15:58:26 -0700 Subject: [PATCH] initial commit Signed-off-by: Zack Koppert --- .env-example | 4 + .github/CODEOWNERS | 1 + .github/dependabot.yml | 15 ++ .github/linters/.hadolint.yaml | 2 + .github/release-drafter.yml | 40 ++++++ .github/workflows/codeql-analysis.yml | 67 +++++++++ .github/workflows/docker-image.yml | 18 +++ .github/workflows/integration_tests.disabled | 13 ++ .github/workflows/linter.yml | 45 ++++++ .github/workflows/python-package.yml | 39 ++++++ .github/workflows/release-drafter.yml | 15 ++ .gitignore | 140 +++++++++++++++++++ CONTRIBUTING.md | 105 ++++++++++++++ Dockerfile | 18 +++ LICENSE | 21 +++ README.md | 55 ++++++++ action.yml | 10 ++ requirements.txt | 2 + stale_repos.py | 62 ++++++++ 19 files changed, 672 insertions(+) create mode 100644 .env-example create mode 100644 .github/CODEOWNERS create mode 100644 .github/dependabot.yml create mode 100644 .github/linters/.hadolint.yaml create mode 100644 .github/release-drafter.yml create mode 100644 .github/workflows/codeql-analysis.yml create mode 100644 .github/workflows/docker-image.yml create mode 100644 .github/workflows/integration_tests.disabled create mode 100644 .github/workflows/linter.yml create mode 100644 .github/workflows/python-package.yml create mode 100644 .github/workflows/release-drafter.yml create mode 100644 .gitignore create mode 100644 CONTRIBUTING.md create mode 100644 Dockerfile create mode 100644 LICENSE create mode 100644 README.md create mode 100644 action.yml create mode 100644 requirements.txt create mode 100755 stale_repos.py diff --git a/.env-example b/.env-example new file mode 100644 index 0000000..438fafc --- /dev/null +++ b/.env-example @@ -0,0 +1,4 @@ +GH_TOKEN=' ' +TOPIC='inner-source' +ORGANIZATION=' ' +GH_ENTERPRISE_URL=' ' diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..e5f6f75 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @zkoppert diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..256c693 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,15 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "pip" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "daily" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" diff --git a/.github/linters/.hadolint.yaml b/.github/linters/.hadolint.yaml new file mode 100644 index 0000000..0aa5f7c --- /dev/null +++ b/.github/linters/.hadolint.yaml @@ -0,0 +1,2 @@ +ignored: + - DL3008 \ No newline at end of file diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml new file mode 100644 index 0000000..40a1c25 --- /dev/null +++ b/.github/release-drafter.yml @@ -0,0 +1,40 @@ +name-template: 'v$RESOLVED_VERSION' +tag-template: 'v$RESOLVED_VERSION' +template: | + # Changelog + $CHANGES + + See details of [all code changes](https://github.com/zkoppert/innersource-crawler/compare/$PREVIOUS_TAG...v$RESOLVED_VERSION) since previous release + +categories: + - title: '🚀 Features' + labels: + - 'feature' + - 'enhancement' + - title: '🐛 Bug Fixes' + labels: + - 'fix' + - 'bugfix' + - 'bug' + - title: '🧰 Maintenance' + labels: + - 'infrastructure' + - 'automation' + - 'documentation' + - 'dependencies' + - title: '🏎 Performance' + label: 'performance' +change-template: '- $TITLE @$AUTHOR (#$NUMBER)' +version-resolver: + major: + labels: + - 'type: breaking' + minor: + labels: + - 'type: enhancement' + patch: + labels: + - 'type: bug' + - 'type: maintenance' + - 'type: documentation' + default: patch diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000..9c798eb --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,67 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ main ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ main ] + schedule: + - cron: '27 19 * * 5' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + language: [ 'python' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] + # Learn more: + # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + # ℹī¸ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏ī¸ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml new file mode 100644 index 0000000..3315a9c --- /dev/null +++ b/.github/workflows/docker-image.yml @@ -0,0 +1,18 @@ +name: Docker Image CI + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Build the Docker image + run: docker build . --file Dockerfile --tag stale_repos:"$(date +%s)" diff --git a/.github/workflows/integration_tests.disabled b/.github/workflows/integration_tests.disabled new file mode 100644 index 0000000..3a58292 --- /dev/null +++ b/.github/workflows/integration_tests.disabled @@ -0,0 +1,13 @@ +name: Integration Test +on: [push] +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + - name: Update requirements.txt + uses: ryan-rozario/pipreqs-action@v2.0.0 + with: + PROJECT_PATH: . + REQUIREMENT_PATH: ./requirements.txt diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml new file mode 100644 index 0000000..147ff14 --- /dev/null +++ b/.github/workflows/linter.yml @@ -0,0 +1,45 @@ +--- + +# +# Documentation: +# https://help.github.com/en/articles/workflow-syntax-for-github-actions +# + +############################# +# Start the job on all push # +############################# +on: + push: + branches: [main] + pull_request: + +############### +# Set the Job # +############### +jobs: + build: + # Name the Job + name: super-linter + # Set the agent to run on + runs-on: ubuntu-latest + ################## + # Load all steps # + ################## + steps: + ########################## + # Checkout the code base # + ########################## + - name: Checkout Code + uses: actions/checkout@v3 + with: + # Full git history is needed to get a proper list of changed files within `super-linter` + fetch-depth: 0 + + ################################ + # Run Linter against code base # + ################################ + - name: Lint Code Base + uses: docker://ghcr.io/github/super-linter:latest + env: + DEFAULT_BRANCH: main + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml new file mode 100644 index 0000000..4adcf60 --- /dev/null +++ b/.github/workflows/python-package.yml @@ -0,0 +1,39 @@ +# This workflow will install Python dependencies, run tests and lint with a variety of Python versions +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions + +name: Python package + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.9, 3.11] + + steps: + - uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install flake8 pytest + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + - name: Lint with flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics +# - name: Test with pytest +# run: | +# pytest diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml new file mode 100644 index 0000000..5b27fd6 --- /dev/null +++ b/.github/workflows/release-drafter.yml @@ -0,0 +1,15 @@ +name: Release Drafter + +on: + push: + # branches to consider in the event; optional, defaults to all + branches: + - main + +jobs: + update_release_draft: + runs-on: ubuntu-latest + steps: + - uses: release-drafter/release-drafter@v5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a747bb1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,140 @@ +# Output files + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..18af7a3 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,105 @@ + + +# Contributing to stale_repos + +First off, thanks for taking the time to contribute! :heart: + +All types of contributions are encouraged and valued. See the [Table of Contents](#table-of-contents) for different ways to help and details about how this project handles them. Please make sure to read the relevant section before making your contribution. It will make it a lot easier for us project owners and smooth out the experience for all involved. The team looks forward to your contributions. :tada: + + +## Table of Contents + +- [I Have a Question](#i-have-a-question) +- [I Want To Contribute](#i-want-to-contribute) +- [Reporting Bugs](#reporting-bugs) +- [Suggesting Enhancements](#suggesting-enhancements) +- [Releases](#releases) + +## I Have a Question + +Before you ask a question, it is best to search for existing [Issues](https://github.com/github/stale_repos/issues) that might help you. In case you have found a suitable issue and still need clarification, you can write your question in this issue. + +If you then still feel the need to ask a question and need clarification, we recommend the following: + +- Open an [Issue](https://github.com/github/stale_repos/issues/new). +- Provide as much context as you can about what you're running into. +- Provide project and platform versions (nodejs, npm, etc), depending on what seems relevant. + +We will then take care of the issue as soon as possible. + +## I Want To Contribute + +> ### Legal Notice +> When contributing to this project, you must agree that you have authored 100% of the content, that you have the necessary rights to the content and that the content you contribute may be provided under the project license. + +## Reporting Bugs + + +### Before Submitting a Bug Report + +A good bug report shouldn't leave others needing to chase you up for more information. Therefore, we ask you to investigate carefully, collect information and describe the issue in detail in your report. Please complete the following steps in advance to help us fix any potential bug as fast as possible. + +- Make sure that you are using the latest version. +- Determine if your bug is really a bug and not an error on your side e.g. using incompatible environment components/versions (Make sure that you have read the documentation. If you are looking for support, you might want to check [this section](#i-have-a-question)). +- To see if other users have experienced (and potentially already solved) the same issue you are having, check if there is not already a bug report existing for your bug or error in the [bug tracker](https://github.com/github/stale_repos/issues). +- Collect information about the bug: + - Stack trace (Traceback) + - OS, Platform and Version (Windows, Linux, macOS, x86, ARM) + - Version of the interpreter, compiler, SDK, runtime environment, package manager, depending on what seems relevant. + - Possibly your input and the output +- Can you reliably reproduce the issue? And can you also reproduce it with older versions? + + +### How Do I Submit a Good Bug Report? + +We use GitHub issues to track bugs and errors. If you run into an issue with the project: + +- Open an [Issue](https://github.com/github/stale_repos/issues/new). (Since we can't be sure at this point whether it is a bug or not, we ask you not to talk about a bug yet and not to label the issue.) +- Explain the behavior you would expect and the actual behavior. +- Please provide as much context as possible and describe the *reproduction steps* that someone else can follow to recreate the issue on their own. This usually includes your code. For good bug reports you should isolate the problem and create a reduced test case. +- Provide the information you collected in the previous section. + +Once it's filed: + +- The project team will label the issue accordingly. +- A team member will try to reproduce the issue with your provided steps. If there are no reproduction steps or no obvious way to reproduce the issue, the team will ask you for those steps and mark the issue as `needs-repro`. Bugs with the `needs-repro` tag will not be addressed until they are reproduced. +- If the team is able to reproduce the issue, it will be marked `needs-fix`, as well as possibly other tags (such as `critical`), and the issue will be left to be implemented by someone. + +## Suggesting Enhancements + +This section guides you through submitting an enhancement suggestion for stale_repos, **including completely new features and minor improvements to existing functionality**. Following these guidelines will help maintainers and the community to understand your suggestion and find related suggestions. + + +### Before Submitting an Enhancement + +- Make sure that you are using the latest version. +- Read the documentation carefully and find out if the functionality is already covered, maybe by an individual configuration. +- Perform a [search](https://github.com/github/stale_repos/issues) to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one. +- Find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature or to develop the feature yourself and contribute it to the project. + + +### How Do I Submit a Good Enhancement Suggestion? + +Enhancement suggestions are tracked as [GitHub issues](https://github.com/github/stale_repos/issues). + +- Use a **clear and descriptive title** for the issue to identify the suggestion. +- Provide a **step-by-step description of the suggested enhancement** in as many details as possible. +- **Describe the current behavior** and **explain which behavior you expected to see instead** and why. At this point you can also tell which alternatives do not work for you. +- You may want to **include screenshots and animated GIFs** which help you demonstrate the steps or point out the part which the suggestion is related to. +- **Explain why this enhancement would be useful** to most stale_repos users. + +## Releases + +To release a new version, maintainers are to release new versions following semantic versioning and via GitHub Releases. +Once the code is ready to release please do the following +1. Create a [GitHub release](https://github.com/github/stale_repos/releases) based off the current draft and review release notes +2. Ensure that the versioning is correct given the content of the release +3. Check the box to release it to the GitHub Marketplace +4. Publish the release +5. Clone the repository at the release tag locally or in a codespace +6. Authenticate to ghcr.io using [these instructions](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry#authenticating-to-the-container-registry) +7. `docker build -t ghcr.io/github/stale_repos:v1 .` where v1 is the current major version number +8. `docker build -t ghcr.io/github/stale_repos:v1.0.0 .` where v1.0.0 is the full version number +9. `docker push ghcr.io/github/stale_repos:v1` where v1 is the current major version number +10. `docker push ghcr.io/github/stale_repos:v1.0.0` where v1.0.0 is the full version number +11. Update the `action.yml` and `README.md` instructions to point to the new docker container if its a major version number change diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..7072ecb --- /dev/null +++ b/Dockerfile @@ -0,0 +1,18 @@ +FROM python:3.8-slim-buster + +WORKDIR /action/workspace +COPY requirements.txt stale_repos.py /action/workspace/ + +RUN python3 -m pip install --no-cache-dir -r requirements.txt \ + && apt-get -y update \ + && apt-get -y install --no-install-recommends git \ + && rm -rf /var/lib/apt/lists/* + +CMD ["/action/workspace/stale_repos.py"] +ENTRYPOINT ["python3", "-u"] + +# To run ineractive debug on the docker container +# 1. Comment out the above CMD and ENTRYPOINT lines +# 2. Uncomment the ENTRYPOINT line below + +#ENTRYPOINT ["bash"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..545898a --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 GitHub + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..816bea3 --- /dev/null +++ b/README.md @@ -0,0 +1,55 @@ +# Stale Repos Action + +This project identifies and reports repositories with no activity for configurable amount of time, in order to surface inactive repos to be considered for archival. The current approach assumes that the repos that you want to evaluate are available in a single GitHub organization. + +## Support + +If you need support using this project or have questions about it, please [open up an issue in this repository](https://github.com/github/stale_repos/issues). Requests made directly to GitHub staff or support team will be redirected here to open an issue. GitHub SLA's and support/services contracts do not apply to this repository. + +## Use as a GitHub Action + +1. Create a repository to host this GitHub Action or select an existing repository. +1. Create the env values from the sample workflow below (GH_TOKEN, ORGANIZATION) with your information as repository secrets. More info on creating secrets can be found [here](https://docs.github.com/en/actions/security-guides/encrypted-secrets). +Note: Your GitHub token will need to have read/write access to all the repositories in the organization that you want evaluated +1. Copy the below example workflow to your repository and put it in the `.github/workflows/` directory with the file extension `.yml` (ie. `.github/workflows/stale_repos.yml`) + +### Example workflow + +```yaml +name: stale repo identifier + +on: + workflow_dispatch: + schedule: + - cron: '3 2 1 * *' + +jobs: + build: + name: stale repo identifier + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Run stale_repos tool + uses: docker://ghcr.io/github/stale_repos:v1 + env: + GH_TOKEN: ${{ secrets.GH_TOKEN }} + ORGANIZATION: ${{ secrets.ORGANIZATION }} + INACTIVE_DAYS: 365 +``` + +## Local usage without Docker + +1. Copy `.env-example` to `.env` +1. Fill out the `.env` file with a _token_ from a user that has access to the organization to scan (listed below). Tokens should have admin:org or read:org access. +1. Fill out the `.env` file with the desired _inactive_days_ value. This should be a whole positive number representing the amount of inactivity that you want for flagging stale repos. +1. Fill out the `.env` file with the exact _organization_ that you want to search in +1. (Optional) Fill out the `.env` file with the exact _URL_ of the GitHub Enterprise that you want to search in. Keep empty if you want to search in the public `github.com`. +1. `pip install -r requirements.txt` +1. Run `python3 ./stale_repos.py`, which will output a list of repositories and the length of their inactivity + +## License + +[MIT](LICENSE) diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..53b155f --- /dev/null +++ b/action.yml @@ -0,0 +1,10 @@ +--- +name: 'stale_repos' +author: 'github' +description: 'A GitHub Action to identify stale repos within an organization that should be considered for archive.' +runs: + using: 'docker' + image: 'docker://ghcr.io/github/stale_repos:v1' +branding: + icon: 'check-square' + color: 'white' diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e0b1d73 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +github3.py==3.2.0 +python-dotenv==1.0.0 diff --git a/stale_repos.py b/stale_repos.py new file mode 100755 index 0000000..2107ac7 --- /dev/null +++ b/stale_repos.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python + +import os +from datetime import datetime, timezone +from os.path import dirname, join + +import github3 +from dotenv import load_dotenv + + +def main(): + """ + Iterate over all repositories in the specified organization on GitHub, + calculate the number of days since each repository was last pushed to, + and print out the URL of any repository that has been inactive for more + days than the specified threshold. + + The following environment variables must be set: + - GH_TOKEN: a personal access token for the GitHub API + - INACTIVE_DAYS: the number of days after which a repository is considered stale + - ORGANIZATION: the name of the organization to search for repositories in + + If GH_ENTERPRISE_URL is set, the script will authenticate to a GitHub Enterprise + instance instead of GitHub.com. + """ + # Load env variables from file + dotenv_path = join(dirname(__file__), ".env") + load_dotenv(dotenv_path) + + # Auth to GitHub.com + ghe = os.getenv("GH_ENTERPRISE_URL", default="").strip() + token = os.getenv("GH_TOKEN") + if ghe and token: + gh = github3.github.GitHubEnterprise(ghe, token=token) + elif token: + gh = github3.login(token=os.getenv("GH_TOKEN")) + else: + raise ValueError("GH_TOKEN environment variable not set") + + # Set the topic + inactive_days_threshold = os.getenv("INACTIVE_DAYS") + if not inactive_days_threshold: + raise ValueError("INACTIVE_DAYS environment variable not set") + + # Set the organization + organization = os.getenv("ORGANIZATION") + if not organization: + raise ValueError("ORGANIZATION environment variable not set") + + # Iterate over repos in the org, acquire inactive days, + # and print out the repo url and days inactive if it's over the threshold (inactive_days) + for repo in gh.repositories_by(organization): + last_push = repo.pushed_at + if last_push is None: + continue + days_inactive = (datetime.now(timezone.utc) - last_push).days + if days_inactive > int(inactive_days_threshold): + print(f"{repo.html_url}: {days_inactive} days inactive") + + +if __name__ == "__main__": + main()