diff --git a/.ci/release/post-release.sh b/.ci/release/post-release.sh new file mode 100755 index 00000000000..e54662cdfea --- /dev/null +++ b/.ci/release/post-release.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +# Bash strict mode +set -euo pipefail + +# Found current script directory +RELATIVE_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" + +# Found project directory +BASE_PROJECT="$(dirname $(dirname "${RELATIVE_DIR}"))" + +# Import dependencies +source "${RELATIVE_DIR}/util.sh" + +# Constants +BASE_URL="https://repo1.maven.org/maven2/co/elastic/apm/elastic-apm-agent" +CF_FILE="${BASE_PROJECT}/cloudfoundry/index.yml" + +# Requirements +check_version "${RELEASE_VERSION}" + +echo "Set next snapshot version" +./mvnw -V versions:set -DprocessAllModules=true -DgenerateBackupPoms=false -DnextSnapshot=true + +# make script idempotent if release is already in CF descriptor +set +e +grep -e "^${RELEASE_VERSION}:" ${CF_FILE} +[[ $? == 0 ]] && exit 0 +set -e +echo "Update cloudfoundry version" +echo "${RELEASE_VERSION}: ${BASE_URL}/${RELEASE_VERSION}/elastic-apm-agent-${RELEASE_VERSION}.jar" >> "${CF_FILE}" diff --git a/.ci/release/pre-release.sh b/.ci/release/pre-release.sh new file mode 100755 index 00000000000..ae981a3dc9e --- /dev/null +++ b/.ci/release/pre-release.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +# Bash strict mode +set -euo pipefail + +# Found current script directory +RELATIVE_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" + +# Found project directory +BASE_PROJECT="$(dirname $(dirname "${RELATIVE_DIR}"))" + +# Import dependencies +source "${RELATIVE_DIR}/util.sh" + +# Requirements +check_version "${RELEASE_VERSION}" + +echo "Set release version" +./mvnw -V versions:set -DprocessAllModules=true -DgenerateBackupPoms=false -DnewVersion="${RELEASE_VERSION}" + +echo "Prepare changelog for release" +java "${BASE_PROJECT}/.ci/ReleaseChangelog.java" CHANGELOG.asciidoc "${RELEASE_VERSION}" diff --git a/.ci/release/update_major_branch.sh b/.ci/release/update-major-branch.sh similarity index 85% rename from .ci/release/update_major_branch.sh rename to .ci/release/update-major-branch.sh index 8fa883878bd..146364f4984 100755 --- a/.ci/release/update_major_branch.sh +++ b/.ci/release/update-major-branch.sh @@ -62,3 +62,10 @@ git checkout --force ${checkout_options} echo -e "\n--- move local branch ${major_branch} to match tag ${tag}" git reset --hard ${tag} + +echo -e "\n--- create new branch with updates" +git checkout -b "update-major-${v}" +git push origin "update-major-${v}" + +echo -e "\n--- create PR to update major branch" +gh pr create --title="post release v${v}: update major branch" --base "${major_branch}" --head "update-major-${v}" -b "post release v${v}" diff --git a/.ci/release/update_cloudfoundry.sh b/.ci/release/update_cloudfoundry.sh deleted file mode 100755 index 436b5b23658..00000000000 --- a/.ci/release/update_cloudfoundry.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail -source "$(dirname "${0}")/util.sh" - -REMOTE_NAME=origin -BRANCH_NAME=main -BASE_URL=https://repo1.maven.org/maven2/co/elastic/apm/elastic-apm-agent -CF_FILE=cloudfoundry/index.yml - -check_version "${1:-}" -v="${1:-}" - -echo -e "\n--- fetch & ensure clean state of ${REMOTE_NAME}/${BRANCH_NAME}" -git fetch ${REMOTE_NAME} ${BRANCH_NAME} -git checkout ${BRANCH_NAME} -git reset --hard ${REMOTE_NAME}/${BRANCH_NAME} - -echo -e "\n--- update ${CF_FILE} if required" - -# make script idempotent if release is already in CF descriptor -set +e -grep -e "^${v}:" ${CF_FILE} -[[ $? == 0 ]] && exit 0 -set -e - -echo "${v}: ${BASE_URL}/${v}/elastic-apm-agent-${v}.jar" >> ${CF_FILE} -git commit ${CF_FILE} -m "Update cloudfoundry for ${v} release" diff --git a/.ci/release/util.sh b/.ci/release/util.sh index 8dd546ad931..15d4859f57b 100644 --- a/.ci/release/util.sh +++ b/.ci/release/util.sh @@ -3,14 +3,12 @@ check_version() { v=${1:-} - if [[ "${v}" == "" ]]; then - echo "usage $0 " # here $0 will be the calling script - echo "where in format '1.2.3'" + if [ -z "${v}" ]; then + >&2 echo "The environment variable 'RELEASE_VERSION' isn't defined" exit 1 fi - - if [[ ! "$v" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then - echo "invalid version format '${v}'" + if [[ ! "${v}" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then + echo "The environment variable 'RELEASE_VERSION' should respect SemVer format" exit 1 fi } diff --git a/.ci/release/wait_maven_artifact_published.sh b/.ci/release/wait_maven_artifact_published.sh deleted file mode 100755 index 7c12d96c221..00000000000 --- a/.ci/release/wait_maven_artifact_published.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail -source "$(dirname "${0}")/util.sh" - -# returns '0' (zero) status code when artifact exists -# return non-zero status when artifact does not exists or unable to execute request - -check_version "${1:-}" -v="${1:-}" - -full_url="https://repo1.maven.org/maven2/co/elastic/apm/elastic-apm-agent/${v}/elastic-apm-agent-${v}.pom" -curl -fs "${full_url}" 2>&1 > /dev/null diff --git a/.github/workflows/pre-post-release.yml b/.github/workflows/pre-post-release.yml new file mode 100644 index 00000000000..997077aec4f --- /dev/null +++ b/.github/workflows/pre-post-release.yml @@ -0,0 +1,97 @@ +--- + +name: Pre/Post Release + +on: + workflow_call: + inputs: + ref: + description: 'Branch or tag ref to run the workflow on' + type: string + required: true + default: 'main' + version: + description: 'The version to release (e.g. 1.2.3). This workflow will automatically perform the required version bumps' + type: string + required: true + phase: + description: 'Pre or post release phase' + type: string # valid values are 'pre' or 'post' + required: true + +env: + RELEASE_VERSION: ${{ inputs.version }} + BRANCH_NAME: ${{ inputs.phase }}-release-v${{ inputs.version }} + +permissions: + contents: read + +jobs: + validate-tag: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Validate release tag does not exist in repo + uses: ./.github/workflows/validate-tag + with: + tag: v${{ env.RELEASE_VERSION }} + + create-pr: + name: "Bump versions and create PR" + runs-on: ubuntu-latest + needs: + - validate-tag + permissions: + contents: write + steps: + - uses: elastic/apm-pipeline-library/.github/actions/github-token@current + with: + url: ${{ secrets.VAULT_ADDR }} + roleId: ${{ secrets.VAULT_ROLE_ID }} + secretId: ${{ secrets.VAULT_SECRET_ID }} + + - uses: elastic/apm-pipeline-library/.github/actions/setup-git@current + with: + username: ${{ env.GIT_USER }} + email: ${{ env.GIT_EMAIL }} + token: ${{ env.GITHUB_TOKEN }} + + - uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref }} + token: ${{ env.GITHUB_TOKEN }} + + - name: Create the release tag (post phase) + if: inputs.phase == 'post' + run: | + git tag "v${{ env.RELEASE_VERSION }}" + git push origin "v${{ env.RELEASE_VERSION }}" + + - name: Create a ${{ inputs.phase }} release branch + run: git checkout -b ${{ env.BRANCH_NAME }} + + - name: Perform pre release changes + if: inputs.phase == 'pre' + uses: ./.github/workflows/maven-goal-jdk + with: + command: ./.ci/release/pre-release.sh + + - name: Perform post release changes + if: inputs.phase == 'post' + uses: ./.github/workflows/maven-goal + with: + command: ./.ci/release/post-release.sh + + - name: Push the ${{ inputs.phase }} release branch + run: | + git add --all + git commit -m "${{ inputs.phase }} release: elastic-apm-agent v${{ env.RELEASE_VERSION }}" + git push origin ${{ env.BRANCH_NAME }} + + - name: Create the ${{ inputs.phase }} release PR + run: gh pr create --title="${{ inputs.phase }} release v${{ env.RELEASE_VERSION }}" --base main --head ${{ env.BRANCH_NAME }} -b "${{ inputs.phase }} release v${{ env.RELEASE_VERSION }}" + env: + GH_TOKEN: ${{ env.GITHUB_TOKEN }} diff --git a/.github/workflows/pre-release.yml b/.github/workflows/pre-release.yml new file mode 100644 index 00000000000..c37de5cf436 --- /dev/null +++ b/.github/workflows/pre-release.yml @@ -0,0 +1,32 @@ +--- + +name: Pre release + +on: + workflow_dispatch: + inputs: + ref: + description: 'Branch or tag ref to run the workflow on' + required: true + default: 'main' + version: + description: 'The version to release (e.g. 1.2.3). This workflow will automatically perform the required version bumps' + required: true + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }} + +jobs: + pre-release: + name: "Bump versions and create PR" + uses: ./.github/workflows/pre-post-release.yml + permissions: + contents: write + with: + ref: ${{ inputs.ref }} + version: ${{ inputs.version }} + phase: 'pre' + secrets: inherit diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d15ea5f5bca..f6124432a13 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,20 +5,13 @@ name: release on: workflow_dispatch: inputs: - branch: - description: 'The branch to release' + ref: + description: 'Branch or tag ref to run the workflow on' required: true - default: 'main' + default: "main" version: description: 'The version to release (e.g. 1.2.3). This workflow will automatically perform the required version bumps' required: true - update_changelog: - description: | - If enabled, everything in the changelog from the "Unreleased" section will be automatically moved to a new section for the new release. - If disabled, the changelog needs to be prepared for the release manually before triggering this workflow. - type: boolean - required: true - default: true skip_preparation: description: | If enabled, the version bump, release notes update and tag creation will be skipped. @@ -39,59 +32,47 @@ on: default: false type: boolean -env: - TAG_NAME: v${{ inputs.version }} - permissions: contents: read concurrency: group: ${{ github.workflow }} +env: + RELEASE_VERSION: ${{ inputs.version }} + jobs: - prepare_release: - permissions: - contents: write - name: "Changelog and Version Bump" - if: ${{ ! inputs.skip_preparation }} + validate-tag: runs-on: ubuntu-latest steps: - - uses: elastic/apm-pipeline-library/.github/actions/github-token@current + - name: Checkout + uses: actions/checkout@v4 with: - url: ${{ secrets.VAULT_ADDR }} - roleId: ${{ secrets.VAULT_ROLE_ID }} - secretId: ${{ secrets.VAULT_SECRET_ID }} - - uses: elastic/apm-pipeline-library/.github/actions/setup-git@current + ref: ${{ inputs.ref }} + fetch-depth: 0 + - name: Validate tag does not exist on current commit + uses: ./.github/workflows/validate-tag with: - username: ${{ env.GIT_USER }} - email: ${{ env.GIT_EMAIL }} - token: ${{ env.GITHUB_TOKEN }} - - uses: actions/checkout@v4 - with: - ref: ${{ inputs.branch }} - token: ${{ env.GITHUB_TOKEN }} - - name: Install JDK and mvn clean - uses: ./.github/workflows/maven-goal - with: - command: ./mvnw clean - - name: Prepare changelog for release - if: ${{ inputs.update_changelog && ! inputs.dry_run }} + tag: v${{ env.RELEASE_VERSION }} + - name: Validate tag match current version run: | - java .ci/ReleaseChangelog.java CHANGELOG.asciidoc ${{ inputs.version }} - git commit -m "Prepare changelog for release ${{ inputs.version }}" CHANGELOG.asciidoc - - name: Bump version and add git tag - if: ${{ ! inputs.dry_run }} - run: ./mvnw release:prepare -B -DpushChanges=false "-Darguments=-DskipTests -Dmaven.javadoc.skip=true" -DreleaseVersion=${{ inputs.version }} - - name: Push changes - if: ${{ ! inputs.dry_run }} - run: git push --atomic origin ${{ inputs.branch }} ${{ env.TAG_NAME }} + if [ "$(mvn -q help:evaluate -Dexpression=project.version -DforceStdout)" != "${{ env.RELEASE_VERSION }}" ]; then + echo "Tag should match pom.xml project.version" + exit 1 + fi + - name: Validate version is a release version + run: | + if [[ "$(./mvnw -q help:evaluate -Dexpression=project.version -DforceStdout)" =~ "-SNAPSHOT" ]]; then + echo "This is a snapshot version" + exit 1 + fi - maven_central_deploy: + maven-central-deploy: name: "Deploy to Maven Central (Buildkite)" if: ${{ ! inputs.skip_maven_deploy && ( inputs.skip_preparation || success() ) }} runs-on: ubuntu-latest needs: - - prepare_release + - validate-tag steps: - id: buildkite continue-on-error: true @@ -102,61 +83,29 @@ jobs: vaultRoleId: ${{ secrets.VAULT_ROLE_ID }} vaultSecretId: ${{ secrets.VAULT_SECRET_ID }} pipeline: apm-agent-java-release - pipelineCommit: ${{ env.TAG_NAME }} + pipelineCommit: ${{ env.RELEASE_VERSION }} waitFor: true printBuildLogs: false buildEnvVars: | dry_run=${{ inputs.dry_run || 'false' }} - await_artifact_on_maven_central: + await-maven-central-artifact: name: "Wait for artifacts to be available on maven central" runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Await artifacts published in maven central - if: ${{ ! inputs.dry_run }} - shell: bash - timeout-minutes: 120 - run: | - until .ci/release/wait_maven_artifact_published.sh ${{ inputs.version }} - do - echo "Artifacts not found on maven central. Sleeping 30 seconds, retrying afterwards" - sleep 30s - done - - update_major_branch: - name: "Update Major Branch" - runs-on: ubuntu-latest needs: - - await_artifact_on_maven_central - permissions: - contents: write + - validate-tag steps: - - uses: elastic/apm-pipeline-library/.github/actions/github-token@current - with: - url: ${{ secrets.VAULT_ADDR }} - roleId: ${{ secrets.VAULT_ROLE_ID }} - secretId: ${{ secrets.VAULT_SECRET_ID }} - - uses: elastic/apm-pipeline-library/.github/actions/setup-git@current - with: - username: ${{ env.GIT_USER }} - email: ${{ env.GIT_EMAIL }} - token: ${{ env.GITHUB_TOKEN }} - - uses: actions/checkout@v4 + - uses: elastic/apm-pipeline-library/.github/actions/await-maven-artifact@current with: - ref: ${{ env.TAG_NAME }} - token: ${{ env.GITHUB_TOKEN }} - - name: Update major branch - run: .ci/release/update_major_branch.sh ${{ inputs.version }} - - name: Push changes - if: ${{ ! inputs.dry_run }} - run: git push -f origin "$(echo '${{ inputs.version }}' | sed -E 's/\..+/.x/')" + groupid: 'co.elastic.apm' + artifactid: 'elastic-apm-agent' + version: ${{ inputs.version }} - update_cloudfoundry: - name: "Update Cloudfoundry" + update-major-branch: + name: "Update Major Branch" runs-on: ubuntu-latest needs: - - await_artifact_on_maven_central + - await-maven-central-artifact permissions: contents: write steps: @@ -172,26 +121,22 @@ jobs: token: ${{ env.GITHUB_TOKEN }} - uses: actions/checkout@v4 with: - ref: ${{ inputs.branch }} + ref: ${{ inputs.ref }} token: ${{ env.GITHUB_TOKEN }} - - name: "Update Cloudfoundry index.yml file" - shell: bash - run: .ci/release/update_cloudfoundry.sh ${{ inputs.version }} - - name: Push changes - if: ${{ ! inputs.dry_run }} - run: git push origin ${{ inputs.branch }} + - name: Update major branch + run: .ci/release/update-major-branch.sh ${{ env.RELEASE_VERSION }} - build_and_push_docker_images: + build-and-push-docker-images: name: "Build and push docker images" runs-on: ubuntu-latest needs: - - await_artifact_on_maven_central + - await-maven-central-artifact env: SONATYPE_FALLBACK: 1 steps: - uses: actions/checkout@v4 with: - ref: ${{ env.TAG_NAME }} + ref: ${{ inputs.ref }} fetch-depth: 0 # Load entire history as it is required for the push-script - uses: elastic/apm-pipeline-library/.github/actions/docker-login@current with: @@ -208,11 +153,11 @@ jobs: shell: bash run: ./scripts/docker-release/push_docker.sh - publish_aws_lambda: + publish-aws-lambda: name: "Publish AWS Lambda" runs-on: ubuntu-latest needs: - - await_artifact_on_maven_central + - await-maven-central-artifact outputs: arn_content: ${{ steps.arn_output.outputs.arn_content }} env: @@ -222,7 +167,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ env.TAG_NAME }} + ref: ${{ inputs.ref }} - name: Build Lambda-layer zip using agent from maven-central uses: ./.github/workflows/maven-goal with: @@ -240,7 +185,7 @@ jobs: if: ${{ ! inputs.dry_run }} run: | # Convert v1.2.3 to ver-1-2-3 - VERSION=${TAG_NAME/v/ver-} + VERSION=${RELEASE_VERSION/v/ver-} VERSION=${VERSION//./-} ELASTIC_LAYER_NAME="elastic-apm-java-${VERSION}" .ci/publish-aws.sh @@ -257,11 +202,11 @@ jobs: cat .ci/.arn-file.md >> $GITHUB_OUTPUT echo 'ARN_CONTENT_EOF' >> $GITHUB_OUTPUT - create_github_release: + create-github-release: name: "Create GitHub Release" needs: - - publish_aws_lambda - - update_major_branch + - publish-aws-lambda + - update-major-branch runs-on: ubuntu-latest if: ${{ ! inputs.dry_run }} permissions: @@ -269,39 +214,52 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ env.TAG_NAME }} + ref: ${{ inputs.ref }} - name: Await release-notes published shell: bash timeout-minutes: 120 run: | - until .ci/release/wait_release_notes_published.sh ${{ inputs.version }} + until .ci/release/wait_release_notes_published.sh ${{ env.RELEASE_VERSION }} do echo "Release notes not published yet. Sleeping 30 seconds, retrying afterwards" sleep 30s done - name: Compute major.x branch id: get_dotx_branch - run: echo "dotx_branch=$(echo '${{ inputs.version }}' | sed -E 's/\..+/.x/')" >> $GITHUB_OUTPUT + run: echo "dotx_branch=$(echo '${{ env.RELEASE_VERSION }}' | sed -E 's/\..+/.x/')" >> $GITHUB_OUTPUT - name: Create GitHub Release env: GH_TOKEN: ${{ github.token }} run: | - gh release create ${{ env.TAG_NAME }} \ - --title="Release ${{ inputs.version }}" \ - --notes="[Release Notes for ${{ inputs.version }}](https://www.elastic.co/guide/en/apm/agent/java/current/release-notes-${{ steps.get_dotx_branch.outputs.dotx_branch }}.html#release-notes-${{ inputs.version }}) - ${{ needs.publish_aws_lambda.outputs.arn_content }}" + gh release create ${{ env.RELEASE_VERSION }} \ + --title="Release ${{ env.RELEASE_VERSION }}" \ + --notes="[Release Notes for ${{ env.RELEASE_VERSION }}](https://www.elastic.co/guide/en/apm/agent/java/current/release-notes-${{ steps.get_dotx_branch.outputs.dotx_branch }}.html#release-notes-${{ env.RELEASE_VERSION }}) + ${{ needs.publish-aws-lambda.outputs.arn_content }}" + + post-release: + name: "Bump versions and create PR" + needs: + - await-maven-central-artifact + uses: ./.github/workflows/pre-post-release.yml + permissions: + contents: write + if: inputs.dry_run == false + with: + ref: ${{ inputs.ref }} + version: ${{ inputs.version }} + phase: 'post' + secrets: inherit notify: if: ${{ always() && ! inputs.dry_run }} needs: - - prepare_release - - maven_central_deploy - - await_artifact_on_maven_central - - update_major_branch - - update_cloudfoundry - - build_and_push_docker_images - - publish_aws_lambda - - create_github_release + - maven-central-deploy + - await-maven-central-artifact + - update-major-branch + - build-and-push-docker-images + - publish-aws-lambda + - post-release + - create-github-release runs-on: ubuntu-latest steps: - id: check diff --git a/.github/workflows/validate-tag/action.yml b/.github/workflows/validate-tag/action.yml new file mode 100644 index 00000000000..1cdb8ef5c36 --- /dev/null +++ b/.github/workflows/validate-tag/action.yml @@ -0,0 +1,25 @@ +--- + +name: validate-tag +description: Validate tag format + +inputs: + tag: + description: 'Tag to validate' + required: true + +runs: + using: "composite" + steps: + - name: Validate tag does not exist on current commit + id: validate-tag + shell: 'bash' + run: | + if ! [ $(echo "${{ inputs.tag }}" | grep -P "(\d{1,2})\.(\d{1,2})\.(\d{1,2})") ]; then + echo "Tag should be a SemVer format" + exit 1 + fi + if [ $(git tag -l "${{ inputs.tag }}") ]; then + echo "The tag ${{ inputs.tag }} already exists" + exit 1 + fi diff --git a/.mvn/maven.config b/.mvn/maven.config index f50bb0f948b..7c3456d7e48 100644 --- a/.mvn/maven.config +++ b/.mvn/maven.config @@ -1,4 +1,3 @@ --V -B -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn -Dhttps.protocols=TLSv1.2 diff --git a/pom.xml b/pom.xml index 55daeaac733..2ec5eced20b 100644 --- a/pom.xml +++ b/pom.xml @@ -380,17 +380,9 @@ - maven-release-plugin - - false - gpg - true - v@{project.version} - - **/apm-agent-benchmarks/src/main/resources/** - **/apm-agent-plugins/apm-profiling-plugin/src/main/resources/** - - + org.codehaus.mojo + versions-maven-plugin + 2.16.2 org.sonatype.plugins