From 31df5daaf22fa1bdf16b266094bf753ce7f689c5 Mon Sep 17 00:00:00 2001 From: Michael Sprauer Date: Sat, 1 Jun 2024 18:38:49 +0200 Subject: [PATCH] import --- .github/actions/collect-changes/action.yaml | 45 ++++++ .github/actions/label-from-status/action.yaml | 48 ++++++ .github/labels.yaml | 111 +++++++++++++ .github/renovate.json5 | 4 + .github/scripts/check-releasenotes.sh | 49 ++++++ .github/scripts/renovate-releasenotes.py | 153 ++++++++++++++++++ .github/workflows/charts-changelog.yaml | 81 ++++++++++ .github/workflows/charts-lint.yaml | 54 +++++++ .github/workflows/charts-release.yaml | 37 +++++ .github/workflows/charts-test.yaml | 116 +++++++++++++ .../workflows/meta-label-pr-ci-status.yaml | 111 +++++++++++++ .../workflows/metadata-label-commenter.yaml | 28 ++++ .github/workflows/metadata-label-pr.yaml | 35 ++++ .github/workflows/pr-metadata.yaml | 60 +++++++ .github/workflows/pr-validate.yaml | 54 +++++++ .github/workflows/pre-commit-check.yaml | 21 +++ .github/workflows/schedule-sync-labels.yaml | 27 ++++ .github/workflows/stale.yaml | 38 +++++ .pre-commit-config.yaml | 17 ++ README.md | 0 charts/home-assistant/.helmignore | 23 +++ charts/home-assistant/Chart.lock | 6 + charts/home-assistant/Chart.yaml | 30 ++++ .../charts/postgresql-15.5.0.tgz | Bin 0 -> 75913 bytes charts/home-assistant/templates/NOTES.txt | 22 +++ charts/home-assistant/templates/_helpers.tpl | 62 +++++++ .../home-assistant/templates/deployment.yaml | 70 ++++++++ charts/home-assistant/templates/hpa.yaml | 32 ++++ charts/home-assistant/templates/ingress.yaml | 61 +++++++ charts/home-assistant/templates/service.yaml | 15 ++ .../templates/serviceaccount.yaml | 13 ++ .../templates/tests/test-connection.yaml | 15 ++ .../tests/__snapshot__/simple_test.yaml.snap | 48 ++++++ charts/home-assistant/tests/simple_test.yaml | 9 ++ charts/home-assistant/values.yaml | 107 ++++++++++++ 35 files changed, 1602 insertions(+) create mode 100644 .github/actions/collect-changes/action.yaml create mode 100644 .github/actions/label-from-status/action.yaml create mode 100644 .github/labels.yaml create mode 100644 .github/renovate.json5 create mode 100755 .github/scripts/check-releasenotes.sh create mode 100755 .github/scripts/renovate-releasenotes.py create mode 100644 .github/workflows/charts-changelog.yaml create mode 100644 .github/workflows/charts-lint.yaml create mode 100644 .github/workflows/charts-release.yaml create mode 100644 .github/workflows/charts-test.yaml create mode 100644 .github/workflows/meta-label-pr-ci-status.yaml create mode 100644 .github/workflows/metadata-label-commenter.yaml create mode 100644 .github/workflows/metadata-label-pr.yaml create mode 100644 .github/workflows/pr-metadata.yaml create mode 100644 .github/workflows/pr-validate.yaml create mode 100644 .github/workflows/pre-commit-check.yaml create mode 100644 .github/workflows/schedule-sync-labels.yaml create mode 100644 .github/workflows/stale.yaml create mode 100644 .pre-commit-config.yaml create mode 100644 README.md create mode 100644 charts/home-assistant/.helmignore create mode 100644 charts/home-assistant/Chart.lock create mode 100644 charts/home-assistant/Chart.yaml create mode 100644 charts/home-assistant/charts/postgresql-15.5.0.tgz create mode 100644 charts/home-assistant/templates/NOTES.txt create mode 100644 charts/home-assistant/templates/_helpers.tpl create mode 100644 charts/home-assistant/templates/deployment.yaml create mode 100644 charts/home-assistant/templates/hpa.yaml create mode 100644 charts/home-assistant/templates/ingress.yaml create mode 100644 charts/home-assistant/templates/service.yaml create mode 100644 charts/home-assistant/templates/serviceaccount.yaml create mode 100644 charts/home-assistant/templates/tests/test-connection.yaml create mode 100644 charts/home-assistant/tests/__snapshot__/simple_test.yaml.snap create mode 100644 charts/home-assistant/tests/simple_test.yaml create mode 100644 charts/home-assistant/values.yaml 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 0000000000000000000000000000000000000000..a531e1c4f3d5ffa37193f9f0a3576a159e3a93a1 GIT binary patch literal 75913 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

jSa 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.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: {}