diff --git a/.github/actions/ensure_backporting/action.yml b/.github/actions/ensure_backporting/action.yml new file mode 100644 index 0000000..2d7f4e1 --- /dev/null +++ b/.github/actions/ensure_backporting/action.yml @@ -0,0 +1,26 @@ +name: ensure backport labels +description: | + A Github action to ensure that a Pull request contains backport labels. + +inputs: + token: + description: The Github token to use to perform operations. + required: true + +runs: + using: composite + steps: + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.11" + + - name: Install required python libraries + run: pip install -U requests + shell: bash + + - name: Run + run: python ${{ github.action_path }}/add_labels.py --repository ${{ github.repository }} --issue-id ${{ github.event.number }} + shell: bash + env: + GITHUB_TOKEN: ${{ inputs.token }} diff --git a/.github/actions/ensure_backporting/add_labels.py b/.github/actions/ensure_backporting/add_labels.py new file mode 100644 index 0000000..9a1f035 --- /dev/null +++ b/.github/actions/ensure_backporting/add_labels.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 +"""Executable used to add backport labels to Github issues.""" + +import argparse +import os +import re +import sys + +import requests + + +class RequestError(Exception): + """An exception class.""" + + +def main() -> None: + """Perform operations. + + :raises RequestError: In case an error occurs when calling requests API. + """ + parser = argparse.ArgumentParser(description="Ensure an issue contains the backport labels.") + parser.add_argument("--issue-id", type=int, required=True, help="The pull request number.") + parser.add_argument( + "--repository", + type=str, + required=True, + help="The Github project name, e.g: 'ansible-collections/amazon.aws'.", + ) + args = parser.parse_args(sys.argv[1:]) + # Get list of labels attached to the pull requests + headers = { + "Accept": "application/vnd.github+json", + "Authorization": f"Bearer {os.environ.get('GITHUB_TOKEN')}", + "X-GitHub-Api-Version": "2022-11-28", + } + + # Get PR Labels + response = requests.get( + f"https://api.github.com/repos/{args.repository}/issues/{args.issue_id}/labels", + headers=headers, + timeout=30, + ) + if not response.ok: + raise RequestError(response.reason) + issue_backport_labels = [ + i["name"] for i in response.json() if re.match("^backport-[0-9]*$", i["name"]) + ] + + # Get Repository Labels + response = requests.get( + f"https://api.github.com/repos/{args.repository}/labels", + headers=headers, + timeout=30, + ) + if not response.ok: + raise RequestError(response.reason) + repository_backport_labels = [ + i["name"] for i in response.json() if re.match("^backport-[0-9]*$", i["name"]) + ] + + labels_to_add = list(set(repository_backport_labels) - set(issue_backport_labels)) + if labels_to_add: + data = {"labels": labels_to_add} + response = requests.post( + f"https://api.github.com/repos/{args.repository}/issues/{args.issue_id}/labels", + headers=headers, + json=data, + timeout=30, + ) + if not response.ok: + raise RequestError(response.reason) + + +if __name__ == "__main__": + main() diff --git a/.github/workflows/ensure_backporting.yml b/.github/workflows/ensure_backporting.yml new file mode 100644 index 0000000..ce07111 --- /dev/null +++ b/.github/workflows/ensure_backporting.yml @@ -0,0 +1,15 @@ +name: Ensure Backporting +on: + workflow_call: + secrets: + GH_TOKEN: + required: false + +jobs: + labelling: + runs-on: ubuntu-latest + if: ${{ contains(github.event.pull_request.labels.*.name, 'mergeit') && !contains(github.event.pull_request.labels.*.name, 'do_not_backport') }} + steps: + - uses: ansible-network/github_actions/.github/actions/ensure_backporting@main + with: + token: ${{ secrets.GH_TOKEN || secrets.GITHUB_TOKEN }}