diff --git a/.github/workflows/release-from-pr.yml b/.github/workflows/release-from-pr.yml new file mode 100644 index 0000000000..45f4832711 --- /dev/null +++ b/.github/workflows/release-from-pr.yml @@ -0,0 +1,303 @@ +--- + +# Releases the agent +name: Release On PR + +on: + pull_request_review: + types: [ submitted ] + branches: + - main + paths: + - 'pom.xml' + +env: + JAVA_VERSION: 17 + JAVA_DIST: temurin + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }} + +jobs: + check: + name: "Check release from PR" + runs-on: ubuntu-latest + if: github.event.review.state == 'approved' + outputs: + is_release: ${{ steps.check.outputs.is_release }} + steps: + - id: check + name: Check for specific release label + run: | + LABEL="release" + echo "Checking for label: $LABEL" + LABEL_EXISTS=$(echo '${{ toJSON(github.event.pull_request.labels.*.name) }}' | jq '.[] | select(. == "'$LABEL'")') + if [ -z "$LABEL_EXISTS" ]; then + echo "Label $LABEL does not exist on the merged PR." + echo "::set-output name=is_release::false" + else + echo "::set-output name=is_release::true" + fi + + merge_ff: + name: "Unlock & Merge FF" + runs-on: ubuntu-latest + needs: + - check + if: needs.check.outputs.is_release == 'true' + 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: ${{ github.event.pull_request.head.ref }} + fetch-depth: 0 + token: ${{ env.GITHUB_TOKEN }} + # TODO: Define if we use lock/unlock branch feature + # - uses: elastic/apm-pipeline-library/.github/actions/branch-lock@feat/action-branch-lock + # with: + # lock: 'false' + # branch: 'main' + # token: ${{ secrets.PAT }} + - name: Merge the PR branch into the base branch + run: | + # Fetch the base branch + git fetch origin "${{ github.event.pull_request.base.ref }}" + git checkout "${{ github.event.pull_request.base.ref }}" + + # Try a fast-forward merge + # If it fails, the workflow will stop and the PR will not be merged + git merge --ff-only "${{ github.event.pull_request.head.ref }}" + + # Push the changes to the base branch + git push origin "${{ github.event.pull_request.base.ref }}" + + prepare_release: + name: "Find tag & Wait propagation" + runs-on: ubuntu-latest + needs: + - check + - merge_ff + if: needs.check.outputs.is_release == 'true' + outputs: + tag_name: ${{ steps.tag.outputs.name }} + steps: + - id: tag + name: Find latest tag + uses: actions/github-script@v6 + with: + result-encoding: string + retries: 3 + script: | + const tags = await github.rest.repos.listTags({ + owner: context.repo.owner, + repo: context.repo.repo, + per_page: 1 + }); + const tag = tags.data[0].name; + core.info(`Latest tag: ${tag}`); + core.setOutput('name', tag); + + - name: Await artifacts published in maven central + shell: bash + timeout-minutes: 120 + run: | + until .ci/release/wait_maven_artifact_published.sh "${TAG_NAME}" + do + echo "Artifacts not found on maven central. Sleeping 30 seconds, retrying afterwards" + sleep 30s + done + + build_and_push_docker_images: + name: "Build and push docker images" + runs-on: ubuntu-latest + needs: + - check + - prepare_release + if: needs.check.outputs.is_release == 'true' + env: + SONATYPE_FALLBACK: 1 + steps: + - name: Set tag name + run: | + echo "TAG_NAME=${{ needs.prepare_release.outputs.tag_name }}" >> ${GITHUB_ENV} + - uses: actions/checkout@v4 + with: + ref: ${{ env.TAG_NAME }} + 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: + registry: docker.elastic.co + secret: secret/apm-team/ci/docker-registry/prod + url: ${{ secrets.VAULT_ADDR }} + roleId: ${{ secrets.VAULT_ROLE_ID }} + secretId: ${{ secrets.VAULT_SECRET_ID }} + - name: "Build docker image" + shell: bash + run: | + ./scripts/docker-release/build_docker.sh + ./scripts/docker-release/push_docker.sh + + publish_aws_lambda: + name: "Publish AWS Lambda" + runs-on: ubuntu-latest + needs: + - check + - prepare_release + if: needs.check.outputs.is_release == 'true' + outputs: + arn_content: ${{ steps.arn_output.outputs.arn_content }} + env: + # Random region. This needs to be set in GH Actions or the usage of aws-cli will fail. + # The default region does not matter, since we are publishing in all regions. + AWS_DEFAULT_REGION: eu-west-1 + steps: + - name: Set tag name + run: | + echo "TAG_NAME=${{ needs.prepare_release.outputs.tag_name }}" >> ${GITHUB_ENV} + - uses: actions/checkout@v4 + with: + ref: ${{ env.TAG_NAME }} + - name: Set up JDK ${{ env.JAVA_VERSION }} + uses: actions/setup-java@v3 + with: + java-version: ${{ env.JAVA_VERSION }} + distribution: ${{ env.JAVA_DIST }} + cache: 'maven' + - name: Build Lambda-layer zip using agent from maven-central + run: ./mvnw dependency:purge-local-repository package -pl apm-agent-lambda-layer + - uses: hashicorp/vault-action@v2.7.4 + with: + url: ${{ secrets.VAULT_ADDR }} + method: approle + roleId: ${{ secrets.VAULT_ROLE_ID }} + secretId: ${{ secrets.VAULT_SECRET_ID }} + secrets: | + secret/observability-team/ci/service-account/apm-aws-lambda access_key_id | AWS_ACCESS_KEY_ID ; + secret/observability-team/ci/service-account/apm-aws-lambda secret_access_key | AWS_SECRET_ACCESS_KEY + - name: Publish + run: | + # Convert v1.2.3 to ver-1-2-3 + VERSION=${TAG_NAME/v/ver-} + VERSION=${VERSION//./-} + .ci/publish-aws.sh + - uses: actions/upload-artifact@v3 + with: + name: arn-file + path: .ci/.arn-file.md + - name: Add ARN file to output + id: arn_output + run: | + echo 'arn_content<> $GITHUB_OUTPUT + cat .ci/.arn-file.md >> $GITHUB_OUTPUT + echo 'ARN_CONTENT_EOF' >> $GITHUB_OUTPUT + + update_major_branch: + name: "Update Major Branch" + runs-on: ubuntu-latest + needs: + - check + - prepare_release + if: needs.check.outputs.is_release == 'true' + permissions: + contents: write + steps: + - name: Set tag name + run: | + echo "TAG_NAME=${{ needs.prepare_release.outputs.tag_name }}" >> ${GITHUB_ENV} + echo "SEM_VER=$(echo '${{ needs.prepare_release.outputs.tag_name }}' | sed 's/v//')" >> ${GITHUB_ENV} + echo "MAJOR_BRANCH=$(echo '${{ needs.prepare_release.outputs.tag_name }}' | sed 's/v//' | sed -E 's/\..+/.x/')" >> ${GITHUB_ENV} + - 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: ${{ env.TAG_NAME }} + token: ${{ env.GITHUB_TOKEN }} + - name: Create a PR major branch + run: git checkout -b "update-major-branch-${MAJOR_BRANCH}" + - run: .ci/release/update_major_branch.sh "${SEM_VER}" + - name: Push PR major branch + run: git push origin "update-major-branch-${MAJOR_BRANCH}" + - name: Push PR major branch + run: gh pr create --title="Update Major Branch with ${TAG_NAME}" --base "${MAJOR_BRANCH}" --head update-major-branch-${MAJOR_BRANCH} -b "Update Major Branch with ${TAG_NAME}" + + + create_github_release: + name: "Create GitHub Release" + needs: + - check + - prepare_release + - publish_aws_lambda + - build_and_push_docker_images + - update_major_branch + runs-on: ubuntu-latest + if: needs.check.outputs.is_release == 'true' + permissions: + contents: write + steps: + - name: Set tag name + run: | + echo "TAG_NAME=${{ needs.prepare_release.outputs.tag_name }}" >> ${GITHUB_ENV} + echo "MAJOR_BRANCH=$(echo '${{ needs.prepare_release.outputs.tag_name }}' | sed 's/v//' | sed -E 's/\..+/.x/')" >> ${GITHUB_ENV} + - uses: actions/checkout@v4 + with: + ref: ${{ env.TAG_NAME }} + - name: Await release-notes published + shell: bash + timeout-minutes: 120 + run: | + until .ci/release/wait_release_notes_published.sh "${TAG_NAME}" + do + echo "Release notes not published yet. Sleeping 30 seconds, retrying afterwards" + sleep 30s + done + - name: Create GitHub Release + env: + GH_TOKEN: ${{ github.token }} + run: | + gh release create "${TAG_NAME}" \ + --title="Release ${TAG_NAME}" \ + --notes="[Release Notes for ${TAG_NAME}](https://www.elastic.co/guide/en/apm/agent/java/current/release-notes-${MAJOR_BRANCH}.html#release-notes-${TAG_NAME}) + ${{ needs.publish_aws_lambda.outputs.arn_content }}" + + notify: + needs: + - check + - update_major_branch + - build_and_push_docker_images + - publish_aws_lambda + - create_github_release + # TODO: Alternative to always if the workflow run + if: needs.check.outputs.is_release == 'true' + runs-on: ubuntu-latest + steps: + - id: check + uses: elastic/apm-pipeline-library/.github/actions/check-dependent-jobs@current + with: + needs: ${{ toJSON(needs) }} + - uses: elastic/apm-pipeline-library/.github/actions/notify-build-status@current + with: + status: ${{ steps.check.outputs.status }} + vaultUrl: ${{ secrets.VAULT_ADDR }} + vaultRoleId: ${{ secrets.VAULT_ROLE_ID }} + vaultSecretId: ${{ secrets.VAULT_SECRET_ID }} + slackChannel: "#apm-agent-java" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1b84073b3b..6aa8de3990 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,6 +1,6 @@ --- # Releases the agent -name: release +name: Prepare Release on: workflow_dispatch: @@ -12,28 +12,6 @@ on: 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. - Select this option if those tasks have already been done in a previous run. - type: boolean - required: true - default: false - skip_maven_deploy: - description: | - If enabled, the deployment to maven central will be skipped. - Select this if the deployment job for this release failed in a previous version but the release was actually published. - Check manually on maven central beforehand! - type: boolean - required: true - default: false env: JAVA_VERSION: 17 @@ -47,11 +25,10 @@ concurrency: group: ${{ github.workflow }} jobs: - prepare_release: + create_pr: permissions: contents: write name: "Changelog and Version Bump" - if: ${{ ! inputs.skip_preparation }} runs-on: ubuntu-latest steps: - uses: elastic/apm-pipeline-library/.github/actions/github-token@current @@ -74,22 +51,33 @@ jobs: java-version: ${{ env.JAVA_VERSION }} distribution: ${{ env.JAVA_DIST }} cache: 'maven' + # TODO: Define if we use lock/unlock branch feature + # - uses: elastic/apm-pipeline-library/.github/actions/branch-lock@feat/action-branch-lock + # with: + # lock: 'true' + # branch: 'main' + # token: ${{ secrets.PAT }} + - name: Create a PR release branch + run: git checkout -b "release-from-pr-${{ inputs.version }}" - name: Prepare changelog for release - if: ${{ inputs.update_changelog }} run: | - java .ci/ReleaseChangelog.java CHANGELOG.asciidoc ${{ inputs.version }} + 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 - run: ./mvnw release:prepare -B -DpushChanges=false "-Darguments=-DskipTests -Dmaven.javadoc.skip=true" -DreleaseVersion=${{ inputs.version }} - - run: git push --atomic origin ${{ inputs.branch }} ${{ env.TAG_NAME }} - + run: ./mvnw release:prepare -B -DpushChanges=false -Darguments="-DskipTests -Dmaven.javadoc.skip=true" -DreleaseVersion="${{ inputs.version }}" + - name: Update Cloudfoundry index.yml file + shell: bash + run: .ci/release/update_cloudfoundry.sh "${{ inputs.version }}" + - name: Push PR release branch + run: git push origin "release-from-pr-${{ inputs.version }}" --tags + - name: Create Pull Request Release + run: gh pr create --title="Release Version ${{ inputs.version }}" -l release --base main --head "release-from-pr-${{ inputs.version }}" -b "New Release ${{ inputs.version }}" 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 + - create_pr steps: - id: buildkite continue-on-error: true @@ -100,7 +88,8 @@ jobs: vaultRoleId: ${{ secrets.VAULT_ROLE_ID }} vaultSecretId: ${{ secrets.VAULT_SECRET_ID }} pipeline: apm-agent-java-release - pipelineVersion: ${{ env.TAG_NAME }} + pipelineBranch: release-from-pr-${{ inputs.version }} + pipelineCommit: ${{ env.TAG_NAME }} waitFor: true printBuildLogs: false # The action fails with .github/actions/buildkite/run.sh: line 24: 3: parameter missing. @@ -109,196 +98,11 @@ jobs: buildEnvVars: | something_something=true - - await_artifact_on_maven_central: - 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 - 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 - 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: ${{ env.TAG_NAME }} - token: ${{ env.GITHUB_TOKEN }} - - run: .ci/release/update_major_branch.sh ${{ inputs.version }} - - run: git push -f origin "$(echo '${{ inputs.version }}' | sed -E 's/\..+/.x/')" - - update_cloudfoundry: - name: "Update Cloudfoundry" - runs-on: ubuntu-latest - needs: - - await_artifact_on_maven_central - 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.branch }} - token: ${{ env.GITHUB_TOKEN }} - - name: "Update Cloudfoundry index.yml file" - shell: bash - run: .ci/release/update_cloudfoundry.sh ${{ inputs.version }} - - run: git push origin ${{ inputs.branch }} - - - build_and_push_docker_images: - name: "Build and push docker images" - runs-on: ubuntu-latest - needs: - - await_artifact_on_maven_central - env: - SONATYPE_FALLBACK: 1 - steps: - - uses: actions/checkout@v4 - with: - ref: ${{ env.TAG_NAME }} - 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: - registry: docker.elastic.co - secret: secret/apm-team/ci/docker-registry/prod - url: ${{ secrets.VAULT_ADDR }} - roleId: ${{ secrets.VAULT_ROLE_ID }} - secretId: ${{ secrets.VAULT_SECRET_ID }} - - name: "Build docker image" - shell: bash - run: | - ./scripts/docker-release/build_docker.sh - ./scripts/docker-release/push_docker.sh - - publish_aws_lambda: - name: "Publish AWS Lambda" - runs-on: ubuntu-latest - needs: - - await_artifact_on_maven_central - outputs: - arn_content: ${{ steps.arn_output.outputs.arn_content }} - env: - # Random region. This needs to be set in GH Actions or the usage of aws-cli will fail. - # The default region does not matter, since we are publishing in all regions. - AWS_DEFAULT_REGION: eu-west-1 - steps: - - uses: actions/checkout@v4 - with: - ref: ${{ env.TAG_NAME }} - - name: Set up JDK ${{ env.JAVA_VERSION }} - uses: actions/setup-java@v3 - with: - java-version: ${{ env.JAVA_VERSION }} - distribution: ${{ env.JAVA_DIST }} - cache: 'maven' - - name: Build Lambda-layer zip using agent from maven-central - run: ./mvnw dependency:purge-local-repository package -pl apm-agent-lambda-layer - - uses: hashicorp/vault-action@v2.7.4 - with: - url: ${{ secrets.VAULT_ADDR }} - method: approle - roleId: ${{ secrets.VAULT_ROLE_ID }} - secretId: ${{ secrets.VAULT_SECRET_ID }} - secrets: | - secret/observability-team/ci/service-account/apm-aws-lambda access_key_id | AWS_ACCESS_KEY_ID ; - secret/observability-team/ci/service-account/apm-aws-lambda secret_access_key | AWS_SECRET_ACCESS_KEY - - name: Publish - run: | - # Convert v1.2.3 to ver-1-2-3 - VERSION=${TAG_NAME/v/ver-} - VERSION=${VERSION//./-} - - ELASTIC_LAYER_NAME="elastic-apm-java-${VERSION}" .ci/publish-aws.sh - - uses: actions/upload-artifact@v3 - with: - name: arn-file - path: .ci/.arn-file.md - - name: Add ARN file to output - id: arn_output - run: | - echo 'arn_content<> $GITHUB_OUTPUT - cat .ci/.arn-file.md >> $GITHUB_OUTPUT - echo 'ARN_CONTENT_EOF' >> $GITHUB_OUTPUT - - - create_github_release: - name: "Create GitHub Release" - needs: - - publish_aws_lambda - - update_major_branch - runs-on: ubuntu-latest - permissions: - contents: write - steps: - - uses: actions/checkout@v4 - with: - ref: ${{ env.TAG_NAME }} - - name: Await release-notes published - shell: bash - timeout-minutes: 120 - run: | - until .ci/release/wait_release_notes_published.sh ${{ inputs.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 - - 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 }}" - - notify: if: always() needs: - - prepare_release + - create_pr - maven_central_deploy - - await_artifact_on_maven_central - - update_major_branch - - update_cloudfoundry - - build_and_push_docker_images - - publish_aws_lambda - - create_github_release runs-on: ubuntu-latest steps: - id: check