diff --git a/.github/actions/collect-changes/action.yaml b/.github/actions/collect-changes/action.yaml new file mode 100644 index 0000000..bc8d465 --- /dev/null +++ b/.github/actions/collect-changes/action.yaml @@ -0,0 +1,45 @@ +name: "Collect changes" +description: "Collects and stores changed files/charts" + +outputs: + changesDetected: + description: "Whether or not changes to charts have been detected" + value: ${{ steps.filter.outputs.addedOrModified }} + addedOrModifiedFiles: + description: "A list of the files changed" + value: ${{ steps.filter.outputs.addedOrModified_files }} + addedOrModifiedCharts: + description: "A list of the charts changed" + value: ${{ steps.filter-charts.outputs.addedOrModified }} + +runs: + using: "composite" + steps: + - name: Collect changed files + uses: dorny/paths-filter@v3 + id: filter + with: + list-files: shell + filters: | + addedOrModified: + - added|modified: 'charts/*/**' + + - name: Collect changed charts + if: | + steps.filter.outputs.addedOrModified == 'true' + id: filter-charts + shell: bash + run: | + CHARTS=() + PATHS=(${{ steps.filter.outputs.addedOrModified_files }}) + # Get only the chart paths + for CHARTPATH in "${PATHS[@]}" + do + IFS='/' read -r -a path_parts <<< "${CHARTPATH}" + CHARTS+=("${path_parts[1]}/${path_parts[2]}") + done + + # Remove duplicates + CHARTS=( `printf "%s\n" "${CHARTS[@]}" | sort -u` ) + # Set output to changed charts + printf "::set-output name=addedOrModified::%s\n" "${CHARTS[*]}" \ No newline at end of file diff --git a/.github/actions/label-from-status/action.yaml b/.github/actions/label-from-status/action.yaml new file mode 100644 index 0000000..d8f3103 --- /dev/null +++ b/.github/actions/label-from-status/action.yaml @@ -0,0 +1,48 @@ +name: "Set issue labels based on status" +description: "Sets / removes issue labels based on CI job status" +inputs: + token: + required: true + description: "The Github API token to use" + issue-number: + required: true + description: "The issue to label" + prefix: + required: true + description: "The label prefix (e.g. lint, install)" + job-status: + required: true + description: "The status of the CI job" + remove-on-skipped: + required: false + default: "false" + description: "Remove the label if the job was skipped" + +runs: + using: "composite" + steps: + - name: Label success + uses: andymckay/labeler@1.0.4 + if: ${{ inputs.job-status == 'success' }} + with: + repo-token: ${{ inputs.token }} + issue-number: ${{ inputs.issue-number }} + add-labels: "${{ inputs.prefix }}:ok" + remove-labels: "${{ inputs.prefix }}:failed" + + - name: Label failure + uses: andymckay/labeler@1.0.4 + if: ${{ inputs.job-status == 'failure' }} + with: + repo-token: ${{ inputs.token }} + issue-number: ${{ inputs.issue-number }} + add-labels: "${{ inputs.prefix }}:failed" + remove-labels: "${{ inputs.prefix }}:ok" + + - name: Remove label + uses: andymckay/labeler@1.0.4 + if: ${{ (inputs.job-status == 'skipped') && (inputs.remove-on-skipped == 'true') }} + with: + repo-token: ${{ inputs.token }} + issue-number: ${{ inputs.issue-number }} + remove-labels: "${{ inputs.prefix }}:ok, ${{ inputs.prefix }}:failed" \ No newline at end of file diff --git a/.github/labels.yaml b/.github/labels.yaml new file mode 100644 index 0000000..61d05da --- /dev/null +++ b/.github/labels.yaml @@ -0,0 +1,111 @@ +--- +# CI Status +- name: "precommit:ok" + color: "0E8A16" + description: >- + CI status: pre-commit validation successful +- name: "precommit:failed" + color: "D93F0B" + description: >- + CI status: pre-commit validation failed +- name: "changelog:ok" + color: "0E8A16" + description: >- + CI status: changelog validation successful +- name: "changelog:failed" + color: "D93F0B" + description: >- + CI status: changelog validation failed +- name: "lint:ok" + color: "0E8A16" + description: >- + CI status: linting successful +- name: "lint:failed" + color: "D93F0B" + description: >- + CI status: linting failed +- name: "install:ok" + color: "0E8A16" + description: >- + CI status: install successful +- name: "install:failed" + color: "D93F0B" + description: >- + CI status: install failed + +# Semantic Type +- name: type/patch + color: "FFEC19" +- name: type/minor + color: "FF9800" +- name: type/major + color: "F6412D" + +# Renovate +- name: renovate/container + color: "ffc300" +- name: renovate/helm + color: "ffc300" + +# Size +- name: size/XS + color: "009900" + description: >- + Categorises a PR that changes 0-9 lines, ignoring generated files. +- name: size/S + color: "77bb00" + description: >- + Categorises a PR that changes 10-29 lines, ignoring generated files. +- name: size/M + color: "eebb00" + description: >- + Categorises a PR that changes 30-99 lines, ignoring generated files. +- name: size/L + color: "ee9900" + description: >- + Categorises a PR that changes 100-499 lines, ignoring generated files. +- name: size/XL + color: "ee5500" + description: >- + Categorises a PR that changes 500-999 lines, ignoring generated files. +- name: size/XXL + color: "ee0000" + description: >- + Categorises a PR that changes 1000+ lines, ignoring generated files. + +# Issue categories +- name: documentation + color: "0075ca" +- name: bug + color: "B60205" +- name: enhancement + color: "a2eeef" +- name: "help wanted" + color: "008672" +- name: wontfix + color: "ffffff" +- name: "support" + color: ffffff +- name: "incomplete-template" + color: ffffff + +- name: "new-chart" + color: "C2E0C6" + description: >- + Categorises a PR or issue that references a new Helm chart. +- name: do-not-merge + color: "ee0701" + description: >- + Categorises a PR that should not be merged in the current state. +- name: "incomplete-docs" + color: B72175 + description: >- + Categorises a PR for which the documentation has not been updated completely. +- name: keepalive + color: "4D28C4" + description: >- + Categorises a PR or issue that should not be marked as stale. +- name: stale + color: "D4C5F9" + description: >- + Categorises a PR or issue that has not been active for a specified time. \ No newline at end of file diff --git a/.github/renovate.json5 b/.github/renovate.json5 new file mode 100644 index 0000000..c099b65 --- /dev/null +++ b/.github/renovate.json5 @@ -0,0 +1,4 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": ["github>MichaelSp/MichaelSp//.github/renovate.json5"], +} \ No newline at end of file diff --git a/.github/scripts/check-releasenotes.sh b/.github/scripts/check-releasenotes.sh new file mode 100755 index 0000000..089a169 --- /dev/null +++ b/.github/scripts/check-releasenotes.sh @@ -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 diff --git a/.github/scripts/renovate-releasenotes.py b/.github/scripts/renovate-releasenotes.py new file mode 100755 index 0000000..058d907 --- /dev/null +++ b/.github/scripts/renovate-releasenotes.py @@ -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="{message}", + 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() diff --git a/.github/workflows/charts-changelog.yaml b/.github/workflows/charts-changelog.yaml new file mode 100644 index 0000000..81f816a --- /dev/null +++ b/.github/workflows/charts-changelog.yaml @@ -0,0 +1,81 @@ +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@v4 + with: + fetch-depth: 0 + + - name: Check changelog annotations + if: inputs.isRenovatePR != 'true' + run: | + CHARTS=(${{ inputs.modifiedCharts }}) + for i in "${CHARTS[@]}" + do + IFS='/' read -r -a chart_parts <<< "$i" + ./.github/scripts/check-releasenotes.sh "charts/${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@v4 + with: + fetch-depth: 0 + + - name: Setup Python + uses: actions/setup-python@v5 + 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 + ./.github/scripts/renovate-releasenotes.py --check-branch "$CHECK_BRANCH" ${{ inputs.modifiedCharts }} + + - name: Create commit + id: create-commit + if: inputs.isRenovatePR == 'true' + uses: stefanzweifel/git-auto-commit-action@v5 + 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 diff --git a/.github/workflows/charts-lint.yaml b/.github/workflows/charts-lint.yaml new file mode 100644 index 0000000..ec3d8a2 --- /dev/null +++ b/.github/workflows/charts-lint.yaml @@ -0,0 +1,54 @@ +name: "Charts: Lint" + +on: + workflow_call: + inputs: + checkoutCommit: + required: true + type: string + chartChangesDetected: + required: true + type: string + +jobs: + lint: + name: Lint charts + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{ inputs.checkoutCommit }} + + - name: Install Kubernetes tools + uses: yokawasa/action-setup-kube-tools@v0.11.1 + with: + setup-tools: | + helmv3 + helm: "3.8.0" + + - uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Set up chart-testing + uses: helm/chart-testing-action@v2.6.1 + + - name: Collect changes + id: list-changed + if: inputs.chartChangesDetected == 'true' + run: | + EXCLUDED=$(yq eval -o=json '.excluded-charts // []' .github/ct-lint.yaml) + CHARTS=$(ct list-changed --config .github/ct-lint.yaml) + CHARTS_JSON=$(echo "${CHARTS}" | jq -R -s -c 'split("\n")[:-1]') + OUTPUT_JSON=$(echo "{\"excluded\": ${EXCLUDED}, \"all\": ${CHARTS_JSON}}" | jq -c '.all-.excluded') + echo ::set-output name=charts::${OUTPUT_JSON} + if [[ $(echo ${OUTPUT_JSON} | jq -c '. | length') -gt 0 ]]; then + echo "::set-output name=detected::true" + fi + + - name: Run chart-testing (lint) + id: lint + if: steps.list-changed.outputs.detected == 'true' + run: ct lint --config .github/ct-lint.yaml diff --git a/.github/workflows/charts-release.yaml b/.github/workflows/charts-release.yaml new file mode 100644 index 0000000..9933b65 --- /dev/null +++ b/.github/workflows/charts-release.yaml @@ -0,0 +1,37 @@ +name: "Charts: Release" + +concurrency: helm-release + +on: + workflow_dispatch: + push: + branches: + - main + paths: + - "charts/**" + +jobs: + release: + runs-on: ubuntu-22.04 + permissions: + contents: write + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Kubernetes tools + uses: yokawasa/action-setup-kube-tools@v0.11.1 + with: + setup-tools: | + helmv3 + + - name: Configure Git + run: | + git config user.name "$GITHUB_ACTOR" + git config user.email "$GITHUB_ACTOR@users.noreply.github.com" + + - name: Run chart-releaser + uses: helm/chart-releaser-action@v1.6.0 + env: + CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + CR_SKIP_EXISTING: "true" diff --git a/.github/workflows/charts-test.yaml b/.github/workflows/charts-test.yaml new file mode 100644 index 0000000..bb94051 --- /dev/null +++ b/.github/workflows/charts-test.yaml @@ -0,0 +1,116 @@ +name: "Charts: Test" + +on: + workflow_call: + inputs: + checkoutCommit: + required: true + type: string + chartChangesDetected: + required: true + type: string + +jobs: + unit-test: + name: Run unit tests + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{ inputs.checkoutCommit }} + + - uses: d3adb5/helm-unittest-action@v2 + with: + helm-version: v3.8.0 + github-token: ${{ secrets.GITHUB_TOKEN }} + - run: helm lint charts/* + + generate-install-matrix: + name: Generate matrix for install + runs-on: ubuntu-latest + outputs: + matrix: | + { + "chart": ${{ steps.list-changed.outputs.charts }} + } + detected: ${{ steps.list-changed.outputs.detected }} + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{ inputs.checkoutCommit }} + + - name: Set up chart-testing + uses: helm/chart-testing-action@v2.6.1 + + - name: Run chart-testing (list-changed) + id: list-changed + if: inputs.chartChangesDetected == 'true' + run: | + EXCLUDED=$(yq eval -o=json '.excluded-charts // []' .github/ct-install.yaml) + CHARTS=$(ct list-changed --config .github/ct-install.yaml) + CHARTS_JSON=$(echo "${CHARTS}" | jq -R -s -c 'split("\n")[:-1]') + OUTPUT_JSON=$(echo "{\"excluded\": ${EXCLUDED}, \"all\": ${CHARTS_JSON}}" | jq -c '.all-.excluded') + echo ::set-output name=charts::${OUTPUT_JSON} + if [[ $(echo ${OUTPUT_JSON} | jq -c '. | length') -gt 0 ]]; then + echo "::set-output name=detected::true" + fi + + install-charts: + needs: + - generate-install-matrix + if: needs.generate-install-matrix.outputs.detected == 'true' + name: Install charts + strategy: + matrix: ${{ fromJson(needs.generate-install-matrix.outputs.matrix) }} + fail-fast: false + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{ inputs.checkoutCommit }} + + - name: Install Kubernetes tools + uses: yokawasa/action-setup-kube-tools@v0.11.1 + with: + setup-tools: | + helmv3 + helm: "3.6.3" + + - uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Set up chart-testing + uses: helm/chart-testing-action@v2.6.1 + + - name: Create k3d cluster + uses: nolar/setup-k3d-k3s@v1 + with: + version: v1.19 + + - name: Remove node taints + run: | + kubectl taint --all=true nodes node.cloudprovider.kubernetes.io/uninitialized- || true + + - name: Run chart-testing (install) + run: ct install --config .github/ct-install.yaml --charts ${{ matrix.chart }} + + # Summarize matrix https://github.community/t/status-check-for-a-matrix-jobs/127354/7 + install_success: + needs: + - generate-install-matrix + - install-charts + if: | + always() + name: Install successful + runs-on: ubuntu-latest + steps: + - name: Check install matrix status + if: ${{ (needs.generate-install-matrix.outputs.detected == 'true') && (needs.install-charts.result != 'success') }} + run: exit 1 diff --git a/.github/workflows/meta-label-pr-ci-status.yaml b/.github/workflows/meta-label-pr-ci-status.yaml new file mode 100644 index 0000000..a451b8d --- /dev/null +++ b/.github/workflows/meta-label-pr-ci-status.yaml @@ -0,0 +1,111 @@ +--- +name: "Metadata: Label pull requests CI status" + +on: + workflow_run: + workflows: + - "Pull Request: Validate" + types: + - completed + +jobs: + label-ci-status: + name: Label CI status + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Download workflow artifact + uses: dawidd6/action-download-artifact@v3.1.4 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + workflow: pr-validate.yaml + run_id: ${{ github.event.workflow_run.id }} + name: pr_metadata + path: ./pr_metadata + + - name: Read the pr_number file + id: pr_num_reader + uses: juliangruber/read-file-action@v1.1.7 + with: + path: ./pr_metadata/pr_number.txt + + - name: "Get workflow job status" + uses: actions/github-script@v7 + id: get-workflow-jobs + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + # https://mhagemann.medium.com/the-ultimate-way-to-slugify-a-url-string-in-javascript-b8e4a0d849e1 + script: | + function slugify(string) { + const a = 'àáâäæãåāăąçćčđďèéêëēėęěğǵḧîïíīįìıİłḿñńǹňôöòóœøōõőṕŕřßśšşșťțûüùúūǘůűųẃẍÿýžźż·/_,:;' + const b = 'aaaaaaaaaacccddeeeeeeeegghiiiiiiiilmnnnnoooooooooprrsssssttuuuuuuuuuwxyyzzz------' + const p = new RegExp(a.split('').join('|'), 'g') + + return string.toString().toLowerCase() + .replace(/\s+/g, '-') // Replace spaces with - + .replace(p, c => b.charAt(a.indexOf(c))) // Replace special characters + .replace(/&/g, '-and-') // Replace & with 'and' + .replace(/[^\w\-]+/g, '') // Remove all non-word characters + .replace(/\-\-+/g, '-') // Replace multiple - with single - + .replace(/^-+/, '') // Trim - from start of text + .replace(/-+$/, '') // Trim - from end of text + } + + let result = new Object + + const wfJobs = await github.rest.actions.listJobsForWorkflowRun({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: context.payload.workflow_run.id, + }) + + for (const job of wfJobs.data.jobs) { + result[slugify(job.name)] = job.conclusion + } + + console.log(result) + return result + + - name: Label pre-commit status + uses: ./.github/actions/label-from-status + with: + token: ${{ secrets.GITHUB_TOKEN }} + issue-number: ${{ steps.pr_num_reader.outputs.content }} + prefix: precommit + job-status: |- + ${{ fromJSON(steps.get-workflow-jobs.outputs.result).pre-commit-check-run-pre-commit-checks || 'skipped' }} + remove-on-skipped: true + + - name: Label changelog status + uses: ./.github/actions/label-from-status + with: + token: ${{ secrets.GITHUB_TOKEN }} + issue-number: ${{ steps.pr_num_reader.outputs.content }} + prefix: changelog + job-status: |- + ${{ fromJSON(steps.get-workflow-jobs.outputs.result).charts-changelog-validate-changelog || 'skipped' }} + remove-on-skipped: true + + - name: Label chart lint status + uses: ./.github/actions/label-from-status + with: + token: ${{ secrets.GITHUB_TOKEN }} + issue-number: ${{ steps.pr_num_reader.outputs.content }} + prefix: lint + job-status: |- + ${{ fromJSON(steps.get-workflow-jobs.outputs.result).charts-lint-lint-charts || 'skipped' }} + remove-on-skipped: true + + - name: Label chart install status + uses: ./.github/actions/label-from-status + with: + token: ${{ secrets.GITHUB_TOKEN }} + issue-number: ${{ steps.pr_num_reader.outputs.content }} + prefix: install + job-status: |- + ${{ fromJSON(steps.get-workflow-jobs.outputs.result).charts-test-install-successful || 'skipped' }} + remove-on-skipped: true diff --git a/.github/workflows/metadata-label-commenter.yaml b/.github/workflows/metadata-label-commenter.yaml new file mode 100644 index 0000000..a8f3189 --- /dev/null +++ b/.github/workflows/metadata-label-commenter.yaml @@ -0,0 +1,28 @@ +--- +name: "Metadata: Label Commenter" + +on: + issues: + types: + - labeled + - unlabeled + pull_request_target: + types: + - labeled + - unlabeled + +permissions: + contents: read + issues: write + pull-requests: write + +jobs: + comment: + name: Label commenter + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + + - uses: peaceiris/actions-label-commenter@v1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/metadata-label-pr.yaml b/.github/workflows/metadata-label-pr.yaml new file mode 100644 index 0000000..3f9e00a --- /dev/null +++ b/.github/workflows/metadata-label-pr.yaml @@ -0,0 +1,35 @@ +--- +name: "Metadata: Label pull requests" + +on: + pull_request_target: + types: + - opened + - edited + - closed + - reopened + - ready_for_review + - synchronize + +jobs: + label-size: + name: Label Size + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + steps: + - name: Label Size + uses: pascalgn/size-label-action@v0.5.2 + env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + with: + sizes: > + { + "0": "XS", + "20": "S", + "50": "M", + "200": "L", + "800": "XL", + "2000": "XXL" + } diff --git a/.github/workflows/pr-metadata.yaml b/.github/workflows/pr-metadata.yaml new file mode 100644 index 0000000..7eb3ddc --- /dev/null +++ b/.github/workflows/pr-metadata.yaml @@ -0,0 +1,60 @@ +name: "Pull Request: Get metadata" + +on: + workflow_call: + outputs: + isRenovatePR: + description: "Is the PR coming from Renovate?" + value: ${{ jobs.pr-metadata.outputs.isRenovatePR }} + isFork: + description: "Is the PR coming from a forked repo?" + value: ${{ jobs.pr-metadata.outputs.isFork }} + addedOrModified: + description: "Does the PR contain any changes?" + value: ${{ jobs.pr-changes.outputs.addedOrModified }} + addedOrModifiedFiles: + description: "A list of the files changed in this PR" + value: ${{ jobs.pr-changes.outputs.addedOrModifiedFiles }} + addedOrModifiedCharts: + description: "A list of the charts changed in this PR" + value: ${{ jobs.pr-changes.outputs.addedOrModifiedCharts }} + +jobs: + pr-metadata: + name: Collect PR metadata + runs-on: ubuntu-latest + outputs: + isRenovatePR: ${{ startsWith(steps.branch-name.outputs.current_branch, 'renovate/') }} + isFork: ${{ github.event.pull_request.head.repo.full_name != github.repository }} + steps: + - name: Get branch name + id: branch-name + uses: tj-actions/branch-names@v6.5 + + - name: Save PR data to file + env: + PR_NUMBER: ${{ github.event.number }} + run: | + echo $PR_NUMBER > pr_number.txt + + - name: Store pr data in artifact + uses: actions/upload-artifact@v4 + with: + name: pr_metadata + path: ./pr_number.txt + retention-days: 5 + + pr-changes: + name: Collect PR changes + runs-on: ubuntu-latest + outputs: + addedOrModified: ${{ steps.collect-changes.outputs.changesDetected }} + addedOrModifiedFiles: ${{ steps.collect-changes.outputs.addedOrModifiedFiles }} + addedOrModifiedCharts: ${{ steps.collect-changes.outputs.addedOrModifiedCharts }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Collect changes + id: collect-changes + uses: ./.github/actions/collect-changes diff --git a/.github/workflows/pr-validate.yaml b/.github/workflows/pr-validate.yaml new file mode 100644 index 0000000..53c1e0c --- /dev/null +++ b/.github/workflows/pr-validate.yaml @@ -0,0 +1,54 @@ +name: "Pull Request: Validate" + +on: + pull_request: + branches: + - main + types: + - opened + - edited + - reopened + - ready_for_review + - synchronize + +concurrency: + group: ${{ github.head_ref }}-pr-validate + cancel-in-progress: true + +jobs: + pr-metadata: + uses: MichaelSp/kassio/.github/workflows/pr-metadata.yaml@main + + pre-commit-check: + uses: MichaelSp/kassio/.github/workflows/pre-commit-check.yaml@main + needs: + - pr-metadata + with: + modifiedFiles: ${{ needs.pr-metadata.outputs.addedOrModifiedFiles }} + + charts-changelog: + uses: MichaelSp/kassio/.github/workflows/charts-changelog.yaml@main + needs: + - pr-metadata + - pre-commit-check + with: + isRenovatePR: ${{ needs.pr-metadata.outputs.isRenovatePR }} + modifiedCharts: ${{ needs.pr-metadata.outputs.addedOrModifiedCharts }} + + charts-lint: + uses: MichaelSp/kassio/.github/workflows/charts-lint.yaml@main + needs: + - pr-metadata + - charts-changelog + with: + checkoutCommit: ${{ needs.charts-changelog.outputs.commitHash }} + chartChangesDetected: ${{ needs.pr-metadata.outputs.addedOrModified }} + + charts-test: + uses: MichaelSp/kassio/.github/workflows/charts-test.yaml@main + needs: + - pr-metadata + - charts-changelog + with: + checkoutCommit: ${{ needs.charts-changelog.outputs.commitHash }} + chartChangesDetected: ${{ needs.pr-metadata.outputs.addedOrModified }} diff --git a/.github/workflows/pre-commit-check.yaml b/.github/workflows/pre-commit-check.yaml new file mode 100644 index 0000000..5f629eb --- /dev/null +++ b/.github/workflows/pre-commit-check.yaml @@ -0,0 +1,21 @@ +name: "Pre-commit consistency check" + +on: + workflow_call: + inputs: + modifiedFiles: + required: true + type: string + +jobs: + pre-commit-check: + name: Run pre-commit checks + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Run against changes + uses: pre-commit/action@v3.0.1 + with: + extra_args: --files ${{ inputs.modifiedFiles }} diff --git a/.github/workflows/schedule-sync-labels.yaml b/.github/workflows/schedule-sync-labels.yaml new file mode 100644 index 0000000..5ef0ee1 --- /dev/null +++ b/.github/workflows/schedule-sync-labels.yaml @@ -0,0 +1,27 @@ +--- +name: "Schedule: Sync labels" + +on: # yamllint disable-line rule:truthy + workflow_dispatch: + schedule: + - cron: "0 * * * *" + +jobs: + labels: + name: Sync Labels + runs-on: ubuntu-latest + if: github.repository == 'MichaelSp/kassio' + permissions: + contents: read + pull-requests: write + issues: write + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Sync Labels + uses: EndBug/label-sync@v2 + with: + config-file: .github/labels.yaml + token: "${{ secrets.GITHUB_TOKEN }}" + delete-other-labels: true diff --git a/.github/workflows/stale.yaml b/.github/workflows/stale.yaml new file mode 100644 index 0000000..49b3549 --- /dev/null +++ b/.github/workflows/stale.yaml @@ -0,0 +1,38 @@ +--- +name: "Mark or close stale issues and PRs" +on: + workflow_dispatch: + schedule: + # Run the stalebot every day at 8pm UTC + - cron: "00 20 * * *" + +jobs: + stale: + runs-on: ubuntu-22.04 + steps: + - name: Check for stale issues and PRs + uses: actions/stale@v9 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + days-before-issue-stale: 60 + days-before-pr-stale: 60 + days-before-close: 14 + days-before-pr-close: 14 + stale-issue-message: > + This issue has been automatically marked as stale because it has not had recent activity. + It will be closed in two weeks if no further activity occurs. + Thank you for your contributions. + stale-pr-message: > + This pull request has been automatically marked as stale because it has not had + recent activity. It will be closed in two weeks if no further activity occurs. + Thank you for your contributions. + close-issue-message: > + This issue has been automatically closed due to inactivity. + Please re-open if this still requires investigation. + close-pr-message: > + This pull request has been automatically closed due to inactivity. + Please re-open if these changes are still required. + stale-pr-label: "stale" + stale-issue-label: "stale" + exempt-issue-labels: "keepalive" + exempt-pr-labels: "keepalive" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..4dd517e --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,17 @@ +# See https://pre-commit.com for more information +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.0.1 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: fix-byte-order-marker + - id: mixed-line-ending + - id: check-merge-conflict + - id: check-case-conflict + +- repo: https://github.com/Lucas-C/pre-commit-hooks + rev: v1.1.10 + hooks: + - id: remove-crlf + - id: remove-tabs \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/charts/home-assistant/.helmignore b/charts/home-assistant/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/charts/home-assistant/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/home-assistant/Chart.lock b/charts/home-assistant/Chart.lock new file mode 100644 index 0000000..1c87cee --- /dev/null +++ b/charts/home-assistant/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: postgresql + repository: oci://registry-1.docker.io/bitnamicharts + version: 15.5.0 +digest: sha256:8c601b568f40b1c355a724f754bdf545960fd268b38a62864051c7a9a0a0c01f +generated: "2024-06-01T16:56:39.423242+02:00" diff --git a/charts/home-assistant/Chart.yaml b/charts/home-assistant/Chart.yaml new file mode 100644 index 0000000..5deadd6 --- /dev/null +++ b/charts/home-assistant/Chart.yaml @@ -0,0 +1,30 @@ +apiVersion: v2 +name: home-assistant +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "2024.5" + +dependencies: + - name: postgresql + version: 15.5.0 + repository: oci://registry-1.docker.io/bitnamicharts + condition: postgresql.enabled diff --git a/charts/home-assistant/charts/postgresql-15.5.0.tgz b/charts/home-assistant/charts/postgresql-15.5.0.tgz new file mode 100644 index 0000000..a531e1c Binary files /dev/null and b/charts/home-assistant/charts/postgresql-15.5.0.tgz differ diff --git a/charts/home-assistant/templates/NOTES.txt b/charts/home-assistant/templates/NOTES.txt new file mode 100644 index 0000000..04fcdae --- /dev/null +++ b/charts/home-assistant/templates/NOTES.txt @@ -0,0 +1,22 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "home-assistant.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch its status by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "home-assistant.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "home-assistant.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "home-assistant.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT +{{- end }} diff --git a/charts/home-assistant/templates/_helpers.tpl b/charts/home-assistant/templates/_helpers.tpl new file mode 100644 index 0000000..6dfd7cf --- /dev/null +++ b/charts/home-assistant/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "home-assistant.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "home-assistant.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "home-assistant.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "home-assistant.labels" -}} +helm.sh/chart: {{ include "home-assistant.chart" . }} +{{ include "home-assistant.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "home-assistant.selectorLabels" -}} +app.kubernetes.io/name: {{ include "home-assistant.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "home-assistant.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "home-assistant.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/charts/home-assistant/templates/deployment.yaml b/charts/home-assistant/templates/deployment.yaml new file mode 100644 index 0000000..37e7d06 --- /dev/null +++ b/charts/home-assistant/templates/deployment.yaml @@ -0,0 +1,70 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "home-assistant.fullname" . }} + labels: + {{- include "home-assistant.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + affinity: + {{- toYaml .Values.affinity | nindent 4 }} + selector: + matchLabels: + {{- include "home-assistant.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "home-assistant.labels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "home-assistant.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: {{ .Values.service.port }} + protocol: TCP + livenessProbe: + {{- toYaml .Values.livenessProbe | nindent 12 }} + readinessProbe: + {{- toYaml .Values.readinessProbe | nindent 12 }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.volumeMounts }} + volumeMounts: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.volumes }} + volumes: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/home-assistant/templates/hpa.yaml b/charts/home-assistant/templates/hpa.yaml new file mode 100644 index 0000000..ce6b54e --- /dev/null +++ b/charts/home-assistant/templates/hpa.yaml @@ -0,0 +1,32 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "home-assistant.fullname" . }} + labels: + {{- include "home-assistant.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "home-assistant.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/charts/home-assistant/templates/ingress.yaml b/charts/home-assistant/templates/ingress.yaml new file mode 100644 index 0000000..cbeee29 --- /dev/null +++ b/charts/home-assistant/templates/ingress.yaml @@ -0,0 +1,61 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "home-assistant.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}} + {{- end }} +{{- end }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + {{- include "home-assistant.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ .pathType }} + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + {{- else }} + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/home-assistant/templates/service.yaml b/charts/home-assistant/templates/service.yaml new file mode 100644 index 0000000..8318734 --- /dev/null +++ b/charts/home-assistant/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "home-assistant.fullname" . }} + labels: + {{- include "home-assistant.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "home-assistant.selectorLabels" . | nindent 4 }} diff --git a/charts/home-assistant/templates/serviceaccount.yaml b/charts/home-assistant/templates/serviceaccount.yaml new file mode 100644 index 0000000..24f065d --- /dev/null +++ b/charts/home-assistant/templates/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "home-assistant.serviceAccountName" . }} + labels: + {{- include "home-assistant.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccount.automount }} +{{- end }} diff --git a/charts/home-assistant/templates/tests/test-connection.yaml b/charts/home-assistant/templates/tests/test-connection.yaml new file mode 100644 index 0000000..ebc75fb --- /dev/null +++ b/charts/home-assistant/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "home-assistant.fullname" . }}-test-connection" + labels: + {{- include "home-assistant.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "home-assistant.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/charts/home-assistant/tests/__snapshot__/simple_test.yaml.snap b/charts/home-assistant/tests/__snapshot__/simple_test.yaml.snap new file mode 100644 index 0000000..2d34662 --- /dev/null +++ b/charts/home-assistant/tests/__snapshot__/simple_test.yaml.snap @@ -0,0 +1,48 @@ +Matches the snapshot: + 1: | + apiVersion: apps/v1 + kind: Deployment + metadata: + labels: + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: home-assistant + app.kubernetes.io/version: "2024.5" + helm.sh/chart: home-assistant-0.1.0 + name: RELEASE-NAME-home-assistant + spec: + affinity: {} + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/name: home-assistant + template: + metadata: + labels: + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: home-assistant + app.kubernetes.io/version: "2024.5" + helm.sh/chart: home-assistant-0.1.0 + spec: + containers: + - image: ghcr.io/home-assistant/home-assistant:2024.5 + imagePullPolicy: IfNotPresent + livenessProbe: + httpGet: + path: / + port: http + name: home-assistant + ports: + - containerPort: 80 + name: http + protocol: TCP + readinessProbe: + httpGet: + path: / + port: http + resources: {} + securityContext: {} + securityContext: {} + serviceAccountName: RELEASE-NAME-home-assistant diff --git a/charts/home-assistant/tests/simple_test.yaml b/charts/home-assistant/tests/simple_test.yaml new file mode 100644 index 0000000..824dfe5 --- /dev/null +++ b/charts/home-assistant/tests/simple_test.yaml @@ -0,0 +1,9 @@ +suite: Simple Test Suite +templates: +- deployment.yaml +chart: + version: 0.1.0 +tests: +- it: Matches the snapshot + asserts: + - matchSnapshot: { } \ No newline at end of file diff --git a/charts/home-assistant/values.yaml b/charts/home-assistant/values.yaml new file mode 100644 index 0000000..67bc7af --- /dev/null +++ b/charts/home-assistant/values.yaml @@ -0,0 +1,107 @@ +# Default values for home-assistant. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +image: + repository: ghcr.io/home-assistant/home-assistant + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: "" + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Automatically mount a ServiceAccount's API credentials? + automount: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +podAnnotations: {} +podLabels: {} + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: false + className: "" + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: chart-example.local + paths: + - path: / + pathType: ImplementationSpecific + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +livenessProbe: + httpGet: + path: / + port: http +readinessProbe: + httpGet: + path: / + port: http + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 100 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + +# Additional volumes on the output Deployment definition. +volumes: [] +# - name: foo +# secret: +# secretName: mysecret +# optional: false + +# Additional volumeMounts on the output Deployment definition. +volumeMounts: [] +# - name: foo +# mountPath: "/etc/foo" +# readOnly: true + +nodeSelector: {} + +tolerations: [] + +affinity: {}