Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .buildkite/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
agents:
provider: "gcp"

steps:
- label: "Run the snapshot"
key: "release"
commands: .ci/release.sh
artifact_paths:
- "release.txt"
- "**/target/*"

notify:
- slack: "#apm-agent-java"
if: 'build.state != "passed"'
126 changes: 126 additions & 0 deletions .ci/ReleaseChangelog.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.OptionalInt;
import java.util.function.Predicate;

public class ReleaseChangelog {

public static void main(String[] args) throws IOException {
if (args.length != 2) {
System.out.println("Expected exactly two arguments: <ChangelogFile> <VersionToRelease>");
System.exit(-1);
}
Path fileName = Paths.get(args[0]);
String version = args[1].trim();
if (!version.matches("\\d+\\.\\d+\\.\\d+")) {
System.out.println("Version must be in the format x.x.x but was not: " + version);
System.exit(-1);
}
Lines f = new Lines(Files.readAllLines(fileName, StandardCharsets.UTF_8));
int unreleasedStart = f.findLine(str -> str.trim().equals("=== Unreleased"), 0).orElseThrow() + 1;
int unreleasedEnd = f.findLine(str -> str.startsWith("[[release-notes-"), unreleasedStart).orElseThrow();

Lines changes = f.cut(unreleasedStart, unreleasedEnd);
f.insert(new Lines(List.of("")), unreleasedStart); //add a blank line below unreleased heading
changes.trim();

// a few sanity checks
if (changes.lineCount() == 0) {
System.out.println("Unreleased changes are empty, there must be something wrong!");
System.exit(-1);
}
OptionalInt wrongIndentedHeading = changes.findLine(str -> str.matches("^==?=?=?[^=].*"), 0);
if (wrongIndentedHeading.isPresent()) {
System.out.println("Found heading which is too high level (must be at least =====) within changes: "
+ changes.getLine(wrongIndentedHeading.getAsInt()));
System.exit(-1);
}

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd")
.withZone(ZoneOffset.UTC);

changes.insert(new Lines(List.of(
"",
String.format("[[release-notes-%s]]", version),
String.format("==== %s - %s", version, formatter.format(Instant.now())),
""
)), 0);

int majorVersion = Integer.parseInt(version.split("\\.")[0]);
String majorHeading = String.format("=== Java Agent version %d.x", majorVersion);
OptionalInt sectionStart = f.findLine(str -> str.trim().equals(majorHeading), 0);
if (sectionStart.isEmpty()) {
System.out.println("Could not find heading for major version: " + majorHeading);
System.out.println("Is this a new major version? If yes, please add an empty section for it manually to the Changelog");
System.exit(-1);
}

f.insert(changes, sectionStart.getAsInt() + 1);

Files.writeString(fileName, f.toString(), StandardCharsets.UTF_8);
}

static class Lines {

private final List<String> lines;

public Lines(List<String> lines) {
this.lines = new ArrayList<>(lines);
}

int lineCount() {
return lines.size();
}

OptionalInt findLine(Predicate<String> condition, int startAt) {
for (int i = startAt; i < lines.size(); i++) {
if (condition.test(lines.get(i))) {
return OptionalInt.of(i);
}
}
return OptionalInt.empty();
}

Lines cut(int startInclusive, int endExclusive) {
List<String> cutLines = new ArrayList<>();
for (int i = startInclusive; i < endExclusive; i++) {
cutLines.add(lines.remove(startInclusive));
}
return new Lines(cutLines);
}

void insert(Lines other, int insertAt) {
this.lines.addAll(insertAt, other.lines);
}

/**
* Trims lines consisting of only blanks at the top and bottom
*/
void trim() {
while (!lines.isEmpty() && lines.get(0).matches("\\s*")) {
lines.remove(0);
}
while (!lines.isEmpty() && lines.get(lines.size() - 1).matches("\\s*")) {
lines.remove(lines.size() - 1);
}
}

@Override
public String toString() {
return String.join("\n", lines);
}

public String getLine(int number) {
return lines.get(number);
}
}

}
33 changes: 33 additions & 0 deletions .ci/release.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/usr/bin/env bash
## This script runs the release given the different environment variables
## dry_run
##
## It relies on the .buildkite/hooks/pre-command so the Vault and other tooling
## are prepared automatically by buildkite.
##

set -eo pipefail

