Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ A branch must meet all the following criteria to be deemed abandoned and safe to
* Must NOT be the base of an open pull request of another branch. The base of a pull request is the branch you told
GitHub you want to merge your pull request into.
* Must NOT be in an optional list of branches to ignore
* Must match one of the given branch prefixes (optional)
* Must be older than a given amount of days

## Inputs
Expand All @@ -27,6 +28,7 @@ A branch must meet all the following criteria to be deemed abandoned and safe to
| ------------- | ------------- | ------------- |
| `ignore_branches` | Comma-separated list of branches to ignore and never delete. You don't need to add your protected branches here. | `foo,bar`
| `last_commit_age_days` | How old in days must be the last commit into the branch for the branch to be deleted. Default: `60` | `90`
| `prefixes` | Comma-separated list of prefixes a branch must match to be deleted. Default: `null` | `feature/,bugfix/`
| `dry_run`* | Whether we're actually deleting branches at all. Possible values: `yes, no` (case sensitive). Default: `yes` | `no`
| `github_token`* | The github token to use on requests to the github api. You can use the one github actions provide | `${{ github.token }}`
| `github_base_url` | The github API's base url. You only need to override this when using Github Enterprise on a different domain. Default: `https://api.github.com` | `https://github.mycompany.com/api/v3`
Expand Down
5 changes: 5 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ inputs:
description: "How old in days must be the last commit into the branch for the branch to be deleted."
required: false
default: "60"
prefixes:
description: "Comma-separated list of prefixes a branch must match to be deleted."
required: false
default: ""
dry_run:
description: "Whether we're actually deleting branches at all. Defaults to 'yes'. Possible values: yes, no (case sensitive)"
required: true
Expand All @@ -37,6 +41,7 @@ runs:
args:
- ${{ inputs.ignore_branches }}
- ${{ inputs.last_commit_age_days }}
- ${{ inputs.prefixes }}
- ${{ inputs.dry_run }}
- ${{ inputs.github_token }}
- ${{ inputs.github_base_url }}
3 changes: 2 additions & 1 deletion main.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from src import actions, io

if __name__ == '__main__':
ignore_branches, last_commit_age_days, dry_run, github_token, github_repo, github_base_url = io.parse_input()
ignore_branches, last_commit_age_days, prefixes, dry_run, github_token, github_repo, github_base_url = io.parse_input()

deleted_branches = actions.run_action(
ignore_branches=ignore_branches,
last_commit_age_days=last_commit_age_days,
prefixes=prefixes,
dry_run=dry_run,
github_repo=github_repo,
github_token=github_token,
Expand Down
4 changes: 3 additions & 1 deletion src/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ def run_action(
github_repo: str,
ignore_branches: list,
last_commit_age_days: int,
prefixes: list,
github_token: str,
github_base_url: str,
dry_run: bool = True
Expand All @@ -13,6 +14,7 @@ def run_action(
'github_repo': github_repo,
'ignore_branches': ignore_branches,
'last_commit_age_days': last_commit_age_days,
'prefixes': prefixes,
'dry_run': dry_run,
'github_base_url': github_base_url
}
Expand All @@ -21,7 +23,7 @@ def run_action(

github = Github(github_repo=github_repo, github_token=github_token, github_base_url=github_base_url)

branches = github.get_deletable_branches(last_commit_age_days=last_commit_age_days, ignore_branches=ignore_branches)
branches = github.get_deletable_branches(last_commit_age_days=last_commit_age_days, ignore_branches=ignore_branches, prefixes=prefixes)

print(f"Branches queued for deletion: {branches}")
if dry_run is False:
Expand Down
14 changes: 12 additions & 2 deletions src/github.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def make_headers(self) -> dict:
def get_paginated_branches_url(self, page: int = 0) -> str:
return f'{self.github_base_url}/repos/{self.github_repo}/branches?protected=false&per_page=30&page={page}'

def get_deletable_branches(self, last_commit_age_days: int, ignore_branches: list) -> list:
def get_deletable_branches(self, last_commit_age_days: int, ignore_branches: list, prefixes: list) -> list:
# Default branch might not be protected
default_branch = self.get_default_branch()

Expand All @@ -42,7 +42,7 @@ def get_deletable_branches(self, last_commit_age_days: int, ignore_branches: lis

print(f'Analyzing branch `{branch_name}`...')

# Immediately discard protected branches, default branch and ignored branches
# Immediately discard protected branches, default branch, ignored branches and branches not matching prefix
if branch_name == default_branch:
print(f'Ignoring `{branch_name}` because it is the default branch')
continue
Expand All @@ -57,6 +57,16 @@ def get_deletable_branches(self, last_commit_age_days: int, ignore_branches: lis
print(f'Ignoring `{branch_name}` because it is on the list of ignored branches')
continue

# If prefixes are provided, only consider branches that match one of the prefixes
if len(prefixes) > 0:
found_prefix = False
for prefix in prefixes:
if branch_name.startswith(prefix):
found_prefix = True
if found_prefix is False:
print(f'Ignoring `{branch_name}` because it does not match any provided prefix')
continue

# Move on if commit is in an open pull request
if self.has_open_pulls(commit_hash=commit_hash):
print(f'Ignoring `{branch_name}` because it has open pulls')
Expand Down
19 changes: 12 additions & 7 deletions src/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
from typing import List


def parse_input() -> (list, int, bool, str, str, str):
def parse_input() -> (list, int, list, bool, str, str, str):
args: List[str] = sys.argv

num_args = len(args)

if num_args < 4 or num_args > 6:
if num_args < 4 or num_args > 7:
input_string = ' '.join(args)
expected_string = f'{args[0]} ignore_branches last_commit_age_days dry_run_yes_no github_token github_repo github_base_url'
expected_string = f'{args[0]} ignore_branches last_commit_age_days prefixes dry_run_yes_no github_token github_repo github_base_url'
raise RuntimeError(f'Incorrect input: {input_string}. Expected: {expected_string}')

branches_raw: str = args[1]
Expand All @@ -20,16 +20,21 @@ def parse_input() -> (list, int, bool, str, str, str):

last_commit_age_days = int(args[2])

prefixes_raw: str = args[3]
prefixes = prefixes_raw.split(',')
if prefixes == ['']:
prefixes = []

# Dry run can only be either `true` or `false`, as strings due to github actions input limitations
dry_run = False if args[3] == 'no' else True
dry_run = False if args[4] == 'no' else True

github_token = args[4]
github_token = args[5]

github_repo = getenv('GITHUB_REPOSITORY')

github_base_url = args[5] if num_args >= 6 else 'https://api.github.com'
github_base_url = args[6] if num_args >= 7 else 'https://api.github.com'

return ignore_branches, last_commit_age_days, dry_run, github_token, github_repo, github_base_url
return ignore_branches, last_commit_age_days, prefixes, dry_run, github_token, github_repo, github_base_url


def format_output(output_strings: dict) -> None:
Expand Down