diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 00000000..abcc13fc --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,65 @@ +version: 2 +jobs: + lint-charts: + docker: + - image: gcr.io/kubernetes-charts-ci/test-image:v3.3.2 + steps: + - checkout + - run: + name: lint + command: | + git remote add upstream https://github.com/billimek/billimek-charts + git fetch upstream master + ct lint --config .circleci/ct.yaml + install-charts: + machine: true + steps: + - checkout + - run: + no_output_timeout: 12m + command: .circleci/install_charts.sh + lint-scripts: + docker: + - image: koalaman/shellcheck-alpine + steps: + - checkout + - run: + name: lint + command: shellcheck -x .circleci/*.sh + release-charts: + machine: true + steps: + - checkout + - add_ssh_keys: + fingerprints: + - "07:2a:c4:7a:48:3b:e5:cd:0c:80:bb:0d:be:f1:25:32" + - run: + command: | + echo "export GIT_REPOSITORY_URL=$CIRCLE_REPOSITORY_URL" >> $BASH_ENV + echo "export GIT_USERNAME=$CIRCLE_PROJECT_USERNAME" >> $BASH_ENV + echo "export GIT_REPOSITORY_NAME=$CIRCLE_PROJECT_REPONAME" >> $BASH_ENV + .circleci/install_tools.sh + .circleci/release.sh + +workflows: + version: 2 + lint-and-install: + jobs: + - lint-scripts + - lint-charts: + filters: + branches: + ignore: master + tags: + ignore: /.*/ + - install-charts: + requires: + - lint-charts + release: + jobs: + - release-charts: + filters: + tags: + ignore: /.*/ + branches: + only: master diff --git a/.circleci/ct.yaml b/.circleci/ct.yaml new file mode 100644 index 00000000..5999be0a --- /dev/null +++ b/.circleci/ct.yaml @@ -0,0 +1,3 @@ +helm-extra-args: --timeout 600 +chart-dirs: + - . \ No newline at end of file diff --git a/.circleci/install_charts.sh b/.circleci/install_charts.sh new file mode 100755 index 00000000..425dc57d --- /dev/null +++ b/.circleci/install_charts.sh @@ -0,0 +1,92 @@ +#!/usr/bin/env bash + +set -o errexit +set -o nounset +set -o pipefail + +readonly CT_VERSION=v2.3.3 +readonly KIND_VERSION=0.2.1 +readonly CLUSTER_NAME=chart-testing +readonly K8S_VERSION=v1.14.0 + +run_ct_container() { + echo 'Running ct container...' + docker run --rm --interactive --detach --network host --name ct \ + --volume "$(pwd)/.circleci/ct.yaml:/etc/ct/ct.yaml" \ + --volume "$(pwd):/workdir" \ + --workdir /workdir \ + "quay.io/helmpack/chart-testing:$CT_VERSION" \ + cat + echo +} + +cleanup() { + echo 'Removing ct container...' + docker kill ct > /dev/null 2>&1 + + echo 'Done!' +} + +docker_exec() { + docker exec --interactive ct "$@" +} + +create_kind_cluster() { + echo 'Installing kind...' + + curl -sSLo kind "https://github.com/kubernetes-sigs/kind/releases/download/$KIND_VERSION/kind-linux-amd64" + chmod +x kind + sudo mv kind /usr/local/bin/kind + + kind create cluster --name "$CLUSTER_NAME" --config .circleci/kind-config.yaml --image "kindest/node:$K8S_VERSION" --wait 60s + + docker_exec mkdir -p /root/.kube + + echo 'Copying kubeconfig to container...' + local kubeconfig + kubeconfig="$(kind get kubeconfig-path --name "$CLUSTER_NAME")" + docker cp "$kubeconfig" ct:/root/.kube/config + + docker_exec kubectl cluster-info + echo + + docker_exec kubectl get nodes + echo +} + +install_local_path_provisioner() { + docker_exec kubectl delete storageclass standard + docker_exec kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/master/deploy/local-path-storage.yaml +} + +install_tiller() { + echo 'Installing Tiller...' + docker_exec kubectl --namespace kube-system create sa tiller + docker_exec kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller + docker_exec helm init --service-account tiller --upgrade --wait + echo +} + +install_charts() { + docker_exec ct install + echo +} + +main() { + run_ct_container + trap cleanup EXIT + + changed=$(docker_exec ct list-changed) + if [[ -z "$changed" ]]; then + echo 'No chart changes detected.' + return + fi + + echo 'Chart changes detected.' + create_kind_cluster + install_local_path_provisioner + install_tiller + install_charts +} + +main diff --git a/.circleci/install_tools.sh b/.circleci/install_tools.sh new file mode 100755 index 00000000..7f886a9d --- /dev/null +++ b/.circleci/install_tools.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +set -o errexit + +readonly HELM_VERSION=2.13.1 +readonly CHART_RELEASER_VERSION=0.1.4 + +echo "Installing Helm..." +curl -LO "https://kubernetes-helm.storage.googleapis.com/helm-v$HELM_VERSION-linux-amd64.tar.gz" +sudo mkdir -p "/usr/local/helm-v$HELM_VERSION" +sudo tar -xzf "helm-v$HELM_VERSION-linux-amd64.tar.gz" -C "/usr/local/helm-v$HELM_VERSION" +sudo ln -s "/usr/local/helm-v$HELM_VERSION/linux-amd64/helm" /usr/local/bin/helm +rm -f "helm-v$HELM_VERSION-linux-amd64.tar.gz" +helm init --client-only + +echo "Installing chart-releaser..." +curl -LO "https://github.com/helm/chart-releaser/releases/download/v${CHART_RELEASER_VERSION}/chart-releaser_${CHART_RELEASER_VERSION}_Linux_x86_64.tar.gz" +sudo mkdir -p "/usr/local/chart-releaser-v$CHART_RELEASER_VERSION" +sudo tar -xzf "chart-releaser_${CHART_RELEASER_VERSION}_Linux_x86_64.tar.gz" -C "/usr/local/chart-releaser-v$CHART_RELEASER_VERSION" +sudo ln -s "/usr/local/chart-releaser-v$CHART_RELEASER_VERSION/chart-releaser" /usr/local/bin/chart-releaser +rm -f "chart-releaser_${CHART_RELEASER_VERSION}_Linux_x86_64.tar.gz" diff --git a/.circleci/kind-config.yaml b/.circleci/kind-config.yaml new file mode 100644 index 00000000..3c696b75 --- /dev/null +++ b/.circleci/kind-config.yaml @@ -0,0 +1,6 @@ +kind: Cluster +apiVersion: kind.sigs.k8s.io/v1alpha3 +nodes: + - role: control-plane + - role: worker + - role: worker diff --git a/.circleci/release.sh b/.circleci/release.sh new file mode 100755 index 00000000..6f55df23 --- /dev/null +++ b/.circleci/release.sh @@ -0,0 +1,109 @@ +#!/usr/bin/env bash + +set -o errexit +set -o nounset +set -o pipefail + +: "${CH_TOKEN:?Environment variable CH_TOKEN must be set}" +: "${GIT_REPOSITORY_URL:?Environment variable GIT_REPO_URL must be set}" +: "${GIT_USERNAME:?Environment variable GIT_USERNAME must be set}" +: "${GIT_EMAIL:?Environment variable GIT_EMAIL must be set}" +: "${GIT_REPOSITORY_NAME:?Environment variable GIT_REPOSITORY_NAME must be set}" + +readonly REPO_ROOT="${REPO_ROOT:-$(git rev-parse --show-toplevel)}" + +main() { + pushd "$REPO_ROOT" > /dev/null + + echo "Fetching tags..." + git fetch --tags + + local latest_tag + latest_tag=$(find_latest_tag) + + local latest_tag_rev + latest_tag_rev=$(git rev-parse --verify "$latest_tag") + echo "$latest_tag_rev $latest_tag (latest tag)" + + local head_rev + head_rev=$(git rev-parse --verify HEAD) + echo "$head_rev HEAD" + + if [[ "$latest_tag_rev" == "$head_rev" ]]; then + echo "No code changes. Nothing to release." + exit + fi + + rm -rf .deploy + mkdir -p .deploy + + echo "Identifying changed charts since tag '$latest_tag'..." + + local changed_charts=() + readarray -t changed_charts <<< "$(git diff --find-renames --name-only "$latest_tag_rev" -- . | cut -d '/' -f 1 | uniq)" + + if [[ -n "${changed_charts[*]}" ]]; then + for chart in "${changed_charts[@]}"; do + if find "$chart" -type f -iname "Chart.yaml" | grep -E -q '.'; then + echo "$chart is a valid chart directory - packaging" + package_chart "$chart" + fi + done + + release_charts + sleep 5 + update_index + else + echo "Nothing to do. No chart changes detected." + fi + + popd > /dev/null +} + +find_latest_tag() { + if ! git describe --tags --abbrev=0 2> /dev/null; then + git rev-list --max-parents=0 --first-parent HEAD + fi +} + +package_chart() { + local chart="$1" + helm dependency build "$chart" + helm package "$chart" --destination .deploy +} + +release_charts() { + chart-releaser upload -o "$GIT_USERNAME" -r "$GIT_REPOSITORY_NAME" -p .deploy +} + +update_index() { + chart-releaser index -o "$GIT_USERNAME" -r "$GIT_REPOSITORY_NAME" -p .deploy/index.yaml + + git config user.email "$GIT_EMAIL" + git config user.name "$GIT_USERNAME" + + for file in */*.md; do + if [[ -e $file ]]; then + mkdir -p ".deploy/docs/$(dirname "$file")" + cp --force "$file" ".deploy/docs/$(dirname "$file")" + fi + done + + git checkout gh-pages + cp --force .deploy/index.yaml index.yaml + + if [[ -e ".deploy/docs" ]]; then + # mkdir -p charts + cp --force --recursive .deploy/docs/* . + fi + + git checkout master -- README.md + + if ! git diff --quiet; then + git add . + git commit --message="Update index.yaml" --signoff + git push "$GIT_REPOSITORY_URL" gh-pages + fi +} + +main