# Make sure we delete this folder before leaving even in case of failure
clean_up () {
ARG=$?
export VAULT_TOKEN=$PREVIOUS_VAULT_TOKEN
echo "--- Deleting tmp workspace"
rm -rf $TMP_WORKSPACE
exit $ARG
}
trap clean_up EXIT

echo "--- Debug JDK installation :coffee:"
echo $JAVA_HOME
echo $PATH
java -version

set +x
echo "--- Deploy the release :package:"
if [[ "$dry_run" == "true" ]] ; then
./mvnw clean install -DskipTests=true -Dmaven.javadoc.skip=true | tee release.txt
else
echo "hello" | tee release.txt
# ./mvnw -V -s .ci/settings.xml -Pgpg clean deploy -DskipTests --batch-mode | tee release.txt
fi
212 changes: 212 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
---
# Releases the agent
name: release

on:
workflow_dispatch:
inputs:
branch:
description: 'The branch to release'
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
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

env:
JAVA_VERSION: 17
JAVA_DIST: adopt

permissions:
contents: write

jobs:
prepare_release:
permissions:
contents: write
name: "Changelog and Version Bump"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
ref: ${{ inputs.branch }}
- uses: elastic/apm-pipeline-library/.github/actions/setup-git@current
- 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: Prepare changelog for release
if: ${{ inputs.update_changelog }}
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
run: ./mvnw release:prepare -B -DpushChanges=false "-Darguments=-DskipTests -Dmaven.javadoc.skip=true" -DreleaseVersion=${{ inputs.version }}
- run: git push --atomic origin ${{ inputs.branch }} v${{ inputs.version }}


maven_central_deploy:
name: "Deploy to Maven Central (Buildkite)"
runs-on: ubuntu-latest
needs:
- prepare_release
steps:
- id: buildkite
name: Run Deploy
uses: reakaleek/apm-pipeline-library/.github/actions/buildkite@feature/buildkite-download-artifacts
with:
vaultUrl: ${{ secrets.VAULT_ADDR }}
vaultRoleId: ${{ secrets.VAULT_ROLE_ID }}
vaultSecretId: ${{ secrets.VAULT_SECRET_ID }}
pipeline: apm-agent-java-release
pipelineVersion: ${{ inputs.version }}
waitFor: true
printBuildLogs: true
artifactName: lambda-zip
artifactPath: "elastic-apm-agent/target/**/elastic-apm-java-aws-lambda-layer-*.zip"
buildEnvVars: |
dry_run=true
# buildEnvVars: |
# dry_run=${{ inputs.dry_run || 'false' }}

# await_artifact_on_maven_central:
# name: "Wait for artifacts to be available on maven central"
# runs-on: ubuntu-latest
# needs:
# - maven_central_deploy
# steps:
# - uses: actions/checkout@v3
# - shell: bash
# 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
# steps:
# - uses: actions/checkout@v3
# with:
# ref: ${{ inputs.branch }}
# - uses: elastic/apm-pipeline-library/.github/actions/setup-git@current
# - 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
# steps:
# - uses: actions/checkout@v3
# with:
# ref: ${{ inputs.branch }}
# - uses: elastic/apm-pipeline-library/.github/actions/setup-git@current
# - name: "Update Cloudfoundry index.yml file"
# shell: bash
# run: .ci/release/update_cloudfoundry.sh ${{ inputs.version }}
# - run: git push origin ${{ inputs.branch }}


# build_docker_images:
# name: "Build and push docker images"
# runs-on: ubuntu-latest
# needs:
# - await_artifact_on_maven_central
# env:
# TAG_NAME: v${{ inputs.version }}
# SONATYPE_FALLBACK: 1
# steps:
# - uses: actions/checkout@v3
# with:
# ref: ${{ inputs.branch }}
# 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/jenkins/build_docker.sh
# ./scripts/jenkins/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 }}
# steps:
# - uses: actions/checkout@v3
# with:
# ref: ${{ inputs.branch }}
# # TODO: actual lambda creation + upload
# - name: Setup dummy ARN file
# run: |
# {
# echo "### ARNs of the APM Java Agent's AWS Lambda Layer"
# echo ''
# echo '|Region|ARN|'
# echo '|------|---|'
# } > ".ci/arn-file.md"
# - 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<<ARN_CONTENT_EOF' >> $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
# steps:
# - uses: actions/checkout@v3
# with:
# ref: ${{ inputs.branch }}
# - name: Await release-notes published
# shell: bash
# 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 v${{ inputs.version }} \
# --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 }}"
Loading