From aaedd037d24a2391d82ec4b8eec0ba76eeb406e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=E1=B4=87=CA=80=C9=B4=E1=B4=85=20S=E1=B4=84=CA=9C?= =?UTF-8?q?=E1=B4=8F=CA=80=C9=A2=E1=B4=87=CA=80s?= Date: Sat, 30 Apr 2022 20:00:09 +0200 Subject: [PATCH] ci: Initial version of Python releasenotes script --- .github/scripts/renovate-releasenotes.py | 131 +++++++++++++++++++++++ .github/scripts/renovate-releasenotes.sh | 52 --------- .github/scripts/requirements.txt | 5 + .github/workflows/charts-changelog.yaml | 14 +-- 4 files changed, 141 insertions(+), 61 deletions(-) create mode 100755 .github/scripts/renovate-releasenotes.py delete mode 100755 .github/scripts/renovate-releasenotes.sh create mode 100644 .github/scripts/requirements.txt diff --git a/.github/scripts/renovate-releasenotes.py b/.github/scripts/renovate-releasenotes.py new file mode 100755 index 00000000..f8a42757 --- /dev/null +++ b/.github/scripts/renovate-releasenotes.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python + +import sys +import typer + +from git import Repo +from loguru import logger +from pathlib import Path + +from ruamel.yaml import YAML +from ruamel.yaml.scalarstring import LiteralScalarString + +app = typer.Typer(add_completion=False) + + +def _setup_logging(debug): + """ + Setup the log formatter for this script + """ + + log_level = "INFO" + if debug: + log_level = "DEBUG" + + logger.remove() + logger.add( + sys.stdout, + colorize=True, + format="{message}", + level=log_level, + ) + + +@app.command() +def main( + chart_folder: Path = typer.Argument( + ..., help="Folder containing the chart to process"), + check_branch: str = typer.Option( + None, help="The branch to compare against."), + debug: bool = False, +): + _setup_logging(debug) + + if not chart_folder.is_dir(): + logger.error(f"Could not find folder {str(chart_folder)}") + raise typer.Exit() + + chart_metadata_file = chart_folder.joinpath('Chart.yaml') + + if not chart_metadata_file.is_file(): + logger.error(f"Could not find file {str(chart_metadata_file)}") + raise typer.Exit() + + git_repository = Repo(search_parent_directories=True) + + if check_branch: + logger.info(f"Trying to find branch {check_branch}...") + branch = next( + (ref for ref in git_repository.remotes.origin.refs if ref.name == check_branch), + None + ) + + if not branch: + logger.error(f"Could not find branch {check_branch}") + raise typer.Exit() + + else: + logger.info(f"Trying to determine default branch...") + branch = next( + (ref for ref in git_repository.remotes.origin.refs if ref.name == "origin/HEAD"), + None + ) + + logger.info(f"Comparing against branch {branch}") + + logger.info(f"Updating changelog annotation for chart {chart_folder}") + + yaml = YAML(typ=['rt', 'string']) + yaml.indent(mapping=2, sequence=4, offset=2) + yaml.explicit_start = True + yaml.preserve_quotes = True + + old_chart_metadata = yaml.load( + git_repository.git.show(f"{branch}:{chart_metadata_file}") + ) + new_chart_metadata = yaml.load(chart_metadata_file.read_text()) + + try: + old_chart_dependencies = old_chart_metadata["dependencies"] + except KeyError: + old_chart_dependencies = [] + + try: + new_chart_dependencies = new_chart_metadata["dependencies"] + except KeyError: + new_chart_dependencies = [] + + annotations = [] + for dependency in new_chart_dependencies: + old_dep = None + if "alias" in dependency.keys(): + old_dep = next( + (old_dep for old_dep in old_chart_dependencies if "alias" in old_dep.keys() and old_dep["alias"] == dependency["alias"]), + None + ) + else: + old_dep = next( + (old_dep for old_dep in old_chart_dependencies if old_dep["name"] == dependency["name"]), + None + ) + + if old_dep and dependency["version"] != old_dep["version"]: + if "alias" in dependency.keys(): + annotations.append({ + "kind": "changed", + "description": f"Upgraded {dependency['name']} chart dependency to version {dependency['version']} for alias '{dependency['alias']}'" + }) + else: + annotations.append({ + "kind": "changed", + "description": f"Upgraded {dependency['name']} chart dependency to version {dependency['version']}" + }) + + annotations = YAML(typ=['rt', 'string']).dump_to_string(annotations) + + if annotations: + new_chart_metadata["annotations"]["artifacthub.io/changes"] = LiteralScalarString(annotations) + yaml.dump(new_chart_metadata, chart_metadata_file) + +if __name__ == "__main__": + app() diff --git a/.github/scripts/renovate-releasenotes.sh b/.github/scripts/renovate-releasenotes.sh deleted file mode 100755 index 0c293fd2..00000000 --- a/.github/scripts/renovate-releasenotes.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env bash - -set -e - -# Check if release notes have been changed -# Usage ./check-releasenotes.sh path - -# require yq -command -v yq >/dev/null 2>&1 || { - printf >&2 "%s\n" "yq (https://github.com/mikefarah/yq) is not installed. Aborting." - exit 1 -} - -# Allow for a specific chart to be passed in as a argument -if [ $# -ge 1 ] && [ -n "$1" ]; then - root="$1" - chart_file="${1}/Chart.yaml" - if [ ! -f "$chart_file" ]; then - printf >&2 "File %s does not exist.\n" "${chart_file}" - exit 1 - fi - cd "${root}" - - if [ -z "$DEFAULT_BRANCH" ]; then - DEFAULT_BRANCH=$(git remote show origin | awk '/HEAD branch/ {print $NF}') - fi - - printf "Updating changelog annotation for chart %s\n" "$root" - - # Loop over all dependencies in current chart version - NEW_DEPENDENCIES=() - while IFS='' read -r line; do NEW_DEPENDENCIES+=("$line"); done < <(yq e '.dependencies[].name' -P Chart.yaml | LC_ALL=C sort) - OLD_DEPENDENCIES=$(git show "origin/$DEFAULT_BRANCH:./Chart.yaml" | yq e '.dependencies[].name' -P - | LC_ALL=C sort) - - tmpfile=$(mktemp) - trap 'rm -f "$tmpfile"' EXIT - - for DEP_NAME in "${NEW_DEPENDENCIES[@]}" - do - NEW_VERSION=$(yq e ".dependencies[] | select(.name == \"$DEP_NAME\") | .version" -P Chart.yaml) - OLD_VERSION=$(git show "origin/$DEFAULT_BRANCH:./Chart.yaml" | yq e ".dependencies[] | select(.name == \"$DEP_NAME\") | .version" -P -) - if [ "${NEW_VERSION}" != "${OLD_VERSION}" ]; then - printf "%s\n" "- kind: changed" >> "${tmpfile}" - printf " description: Upgraded \`%s\` chart dependency to version \`%s\`.\n" "${DEP_NAME}" "${NEW_VERSION}" >> "${tmpfile}" - fi - done - - yq eval-all --inplace 'select(fileIndex == 0).annotations."artifacthub.io/changes" = (select(fileIndex == 1) | to_yaml) | select(fileIndex==0)' Chart.yaml "${tmpfile}" -else - printf >&2 "%s\n" "No chart folder has been specified." - exit 1 -fi diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt new file mode 100644 index 00000000..ba430941 --- /dev/null +++ b/.github/scripts/requirements.txt @@ -0,0 +1,5 @@ +GitPython==3.1.27 +loguru==0.6.0 +ruamel.yaml==0.17.21 +ruamel.yaml.string==0.1.0 +typer==0.4.1 diff --git a/.github/workflows/charts-changelog.yaml b/.github/workflows/charts-changelog.yaml index 75ca2df0..eb922580 100644 --- a/.github/workflows/charts-changelog.yaml +++ b/.github/workflows/charts-changelog.yaml @@ -48,24 +48,20 @@ jobs: with: fetch-depth: 0 - - name: Install Kubernetes tools - if: inputs.isRenovatePR == 'true' - uses: yokawasa/action-setup-kube-tools@v0.8.0 - with: - setup-tools: | - yq - yq: "4.20.1" + - name: Setup Python + uses: actions/setup-python@v3.1.2 - name: Annotate Charts.yaml for Renovate PR's if: inputs.isRenovatePR == 'true' env: - DEFAULT_BRANCH: "${{ github.event.repository.default_branch }}" + CHECK_BRANCH: "origin/${{ github.event.repository.default_branch }}" run: | + pip install -r ./.github/scripts/requirements.txt CHARTS=(${{ inputs.modifiedCharts }}) for i in "${CHARTS[@]}" do IFS='/' read -r -a chart_parts <<< "$i" - ./.github/scripts/renovate-releasenotes.sh "charts/${chart_parts[0]}/${chart_parts[1]}" + ./.github/scripts/renovate-releasenotes.py --check-branch "$CHECK_BRANCH" "charts/${chart_parts[0]}/${chart_parts[1]}" echo "" done