mirror of
https://github.com/TeamPiped/Piped-Kubernetes.git
synced 2025-01-06 01:20:36 +05:30
CI: Add Renovate config and chart changelog + linting.
This commit is contained in:
parent
1bb362f205
commit
b4648026cf
2
.github/CODEOWNERS
vendored
Normal file
2
.github/CODEOWNERS
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners
|
||||||
|
* @samip5
|
104
.github/renovate.json5
vendored
Normal file
104
.github/renovate.json5
vendored
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
{
|
||||||
|
"enabled": true,
|
||||||
|
"dependencyDashboard": true,
|
||||||
|
"dependencyDashboardTitle": "Renovate Dashboard",
|
||||||
|
"assigneesFromCodeOwners": true,
|
||||||
|
"reviewersFromCodeOwners": true,
|
||||||
|
"suppressNotifications": ["prIgnoreNotification"],
|
||||||
|
"prConcurrentLimit": 5,
|
||||||
|
"helm-values": {
|
||||||
|
"enabled": false
|
||||||
|
},
|
||||||
|
"helmv3": {
|
||||||
|
"fileMatch": ["charts/.+/Chart\\.yaml$"]
|
||||||
|
},
|
||||||
|
"packageRules": [
|
||||||
|
// Setup datasources
|
||||||
|
{
|
||||||
|
"matchDatasources": ["helm"],
|
||||||
|
"commitMessageTopic": "Helm chart {{depName}}",
|
||||||
|
"separateMinorPatch": true
|
||||||
|
},
|
||||||
|
// Custom version schemes
|
||||||
|
{
|
||||||
|
"matchDatasources": ["github-tags"],
|
||||||
|
"matchPackageNames": ["potiuk/get-workflow-origin"],
|
||||||
|
"versioning": "regex:^v(?<major>\\d+)_(?<minor>\\d+)(_(?<patch>\\d+))?$"
|
||||||
|
},
|
||||||
|
///
|
||||||
|
/// Automatically update minor/patch Github Actions
|
||||||
|
///
|
||||||
|
{
|
||||||
|
"matchManagers": ["github-actions"],
|
||||||
|
"automerge": true,
|
||||||
|
"automergeType": "branch",
|
||||||
|
"matchUpdateTypes": ["minor", "patch"]
|
||||||
|
},
|
||||||
|
//
|
||||||
|
// Common library dep
|
||||||
|
//
|
||||||
|
{
|
||||||
|
"matchDatasources": ["helm"],
|
||||||
|
"commitMessagePrefix": "[{{{parentDir}}}]",
|
||||||
|
"branchTopic": "{{{parentDir}}}-{{{depNameSanitized}}}-{{{newMajor}}}{{#if isPatch}}.{{{newMinor}}}{{/if}}.x{{#if isLockfileUpdate}}-lockfile{{/if}}",
|
||||||
|
"updateTypes": ["major"],
|
||||||
|
"bumpVersion": "major",
|
||||||
|
"labels": ["type/major"],
|
||||||
|
"packageNames": ["common"],
|
||||||
|
"groupName": ["common library major"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matchDatasources": ["helm"],
|
||||||
|
"updateTypes": ["minor"],
|
||||||
|
"bumpVersion": "minor",
|
||||||
|
"labels": ["type/minor"],
|
||||||
|
"packageNames": ["common"],
|
||||||
|
"groupName": ["common library minor"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matchDatasources": ["helm"],
|
||||||
|
"updateTypes": ["patch"],
|
||||||
|
"bumpVersion": "patch",
|
||||||
|
"labels": ["type/patch"],
|
||||||
|
"packageNames": ["common"],
|
||||||
|
"groupName": ["common library patch"]
|
||||||
|
},
|
||||||
|
//
|
||||||
|
// Other external chart deps
|
||||||
|
//
|
||||||
|
{
|
||||||
|
"matchDatasources": ["helm"],
|
||||||
|
"commitMessagePrefix": "[{{{parentDir}}}]",
|
||||||
|
"branchTopic": "{{{parentDir}}}-{{{depNameSanitized}}}-{{{newMajor}}}{{#if isPatch}}.{{{newMinor}}}{{/if}}.x{{#if isLockfileUpdate}}-lockfile{{/if}}",
|
||||||
|
"updateTypes": ["major"],
|
||||||
|
"bumpVersion": "major",
|
||||||
|
"labels": ["type/major"],
|
||||||
|
"excludePackageNames": ["common"],
|
||||||
|
"schedule": [
|
||||||
|
"every 3 months on the first day of the month"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matchDatasources": ["helm"],
|
||||||
|
"updateTypes": ["minor"],
|
||||||
|
"bumpVersion": "minor",
|
||||||
|
"labels": ["type/minor"],
|
||||||
|
"excludePackageNames": ["common"],
|
||||||
|
"groupName": ["external dependency minor"],
|
||||||
|
"schedule": [
|
||||||
|
"every 2 months on the first day of the month"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matchDatasources": ["helm"],
|
||||||
|
"updateTypes": ["patch"],
|
||||||
|
"bumpVersion": "patch",
|
||||||
|
"labels": ["type/patch"],
|
||||||
|
"excludePackageNames": ["common"],
|
||||||
|
"groupName": ["external dependency patch"],
|
||||||
|
"schedule": [
|
||||||
|
"every 1 months on the first day of the month"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
49
.github/scripts/check-releasenotes.sh
vendored
Executable file
49
.github/scripts/check-releasenotes.sh
vendored
Executable file
@ -0,0 +1,49 @@
|
|||||||
|
#!/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
|
||||||
|
}
|
||||||
|
|
||||||
|
# Absolute path of repository
|
||||||
|
repository=$(git rev-parse --show-toplevel)
|
||||||
|
|
||||||
|
# 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\n 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
|
||||||
|
|
||||||
|
CURRENT=$(cat Chart.yaml | yq e '.annotations."artifacthub.io/changes"' -P -)
|
||||||
|
|
||||||
|
if [ "$CURRENT" == "" ] || [ "$CURRENT" == "null" ]; then
|
||||||
|
printf >&2 "Changelog annotation has not been set in %s!\n" "$chart_file"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
DEFAULT_BRANCH=$(git remote show origin | awk '/HEAD branch/ {print $NF}')
|
||||||
|
ORIGINAL=$(git show origin/$DEFAULT_BRANCH:./Chart.yaml | yq e '.annotations."artifacthub.io/changes"' -P -)
|
||||||
|
|
||||||
|
if [ "$CURRENT" == "$ORIGINAL" ]; then
|
||||||
|
printf >&2 "Changelog annotation has not been updated in %s!\n" "$chart_file"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
printf >&2 "%s\n" "No chart folder has been specified."
|
||||||
|
exit 1
|
||||||
|
fi
|
153
.github/scripts/renovate-releasenotes.py
vendored
Executable file
153
.github/scripts/renovate-releasenotes.py
vendored
Executable file
@ -0,0 +1,153 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import typer
|
||||||
|
|
||||||
|
from git import Repo
|
||||||
|
from loguru import logger
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from ruamel.yaml import YAML
|
||||||
|
from ruamel.yaml.comments import CommentedMap
|
||||||
|
from ruamel.yaml.scalarstring import LiteralScalarString
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
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="<level>{message}</level>",
|
||||||
|
level=log_level,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.command()
|
||||||
|
def main(
|
||||||
|
chart_folders: List[Path] = typer.Argument(
|
||||||
|
..., help="Folders containing the chart to process"),
|
||||||
|
check_branch: str = typer.Option(
|
||||||
|
None, help="The branch to compare against."),
|
||||||
|
chart_base_folder: Path = typer.Option(
|
||||||
|
"charts", help="The base folder where the charts reside."),
|
||||||
|
debug: bool = False,
|
||||||
|
):
|
||||||
|
_setup_logging(debug)
|
||||||
|
|
||||||
|
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
|
||||||
|
)
|
||||||
|
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
|
||||||
|
)
|
||||||
|
|
||||||
|
if not branch:
|
||||||
|
logger.error(
|
||||||
|
f"Could not find branch {check_branch} to compare against.")
|
||||||
|
raise typer.Exit(1)
|
||||||
|
|
||||||
|
logger.info(f"Comparing against branch {branch}")
|
||||||
|
|
||||||
|
for chart_folder in chart_folders:
|
||||||
|
chart_folder = chart_base_folder.joinpath(chart_folder)
|
||||||
|
if not chart_folder.is_dir():
|
||||||
|
logger.error(f"Could not find folder {str(chart_folder)}")
|
||||||
|
raise typer.Exit(1)
|
||||||
|
|
||||||
|
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(1)
|
||||||
|
|
||||||
|
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
|
||||||
|
yaml.width = 4096
|
||||||
|
|
||||||
|
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
|
||||||
|
)
|
||||||
|
|
||||||
|
add_annotation = False
|
||||||
|
if old_dep:
|
||||||
|
if dependency["version"] != old_dep["version"]:
|
||||||
|
add_annotation = True
|
||||||
|
else:
|
||||||
|
add_annotation = True
|
||||||
|
|
||||||
|
if add_annotation:
|
||||||
|
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']}"
|
||||||
|
})
|
||||||
|
|
||||||
|
if annotations:
|
||||||
|
annotations = YAML(typ=['rt', 'string']
|
||||||
|
).dump_to_string(annotations)
|
||||||
|
|
||||||
|
if not "annotations" in new_chart_metadata:
|
||||||
|
new_chart_metadata["annotations"] = CommentedMap()
|
||||||
|
|
||||||
|
new_chart_metadata["annotations"]["artifacthub.io/changes"] = LiteralScalarString(
|
||||||
|
annotations)
|
||||||
|
yaml.dump(new_chart_metadata, chart_metadata_file)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app()
|
5
.github/scripts/requirements.txt
vendored
Normal file
5
.github/scripts/requirements.txt
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
GitPython==3.1.31
|
||||||
|
loguru==0.6.0
|
||||||
|
ruamel.yaml==0.17.21
|
||||||
|
ruamel.yaml.string==0.1.0
|
||||||
|
typer==0.7.0
|
87
.github/workflows/charts-changelog.yaml
vendored
Normal file
87
.github/workflows/charts-changelog.yaml
vendored
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
name: "Charts: Update README"
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
modifiedCharts:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
isRenovatePR:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
outputs:
|
||||||
|
commitHash:
|
||||||
|
description: "The most recent commit hash at the end of this workflow"
|
||||||
|
value: ${{ jobs.generate-changelog.outputs.commitHash }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
validate-changelog:
|
||||||
|
name: Validate changelog
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Check changelog annotations
|
||||||
|
if: inputs.isRenovatePR != 'true'
|
||||||
|
run: |
|
||||||
|
IN_CHARTS=(${{ inputs.modifiedCharts }})
|
||||||
|
CHARTS=($(python -c 'import sys;a=sys.argv[1].translate(str.maketrans("","","[]")).split(",");print(" ".join(a))' $IN_CHARTS))
|
||||||
|
for i in "${CHARTS[@]}"
|
||||||
|
do
|
||||||
|
IFS='/' read -r -a chart_parts <<< "$i"
|
||||||
|
./.github/scripts/check-releasenotes.sh "${chart_parts[0]}/${chart_parts[1]}"
|
||||||
|
echo ""
|
||||||
|
done
|
||||||
|
generate-changelog:
|
||||||
|
name: Generate changelog annotations
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs:
|
||||||
|
- validate-changelog
|
||||||
|
outputs:
|
||||||
|
commitHash: ${{ steps.save-commit-hash.outputs.commit_hash }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Setup Python
|
||||||
|
uses: actions/setup-python@v4
|
||||||
|
with:
|
||||||
|
python-version: "3.10"
|
||||||
|
|
||||||
|
- name: Annotate Charts.yaml for Renovate PR's
|
||||||
|
if: inputs.isRenovatePR == 'true'
|
||||||
|
env:
|
||||||
|
CHECK_BRANCH: "origin/${{ github.event.repository.default_branch }}"
|
||||||
|
run: |
|
||||||
|
pip install -r ./.github/scripts/requirements.txt
|
||||||
|
IN_CHARTS=(${{ inputs.modifiedCharts }})
|
||||||
|
CHARTS=($(python -c 'import sys;a=sys.argv[1].translate(str.maketrans("","","[]")).split(",");print(" ".join(a))' $IN_CHARTS))
|
||||||
|
for i in "${CHARTS[@]}"
|
||||||
|
do
|
||||||
|
IFS='/' read -r -a chart_parts <<< "$i"
|
||||||
|
./.github/scripts/renovate-releasenotes.py --debug --check-branch "$CHECK_BRANCH" "${chart_parts[0]}/${chart_parts[1]}"
|
||||||
|
echo ""
|
||||||
|
done
|
||||||
|
- name: Create commit
|
||||||
|
id: create-commit
|
||||||
|
if: inputs.isRenovatePR == 'true'
|
||||||
|
uses: stefanzweifel/git-auto-commit-action@v4
|
||||||
|
with:
|
||||||
|
file_pattern: charts/
|
||||||
|
commit_message: "chore: Auto-update chart metadata"
|
||||||
|
commit_user_name: ${{ github.actor }}
|
||||||
|
commit_user_email: ${{ github.actor }}@users.noreply.github.com
|
||||||
|
|
||||||
|
- name: Save commit hash
|
||||||
|
id: save-commit-hash
|
||||||
|
run: |
|
||||||
|
if [ "${{ steps.create-commit.outputs.changes_detected || 'unknown' }}" == "true" ]; then
|
||||||
|
echo '::set-output name=commit_hash::${{ steps.create-commit.outputs.commit_hash }}'
|
||||||
|
else
|
||||||
|
echo "::set-output name=commit_hash::${GITHUB_SHA}"
|
||||||
|
fi
|
75
.github/workflows/charts-lint.yaml
vendored
Normal file
75
.github/workflows/charts-lint.yaml
vendored
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
name: "Charts: Lint"
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
checkoutCommit:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
isRenovatePR:
|
||||||
|
required: true
|
||||||
|
default: 'false'
|
||||||
|
type: string
|
||||||
|
chartsToLint:
|
||||||
|
description: >
|
||||||
|
A JSON encoded array of charts to lint
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
|
||||||
|
env:
|
||||||
|
HELM_VERSION: 3.10.2
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lint-chart:
|
||||||
|
if: ${{ inputs.chartsToLint != '[]' }}
|
||||||
|
name: Lint chart
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
chart: ${{ fromJSON(inputs.chartsToLint) }}
|
||||||
|
fail-fast: false
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
ref: ${{ inputs.checkoutCommit }}
|
||||||
|
|
||||||
|
- name: Verify chart version
|
||||||
|
uses: bjw-s/helm-charts-actions/verify-chart-version@main
|
||||||
|
id: verify-chart-version
|
||||||
|
with:
|
||||||
|
chart: "charts/${{ matrix.chart }}"
|
||||||
|
|
||||||
|
- name: Verify chart changelog
|
||||||
|
uses: bjw-s/helm-charts-actions/verify-chart-changelog@main
|
||||||
|
if: inputs.isRenovatePR != 'true'
|
||||||
|
id: verify-chart-changelog
|
||||||
|
with:
|
||||||
|
chart: "charts/${{ matrix.chart }}"
|
||||||
|
|
||||||
|
- name: Install Kubernetes tools
|
||||||
|
uses: yokawasa/action-setup-kube-tools@v0.9.3
|
||||||
|
with:
|
||||||
|
setup-tools: |
|
||||||
|
helmv3
|
||||||
|
helm: "${{ env.HELM_VERSION }}"
|
||||||
|
|
||||||
|
- name: Set up chart-testing
|
||||||
|
uses: helm/chart-testing-action@v2.4.0
|
||||||
|
|
||||||
|
- name: Run chart-testing (install)
|
||||||
|
run: ct lint --config .ci/ct/ct.yaml --charts "charts/${{ matrix.chart }}"
|
||||||
|
|
||||||
|
# Summarize matrix https://github.community/t/status-check-for-a-matrix-jobs/127354/7
|
||||||
|
lint_success:
|
||||||
|
needs:
|
||||||
|
- lint-chart
|
||||||
|
if: |
|
||||||
|
always()
|
||||||
|
name: Lint successful
|
||||||
|
runs-on: ["self-hosted", "X64"]
|
||||||
|
steps:
|
||||||
|
- name: Check lint matrix status
|
||||||
|
if: ${{ (inputs.chartsToLint != '' && inputs.chartsToLint != '[]') && (needs.lint-chart.result != 'success') }}
|
||||||
|
run: exit 1
|
Loading…
Reference in New Issue
Block a user