diff --git a/README.md b/README.md index d056ce1..170d2ef 100644 --- a/README.md +++ b/README.md @@ -117,66 +117,69 @@ that follow the main steps of the job itself. See the [Workflow component job]( ### Component Release Pipeline ``` - Component Release Pipeline - start -┌───────────────────────────┐ -│ │ -│ │ - triggered by `v1.2.3` git tag -│ │ webhook -│ component-release │ -│ │ - locate release candidate image -│ │ associated with git tag -│ │ -└───────────────────────────┘ - │ - │ - ▼ -┌───────────────────────────┐ -│ │ -│ │ -│ │ - retag candidate image with -│ release candidate promote │ official release (v1.2.3) -│ │ -│ │ -│ │ -└───────────────────────────┘ - │ - │ - ▼ -┌───────────────────────────┐ -│ │ -│ │ -│ component release │ - publish release data to -│ publish │ workflow-manager-api -│ │ -│ │ -│ │ -└───────────────────────────┘ - │ - │ - ▼ -┌───────────────────────────┐ -│ │ -│ │ -│ component chart │ - package release component chart -│ publish │ -│ │ - publish to both 'production' and -│ │ 'dev' chart repos -│ │ -└───────────────────────────┘ - │ - │ - ▼ -┌───────────────────────────┐ -│ │ -│ │ -│ │ - sign release chart in 'production' -│ component chart sign │ chart repo -│ │ -│ │ -│ │ -└───────────────────────────┘ + + + Component Release Pipeline + start + + ┌───────────────────────────┐ + │ │ + │ │ - triggered by `v1.2.3` git tag + │ │ webhook + │ component-release │ + │ │ - locate release candidate image + │ │ associated with git tag + │ │ + └───────────────────────────┘ + │ + │ + ▼ + ┌───────────────────────────┐ + │ │ + │ │ + │ │ - retag candidate image with + │ release candidate promote │ official release (v1.2.3) + │ │ + │ │ + │ │ + └───────────────────────────┘ + │ + │ + ▼ + ┌───────────────────────────┐ + │ │ + │ │ + │ component release │ - publish release data to + │ publish │ workflow-manager-api + │ │ + │ │ + │ │ + └───────────────────────────┘ + │ + │ + ▼ + ┌───────────────────────────┐ + │ │ + │ │ - publish signed and packaged chart + │ component chart │ to 'production' + │ publish │ + │ │ - publish packaged chart 'dev' + │ │ chart repos + │ │ + └───────────────────────────┘ + │ + │ + ▼ + ┌───────────────────────────┐ + │ │ + │ │ + │ │ - verifies signature of chart in + │ component chart verify │ 'production' chart repo + │ │ + │ │ + │ │ + └───────────────────────────┘ ``` ### When Workflow-CLI is tagged @@ -225,64 +228,53 @@ that follow the main steps of the job itself. See the [Workflow component job]( ### When a Workflow Helm Chart is to be released ``` + Workflow Chart Release Pipeline - -┌───────────────────────────┐ - triggered manually with -│ │ supplied release tag -│ │ -│ │ - update chart dependencies by -│ workflow-chart-publish │ gathering latest releases for -│ │ all component charts -│ │ -│ │ - update index file, package and -└───────────────────────────┘ upload to the 'staging' charts - │ - │ - ▼ -┌───────────────────────────┐ - lease GKE cluster, install -│ │ Workflow chart (version handed -│ │ down from upstream) -│ │ -│ workflow-chart-e2e │ - install workflow-e2e chart -│ │ -│ │ - archive test results and -│ │ report job status to appropriate -└───────────────────────────┘ channel(s) - │ - │ - ▼ -┌───────────────────────────┐ - triggered manually with -│ │ supplied release tag -│ │ -│ │ - pull down approved chart -│ workflow-chart-release │ from 'staging' chart repo -│ │ -│ │ - update index file, upload -│ │ chart to 'production' charts -└───────────────────────────┘ repo - │ - │ - ▼ + - triggered manually with supplied release +┌───────────────────────────┐ tag +│ │ +│ │ - update chart dependencies by gathering +│ │ latest releases for all component charts +│ workflow-chart-stage │ +│ │ - upload signed and packaged candidate chart +│ │ (sans index file) to 'production' repo +│ │ +└───────────────────────────┘ - upload packaged candidate chart (with + │ index file) to 'staging' charts repo + │ + ▼ ┌───────────────────────────┐ +│ │ - lease GKE cluster, install Workflow chart +│ │ (version handed down from upstream) from +│ │ 'staging' repo +│ workflow-chart-e2e │ +│ │ - install workflow-e2e chart +│ │ +│ │ - archive test results and report job status +└───────────────────────────┘ to appropriate channel(s) + │ + │ + ▼ +┌───────────────────────────┐ +│ │ - triggered manually with supplied release +│ │ tag │ │ -│ │ - fetch specific chart version -│ │ -│ helm-chart-sign │ - sign chart with signing key +│ workflow-chart-release │ - pull down approved, signed chart from +│ │ 'production' chart repo │ │ -│ │ - upload new *.tgz and *.tgz.prov -│ │ files to chart repo -└───────────────────────────┘ - │ - │ - ▼ +│ │ - update index file, upload to 'production' +└───────────────────────────┘ charts repo, making it officially + │ fetchable/installable + │ + ▼ ┌───────────────────────────┐ │ │ +│ │ - verifies signature of chart from 'production' +│ │ repo +│ helm-chart-verify │ +│ │ - (job succeeds if command succeeds) │ │ -│ │ - non-signatory node runs `helm fetch -│ helm-chart-verify │ --verify --version ` -│ │ -│ │ - (job succeeds if command succeeds) │ │ └───────────────────────────┘ ``` diff --git a/bash/scripts/helm_chart_actions.sh b/bash/scripts/helm_chart_actions.sh index a386fc4..6748bd2 100644 --- a/bash/scripts/helm_chart_actions.sh +++ b/bash/scripts/helm_chart_actions.sh @@ -1,12 +1,17 @@ #!/usr/bin/env bash + set -eo pipefail -sign-helm-chart() { +export DEIS_CHARTS_BASE_URL="https://charts.deis.com" +export DEIS_CHARTS_BUCKET_BASE_URL="s3://helm-charts" + +# sign-and-package-helm-chart signs and packages the helm chart provided by chart, +# expecting a signing key passphrase in SIGNING_KEY_PASSPHRASE. +sign-and-package-helm-chart() { chart="${1}" - version="${2}" - if [ -z "${chart}" ] || [ -z "${version}" ]; then - echo 'usage: sign-helm-chart ' + if [ -z "${chart}" ]; then + echo 'usage: sign-and-package-helm-chart ' return 1 fi @@ -15,39 +20,19 @@ sign-helm-chart() { return 1 fi - set -x - chart_repo="${CHART_REPO:-${chart}}" signing_key="${SIGNING_KEY:-Deis, Inc. (Helm chart signing key)}" keyring="${KEYRING:-${JENKINS_HOME}/.gnupg/secring.gpg}" - helm repo add "${chart_repo}" https://charts.deis.com/"${chart_repo}" - helm fetch --untar "${chart_repo}"/"${chart}" --version "${version}" - set +x + echo "Signing packaged chart '${chart}' with key '${signing_key}' from keyring '${keyring}'..." >&2 # HACK(vdice): create pseudo-terminal to emulate entering passphrase when prompted # Remove once helm supports gpg-agent/automated passphrase entry printf '%s\n' "${SIGNING_KEY_PASSPHRASE}" | \ script -q -c "helm package --sign --key '${signing_key}' --keyring ${keyring} ${chart}" /dev/null &> /dev/null - - if [ ! -f "${chart}-${version}.tgz.prov" ]; then - echo "${chart}-${version}.tgz.prov not found! Signing unsuccessful" - return 1 - fi -} - -upload-signed-chart() { - signed_chart="${1}" - chart_repo="${2}" - - if [ -z "${signed_chart}" ] || [ -z "${chart_repo}" ]; then - echo 'usage: upload-signed-chart ' - return 1 - fi - - aws s3 cp "${signed_chart}.tgz" s3://helm-charts/"${chart_repo}"/ \ - && aws s3 cp "${signed_chart}.tgz.prov" s3://helm-charts/"${chart_repo}"/ } +# download-and-init-helm downloads helm based on HELM_VERSION and HELM_OS and +# runs 'helm init -c' using HELM_HOME download-and-init-helm() { export HELM_VERSION="${HELM_VERSION:-canary}" export HELM_OS="${HELM_OS:-linux}" @@ -58,3 +43,155 @@ download-and-init-helm() { && export PATH="${HELM_OS}-amd64:${PATH}" \ && helm init -c } + +# publish-helm-chart publishes the given chart to the chart repo determined +# by the given repo_type. Will also attempt to sign chart if SIGN_CHART is true OR +# repo_type is 'staging' +publish-helm-chart() { + local chart="${1}" + local repo_type="${2}" + + # give ACTUAL_COMMIT precedence for use in chart versioning, assuming COMPONENT_REPO is empty/null + # otherwise, ACTUAL_COMMIT is tied to the COMPONENT_REPO for use in assembling the workflow chart below + # shellcheck disable=SC2153 + if [ -n "${ACTUAL_COMMIT}" ] && [ -z "${COMPONENT_REPO}" ]; then + SHORT_SHA="${ACTUAL_COMMIT:0:7}" + fi + + # if repo_type not 'staging', check out RELEASE_TAG tag (if empty, just stays on master commit) + if [ "${repo_type}" != 'staging' ]; then + git checkout -q "${RELEASE_TAG}" + fi + + short_sha="${SHORT_SHA:-$(git rev-parse --short HEAD)}" + git_tag="${RELEASE_TAG:-$(git describe --abbrev=0 --tags)}" + timestamp="${TIMESTAMP:-$(date -u +%Y%m%d%H%M%S)}" + chart_repo="$(echo "${chart}-${repo_type}" | sed -e 's/-production//g')" + + if [ -d "${PWD}"/charts ]; then + cd "${PWD}"/charts + download-and-init-helm + + chart_version="${git_tag}" + # if dev/pr chart, will use incremented patch version (v1.2.3 -> v1.2.4) and add prerelease build info + incremented_patch_version="$(( ${chart_version: -1} +1))" + if [ "${chart_repo}" == "${chart}-dev" ]; then + chart_version="${chart_version%?}${incremented_patch_version}-dev-${timestamp}-sha.${short_sha}" + elif [ "${chart_repo}" == "${chart}-pr" ]; then + # TODO: add timestamp once https://github.com/Masterminds/semver/issues/34 is resolved + # chart_version="${chart_version%?}${incremented_patch_version}-${timestamp}-sha.${short_sha}" + chart_version="${chart_version%?}${incremented_patch_version}-sha.${short_sha}" + fi + + update-chart "${chart}" "${chart_version}" "${chart_repo}" + + if [ "${SIGN_CHART}" == true ]; then + sign-and-package-helm-chart "${chart}" + aws s3 cp "${chart}-${chart_version}".tgz.prov "${DEIS_CHARTS_BUCKET_BASE_URL}/${chart}"/ + else + helm package "${chart}" + fi + + # download index file from aws s3 bucket + aws s3 cp "${DEIS_CHARTS_BUCKET_BASE_URL}/${chart_repo}/index.yaml" . + + # update index file + helm repo index . --url "${DEIS_CHARTS_BASE_URL}/${chart_repo}" --merge ./index.yaml + + # push packaged chart and updated index file to aws s3 bucket + aws s3 cp "${chart}-${chart_version}".tgz "${DEIS_CHARTS_BUCKET_BASE_URL}/${chart_repo}"/ \ + && aws s3 cp --cache-control max_age=0 index.yaml "${DEIS_CHARTS_BUCKET_BASE_URL}/${chart_repo}"/index.yaml \ + && aws s3 cp "${chart}"/values.yaml "${DEIS_CHARTS_BUCKET_BASE_URL}/${chart_repo}/values-${chart_version}".yaml + else + echo "No 'charts' directory found at project level; nothing to publish." + fi +} + +# update-chart updates a given chart, using the provided chart, chart_version +# and chart_repo values. If the chart is 'workflow', a space-delimited list of +# component charts is expected to be present in a COMPONENT_CHART_AND_REPOS env var +update-chart() { + local chart="${1}" + local chart_version="${2}" + local chart_repo="${3}" + + # update the chart version + perl -i -0pe "s//${chart_version}/g" "${chart}"/Chart.yaml + + if [ "${chart}" != 'workflow' ]; then + ## make component chart updates + if [ "${chart_repo}" == "${chart}" ]; then + ## chart repo is production repo; update values appropriately + # update all org values to "deis" + perl -i -0pe 's/"deisci"/"deis"/g' "${chart}"/values.yaml + # update the image pull policy to "IfNotPresent" + perl -i -0pe 's/"Always"/"IfNotPresent"/g' "${chart}"/values.yaml + # update the dockerTag value to chart_version + perl -i -0pe "s/canary/${chart_version}/g" "${chart}"/values.yaml + fi + # send chart version on for use in downstream jobs + echo "COMPONENT_CHART_VERSION=${chart_version}" >> "${ENV_FILE_PATH:-/dev/null}" + else + ## make workflow chart updates + # update requirements.yaml with correct chart version and chart repo for each component + for component in ${COMPONENT_CHART_AND_REPOS}; do + IFS=':' read -r -a chart_and_repo <<< "${component}" + component_chart="${chart_and_repo[0]}" + component_repo="${chart_and_repo[1]}" + latest_tag="$(get-latest-component-release "${component_repo}")" + + component_chart_version="${latest_tag}" + component_chart_repo="${component_chart}" + # if COMPONENT_REPO matches this component repo and COMPONENT_CHART_VERSION is non-empty/non-null, + # this signifies we need to set component chart version to correlate with PR artifact + # shellcheck disable=SC2153 + if [ "${COMPONENT_REPO}" == "${component_repo}" ] && [ -n "${COMPONENT_CHART_VERSION}" ] && [ "${chart_repo}" == "${chart}-pr" ]; then + component_chart_version="${COMPONENT_CHART_VERSION}" + component_chart_repo="${component_chart}-pr" + elif [ "${chart_version}" != "${git_tag}" ]; then + # workflow chart version has build data; is -dev variant. assign component version/repo accordingly + component_chart_version=">=${latest_tag}-dev" + component_chart_repo="${component_chart}-dev" + fi + + perl -i -0pe 's/<'"${component_chart}"'-tag>/"'"${component_chart_version}"'"/g' "${chart}"/requirements.yaml + perl -i -0pe 's='"${DEIS_CHARTS_BASE_URL}/${component_chart}\n"'='"${DEIS_CHARTS_BASE_URL}/${component_chart_repo}\n"'=g' "${chart}"/requirements.yaml + helm repo add "${component_chart_repo}" "${DEIS_CHARTS_BASE_URL}/${component_chart_repo}" + + # DEBUG + helm search "${component_chart_repo}"/"${component_chart}" -l + done + + # TEMP FIX: remove when registry-proxy no longer under deis (https://github.com/deis/workflow/issues/644 closed) + perl -i -0pe 's//"v1.1.1"/g' "${chart}"/requirements.yaml + helm repo add registry-proxy "${DEIS_CHARTS_BASE_URL}/registry-proxy" + + # DEBUG + helm repo list + + # display resulting requirements.yaml to verify component chart versions + cat "${chart}"/requirements.yaml + + # fetch all dependent charts based on above + helm dependency update "${chart}" + + if [ "${chart_repo}" == "${chart}-staging" ]; then + # 'stage' signed chart on production sans index.file (so chart may not be used + # but is ready to copy to production repo with index.file if approved) + sign-and-package-helm-chart "${chart}" + + aws s3 cp "${chart}-${chart_version}".tgz "${DEIS_CHARTS_BUCKET_BASE_URL}/${chart}"/ \ + && aws s3 cp "${chart}-${chart_version}".tgz.prov "${DEIS_CHARTS_BUCKET_BASE_URL}/${chart}"/ \ + && aws s3 cp "${chart}"/values.yaml "${DEIS_CHARTS_BUCKET_BASE_URL}/${chart}/values-${chart_version}".yaml + fi + + if [ "${chart_repo}" != "${chart}" ]; then + # modify workflow-manager/doctor urls in values.yaml to point to staging + perl -i -0pe "s/versions.deis/versions-staging.deis/g" "${chart}"/values.yaml + perl -i -0pe "s/doctor.deis/doctor-staging.deis/g" "${chart}"/values.yaml + fi + + # set WORKFLOW_TAG for downstream e2e job to read from + echo "WORKFLOW_TAG=${chart_version}" >> "${ENV_FILE_PATH:-/dev/null}" + fi +} diff --git a/bash/scripts/publish_helm_chart.sh b/bash/scripts/publish_helm_chart.sh deleted file mode 100644 index e097e81..0000000 --- a/bash/scripts/publish_helm_chart.sh +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/env bash - -set -eo pipefail - -export DEIS_CHARTS_BASE_URL="https://charts.deis.com" -export DEIS_CHARTS_BUCKET_BASE_URL="s3://helm-charts" - -# publish-helm-chart publishes the given chart to the chart repo determined -# by the given repo_type -publish-helm-chart() { - local chart="${1}" - local repo_type="${2}" - - # give ACTUAL_COMMIT precedence for use in chart versioning, assuming COMPONENT_REPO is empty/null - # otherwise, ACTUAL_COMMIT is tied to the COMPONENT_REPO for use in assembling the workflow chart below - # shellcheck disable=SC2153 - if [ -n "${ACTUAL_COMMIT}" ] && [ -z "${COMPONENT_REPO}" ]; then - SHORT_SHA="${ACTUAL_COMMIT:0:7}" - fi - - # if repo_type not 'staging', check out RELEASE_TAG tag (if empty, just stays on master commit) - if [ "${repo_type}" != 'staging' ]; then - git checkout -q "${RELEASE_TAG}" - fi - - short_sha="${SHORT_SHA:-$(git rev-parse --short HEAD)}" - git_tag="${RELEASE_TAG:-$(git describe --abbrev=0 --tags)}" - timestamp="${TIMESTAMP:-$(date -u +%Y%m%d%H%M%S)}" - chart_repo="$(echo "${chart}-${repo_type}" | sed -e 's/-production//g')" - - if [ -d "${PWD}"/charts ]; then - cd "${PWD}"/charts - download-and-init-helm - - chart_version="${git_tag}" - # if dev/pr chart, will use incremented patch version (v1.2.3 -> v1.2.4) and add prerelease build info - incremented_patch_version="$(( ${chart_version: -1} +1))" - if [ "${chart_repo}" == "${chart}-dev" ]; then - chart_version="${chart_version%?}${incremented_patch_version}-dev-${timestamp}-sha.${short_sha}" - elif [ "${chart_repo}" == "${chart}-pr" ]; then - # TODO: add timestamp once https://github.com/Masterminds/semver/issues/34 is resolved - # chart_version="${chart_version%?}${incremented_patch_version}-${timestamp}-sha.${short_sha}" - chart_version="${chart_version%?}${incremented_patch_version}-sha.${short_sha}" - fi - - update-chart "${chart}" "${chart_version}" "${chart_repo}" - - helm package "${chart}" - - # download index file from aws s3 bucket - aws s3 cp "${DEIS_CHARTS_BUCKET_BASE_URL}/${chart_repo}/index.yaml" . - - # update index file - helm repo index . --url "${DEIS_CHARTS_BASE_URL}/${chart_repo}" --merge ./index.yaml - - # push packaged chart and updated index file to aws s3 bucket - aws s3 cp "${chart}-${chart_version}".tgz "${DEIS_CHARTS_BUCKET_BASE_URL}/${chart_repo}"/ \ - && aws s3 cp --cache-control max_age=0 index.yaml "${DEIS_CHARTS_BUCKET_BASE_URL}/${chart_repo}"/index.yaml \ - && aws s3 cp "${chart}"/values.yaml "${DEIS_CHARTS_BUCKET_BASE_URL}/${chart_repo}/values-${chart_version}".yaml - else - echo "No 'charts' directory found at project level; nothing to publish." - fi -} - -# update-chart updates a given chart, using the provided chart, chart_version -# and chart_repo values. If the chart is 'workflow', a space-delimited list of -# component charts is expected to be present in a COMPONENT_CHART_AND_REPOS env var -update-chart() { - local chart="${1}" - local chart_version="${2}" - local chart_repo="${3}" - - # update the chart version - perl -i -0pe "s//${chart_version}/g" "${chart}"/Chart.yaml - - if [ "${chart}" != 'workflow' ]; then - ## make component chart updates - if [ "${chart_repo}" == "${chart}" ]; then - ## chart repo is production repo; update values appropriately - # update all org values to "deis" - perl -i -0pe 's/"deisci"/"deis"/g' "${chart}"/values.yaml - # update the image pull policy to "IfNotPresent" - perl -i -0pe 's/"Always"/"IfNotPresent"/g' "${chart}"/values.yaml - # update the dockerTag value to chart_version - perl -i -0pe "s/canary/${chart_version}/g" "${chart}"/values.yaml - fi - # send chart version on for use in downstream jobs - echo "COMPONENT_CHART_VERSION=${chart_version}" >> "${ENV_FILE_PATH:-/dev/null}" - else - ## make workflow chart updates - # update requirements.yaml with correct chart version and chart repo for each component - for component in ${COMPONENT_CHART_AND_REPOS}; do - IFS=':' read -r -a chart_and_repo <<< "${component}" - component_chart="${chart_and_repo[0]}" - component_repo="${chart_and_repo[1]}" - latest_tag="$(get-latest-component-release "${component_repo}")" - - component_chart_version="${latest_tag}" - component_chart_repo="${component_chart}" - # if COMPONENT_REPO matches this component repo and COMPONENT_CHART_VERSION is non-empty/non-null, - # this signifies we need to set component chart version to correlate with PR artifact - # shellcheck disable=SC2153 - if [ "${COMPONENT_REPO}" == "${component_repo}" ] && [ -n "${COMPONENT_CHART_VERSION}" ] && [ "${chart_repo}" == "${chart}-pr" ]; then - component_chart_version="${COMPONENT_CHART_VERSION}" - component_chart_repo="${component_chart}-pr" - elif [ "${chart_version}" != "${git_tag}" ]; then - # workflow chart version has build data; is -dev variant. assign component version/repo accordingly - component_chart_version=">=${latest_tag}-dev" - component_chart_repo="${component_chart}-dev" - fi - - perl -i -0pe 's/<'"${component_chart}"'-tag>/"'"${component_chart_version}"'"/g' "${chart}"/requirements.yaml - perl -i -0pe 's='"${DEIS_CHARTS_BASE_URL}/${component_chart}\n"'='"${DEIS_CHARTS_BASE_URL}/${component_chart_repo}\n"'=g' "${chart}"/requirements.yaml - helm repo add "${component_chart_repo}" "${DEIS_CHARTS_BASE_URL}/${component_chart_repo}" - - # DEBUG - helm search "${component_chart_repo}"/"${component_chart}" -l - done - - # TEMP FIX: remove when registry-proxy no longer under deis (https://github.com/deis/workflow/issues/644 closed) - perl -i -0pe 's//"v1.1.1"/g' "${chart}"/requirements.yaml - helm repo add registry-proxy "${DEIS_CHARTS_BASE_URL}/registry-proxy" - - # DEBUG - helm repo list - - # display resulting requirements.yaml to verify component chart versions - cat "${chart}"/requirements.yaml - - # fetch all dependent charts based on above - helm dependency update "${chart}" - - if [ "${chart_repo}" == "${chart}-staging" ]; then - # 'stage' chart on production sans index.file (so chart may not be used) - helm package "${chart}" - - aws s3 cp "${chart}-${chart_version}".tgz "${DEIS_CHARTS_BUCKET_BASE_URL}/${chart}"/ \ - && aws s3 cp "${chart}"/values.yaml "${DEIS_CHARTS_BUCKET_BASE_URL}/${chart}/values-${chart_version}".yaml - fi - - if [ "${chart_repo}" != "${chart}" ]; then - # modify workflow-manager/doctor urls in values.yaml to point to staging - perl -i -0pe "s/versions.deis/versions-staging.deis/g" "${chart}"/values.yaml - perl -i -0pe "s/doctor.deis/doctor-staging.deis/g" "${chart}"/values.yaml - fi - - # set WORKFLOW_TAG for downstream e2e job to read from - echo "WORKFLOW_TAG=${chart_version}" >> "${ENV_FILE_PATH:-/dev/null}" - fi -} diff --git a/bash/tests/helm_chart_actions_test.bats b/bash/tests/helm_chart_actions_test.bats index b864f4d..7ba6463 100644 --- a/bash/tests/helm_chart_actions_test.bats +++ b/bash/tests/helm_chart_actions_test.bats @@ -3,59 +3,352 @@ setup() { . "${BATS_TEST_DIRNAME}/../scripts/helm_chart_actions.sh" load stub + + stub wget + stub git + stub aws stub helm + stub tar + stub get-latest-component-release "echo 'v3.0.3'" - CHART='workflow' - VERSION='v1.2.3' + PWD="${BATS_TEST_DIRNAME}/tmp" + WORKDIR="${PWD}/charts" + ENV_FILE_PATH="${WORKDIR}/env.file" } teardown() { rm_stubs } -@test "sign-helm-chart : CHART and VERSION missing" { - run sign-helm-chart +setup-publish-chart-workspace() { + SHORT_SHA='abc1234' + RELEASE_TAG='v1.2.3' + EXPECTED_PRERELEASE_TAG='v1.2.4' + TIMESTAMP="$(date -u +%Y%m%d%H%M%S)" + + chart="${1}" + + mkdir -p "${WORKDIR}/${chart}" + echo '' > "${WORKDIR}/${chart}/Chart.yaml" +} + +# sign-and-package-helm-chart +@test "sign-and-package-helm-chart : usage" { + run sign-and-package-helm-chart [ "${status}" -eq 1 ] - [ "${output}" == "usage: sign-helm-chart " ] + [ "${output}" == "usage: sign-and-package-helm-chart " ] } -@test "sign-helm-chart : SIGNING_KEY_PASSPHRASE not in env" { - run sign-helm-chart "${CHART}" "${VERSION}" +@test "sign-and-package-helm-chart : default, no SIGNING_KEY_PASSPHRASE" { + run sign-and-package-helm-chart 'workflow' [ "${status}" -eq 1 ] [ "${output}" == "SIGNING_KEY_PASSPHRASE must be available in the env to sign a helm chart" ] } -@test "sign-helm-chart : defaults" { +@test "sign-and-package-helm-chart : default, SIGNING_KEY_PASSPHRASE available" { + stub script SIGNING_KEY_PASSPHRASE="foo" - run sign-helm-chart "${CHART}" "${VERSION}" + run sign-and-package-helm-chart 'workflow' - [ "${status}" -eq 1 ] - [ "${lines[0]}" == "++ chart_repo=workflow" ] - [ "${lines[1]}" == "++ signing_key='Deis, Inc. (Helm chart signing key)'" ] - [ "${lines[2]}" == "++ keyring=/.gnupg/secring.gpg" ] - [ "${lines[3]}" == "++ helm repo add workflow https://charts.deis.com/workflow" ] - [ "${lines[4]}" == "++ helm fetch --untar workflow/workflow --version v1.2.3" ] - [ "${lines[5]}" == "++ set +x" ] - [ "${lines[6]}" == "${CHART}-${VERSION}.tgz.prov not found! Signing unsuccessful" ] + [ "${output}" == "Signing packaged chart 'workflow' with key 'Deis, Inc. (Helm chart signing key)' from keyring '/.gnupg/secring.gpg'..." ] } -@test "sign-helm-chart : override defaults via env" { +@test "sign-and-package-helm-chart : non-defaults, SIGNING_KEY_PASSPHRASE available" { + stub script SIGNING_KEY_PASSPHRASE="foo" - CHART_REPO="workflow-dev" SIGNING_KEY="Different Key" KEYRING="/diff/keyring/location" - run sign-helm-chart "${CHART}" "${VERSION}" + run sign-and-package-helm-chart 'workflow' - [ "${status}" -eq 1 ] - [ "${lines[0]}" == "++ chart_repo=workflow-dev" ] - [ "${lines[1]}" == "++ signing_key='Different Key'" ] - [ "${lines[2]}" == "++ keyring=/diff/keyring/location" ] - [ "${lines[3]}" == "++ helm repo add workflow-dev https://charts.deis.com/workflow-dev" ] - [ "${lines[4]}" == "++ helm fetch --untar workflow-dev/workflow --version v1.2.3" ] - [ "${lines[5]}" == "++ set +x" ] - [ "${lines[6]}" == "${CHART}-${VERSION}.tgz.prov not found! Signing unsuccessful" ] + [ "${output}" == "Signing packaged chart 'workflow' with key 'Different Key' from keyring '/diff/keyring/location'..." ] +} + +# publish-helm-chart +@test "publish-helm-chart: no charts dir" { + run publish-helm-chart + + [ "${status}" -eq 0 ] + [ "${output}" == "No 'charts' directory found at project level; nothing to publish." ] +} + +@test "publish-helm-chart: component dev" { + chart='router' + repo_type='dev' + setup-publish-chart-workspace "${chart}" + + echo '"deisci" "Always" canary' > "${WORKDIR}/${chart}/values.yaml" + + run publish-helm-chart "${chart}" "${repo_type}" + + [ "${status}" -eq 0 ] + [ "$(cat "${WORKDIR}/${chart}/Chart.yaml")" == "${EXPECTED_PRERELEASE_TAG}-dev-${TIMESTAMP}-sha.${SHORT_SHA}" ] + [ "$(cat "${WORKDIR}/env.file")" == "COMPONENT_CHART_VERSION=${EXPECTED_PRERELEASE_TAG}-dev-${TIMESTAMP}-sha.${SHORT_SHA}" ] + [ "$(cat "${WORKDIR}/${chart}/values.yaml")" == "\"deisci\" \"Always\" canary" ] +} + +@test "publish-helm-chart: component pr" { + chart='router' + repo_type='pr' + setup-publish-chart-workspace "${chart}" + + echo '"deisci" "Always" canary' > "${WORKDIR}/${chart}/values.yaml" + + run publish-helm-chart "${chart}" "${repo_type}" + + [ "${status}" -eq 0 ] + [ "$(cat "${WORKDIR}/${chart}/Chart.yaml")" == "${EXPECTED_PRERELEASE_TAG}-sha.${SHORT_SHA}" ] + [ "$(cat "${WORKDIR}/env.file")" == "COMPONENT_CHART_VERSION=${EXPECTED_PRERELEASE_TAG}-sha.${SHORT_SHA}" ] + [ "$(cat "${WORKDIR}/${chart}/values.yaml")" == "\"deisci\" \"Always\" canary" ] +} + +@test "publish-helm-chart: component pr, ACTUAL_COMMIT set" { + ACTUAL_COMMIT='ghi78912345' + chart='router' + repo_type='pr' + setup-publish-chart-workspace "${chart}" + + echo '"deisci" "Always" canary' > "${WORKDIR}/${chart}/values.yaml" + + run publish-helm-chart "${chart}" "${repo_type}" + + [ "${status}" -eq 0 ] + [ "$(cat "${WORKDIR}/${chart}/Chart.yaml")" == "${EXPECTED_PRERELEASE_TAG}-sha.ghi7891" ] + [ "$(cat "${WORKDIR}/env.file")" == "COMPONENT_CHART_VERSION=${EXPECTED_PRERELEASE_TAG}-sha.ghi7891" ] + [ "$(cat "${WORKDIR}/${chart}/values.yaml")" == "\"deisci\" \"Always\" canary" ] +} + +@test "publish-helm-chart: component pr" { + chart='router' + repo_type='pr' + setup-publish-chart-workspace "${chart}" + + run publish-helm-chart "${chart}" "${repo_type}" + + [ "${status}" -eq 0 ] + [ "$(cat "${WORKDIR}/${chart}/Chart.yaml")" == "${EXPECTED_PRERELEASE_TAG}-sha.${SHORT_SHA}" ] +} + +@test "publish-helm-chart: component pr, ACTUAL_COMMIT set" { + ACTUAL_COMMIT='ghi78912345' + chart='router' + repo_type='pr' + setup-publish-chart-workspace "${chart}" + + run publish-helm-chart "${chart}" "${repo_type}" + + [ "${status}" -eq 0 ] + [ "$(cat "${WORKDIR}/${chart}/Chart.yaml")" == "${EXPECTED_PRERELEASE_TAG}-sha.ghi7891" ] +} + +@test "publish-helm-chart: component production, SIGN_CHART true" { + SIGN_CHART=true + SIGNING_KEY_PASSPHRASE='foo' + chart='router' + repo_type='production' + setup-publish-chart-workspace "${chart}" + + echo '"deisci" "Always" canary' > "${WORKDIR}/${chart}/values.yaml" + + run publish-helm-chart "${chart}" "${repo_type}" + + [ "${status}" -eq 0 ] + [ "${output}" == "Signing packaged chart '${chart}' with key 'Deis, Inc. (Helm chart signing key)' from keyring '/.gnupg/secring.gpg'..." ] + [ "$(cat "${WORKDIR}/${chart}/Chart.yaml")" == "${RELEASE_TAG}" ] + [ "$(cat "${WORKDIR}/${chart}/values.yaml")" == "\"deis\" \"IfNotPresent\" ${RELEASE_TAG}" ] +} + +@test "publish-helm-chart: component production, SIGN_CHART false" { + SIGN_CHART=false + chart='router' + repo_type='production' + setup-publish-chart-workspace "${chart}" + + echo '"deisci" "Always" canary' > "${WORKDIR}/${chart}/values.yaml" + + run publish-helm-chart "${chart}" "${repo_type}" + + [ "${status}" -eq 0 ] + [ "${output}" == "" ] + [ "$(cat "${WORKDIR}/${chart}/Chart.yaml")" == "${RELEASE_TAG}" ] + [ "$(cat "${WORKDIR}/${chart}/values.yaml")" == "\"deis\" \"IfNotPresent\" ${RELEASE_TAG}" ] +} + +@test "publish-helm-chart: workflow dev" { + chart='workflow' + repo_type='dev' + setup-publish-chart-workspace "${chart}" + COMPONENT_CHART_AND_REPOS="registry:registry registry-proxy:registry-proxy database:postgres" + + echo ' https://charts.deis.com/registry + https://charts.deis.com/registry-proxy + https://charts.deis.com/database' > "${WORKDIR}/${chart}/requirements.yaml" + + echo 'versions.deis.com doctor.deis.com' > "${WORKDIR}/${chart}/values.yaml" + + run publish-helm-chart "${chart}" "${repo_type}" + + expected_requirements_yaml='">=v3.0.3-dev" https://charts.deis.com/registry-dev +">=v3.0.3-dev" https://charts.deis.com/registry-proxy-dev +">=v3.0.3-dev" https://charts.deis.com/database-dev' + + [ "${status}" -eq 0 ] + [ "$(cat "${WORKDIR}/${chart}/Chart.yaml")" == "${EXPECTED_PRERELEASE_TAG}-dev-${TIMESTAMP}-sha.${SHORT_SHA}" ] + [ "$(cat "${WORKDIR}/${chart}/requirements.yaml")" == "${expected_requirements_yaml}" ] + [ "$(cat "${WORKDIR}/${chart}/values.yaml")" == 'versions-staging.deis.com doctor-staging.deis.com' ] + [ "$(cat "${WORKDIR}/env.file")" == "WORKFLOW_TAG=${EXPECTED_PRERELEASE_TAG}-dev-${TIMESTAMP}-sha.${SHORT_SHA}" ] +} + +@test "publish-helm-chart: workflow dev; COMPONENT_REPO and ACTUAL_COMMIT in env" { + COMPONENT_REPO=registry-proxy + ACTUAL_COMMIT='ghi78912345' + chart='workflow' + repo_type='dev' + setup-publish-chart-workspace "${chart}" + COMPONENT_CHART_AND_REPOS="registry:registry registry-proxy:registry-proxy database:postgres" + + echo ' https://charts.deis.com/registry + https://charts.deis.com/registry-proxy + https://charts.deis.com/database' > "${WORKDIR}/${chart}/requirements.yaml" + + echo 'versions.deis.com doctor.deis.com' > "${WORKDIR}/${chart}/values.yaml" + + run publish-helm-chart "${chart}" "${repo_type}" + + expected_requirements_yaml='">=v3.0.3-dev" https://charts.deis.com/registry-dev +">=v3.0.3-dev" https://charts.deis.com/registry-proxy-dev +">=v3.0.3-dev" https://charts.deis.com/database-dev' + + [ "${status}" -eq 0 ] + [ "$(cat "${WORKDIR}/${chart}/Chart.yaml")" == "${EXPECTED_PRERELEASE_TAG}-dev-${TIMESTAMP}-sha.${SHORT_SHA}" ] + [ "$(cat "${WORKDIR}/${chart}/requirements.yaml")" == "${expected_requirements_yaml}" ] + [ "$(cat "${WORKDIR}/${chart}/values.yaml")" == 'versions-staging.deis.com doctor-staging.deis.com' ] + [ "$(cat "${WORKDIR}/env.file")" == "WORKFLOW_TAG=${EXPECTED_PRERELEASE_TAG}-dev-${TIMESTAMP}-sha.${SHORT_SHA}" ] +} + +@test "publish-helm-chart: workflow pr; no COMPONENT_REPO, COMPONENT_CHART_VERSION or ACTUAL_COMMIT" { + chart='workflow' + repo_type='pr' + setup-publish-chart-workspace "${chart}" + COMPONENT_CHART_AND_REPOS="registry:registry registry-proxy:registry-proxy database:postgres" + + echo ' https://charts.deis.com/registry + https://charts.deis.com/registry-proxy + https://charts.deis.com/database' > "${WORKDIR}/${chart}/requirements.yaml" + + echo 'versions.deis.com doctor.deis.com' > "${WORKDIR}/${chart}/values.yaml" + + run publish-helm-chart "${chart}" "${repo_type}" + + expected_requirements_yaml='">=v3.0.3-dev" https://charts.deis.com/registry-dev +">=v3.0.3-dev" https://charts.deis.com/registry-proxy-dev +">=v3.0.3-dev" https://charts.deis.com/database-dev' + + [ "${status}" -eq 0 ] + [ "$(cat "${WORKDIR}/${chart}/Chart.yaml")" == "${EXPECTED_PRERELEASE_TAG}-sha.${SHORT_SHA}" ] + [ "$(cat "${WORKDIR}/${chart}/requirements.yaml")" == "${expected_requirements_yaml}" ] + [ "$(cat "${WORKDIR}/${chart}/values.yaml")" == 'versions-staging.deis.com doctor-staging.deis.com' ] + [ "$(cat "${WORKDIR}/env.file")" == "WORKFLOW_TAG=${EXPECTED_PRERELEASE_TAG}-sha.${SHORT_SHA}" ] +} + +@test "publish-helm-chart: workflow pr; ACTUAL_COMMIT in env" { + ACTUAL_COMMIT='ghi78912345' + chart='workflow' + repo_type='pr' + setup-publish-chart-workspace "${chart}" + + echo 'versions.deis.com doctor.deis.com' > "${WORKDIR}/${chart}/values.yaml" + + run publish-helm-chart "${chart}" "${repo_type}" + + [ "${status}" -eq 0 ] + [ "$(cat "${WORKDIR}/${chart}/Chart.yaml")" == "${EXPECTED_PRERELEASE_TAG}-sha.ghi7891" ] + [ "$(cat "${WORKDIR}/${chart}/values.yaml")" == 'versions-staging.deis.com doctor-staging.deis.com' ] + [ "$(cat "${WORKDIR}/env.file")" == "WORKFLOW_TAG=${EXPECTED_PRERELEASE_TAG}-sha.ghi7891" ] +} + +@test "publish-helm-chart: workflow pr; COMPONENT_REPO, COMPONENT_CHART_VERSION and ACTUAL_COMMIT in env" { + COMPONENT_REPO=registry-proxy + COMPONENT_CHART_VERSION="v3.0.4-sha.jkl5678" + ACTUAL_COMMIT='ghi78912345' + chart='workflow' + repo_type='pr' + setup-publish-chart-workspace "${chart}" + COMPONENT_CHART_AND_REPOS="registry:registry registry-proxy:registry-proxy database:postgres" + + echo ' https://charts.deis.com/registry + https://charts.deis.com/registry-proxy + https://charts.deis.com/database' > "${WORKDIR}/${chart}/requirements.yaml" + + echo 'versions.deis.com doctor.deis.com' > "${WORKDIR}/${chart}/values.yaml" + + run publish-helm-chart "${chart}" "${repo_type}" + + expected_requirements_yaml='">=v3.0.3-dev" https://charts.deis.com/registry-dev +"'"${COMPONENT_CHART_VERSION}"'" https://charts.deis.com/registry-proxy-pr +">=v3.0.3-dev" https://charts.deis.com/database-dev' + + [ "${status}" -eq 0 ] + [ "$(cat "${WORKDIR}/${chart}/Chart.yaml")" == "${EXPECTED_PRERELEASE_TAG}-sha.${SHORT_SHA}" ] + [ "$(cat "${WORKDIR}/${chart}/requirements.yaml")" == "${expected_requirements_yaml}" ] + [ "$(cat "${WORKDIR}/${chart}/values.yaml")" == 'versions-staging.deis.com doctor-staging.deis.com' ] + [ "$(cat "${WORKDIR}/env.file")" == "WORKFLOW_TAG=${EXPECTED_PRERELEASE_TAG}-sha.${SHORT_SHA}" ] +} + +@test "publish-helm-chart: workflow staging" { + SIGNING_KEY_PASSPHRASE='foo' + chart='workflow' + repo_type='staging' + setup-publish-chart-workspace "${chart}" + COMPONENT_CHART_AND_REPOS="registry:registry registry-proxy:registry-proxy database:postgres" + + echo ' https://charts.deis.com/registry + https://charts.deis.com/registry-proxy + https://charts.deis.com/database' > "${WORKDIR}/${chart}/requirements.yaml" + + echo 'versions.deis.com doctor.deis.com' > "${WORKDIR}/${chart}/values.yaml" + + run publish-helm-chart "${chart}" "${repo_type}" + + expected_requirements_yaml='"v3.0.3" https://charts.deis.com/registry +"v3.0.3" https://charts.deis.com/registry-proxy +"v3.0.3" https://charts.deis.com/database' + + expected_output=''"${expected_requirements_yaml}"' +Signing packaged chart '"'workflow'"' with key '"'Deis, Inc. (Helm chart signing key)'"' from keyring '"'/.gnupg/secring.gpg'"'...' + + [ "${status}" -eq 0 ] + [ "${output}" == "${expected_output}" ] + [ "$(cat "${WORKDIR}/${chart}/Chart.yaml")" == "${RELEASE_TAG}" ] + [ "$(cat "${WORKDIR}/${chart}/requirements.yaml")" == "${expected_requirements_yaml}" ] + [ "$(cat "${WORKDIR}/${chart}/values.yaml")" == 'versions-staging.deis.com doctor-staging.deis.com' ] + [ "$(cat "${WORKDIR}/env.file")" == "WORKFLOW_TAG=${RELEASE_TAG}" ] +} + +@test "publish-helm-chart: workflow production" { + chart='workflow' + repo_type='production' + setup-publish-chart-workspace "${chart}" + COMPONENT_CHART_AND_REPOS="registry:registry registry-proxy:registry-proxy database:postgres" + + echo ' https://charts.deis.com/registry + https://charts.deis.com/registry-proxy + https://charts.deis.com/database' > "${WORKDIR}/${chart}/requirements.yaml" + + echo 'versions.deis.com doctor.deis.com' > "${WORKDIR}/${chart}/values.yaml" + + run publish-helm-chart "${chart}" "${repo_type}" + + expected_requirements_yaml='"v3.0.3" https://charts.deis.com/registry +"v3.0.3" https://charts.deis.com/registry-proxy +"v3.0.3" https://charts.deis.com/database' + + [ "${status}" -eq 0 ] + [ "$(cat "${WORKDIR}/${chart}/Chart.yaml")" == "${RELEASE_TAG}" ] + [ "$(cat "${WORKDIR}/${chart}/requirements.yaml")" == "${expected_requirements_yaml}" ] + [ "$(cat "${WORKDIR}/${chart}/values.yaml")" == 'versions.deis.com doctor.deis.com' ] + [ "$(cat "${WORKDIR}/env.file")" == "WORKFLOW_TAG=${RELEASE_TAG}" ] } diff --git a/bash/tests/publish_helm_chart_test.bats b/bash/tests/publish_helm_chart_test.bats deleted file mode 100644 index 363e274..0000000 --- a/bash/tests/publish_helm_chart_test.bats +++ /dev/null @@ -1,293 +0,0 @@ -#!/usr/bin/env bats - -setup() { - . "${BATS_TEST_DIRNAME}/../scripts/publish_helm_chart.sh" - load stub - - stub wget - stub git - stub aws - stub helm - stub download-and-init-helm - stub get-latest-component-release "echo 'v3.0.3'" - - PWD="${BATS_TEST_DIRNAME}/tmp" - WORKDIR="${PWD}/charts" - ENV_FILE_PATH="${WORKDIR}/env.file" - SHORT_SHA='abc1234' - RELEASE_TAG='v1.2.3' - EXPECTED_PRERELEASE_TAG='v1.2.4' - TIMESTAMP="$(date -u +%Y%m%d%H%M%S)" -} - -teardown() { - rm_stubs -} - -setup-chart-workspace() { - chart="${1}" - - mkdir -p "${WORKDIR}/${chart}" - echo '' > "${WORKDIR}/${chart}/Chart.yaml" -} - -@test "publish-helm-chart: no charts dir" { - run publish-helm-chart - - [ "${status}" -eq 0 ] - [ "${output}" == "No 'charts' directory found at project level; nothing to publish." ] -} - -@test "publish-helm-chart: component dev" { - chart='router' - repo_type='dev' - setup-chart-workspace "${chart}" - - echo '"deisci" "Always" canary' > "${WORKDIR}/${chart}/values.yaml" - - run publish-helm-chart "${chart}" "${repo_type}" - - [ "${status}" -eq 0 ] - [ "$(cat "${WORKDIR}/${chart}/Chart.yaml")" == "${EXPECTED_PRERELEASE_TAG}-dev-${TIMESTAMP}-sha.${SHORT_SHA}" ] - [ "$(cat "${WORKDIR}/env.file")" == "COMPONENT_CHART_VERSION=${EXPECTED_PRERELEASE_TAG}-dev-${TIMESTAMP}-sha.${SHORT_SHA}" ] - [ "$(cat "${WORKDIR}/${chart}/values.yaml")" == "\"deisci\" \"Always\" canary" ] -} - -@test "publish-helm-chart: component pr" { - chart='router' - repo_type='pr' - setup-chart-workspace "${chart}" - - echo '"deisci" "Always" canary' > "${WORKDIR}/${chart}/values.yaml" - - run publish-helm-chart "${chart}" "${repo_type}" - - [ "${status}" -eq 0 ] - [ "$(cat "${WORKDIR}/${chart}/Chart.yaml")" == "${EXPECTED_PRERELEASE_TAG}-sha.${SHORT_SHA}" ] - [ "$(cat "${WORKDIR}/env.file")" == "COMPONENT_CHART_VERSION=${EXPECTED_PRERELEASE_TAG}-sha.${SHORT_SHA}" ] - [ "$(cat "${WORKDIR}/${chart}/values.yaml")" == "\"deisci\" \"Always\" canary" ] -} - -@test "publish-helm-chart: component pr, ACTUAL_COMMIT set" { - ACTUAL_COMMIT='ghi78912345' - chart='router' - repo_type='pr' - setup-chart-workspace "${chart}" - - echo '"deisci" "Always" canary' > "${WORKDIR}/${chart}/values.yaml" - - run publish-helm-chart "${chart}" "${repo_type}" - - [ "${status}" -eq 0 ] - [ "$(cat "${WORKDIR}/${chart}/Chart.yaml")" == "${EXPECTED_PRERELEASE_TAG}-sha.ghi7891" ] - [ "$(cat "${WORKDIR}/env.file")" == "COMPONENT_CHART_VERSION=${EXPECTED_PRERELEASE_TAG}-sha.ghi7891" ] - [ "$(cat "${WORKDIR}/${chart}/values.yaml")" == "\"deisci\" \"Always\" canary" ] -} - -@test "publish-helm-chart: component pr" { - chart='router' - repo_type='pr' - setup-chart-workspace "${chart}" - - run publish-helm-chart "${chart}" "${repo_type}" - - [ "${status}" -eq 0 ] - [ "$(cat "${WORKDIR}/${chart}/Chart.yaml")" == "${EXPECTED_PRERELEASE_TAG}-sha.${SHORT_SHA}" ] -} - -@test "publish-helm-chart: component pr, ACTUAL_COMMIT set" { - ACTUAL_COMMIT='ghi78912345' - chart='router' - repo_type='pr' - setup-chart-workspace "${chart}" - - run publish-helm-chart "${chart}" "${repo_type}" - - [ "${status}" -eq 0 ] - [ "$(cat "${WORKDIR}/${chart}/Chart.yaml")" == "${EXPECTED_PRERELEASE_TAG}-sha.ghi7891" ] -} - -@test "publish-helm-chart: component production" { - chart='router' - repo_type='production' - setup-chart-workspace "${chart}" - - echo '"deisci" "Always" canary' > "${WORKDIR}/${chart}/values.yaml" - - run publish-helm-chart "${chart}" "${repo_type}" - - [ "${status}" -eq 0 ] - [ "$(cat "${WORKDIR}/${chart}/Chart.yaml")" == "${RELEASE_TAG}" ] - [ "$(cat "${WORKDIR}/${chart}/values.yaml")" == "\"deis\" \"IfNotPresent\" ${RELEASE_TAG}" ] -} - -@test "publish-helm-chart: workflow dev" { - chart='workflow' - repo_type='dev' - setup-chart-workspace "${chart}" - COMPONENT_CHART_AND_REPOS="registry:registry registry-proxy:registry-proxy database:postgres" - - echo ' https://charts.deis.com/registry - https://charts.deis.com/registry-proxy - https://charts.deis.com/database' > "${WORKDIR}/${chart}/requirements.yaml" - - echo 'versions.deis.com doctor.deis.com' > "${WORKDIR}/${chart}/values.yaml" - - run publish-helm-chart "${chart}" "${repo_type}" - - expected_requirements_yaml='">=v3.0.3-dev" https://charts.deis.com/registry-dev -">=v3.0.3-dev" https://charts.deis.com/registry-proxy-dev -">=v3.0.3-dev" https://charts.deis.com/database-dev' - - [ "${status}" -eq 0 ] - [ "$(cat "${WORKDIR}/${chart}/Chart.yaml")" == "${EXPECTED_PRERELEASE_TAG}-dev-${TIMESTAMP}-sha.${SHORT_SHA}" ] - [ "$(cat "${WORKDIR}/${chart}/requirements.yaml")" == "${expected_requirements_yaml}" ] - [ "$(cat "${WORKDIR}/${chart}/values.yaml")" == 'versions-staging.deis.com doctor-staging.deis.com' ] - [ "$(cat "${WORKDIR}/env.file")" == "WORKFLOW_TAG=${EXPECTED_PRERELEASE_TAG}-dev-${TIMESTAMP}-sha.${SHORT_SHA}" ] -} - -@test "publish-helm-chart: workflow dev; COMPONENT_REPO and ACTUAL_COMMIT in env" { - COMPONENT_REPO=registry-proxy - ACTUAL_COMMIT='ghi78912345' - chart='workflow' - repo_type='dev' - setup-chart-workspace "${chart}" - COMPONENT_CHART_AND_REPOS="registry:registry registry-proxy:registry-proxy database:postgres" - - echo ' https://charts.deis.com/registry - https://charts.deis.com/registry-proxy - https://charts.deis.com/database' > "${WORKDIR}/${chart}/requirements.yaml" - - echo 'versions.deis.com doctor.deis.com' > "${WORKDIR}/${chart}/values.yaml" - - run publish-helm-chart "${chart}" "${repo_type}" - - expected_requirements_yaml='">=v3.0.3-dev" https://charts.deis.com/registry-dev -">=v3.0.3-dev" https://charts.deis.com/registry-proxy-dev -">=v3.0.3-dev" https://charts.deis.com/database-dev' - - [ "${status}" -eq 0 ] - [ "$(cat "${WORKDIR}/${chart}/Chart.yaml")" == "${EXPECTED_PRERELEASE_TAG}-dev-${TIMESTAMP}-sha.${SHORT_SHA}" ] - [ "$(cat "${WORKDIR}/${chart}/requirements.yaml")" == "${expected_requirements_yaml}" ] - [ "$(cat "${WORKDIR}/${chart}/values.yaml")" == 'versions-staging.deis.com doctor-staging.deis.com' ] - [ "$(cat "${WORKDIR}/env.file")" == "WORKFLOW_TAG=${EXPECTED_PRERELEASE_TAG}-dev-${TIMESTAMP}-sha.${SHORT_SHA}" ] -} - -@test "publish-helm-chart: workflow pr; no COMPONENT_REPO, COMPONENT_CHART_VERSION or ACTUAL_COMMIT" { - chart='workflow' - repo_type='pr' - setup-chart-workspace "${chart}" - COMPONENT_CHART_AND_REPOS="registry:registry registry-proxy:registry-proxy database:postgres" - - echo ' https://charts.deis.com/registry - https://charts.deis.com/registry-proxy - https://charts.deis.com/database' > "${WORKDIR}/${chart}/requirements.yaml" - - echo 'versions.deis.com doctor.deis.com' > "${WORKDIR}/${chart}/values.yaml" - - run publish-helm-chart "${chart}" "${repo_type}" - - expected_requirements_yaml='">=v3.0.3-dev" https://charts.deis.com/registry-dev -">=v3.0.3-dev" https://charts.deis.com/registry-proxy-dev -">=v3.0.3-dev" https://charts.deis.com/database-dev' - - [ "${status}" -eq 0 ] - [ "$(cat "${WORKDIR}/${chart}/Chart.yaml")" == "${EXPECTED_PRERELEASE_TAG}-sha.${SHORT_SHA}" ] - [ "$(cat "${WORKDIR}/${chart}/requirements.yaml")" == "${expected_requirements_yaml}" ] - [ "$(cat "${WORKDIR}/${chart}/values.yaml")" == 'versions-staging.deis.com doctor-staging.deis.com' ] - [ "$(cat "${WORKDIR}/env.file")" == "WORKFLOW_TAG=${EXPECTED_PRERELEASE_TAG}-sha.${SHORT_SHA}" ] -} - -@test "publish-helm-chart: workflow pr; ACTUAL_COMMIT in env" { - ACTUAL_COMMIT='ghi78912345' - chart='workflow' - repo_type='pr' - setup-chart-workspace "${chart}" - - echo 'versions.deis.com doctor.deis.com' > "${WORKDIR}/${chart}/values.yaml" - - run publish-helm-chart "${chart}" "${repo_type}" - - [ "${status}" -eq 0 ] - [ "$(cat "${WORKDIR}/${chart}/Chart.yaml")" == "${EXPECTED_PRERELEASE_TAG}-sha.ghi7891" ] - [ "$(cat "${WORKDIR}/${chart}/values.yaml")" == 'versions-staging.deis.com doctor-staging.deis.com' ] - [ "$(cat "${WORKDIR}/env.file")" == "WORKFLOW_TAG=${EXPECTED_PRERELEASE_TAG}-sha.ghi7891" ] -} - -@test "publish-helm-chart: workflow pr; COMPONENT_REPO, COMPONENT_CHART_VERSION and ACTUAL_COMMIT in env" { - COMPONENT_REPO=registry-proxy - COMPONENT_CHART_VERSION="v3.0.4-sha.jkl5678" - ACTUAL_COMMIT='ghi78912345' - chart='workflow' - repo_type='pr' - setup-chart-workspace "${chart}" - COMPONENT_CHART_AND_REPOS="registry:registry registry-proxy:registry-proxy database:postgres" - - echo ' https://charts.deis.com/registry - https://charts.deis.com/registry-proxy - https://charts.deis.com/database' > "${WORKDIR}/${chart}/requirements.yaml" - - echo 'versions.deis.com doctor.deis.com' > "${WORKDIR}/${chart}/values.yaml" - - run publish-helm-chart "${chart}" "${repo_type}" - - expected_requirements_yaml='">=v3.0.3-dev" https://charts.deis.com/registry-dev -"'"${COMPONENT_CHART_VERSION}"'" https://charts.deis.com/registry-proxy-pr -">=v3.0.3-dev" https://charts.deis.com/database-dev' - - [ "${status}" -eq 0 ] - [ "$(cat "${WORKDIR}/${chart}/Chart.yaml")" == "${EXPECTED_PRERELEASE_TAG}-sha.${SHORT_SHA}" ] - [ "$(cat "${WORKDIR}/${chart}/requirements.yaml")" == "${expected_requirements_yaml}" ] - [ "$(cat "${WORKDIR}/${chart}/values.yaml")" == 'versions-staging.deis.com doctor-staging.deis.com' ] - [ "$(cat "${WORKDIR}/env.file")" == "WORKFLOW_TAG=${EXPECTED_PRERELEASE_TAG}-sha.${SHORT_SHA}" ] -} - -@test "publish-helm-chart: workflow staging" { - chart='workflow' - repo_type='staging' - setup-chart-workspace "${chart}" - COMPONENT_CHART_AND_REPOS="registry:registry registry-proxy:registry-proxy database:postgres" - - echo ' https://charts.deis.com/registry - https://charts.deis.com/registry-proxy - https://charts.deis.com/database' > "${WORKDIR}/${chart}/requirements.yaml" - - echo 'versions.deis.com doctor.deis.com' > "${WORKDIR}/${chart}/values.yaml" - - run publish-helm-chart "${chart}" "${repo_type}" - - expected_requirements_yaml='"v3.0.3" https://charts.deis.com/registry -"v3.0.3" https://charts.deis.com/registry-proxy -"v3.0.3" https://charts.deis.com/database' - - [ "${status}" -eq 0 ] - [ "$(cat "${WORKDIR}/${chart}/Chart.yaml")" == "${RELEASE_TAG}" ] - [ "$(cat "${WORKDIR}/${chart}/requirements.yaml")" == "${expected_requirements_yaml}" ] - [ "$(cat "${WORKDIR}/${chart}/values.yaml")" == 'versions-staging.deis.com doctor-staging.deis.com' ] - [ "$(cat "${WORKDIR}/env.file")" == "WORKFLOW_TAG=${RELEASE_TAG}" ] -} - -@test "publish-helm-chart: workflow production" { - chart='workflow' - repo_type='production' - setup-chart-workspace "${chart}" - COMPONENT_CHART_AND_REPOS="registry:registry registry-proxy:registry-proxy database:postgres" - - echo ' https://charts.deis.com/registry - https://charts.deis.com/registry-proxy - https://charts.deis.com/database' > "${WORKDIR}/${chart}/requirements.yaml" - - echo 'versions.deis.com doctor.deis.com' > "${WORKDIR}/${chart}/values.yaml" - - run publish-helm-chart "${chart}" "${repo_type}" - - expected_requirements_yaml='"v3.0.3" https://charts.deis.com/registry -"v3.0.3" https://charts.deis.com/registry-proxy -"v3.0.3" https://charts.deis.com/database' - - [ "${status}" -eq 0 ] - [ "$(cat "${WORKDIR}/${chart}/Chart.yaml")" == "${RELEASE_TAG}" ] - [ "$(cat "${WORKDIR}/${chart}/requirements.yaml")" == "${expected_requirements_yaml}" ] - [ "$(cat "${WORKDIR}/${chart}/values.yaml")" == 'versions.deis.com doctor.deis.com' ] - [ "$(cat "${WORKDIR}/env.file")" == "WORKFLOW_TAG=${RELEASE_TAG}" ] -} diff --git a/common.groovy b/common.groovy index d92d3a3..875bccd 100644 --- a/common.groovy +++ b/common.groovy @@ -4,6 +4,9 @@ evaluate(new File("${workspace}/repo.groovy")) defaults = [ + // default, ubuntu-based jenkins nodes + nodes: ['node1-ec2', 'node2-ec2', 'node3-ec2', 'node4-ec2', 'node8-kubernetes'], + signingNode: ['node7-ec2'], tmpPath: '/tmp/${JOB_NAME}/${BUILD_NUMBER}', envFile: '/tmp/${JOB_NAME}/${BUILD_NUMBER}/env.properties', daysToKeep: 14, diff --git a/docs/pipelines/component_release_pipeline.monopic b/docs/pipelines/component_release_pipeline.monopic index 57638e9..ec928f0 100644 Binary files a/docs/pipelines/component_release_pipeline.monopic and b/docs/pipelines/component_release_pipeline.monopic differ diff --git a/docs/pipelines/workflow_chart_release_pipeline.monopic b/docs/pipelines/workflow_chart_release_pipeline.monopic index 5b8a7ea..cc5193f 100644 Binary files a/docs/pipelines/workflow_chart_release_pipeline.monopic and b/docs/pipelines/workflow_chart_release_pipeline.monopic differ diff --git a/jobs/component_chart_publish.groovy b/jobs/component_chart_publish.groovy index 9aa0a22..bc5692f 100644 --- a/jobs/component_chart_publish.groovy +++ b/jobs/component_chart_publish.groovy @@ -5,6 +5,7 @@ evaluate(new File("${workspace}/common.groovy")) repos.each { Map repo -> if (repo.chart) { def chart = repo.chart + def jobName = "${chart}-chart-publish" job(jobName) { description "Publishes a new ${chart} chart release to the chart repo determined by CHART_REPO_TYPE." @@ -59,10 +60,16 @@ repos.each { Map repo -> } parameters { - choiceParam('CHART_REPO_TYPE', ['dev', 'pr', 'staging', 'production'], 'Type of chart repo for publishing (default: dev)') + nodeParam('NODE') { + description("select node (must be ${defaults.signingNode} if chart is to be signed)") + defaultNodes(defaults.nodes) + allowedNodes(defaults.nodes + defaults.signingNode) + } + choiceParam('CHART_REPO_TYPE', ['dev', 'pr', 'production'], 'Type of chart repo for publishing (default: dev)') stringParam('RELEASE_TAG', '', 'Release tag (Default: empty, will use latest git tag for repo)') stringParam('HELM_VERSION', defaults.helm.version, 'Version of Helm to download/use') stringParam('ACTUAL_COMMIT', '', "Component commit SHA") + booleanParam('SIGN_CHART', false, "Sign chart? (default: false/no)") } wrappers { @@ -74,16 +81,15 @@ repos.each { Map repo -> string("AWS_SECRET_ACCESS_KEY", '313da896-1579-41fa-9c70-c6b13d938e9c') string("GITHUB_ACCESS_TOKEN", defaults.github.credentialsID) string("SLACK_INCOMING_WEBHOOK_URL", defaults.slack.webhookURL) + string("SIGNING_KEY_PASSPHRASE", '3963b12b-bad3-429b-b1e5-e047a159bf02') } } steps { shell new File("${workspace}/bash/scripts/helm_chart_actions.sh").text + - new File("${workspace}/bash/scripts/publish_helm_chart.sh").text + """ export ENV_FILE_PATH="${defaults.envFile}" mkdir -p ${defaults.tmpPath} - set -x publish-helm-chart ${chart} \${CHART_REPO_TYPE} """.stripIndent().trim() } diff --git a/jobs/component_release.groovy b/jobs/component_release.groovy index 26ff259..711de97 100644 --- a/jobs/component_release.groovy +++ b/jobs/component_release.groovy @@ -147,7 +147,12 @@ repos.each { Map repo -> } parameters { propertiesFile(defaults.envFile) - predefinedProps(['CHART_REPO_TYPE': 'production']) + predefinedProps([ + 'CHART_REPO_TYPE': 'production', + 'NODE': defaults.signingNode[0], + 'SIGN_CHART': true, + ] + ) } } } @@ -155,16 +160,16 @@ repos.each { Map repo -> } } - // Trigger downstream signing job + // Trigger downstream chart signature verification job conditionalSteps { condition { status('SUCCESS', 'SUCCESS') } steps { downstreamParameterized { - trigger("helm-chart-sign") { + trigger("helm-chart-verify") { parameters { + propertiesFile(defaults.envFile) predefinedProps([ 'CHART': repo.chart, - 'VERSION': '${TAG}', 'CHART_REPO_TYPE': 'production', 'UPSTREAM_SLACK_CHANNEL': repo.slackChannel, ]) diff --git a/jobs/helm_chart_sign.groovy b/jobs/helm_chart_sign.groovy deleted file mode 100644 index 409fac6..0000000 --- a/jobs/helm_chart_sign.groovy +++ /dev/null @@ -1,164 +0,0 @@ -def workspace = new File(".").getAbsolutePath() -if (!new File("${workspace}/common.groovy").canRead()) { workspace = "${WORKSPACE}"} -evaluate(new File("${workspace}/common.groovy")) - -job("helm-chart-sign") { - description "Signs a Deis Helm chart" - - publishers { - wsCleanup() // Scrub workspace clean after build - - postBuildScripts { - onlyIfBuildSucceeds(false) - steps { - defaults.statusesToNotify.each { buildStatus -> - conditionalSteps { - condition { - status(buildStatus, buildStatus) - steps { - shell new File("${workspace}/bash/scripts/slack_notify.sh").text + - "slack-notify \${UPSTREAM_SLACK_CHANNEL} '${buildStatus}'" - } - } - } - } - } - } - } - - logRotator { - daysToKeep defaults.daysToKeep - } - - parameters { - nodeParam('SIGNATORY_NODE'){ - description('select signatory node') - defaultNodes(['node7-ec2']) - allowedNodes(['node7-ec2']) - } - stringParam('CHART', '', 'Name of chart to be signed') - choiceParam('CHART_REPO_TYPE', ['dev', 'staging', 'production'], 'Type of chart repo for publishing (default: dev)') - stringParam('VERSION', '', 'Specific version of the chart to be signed') - stringParam('HELM_VERSION', defaults.helm.version, 'Version of Helm to download/use') - stringParam('UPSTREAM_SLACK_CHANNEL', defaults.slack.channel, "Upstream Slack channel") - } - - wrappers { - buildName('${CHART} ${VERSION} #${BUILD_NUMBER}') - timestamps() - colorizeOutput 'xterm' - credentialsBinding { - string("AWS_ACCESS_KEY_ID", '57e64439-4521-4a4f-9315-eac10ecdea75') - string("AWS_SECRET_ACCESS_KEY", '313da896-1579-41fa-9c70-c6b13d938e9c') - string("SLACK_INCOMING_WEBHOOK_URL", defaults.slack.webhookURL) - string("SIGNING_KEY_PASSPHRASE", '3963b12b-bad3-429b-b1e5-e047a159bf02') - } - } - - steps { - shell new File("${workspace}/bash/scripts/helm_chart_actions.sh").text + - ''' - #!/usr/bin/env bash - - set -eo pipefail - - CHART_REPO="$(echo "${CHART}-${CHART_REPO_TYPE}" | sed -e 's/-production//g')" - - download-and-init-helm - - sign-helm-chart "${CHART}" "${VERSION}" - - helm verify "${CHART}-${VERSION}".tgz - - upload-signed-chart "${CHART}-${VERSION}" "${CHART_REPO}" - '''.stripIndent().trim() - - conditionalSteps { - condition { - status('SUCCESS', 'SUCCESS') - } - steps { - downstreamParameterized { - trigger("helm-chart-verify") { - block { - buildStepFailure('FAILURE') - failure('FAILURE') - unstable('UNSTABLE') - } - parameters { - predefinedProps([ - 'CHART': '${CHART}', - 'VERSION': '${VERSION}', - 'CHART_REPO_TYPE': '${CHART_REPO_TYPE}', - ]) - } - } - } - } - } - } -} - -job("helm-chart-verify") { - description "Verifies a signed Deis Helm chart" - - publishers { - wsCleanup() // Scrub workspace clean after build - - postBuildScripts { - onlyIfBuildSucceeds(false) - steps { - defaults.statusesToNotify.each { buildStatus -> - conditionalSteps { - condition { - status(buildStatus, buildStatus) - steps { - shell new File("${workspace}/bash/scripts/slack_notify.sh").text + - "slack-notify '#testing' '${buildStatus}'" - } - } - } - } - } - } - } - - logRotator { - daysToKeep defaults.daysToKeep - } - - parameters { - stringParam('CHART', '', 'Name of chart to be signed') - choiceParam('CHART_REPO_TYPE', ['dev', 'staging', 'production'], 'Type of chart repo for publishing (default: dev)') - stringParam('VERSION', '', 'Specific version of the chart to be signed') - stringParam('HELM_VERSION', defaults.helm.version, 'Version of Helm to download/use') - } - - wrappers { - buildName('${CHART} ${VERSION} #${BUILD_NUMBER}') - timestamps() - colorizeOutput 'xterm' - credentialsBinding { - string("SLACK_INCOMING_WEBHOOK_URL", defaults.slack.webhookURL) - } - } - - steps { - shell new File("${workspace}/bash/scripts/helm_chart_actions.sh").text + - ''' - #!/usr/bin/env bash - - set -eo pipefail - - CHART_REPO="$(echo "${CHART}-${CHART_REPO_TYPE}" | sed -e 's/-production//g')" - - download-and-init-helm - - # fetch key from keyserver - gpg --keyserver pgp.mit.edu --recv-keys 1D6A97D0 - - helm repo add "${CHART}" https://charts.deis.com/"${CHART_REPO}" - helm fetch --verify "${CHART_REPO}"/"${CHART}" --version "${VERSION}" - '''.stripIndent().trim() - } -} diff --git a/jobs/helm_chart_verify.groovy b/jobs/helm_chart_verify.groovy new file mode 100644 index 0000000..aabaddf --- /dev/null +++ b/jobs/helm_chart_verify.groovy @@ -0,0 +1,68 @@ +def workspace = new File(".").getAbsolutePath() +if (!new File("${workspace}/common.groovy").canRead()) { workspace = "${WORKSPACE}"} +evaluate(new File("${workspace}/common.groovy")) + +job("helm-chart-verify") { + description "Verifies a signed Deis Helm chart" + + publishers { + wsCleanup() // Scrub workspace clean after build + + postBuildScripts { + onlyIfBuildSucceeds(false) + steps { + defaults.statusesToNotify.each { buildStatus -> + conditionalSteps { + condition { + status(buildStatus, buildStatus) + steps { + shell new File("${workspace}/bash/scripts/slack_notify.sh").text + + "slack-notify \${UPSTREAM_SLACK_CHANNEL} '${buildStatus}'" + } + } + } + } + } + } + } + + logRotator { + daysToKeep defaults.daysToKeep + } + + parameters { + stringParam('CHART', '', 'Name of chart to be signed') + choiceParam('CHART_REPO_TYPE', ['dev', 'staging', 'production'], 'Type of chart repo for publishing (default: dev)') + stringParam('RELEASE_TAG', '', 'Specific version of the chart to be verified') + stringParam('HELM_VERSION', defaults.helm.version, 'Version of Helm to download/use') + stringParam('UPSTREAM_SLACK_CHANNEL', defaults.slack.channel, "Upstream Slack channel") + } + + wrappers { + buildName('${CHART} ${RELEASE_TAG} #${BUILD_NUMBER}') + timestamps() + colorizeOutput 'xterm' + credentialsBinding { + string("SLACK_INCOMING_WEBHOOK_URL", defaults.slack.webhookURL) + } + } + + steps { + shell new File("${workspace}/bash/scripts/helm_chart_actions.sh").text + + ''' + #!/usr/bin/env bash + + set -eo pipefail + + CHART_REPO="$(echo "${CHART}-${CHART_REPO_TYPE}" | sed -e 's/-production//g')" + + download-and-init-helm + + # fetch key from keyserver + gpg --keyserver pgp.mit.edu --recv-keys 1D6A97D0 + + helm repo add "${CHART}" https://charts.deis.com/"${CHART_REPO}" + helm fetch --verify "${CHART_REPO}"/"${CHART}" --version "${RELEASE_TAG}" + '''.stripIndent().trim() + } +} diff --git a/jobs/workflow_chart_pipeline.groovy b/jobs/workflow_chart_pipeline.groovy index 1696dd2..8636d91 100644 --- a/jobs/workflow_chart_pipeline.groovy +++ b/jobs/workflow_chart_pipeline.groovy @@ -64,19 +64,18 @@ job("${chart}-chart-publish") { } parameters { - choiceParam('CHART_REPO_TYPE', ['dev', 'pr', 'staging', 'production'], 'Type of chart repo for publishing (default: dev)') - stringParam('RELEASE_TAG', '', 'Release tag') + choiceParam('CHART_REPO_TYPE', ['dev', 'pr'], 'Type of chart repo for publishing (default: dev)') // TODO: once defaults.helm.version gets bumped to 2.1.0, switch back. (We need canary for semver feature) // stringParam('HELM_VERSION', defaults.helm.version, 'Version of Helm to download/use') stringParam('HELM_VERSION', 'canary', 'Version of Helm to download/use') stringParam('UPSTREAM_SLACK_CHANNEL', repo.slackChannel, "Upstream Slack channel") - stringParam('COMPONENT_REPO', repo.name, "Component repo name") + stringParam('COMPONENT_REPO', '', "Component repo name") stringParam('COMPONENT_CHART_VERSION', '', "Component chart version") stringParam('ACTUAL_COMMIT', '', "Actual commit SHA for versioning chart; will be tied to COMPONENT_REPO if provided") } wrappers { - buildName('${RELEASE_TAG} ${COMPONENT_REPO} ${CHART_REPO_TYPE} #${BUILD_NUMBER}') + buildName('${COMPONENT_REPO} ${CHART_REPO_TYPE} #${BUILD_NUMBER}') timestamps() colorizeOutput 'xterm' credentialsBinding { @@ -93,7 +92,6 @@ job("${chart}-chart-publish") { shell new File("${workspace}/bash/scripts/get_latest_component_release.sh").text + new File("${workspace}/bash/scripts/helm_chart_actions.sh").text + - new File("${workspace}/bash/scripts/publish_helm_chart.sh").text + """ export COMPONENT_CHART_AND_REPOS="${components}" export ENV_FILE_PATH="${defaults.envFile}" @@ -245,8 +243,106 @@ job("${chart}-chart-e2e") { } } +job("${chart}-chart-stage") { + description "Publishes a signed Workflow chart to the 'staging' chart repo" + + scm { + git { + remote { + github("deis/${repo.name}") + credentials('597819a0-b0b9-4974-a79b-3a5c2322606d') + } + branch('master') + } + } + + concurrentBuild() + throttleConcurrentBuilds { + maxTotal(defaults.maxTotalConcurrentBuilds) + } + + publishers { + wsCleanup() // Scrub workspace clean after build + + postBuildScripts { + onlyIfBuildSucceeds(false) + steps { + defaults.statusesToNotify.each { buildStatus -> + conditionalSteps { + condition { + status(buildStatus, buildStatus) + steps { + shell new File("${workspace}/bash/scripts/slack_notify.sh").text + + "slack-notify '${repo.slackChannel}' '${buildStatus}'" + } + } + } + } + } + } + } + + logRotator { + daysToKeep defaults.daysToKeep + } + + parameters { + nodeParam('SIGNATORY_NODE'){ + description('select signatory node') + defaultNodes([defaults.signingNode]) + allowedNodes([defaults.signingNode]) + } + stringParam('RELEASE_TAG', '', 'Release tag') + stringParam('HELM_VERSION', defaults.helm.version, 'Version of Helm to download/use') + } + + wrappers { + buildName('${RELEASE_TAG} #${BUILD_NUMBER}') + timestamps() + colorizeOutput 'xterm' + credentialsBinding { + string("AWS_ACCESS_KEY_ID", '57e64439-4521-4a4f-9315-eac10ecdea75') + string("AWS_SECRET_ACCESS_KEY", '313da896-1579-41fa-9c70-c6b13d938e9c') + string("SLACK_INCOMING_WEBHOOK_URL", defaults.slack.webhookURL) + string("SIGNING_KEY_PASSPHRASE", '3963b12b-bad3-429b-b1e5-e047a159bf02') + } + } + + steps { + def components = repos.collectMany { + it.workflowComponent ? [it.chart+':'+it.name] : [] }.join(' ') as String + + shell new File("${workspace}/bash/scripts/get_latest_component_release.sh").text + + new File("${workspace}/bash/scripts/helm_chart_actions.sh").text + + """ + export COMPONENT_CHART_AND_REPOS="${components}" + + publish-helm-chart ${chart} 'staging' + """.stripIndent().trim() + + conditionalSteps { + condition { status('SUCCESS', 'SUCCESS') } + steps { + // Trigger e2e against staged release candidate chart + downstreamParameterized { + trigger("${chart}-chart-e2e") { + parameters { + propertiesFile(defaults.envFile) + predefinedProps([ + 'CHART_REPO_TYPE': 'staging', + 'HELM_VERSION': '${HELM_VERSION}', + 'UPSTREAM_SLACK_CHANNEL': repo.slackChannel, + ]) + } + } + } + } + } + } +} + job("${chart}-chart-release") { - description "Publishes official Workflow chart by copying e2e-approved chart from the `${chartRepo.staging}` repo to the `${chartRepo.production}` repo." + description "Publishes official Workflow chart by copying e2e-approved, signed chart from the `${chartRepo.staging}` repo to the `${chartRepo.production}` repo." logRotator { daysToKeep defaults.daysToKeep @@ -309,13 +405,13 @@ job("${chart}-chart-release") { aws s3 cp index.yaml s3://helm-charts/${chartRepo.production}/index.yaml """.stripIndent().trim() - conditionalSteps { - condition { - status('SUCCESS', 'SUCCESS') - } - steps { + + conditionalSteps { + condition { status('SUCCESS', 'SUCCESS') } + steps { + // Trigger job to verify signature of release chart downstreamParameterized { - trigger("helm-chart-sign") { + trigger("helm-chart-verify") { parameters { predefinedProps([ 'CHART': chart,