777 on new scripts (+2 squashed commit)

Squashed commit:

[9ae7dd0f] add helm-docs to workflow

[2206f5ba] fix small typo in workflows (+1 squashed commits)

Squashed commits:

[29c2ceb4] Documentation-Cleanup (#181)

* work on readme generation

* document windows setup

* add simple pre-commit install script

* more docs for git setup

* Update pre-commit

* pre-commit automatic fixes

* Increase all patch versions

* Auto Readme and Config doc

* Auto app-readme.md generation

* increase common and common-test versions accordingly (due to cleanup)

* move contribution guidelines to /development in wiki

* fix some end-of-line issues (again)

* fix line 14 of workflows
This commit is contained in:
Kjeld Schouten-Lebbing
2021-02-23 18:21:54 +01:00
committed by kjeld Schouten-Lebbing
parent 94a6d6f9e1
commit 1d51be0e3d
674 changed files with 6631 additions and 1813 deletions

0
.tools/fixfolders.sh Normal file → Executable file
View File

57
.tools/gen-helm-docs.sh Executable file
View File

@@ -0,0 +1,57 @@
#!/usr/bin/env bash
set -eu
# Generate helm-docs for Helm charts
# Usage ./gen-helm-docs.sh [chart]
# require helm-docs
command -v helm-docs >/dev/null 2>&1 || {
echo >&2 "helm-docs is not installed. Aborting."
exit 1
}
# Absolute path of repository
repository=$(git rev-parse --show-toplevel)
# Templates to copy into each chart directory
readme_template="${repository}/.tools/templates/chart/README.md.gotmpl"
config_template="${repository}/.tools/templates/chart/docs/CONFIG.md.gotmpl"
app_readme_template="${repository}/.tools/templates/chart/app-readme.md.gotmpl"
# Gather all charts using the common library, excluding common-test
charts=$(find "${repository}" -name "Chart.yaml" -exec grep --exclude="*common-test*" -l "\- name\: common" {} \;)
root="${repository}"
for chart in charts/*; do
if [ -d "${chart}" ]; then
maxfolderversion=$(ls -l ${chart} | grep ^d | awk '{print $9}' | tail -n 1)
maxchartversion=$(cat ${chart}/${maxfolderversion}/Chart.yaml | grep "^version: " | awk -F" " '{ print $2 }')
chartname=$(basename ${chart})
mkdir -p ${chart}/${maxfolderversion}/docs || true
echo "-] Copying templates to ${chart}/${maxfolderversion}"
# Copy README template into each Chart directory, remove current if existing
rm -f "${chart}/${maxfolderversion}/README.md.gotmpl" || true
cp -f "${readme_template}" "${chart}/${maxfolderversion}/README.md.gotmpl" || true
# Copy README template into each Chart directory, remove current if existing
rm -f "${chart}/${maxfolderversion}/app-readme.md.gotmpl" || true
cp -f "${app_readme_template}" "${chart}/${maxfolderversion}/app-readme.md.gotmpl" || true
# Copy CONFIG template to each Chart directory, do not overwrite if exists
cp -n "${config_template}" "${chart}/${maxfolderversion}/docs/CONFIG.md.gotmpl" || true
helm-docs \
--ignore-file="${repository}/.helmdocsignore" \
--template-files="${chart}/${maxfolderversion}/README.md.gotmpl" \
--chart-search-root="${chart}/${maxfolderversion}"
helm-docs \
--ignore-file="${repository}/.helmdocsignore" \
--output-file="docs/CONFIG.md" \
--template-files="${chart}/${maxfolderversion}/docs/CONFIG.md.gotmpl" \
--chart-search-root="${chart}/${maxfolderversion}"
helm-docs \
--ignore-file="${repository}/.helmdocsignore" \
--output-file="app-readme.md" \
--template-files="${chart}/${maxfolderversion}/app-readme.md.gotmpl" \
--chart-search-root="${chart}/${maxfolderversion}"
fi
done

View File

@@ -0,0 +1,4 @@
pip install pre-commit
git config --unset-all core.hooksPath
cd ..
pre-commit install

View File

@@ -0,0 +1,26 @@
# 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
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/
# OWNERS file for Kubernetes
OWNERS
# helm-docs templates
*.gotmpl

View File

@@ -0,0 +1,20 @@
apiVersion: v2
appVersion: 1.0.0
description: ${CHARTNAME} helm package
name: ${CHARTNAME}
version: 1.0.0
kubeVersion: ">=1.16.0-0"
keywords:
- ${CHARTNAME}
home: https://github.com/k8s-at-home/charts/tree/master/charts/${CHARTNAME}
icon: https://${CHARTNAME}.org/icon
sources:
- https://github.com/${CHARTNAME}/${CHARTNAME}-docker
- https://github.com/k8s-at-home/charts/tree/master/charts/${CHARTNAME}
maintainers:
- name: ${CHARTNAME}
email: ${CHARTNAME}@${CHARTNAME}.com
dependencies:
- name: common
repository: https://k8s-at-home.com/charts/
version: 3.0.1

View File

@@ -0,0 +1,117 @@
# ${CHARTNAME}
![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) ![AppVersion: 1.0.0](https://img.shields.io/badge/AppVersion-1.0.0-informational?style=flat-square)
${CHARTNAME} helm package
**This chart is not maintained by the upstream project and any issues with the chart should be raised [here](https://github.com/k8s-at-home/charts/issues/new/choose)**
## Source Code
* <https://github.com/${CHARTNAME}/${CHARTNAME}-docker>
* <https://github.com/k8s-at-home/charts/tree/master/charts/${CHARTNAME}>
## Requirements
Kubernetes: `>=1.16.0-0`
## Dependencies
| Repository | Name | Version |
|------------|------|---------|
| https://k8s-at-home.com/charts/ | common | 3.0.1 |
## TL;DR
```console
helm repo add k8s-at-home https://k8s-at-home.com/charts/
helm repo update
helm install ${CHARTNAME} k8s-at-home/${CHARTNAME}
```
## Installing the Chart
To install the chart with the release name `${CHARTNAME}`
```console
helm install ${CHARTNAME} k8s-at-home/${CHARTNAME}
```
## Uninstalling the Chart
To uninstall the `${CHARTNAME}` deployment
```console
helm uninstall ${CHARTNAME}
```
The command removes all the Kubernetes components associated with the chart **including persistent volumes** and deletes the release.
## Configuration
Read through the [values.yaml](./values.yaml) file. It has several commented out suggested values.
Other values may be used from the [values.yaml](../common/values.yaml) from the [common library](../common).
Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`.
```console
helm install ${CHARTNAME} \
--set env.TZ="America/New York" \
k8s-at-home/${CHARTNAME}
```
Alternatively, a YAML file that specifies the values for the above parameters can be provided while installing the chart.
```console
helm install ${CHARTNAME} k8s-at-home/${CHARTNAME} -f values.yaml
```
## Custom configuration
N/A
## Values
**Important**: When deploying an application Helm chart you can add more values from our common library chart [here](https://github.com/k8s-at-home/charts/tree/master/charts/common/)
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| env | object | `{}` | |
| image.pullPolicy | string | `"IfNotPresent"` | |
| image.repository | string | `"${CHARTNAME}/${CHARTNAME}"` | |
| image.tag | string | `"1.0.0"` | |
| ingress.enabled | bool | `false` | |
| service.port.port | int | `1880` | |
| strategy.type | string | `"Recreate"` | |
## Changelog
All notable changes to this application Helm chart will be documented in this file but does not include changes from our common library. To read those click [here](https://github.com/k8s-at-home/charts/tree/master/charts/common/README.md#Changelog).
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
### [1.0.0]
#### Added
- N/A
#### Changed
- N/A
#### Removed
- N/A
[1.0.0]: #1.0.0
## Support
- See the [Wiki](https://github.com/k8s-at-home/charts/wiki)
- Open a [issue](https://github.com/k8s-at-home/charts/issues/new/choose)
- Ask a [question](https://github.com/k8s-at-home/charts/discussions)
- Join our [Discord](https://discord.gg/sTMX7Vh) community
----------------------------------------------
Autogenerated from chart metadata using [helm-docs v1.5.0](https://github.com/norwoodj/helm-docs/releases/v1.5.0)

View File

@@ -0,0 +1,95 @@
{{- define "custom.introheader" -}}
# Introduction
{{- end -}}
{{- define "custom.repository.organization" -}}
TrueCharts
{{- end -}}
{{- define "custom.repository.url" -}}
https://github.com/truecharts/charts
{{- end -}}
{{- define "custom.helm.url" -}}
https://charts.truecharts.org
{{- end -}}
{{- define "custom.helm.path" -}}
{{ template "custom.repository.organization" . }}/{{ template "chart.name" . }}
{{- end -}}
{{- define "custom.notes" -}}
TrueCharts are designed to be installed as TrueNAS SCALE app only. We can not guarantee this charts works as a stand-alone helm installation.
**This chart is not maintained by the upstream project and any issues with the chart should be raised [here](https://github.com/truecharts/charts/issues/new/choose)**
{{- end -}}
{{- define "custom.requirements" -}}
## Requirements
{{ template "chart.kubeVersionLine" . }}
{{- end -}}
{{- define "custom.dependencies" -}}
## Dependencies
{{ template "chart.requirementsTable" . }}
{{- end -}}
{{- define "custom.install" -}}
## Installing the Chart
To install the chart with the release name `{{ template "chart.name" . }}`
- Open TrueNAS SCALE
- Go to Apps
- Click "Install" for this specific Apps
- Fill out the configuration form
{{- end -}}
{{- define "custom.uninstall" -}}
## Uninstalling the Chart
To uninstall the `{{ template "chart.name" . }}` deployment
- Open TrueNAS SCALE
- Go to Apps
- Go to "Installed Apps"
- Expand the menu in the top-right corner of this App
- Click "Remove" for this specific Apps
The command removes all the Kubernetes components associated with the chart **including storage volumes** _(Except hostPath Storage)_ and deletes the release.
{{- end -}}
{{- define "custom.configuration.header" -}}
## Configuration
{{- end -}}
{{- define "custom.support" -}}
## Support
- See the [Wiki](https://wiki.truecharts.org)
- Open a [issue](https://github.com/truecharts/charts/issues/new/choose)
- Ask a [question](https://github.com/truecharts/charts/discussions)
{{- end -}}
{{ template "custom.introheader" . }}
{{ template "chart.versionBadge" . }}{{ template "chart.typeBadge" . }}{{ template "chart.appVersionBadge" . }}
{{ template "chart.description" . }}
{{ template "custom.notes" . }}
{{ template "chart.sourcesSection" . }}
{{ template "custom.requirements" . }}
{{ template "custom.dependencies" . }}
{{ template "custom.install" . }}
{{ template "custom.uninstall" . }}
{{ template "custom.support" . }}
{{ template "helm-docs.versionFooter" . }}

View File

View File

@@ -0,0 +1,5 @@
{{- define "custom.notes" -}}
{{- end -}}
{{ template "chart.description" . }}
{{ template "custom.notes" . }}

View File

@@ -0,0 +1,11 @@
{{- define "custom.custom.configuration.header" -}}
# Configuration Options
{{- end -}}
{{- define "custom.custom.configuration" -}}
{{ template "custom.custom.configuration.header" . }}
N/A
{{- end -}}
{{ template "custom.custom.configuration" . }}

View File

@@ -0,0 +1 @@
{{- include "common.notes.defaultNotes" . -}}

View File

@@ -0,0 +1 @@
{{ include "common.all" . }}

View File

@@ -0,0 +1,32 @@
#
# IMPORTANT NOTE
#
# This chart inherits from our common library chart. You can check the default values/options here:
# https://github.com/k8s-at-home/charts/tree/master/charts/common/values.yaml
#
image:
repository: ${CHARTNAME}/${CHARTNAME}
pullPolicy: IfNotPresent
tag: 1.0.0
strategy:
type: Recreate
# See more environment variables in the ${CHARTNAME} documentation
# https://${CHARTNAME}.org/docs
env: {}
# TZ:
service:
port:
port: 1880
ingress:
enabled: false
# persistence:
# data:
# enabled: false
# emptyDir: false
# mountPath: /data

View File

@@ -0,0 +1,219 @@
# frozen_string_literal: true
require_relative '../test_helper'
class Test < ChartTest
@@chart = Chart.new('library/common-test')
describe @@chart.name do
describe 'controller type' do
it 'defaults to "Deployment"' do
assert_nil(resource('StatefulSet'))
assert_nil(resource('DaemonSet'))
refute_nil(resource('Deployment'))
end
it 'accepts "statefulset"' do
chart.value controllerType: 'statefulset'
assert_nil(resource('Deployment'))
assert_nil(resource('DaemonSet'))
refute_nil(resource('StatefulSet'))
end
it 'accepts "daemonset"' do
chart.value controllerType: 'daemonset'
assert_nil(resource('Deployment'))
assert_nil(resource('StatefulSet'))
refute_nil(resource('DaemonSet'))
end
end
describe 'pod replicas' do
it 'defaults to 1' do
jq('.spec.replicas', resource('Deployment')).must_equal 1
end
it 'accepts integer as value' do
chart.value replicas: 3
jq('.spec.replicas', resource('Deployment')).must_equal 3
end
end
describe 'Environment settings' do
it 'Check no environment variables' do
values = {}
chart.value values
jq('.spec.template.spec.containers[0].env[0].name', resource('Deployment')).must_equal 'PUID'
jq('.spec.template.spec.containers[0].env[0].value', resource('Deployment')).must_equal "568"
jq('.spec.template.spec.containers[0].env[1].name', resource('Deployment')).must_equal 'PGID'
jq('.spec.template.spec.containers[0].env[1].value', resource('Deployment')).must_equal "568"
jq('.spec.template.spec.containers[0].env[2].name', resource('Deployment')).must_equal 'UMASK'
jq('.spec.template.spec.containers[0].env[2].value', resource('Deployment')).must_equal "002"
end
it 'set "static" environment variables' do
values = {
env: {
STATIC_ENV: 'value_of_env'
}
}
chart.value values
jq('.spec.template.spec.containers[0].env[0].name', resource('Deployment')).must_equal 'PUID'
jq('.spec.template.spec.containers[0].env[0].value', resource('Deployment')).must_equal "568"
jq('.spec.template.spec.containers[0].env[1].name', resource('Deployment')).must_equal 'PGID'
jq('.spec.template.spec.containers[0].env[1].value', resource('Deployment')).must_equal "568"
jq('.spec.template.spec.containers[0].env[2].name', resource('Deployment')).must_equal 'UMASK'
jq('.spec.template.spec.containers[0].env[2].value', resource('Deployment')).must_equal "002"
jq('.spec.template.spec.containers[0].env[3].name', resource('Deployment')).must_equal values[:env].keys[0].to_s
jq('.spec.template.spec.containers[0].env[3].value', resource('Deployment')).must_equal values[:env].values[0].to_s
end
it 'set "valueFrom" environment variables' do
values = {
envValueFrom: {
NODE_NAME: {
fieldRef: {
fieldPath: "spec.nodeName"
}
}
}
}
chart.value values
jq('.spec.template.spec.containers[0].env[0].name', resource('Deployment')).must_equal 'PUID'
jq('.spec.template.spec.containers[0].env[0].value', resource('Deployment')).must_equal "568"
jq('.spec.template.spec.containers[0].env[1].name', resource('Deployment')).must_equal 'PGID'
jq('.spec.template.spec.containers[0].env[1].value', resource('Deployment')).must_equal "568"
jq('.spec.template.spec.containers[0].env[2].name', resource('Deployment')).must_equal 'UMASK'
jq('.spec.template.spec.containers[0].env[2].value', resource('Deployment')).must_equal "002"
jq('.spec.template.spec.containers[0].env[3].name', resource('Deployment')).must_equal values[:envValueFrom].keys[0].to_s
jq('.spec.template.spec.containers[0].env[3].valueFrom | keys[0]', resource('Deployment')).must_equal values[:envValueFrom].values[0].keys[0].to_s
end
it 'set "static" and "Dynamic/Tpl" environment variables' do
values = {
env: {
STATIC_ENV: 'value_of_env'
},
envTpl: {
DYN_ENV: "{{ .Release.Name }}-admin"
}
}
chart.value values
jq('.spec.template.spec.containers[0].env[0].name', resource('Deployment')).must_equal 'PUID'
jq('.spec.template.spec.containers[0].env[0].value', resource('Deployment')).must_equal "568"
jq('.spec.template.spec.containers[0].env[1].name', resource('Deployment')).must_equal 'PGID'
jq('.spec.template.spec.containers[0].env[1].value', resource('Deployment')).must_equal "568"
jq('.spec.template.spec.containers[0].env[2].name', resource('Deployment')).must_equal 'UMASK'
jq('.spec.template.spec.containers[0].env[2].value', resource('Deployment')).must_equal "002"
jq('.spec.template.spec.containers[0].env[3].name', resource('Deployment')).must_equal values[:env].keys[0].to_s
jq('.spec.template.spec.containers[0].env[3].value', resource('Deployment')).must_equal values[:env].values[0].to_s
jq('.spec.template.spec.containers[0].env[4].name', resource('Deployment')).must_equal values[:envTpl].keys[0].to_s
jq('.spec.template.spec.containers[0].env[4].value', resource('Deployment')).must_equal 'common-test-admin'
end
it 'set "Dynamic/Tpl" environment variables' do
values = {
envTpl: {
DYN_ENV: "{{ .Release.Name }}-admin"
}
}
chart.value values
jq('.spec.template.spec.containers[0].env[0].name', resource('Deployment')).must_equal 'PUID'
jq('.spec.template.spec.containers[0].env[0].value', resource('Deployment')).must_equal "568"
jq('.spec.template.spec.containers[0].env[1].name', resource('Deployment')).must_equal 'PGID'
jq('.spec.template.spec.containers[0].env[1].value', resource('Deployment')).must_equal "568"
jq('.spec.template.spec.containers[0].env[2].name', resource('Deployment')).must_equal 'UMASK'
jq('.spec.template.spec.containers[0].env[2].value', resource('Deployment')).must_equal "002"
jq('.spec.template.spec.containers[0].env[3].name', resource('Deployment')).must_equal values[:envTpl].keys[0].to_s
jq('.spec.template.spec.containers[0].env[3].value', resource('Deployment')).must_equal 'common-test-admin'
end
end
describe 'ports settings' do
default_name = 'http'
default_port = 8080
it 'defaults to name "http" on port 8080' do
jq('.spec.ports[0].port', resource('Service')).must_equal default_port
jq('.spec.ports[0].targetPort', resource('Service')).must_equal default_name
jq('.spec.ports[0].name', resource('Service')).must_equal default_name
jq('.spec.template.spec.containers[0].ports[0].containerPort', resource('Deployment')).must_equal default_port
jq('.spec.template.spec.containers[0].ports[0].name', resource('Deployment')).must_equal default_name
end
it 'port name can be overridden' do
values = {
service: {
port: {
name: 'server'
}
}
}
chart.value values
jq('.spec.ports[0].port', resource('Service')).must_equal default_port
jq('.spec.ports[0].targetPort', resource('Service')).must_equal values[:service][:port][:name]
jq('.spec.ports[0].name', resource('Service')).must_equal values[:service][:port][:name]
jq('.spec.template.spec.containers[0].ports[0].containerPort', resource('Deployment')).must_equal default_port
jq('.spec.template.spec.containers[0].ports[0].name', resource('Deployment')).must_equal values[:service][:port][:name]
end
it 'targetPort can be overridden' do
values = {
service: {
port: {
targetPort: 80
}
}
}
chart.value values
jq('.spec.ports[0].port', resource('Service')).must_equal default_port
jq('.spec.ports[0].targetPort', resource('Service')).must_equal values[:service][:port][:targetPort]
jq('.spec.ports[0].name', resource('Service')).must_equal default_name
jq('.spec.template.spec.containers[0].ports[0].containerPort', resource('Deployment')).must_equal values[:service][:port][:targetPort]
jq('.spec.template.spec.containers[0].ports[0].name', resource('Deployment')).must_equal default_name
end
it 'targetPort cannot be a named port' do
values = {
service: {
port: {
targetPort: 'test'
}
}
}
chart.value values
exception = assert_raises HelmCompileError do
chart.execute_helm_template!
end
assert_match("Our charts do not support named ports for targetPort. (port name #{default_name}, targetPort #{values[:service][:port][:targetPort]})", exception.message)
end
end
describe 'statefulset volumeClaimTemplates' do
it 'volumeClaimTemplates should be empty by default' do
chart.value controllerType: 'statefulset'
assert_nil(resource('StatefulSet')['spec']['volumeClaimTemplates'])
end
it 'can set values for volumeClaimTemplates' do
values = {
controllerType: 'statefulset',
volumeClaimTemplates: [
{
name: 'storage',
accessMode: 'ReadWriteOnce',
size: '10Gi',
storageClass: 'storage'
}
]
}
chart.value values
jq('.spec.volumeClaimTemplates[0].metadata.name', resource('StatefulSet')).must_equal values[:volumeClaimTemplates][0][:name]
jq('.spec.volumeClaimTemplates[0].spec.accessModes[0]', resource('StatefulSet')).must_equal values[:volumeClaimTemplates][0][:accessMode]
jq('.spec.volumeClaimTemplates[0].spec.resources.requests.storage', resource('StatefulSet')).must_equal values[:volumeClaimTemplates][0][:size]
jq('.spec.volumeClaimTemplates[0].spec.storageClassName', resource('StatefulSet')).must_equal values[:volumeClaimTemplates][0][:storageClass]
end
end
end
end

119
.tools/tests/test_helper.rb Normal file
View File

@@ -0,0 +1,119 @@
# frozen_string_literal: true
require 'json'
require 'yaml'
require 'open3'
require 'jq/extend'
require 'minitest-implicit-subject'
require "minitest/reporters"
require 'minitest/autorun'
require 'minitest/pride'
class HelmCompileError < StandardError
end
class HelmDepsError < StandardError
end
class Chart
attr_reader :name, :path, :values
def initialize(chart)
@name = chart.split('/').last
@path = File.expand_path(chart)
@values = default_values
update_deps!
end
def update_deps!
command = "helm dep update '#{path}'"
stdout, stderr, status = Open3.capture3(command)
raise HelmDepsError, stderr if status != 0
end
def reset!
@values = default_values
@parsed_resources = nil
end
def value(value)
values.merge!(value)
end
def configure_custom_name(name)
@name = name
end
def execute_helm_template!
file = Tempfile.new(name)
file.write(JSON.parse(values.to_json).to_yaml)
file.close
begin
command = "helm template '#{name}' '#{path}' --namespace='default' --values='#{file.path}'"
stdout, stderr, status = Open3.capture3(command)
raise HelmCompileError, stderr if status != 0
stdout
ensure
file.unlink
end
end
def parsed_resources
@parsed_resources ||= begin
output = execute_helm_template!
puts output if ENV.fetch('DEBUG', 'false') == 'true'
YAML.load_stream(output)
end
end
def resources(matcher = nil)
return parsed_resources unless matcher
parsed_resources.select do |r|
r >= Hash[matcher.map { |k, v| [k.to_s, v] }]
end
end
def default_values
{
}
end
end
class ExtendedMinitest < Minitest::Test
extend MiniTest::Spec::DSL
end
class ChartTest < ExtendedMinitest
Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new
before do
chart.reset!
end
def chart
self.class.class_variable_get('@@chart')
end
def resource(name)
chart.resources(kind: name).first
end
def jq(matcher, object)
value(object.jq(matcher)[0])
end
end
class Minitest::Result
def name
test_name = defined?(@name) ? @name : super
test_name.to_s.gsub /\Atest_\d{4,}_/, ""
end
end