diff --git a/.buildkite/hooks/post-checkout b/.buildkite/hooks/post-checkout new file mode 100644 index 0000000000..67ae21491b --- /dev/null +++ b/.buildkite/hooks/post-checkout @@ -0,0 +1,53 @@ +#!/bin/bash + +set -euo pipefail + +checkout_merge() { + local target_branch=$1 + local pr_commit=$2 + local merge_branch=$3 + + if [[ -z "${target_branch}" ]]; then + echo "No pull request target branch" + exit 1 + fi + + git fetch -v origin "${target_branch}" + git checkout FETCH_HEAD + echo "Current branch: $(git rev-parse --abbrev-ref HEAD)" + + # create temporal branch to merge the PR with the target branch + git checkout -b ${merge_branch} + echo "New branch created: $(git rev-parse --abbrev-ref HEAD)" + + # set author identity so it can be run git merge + git config user.name "github-merged-pr-post-checkout" + git config user.email "auto-merge@buildkite" + + git merge --no-edit "${BUILDKITE_COMMIT}" || { + local merge_result=$? + echo "Merge failed: ${merge_result}" + git merge --abort + exit ${merge_result} + } +} + +pull_request="${BUILDKITE_PULL_REQUEST:-false}" + +if [[ "${pull_request}" == "false" ]]; then + echo "Not a pull request, skipping" + exit 0 +fi + +TARGET_BRANCH="${BUILDKITE_PULL_REQUEST_BASE_BRANCH:-master}" +PR_COMMIT="${BUILDKITE_COMMIT}" +PR_ID=${BUILDKITE_PULL_REQUEST} +MERGE_BRANCH="pr_merge_${PR_ID}" + +checkout_merge "${TARGET_BRANCH}" "${PR_COMMIT}" "${MERGE_BRANCH}" + +echo "Commit information" +git log --format=%B -n 1 + +# Ensure buildkite groups are rendered +echo "" diff --git a/.buildkite/hooks/pre-command b/.buildkite/hooks/pre-command new file mode 100644 index 0000000000..ec76774033 --- /dev/null +++ b/.buildkite/hooks/pre-command @@ -0,0 +1,52 @@ +#!/bin/bash + +set -euo pipefail + +function retry { + local retries=$1 + shift + + local count=0 + until "$@"; do + exit=$? + wait=$((2 ** count)) + count=$((count + 1)) + if [ $count -lt "$retries" ]; then + >&2 echo "Retry $count/$retries exited $exit, retrying in $wait seconds..." + sleep $wait + else + >&2 echo "Retry $count/$retries exited $exit, no more retries left." + return $exit + fi + done + return 0 +} + +GCP_SERVICE_ACCOUNT_SECRET_PATH=secret/ci/elastic-elastic-package/gcp-service-account +AWS_SERVICE_ACCOUNT_SECRET_PATH=kv/ci-shared/platform-ingest/aws_account_auth +GITHUB_TOKEN_VAULT_PATH=kv/ci-shared/platform-ingest/github_token + +# Secrets must be redacted +# https://buildkite.com/docs/pipelines/managing-log-output#redacted-environment-variables + +if [[ "$BUILDKITE_PIPELINE_SLUG" == "elastic-package" && "$BUILDKITE_STEP_KEY" == "integration-parallel-gcp" ]]; then + export ELASTIC_PACKAGE_GCP_PROJECT_SECRET=$(retry 5 vault read -field projectId ${GCP_SERVICE_ACCOUNT_SECRET_PATH}) + export ELASTIC_PACKAGE_GCP_CREDENTIALS_SECRET=$(retry 5 vault read -field credentials ${GCP_SERVICE_ACCOUNT_SECRET_PATH}) + + # Environment variables required by the service deployer + export GOOGLE_CREDENTIALS=${ELASTIC_PACKAGE_GCP_CREDENTIALS_SECRET} + export GCP_PROJECT_ID=${ELASTIC_PACKAGE_GCP_PROJECT_SECRET} +fi + +if [[ "$BUILDKITE_PIPELINE_SLUG" == "elastic-package" && "$BUILDKITE_STEP_KEY" == "integration-parallel-aws" ]]; then + export ELASTIC_PACKAGE_AWS_SECRET_KEY=$(retry 5 vault kv get -field secret_key ${AWS_SERVICE_ACCOUNT_SECRET_PATH}) + export ELASTIC_PACKAGE_AWS_ACCESS_KEY=$(retry 5 vault kv get -field access_key ${AWS_SERVICE_ACCOUNT_SECRET_PATH}) + + # Environment variables required by the service deployer + export AWS_SECRET_ACCESS_KEY=${ELASTIC_PACKAGE_AWS_SECRET_KEY} + export AWS_ACCESS_KEY_ID=${ELASTIC_PACKAGE_AWS_ACCESS_KEY} +fi + +if [[ "$BUILDKITE_PIPELINE_SLUG" == "elastic-package" && "$BUILDKITE_STEP_KEY" == "release" ]]; then + export GITHUB_TOKEN=$(retry 5 vault kv get -field token ${GITHUB_TOKEN_VAULT_PATH}) +fi diff --git a/.buildkite/pipeline.trigger.integration.tests.sh b/.buildkite/pipeline.trigger.integration.tests.sh new file mode 100755 index 0000000000..04a7e94496 --- /dev/null +++ b/.buildkite/pipeline.trigger.integration.tests.sh @@ -0,0 +1,79 @@ +#!/bin/bash + +# exit immediately on failure, or if an undefined variable is used +set -eu + +# begin the pipeline.yml file +echo "steps:" +echo " - group: \":terminal: Integration test suite\"" +echo " key: \"integration-tests\"" +echo " steps:" + +# Integration tests related stack command +STACK_COMMAND_TESTS=( + test-stack-command-default + test-stack-command-oldest + test-stack-command-7x + test-stack-command-86 + test-stack-command-8x +) + +for test in ${STACK_COMMAND_TESTS[@]}; do + echo " - label: \":go: Running integration test: ${test}\"" + echo " command: ./.buildkite/scripts/integration_tests.sh -t ${test}" + echo " agents:" + echo " provider: \"gcp\"" + echo " artifact_paths:" + echo " - build/elastic-stack-dump/stack/*/logs/*.log" + echo " - build/elastic-stack-dump/stack/*/logs/fleet-server-internal/*.log" + echo " - build/elastic-stack-status/*/*" +done + +CHECK_PACKAGES_TESTS=( + test-check-packages-other + test-check-packages-with-kind + test-check-packages-with-custom-agent + test-check-packages-benchmarks +) +for test in ${CHECK_PACKAGES_TESTS[@]}; do + echo " - label: \":go: Running integration test: ${test}\"" + echo " command: ./.buildkite/scripts/integration_tests.sh -t ${test}" + echo " agents:" + echo " provider: \"gcp\"" + echo " artifact_paths:" + echo " - build/test-results/*.xml" + echo " - build/elastic-stack-dump/stack/check-*/logs/*.log" + echo " - build/elastic-stack-dump/stack/check-*/logs/fleet-server-internal/*.log" + if [[ $test =~ with-kind$ ]]; then + echo " - build/kubectl-dump.txt" + fi +done + +pushd test/packages/parallel > /dev/null +for package in $(find . -maxdepth 1 -mindepth 1 -type d) ; do + package_name=$(basename ${package}) + echo " - label: \":go: Running integration test: ${package_name}\"" + echo " key: \"integration-parallel-${package_name}\"" + echo " command: ./.buildkite/scripts/integration_tests.sh -t test-check-packages-parallel -p ${package_name}" + echo " agents:" + echo " provider: \"gcp\"" + echo " artifact_paths:" + echo " - build/test-results/*.xml" + echo " - build/elastic-stack-dump/stack/check-*/logs/*.log" + echo " - build/elastic-stack-dump/stack/check-*/logs/fleet-server-internal/*.log" +done + +popd > /dev/null + +echo " - label: \":go: Running integration test: test-build-zip\"" +echo " command: ./.buildkite/scripts/integration_tests.sh -t test-build-zip" +echo " agents:" +echo " provider: \"gcp\"" +echo " artifact_paths:" +echo " - build/elastic-stack-dump/stack/*/logs/*.log" +echo " - build/packages/*.sig" + +echo " - label: \":go: Running integration test: test-profiles-command\"" +echo " command: ./.buildkite/scripts/integration_tests.sh -t test-profiles-command" +echo " agents:" +echo " provider: \"gcp\"" diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index cfdf57f398..53c66fc35d 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -1,12 +1,20 @@ +env: + SETUP_GVM_VERSION: 'v0.5.0' # https://github.com/andrewkroh/gvm/issues/44#issuecomment-1013231151 + DOCKER_COMPOSE_VERSION: "1.25.5" # "v2.15.1" + KIND_VERSION: 'v0.17.0' + K8S_VERSION: 'v1.26.0' + steps: - label: ":go: Run check-static" + key: check-static command: "make check-static" agents: image: "golang:1.19.5" cpu: "8" memory: "4G" - - label: ":go: Run unit tests" + - label: ":go: :linux: Run unit tests" + key: unit-tests-linux command: "make test-go-ci" artifact_paths: - "build/test-results/*.xml" @@ -19,10 +27,31 @@ steps: - wait: ~ continue_on_failure: true - - label: "Junit annotate" + - label: ":pipeline: Trigger Integration tests" + command: ".buildkite/pipeline.trigger.integration.tests.sh | buildkite-agent pipeline upload" + depends_on: + - step: check-static + allow_failure: false + - step: unit-tests-linux + allow_failure: false + + - wait: ~ + continue_on_failure: true + + - label: ":junit: Junit annotate" plugins: - junit-annotate#v2.4.1: artifacts: "build/test-results/*.xml" agents: - provider: "gcp" + provider: "gcp" # junit plugin requires docker + - label: ":github: Release" + key: "release" + # build.tag != null && build.branch == "main" + if: | + build.tag =~ /^v[0-9]+[.][0-9]+[.][0-9]+$$/ && build.branch == "main" + command: ".buildkite/scripts/release.sh" + agents: + image: "golang:1.19.5" + cpu: "8" + memory: "4G" diff --git a/.buildkite/scripts/integration_tests.sh b/.buildkite/scripts/integration_tests.sh new file mode 100755 index 0000000000..896927a07e --- /dev/null +++ b/.buildkite/scripts/integration_tests.sh @@ -0,0 +1,106 @@ +#!/bin/bash + +set -euo pipefail + +PARALLEL_TARGET="test-check-packages-parallel" +KIND_TARGET="test-check-packages-with-kind" + +usage() { + echo "$0 [-t ] [-h]" + echo "Trigger integration tests related to a target in Makefile" + echo -e "\t-t : Makefile target. Mandatory" + echo -e "\t-p : Package (required for test-check-packages-parallel target)." + echo -e "\t-h: Show this message" +} + +with_kubernetes() { + # FIXME add retry logic + mkdir -p ${WORKSPACE}/bin + curl -sSLo ${WORKSPACE}/bin/kind "https://github.com/kubernetes-sigs/kind/releases/download/${KIND_VERSION}/kind-linux-amd64" + chmod +x ${WORKSPACE}/bin/kind + kind version + which kind + + mkdir -p ${WORKSPACE}/bin + curl -sSLo ${WORKSPACE}/bin/kubectl "https://storage.googleapis.com/kubernetes-release/release/${K8S_VERSION}/bin/linux/amd64/kubectl" + chmod +x ${WORKSPACE}/bin/kubectl + kubectl version --client + which kubectl +} + +with_go() { + # FIXME add retry logic + mkdir -p ${WORKSPACE}/bin + curl -sL -o ${WORKSPACE}/bin/gvm "https://github.com/andrewkroh/gvm/releases/download/${SETUP_GVM_VERSION}/gvm-linux-amd64" + chmod +x ${WORKSPACE}/bin/gvm + eval "$(gvm $(cat .go-version))" + go version + which go +} + +with_docker_compose() { + # FIXME add retry logic + mkdir -p ${WORKSPACE}/bin + curl -SL -o ${WORKSPACE}/bin/docker-compose "https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-linux-x86_64" + chmod +x ${WORKSPACE}/bin/docker-compose + docker-compose version +} + +TARGET="" +PACKAGE="" +while getopts ":t:p:h" o; do + case "${o}" in + t) + TARGET=${OPTARG} + ;; + p) + PACKAGE=${OPTARG} + ;; + h) + usage + exit 0 + ;; + \?) + echo "Invalid option ${OPTARG}" + usage + exit 1 + ;; + :) + echo "Missing argument for -${OPTARG}" + usage + exit 1 + ;; + esac +done + +if [[ "${TARGET}" == "" ]]; then + echo "Missing target" + usage + exit 1 +fi + +echo "Current path: $(pwd)" +WORKSPACE="$(pwd)" +export PATH="${WORKSPACE}/bin:${PATH}" +echo "Path: $PATH" + +echo "--- install go" +with_go +export PATH="$(go env GOPATH)/bin:${PATH}" + +echo "--- install docker-compose" +with_docker_compose + +if [[ "${TARGET}" == "${KIND_TARGET}" ]]; then + echo "--- install kubectl & kind" + with_kubernetes +fi + +echo "--- Run integration test ${TARGET}" +if [[ "${TARGET}" == "${PARALLEL_TARGET}" ]]; then + make install + make PACKAGE_UNDER_TEST=${PACKAGE} ${TARGET} + exit 0 +fi + +make install ${TARGET} check-git-clean diff --git a/.buildkite/scripts/release.sh b/.buildkite/scripts/release.sh new file mode 100755 index 0000000000..afb3d18f48 --- /dev/null +++ b/.buildkite/scripts/release.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +set -euo pipefail + +echo "--- fetching tags" +# Ensure that tags are present so goreleaser can build the changelog from the last release. +git rev-parse --is-shallow-repository +git fetch origin --tags + +echo "--- running goreleaser" +# Run latest version of goreleaser +curl -sL https://git.io/goreleaser | bash + diff --git a/.ci/Jenkinsfile b/.ci/Jenkinsfile index de7de19137..ea14834c2d 100644 --- a/.ci/Jenkinsfile +++ b/.ci/Jenkinsfile @@ -11,7 +11,6 @@ pipeline { REPO = "elastic-package" BASE_DIR="src/github.com/elastic/elastic-package" JOB_GIT_CREDENTIALS = "f6c7695a-671e-4f4f-a331-acdce44ff9ba" - GITHUB_TOKEN_CREDENTIALS = "2a9602aa-ab9f-4e52-baf3-b71ca88469c7" PIPELINE_LOG_LEVEL='INFO' AWS_ACCOUNT_SECRET = 'secret/observability-team/ci/elastic-observability-aws-account-auth' HOME = "${env.WORKSPACE}" @@ -117,22 +116,6 @@ pipeline { } } } - stage('Release') { - when { - tag pattern: '(v)?\\d+\\.\\d+\\.\\d+', comparator: 'REGEXP' - } - steps { - dir("${BASE_DIR}"){ - withMageEnv(){ - withCredentials([string(credentialsId: "${GITHUB_TOKEN_CREDENTIALS}", variable: 'GITHUB_TOKEN')]) { - // Ensure that tags are present so goreleaser can build the changelog from the last release. - gitCmd(cmd: 'fetch', args: '--unshallow --tags') - sh 'curl -sL https://git.io/goreleaser | bash' - } - } - } - } - } } } } diff --git a/.ci/package-storage-publish.groovy b/.ci/package-storage-publish.groovy index 9dc4d16015..8c6066d6d4 100644 --- a/.ci/package-storage-publish.groovy +++ b/.ci/package-storage-publish.groovy @@ -10,7 +10,6 @@ pipeline { BASE_DIR="src/github.com/elastic/elastic-package" JOB_GIT_CREDENTIALS = "f6c7695a-671e-4f4f-a331-acdce44ff9ba" - GITHUB_TOKEN_CREDENTIALS = "2a9602aa-ab9f-4e52-baf3-b71ca88469c7" PIPELINE_LOG_LEVEL='INFO' // Signing