Skip to content
Open
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Calculate Artifact Size
description: Calculates size for JVM artifacts

inputs:
upload:
description: Whether the metrics should be uploaded to S3/Cloudwatch
type: boolean
release_metrics:
description: Whether the metrics are coming from a release build
type: boolean

runs:
using: composite
steps:
- name: Calculate and upload artifact sizes
shell: bash
env:
GITHUB_REPOSITORY: ${{ github.repository }}
IDENTIFIER: ${{ github.ref_name }}
UPLOAD: ${{ inputs.upload }}
RELEASE_METRICS: ${{ inputs.release_metrics }}
run: |
chmod +x ../utils/calculate-and-upload/main.sh
../utils/calculate-and-upload/main.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: Process artifact size metrics
description: Compares artifact size metrics, leaves a comment, and fails if a size increase of ≥5% is detected.

inputs:
download:
description: Whether the artifact size metrics should be downloaded from S3
type: boolean

runs:
using: composite
steps:
- name: Download and process artifact size metrics
description: Compares artifact size metrics and sets LARGE_DIFF to true if a size increase of ≥5% is detected.
shell: bash
env:
DOWNLOAD: ${{ inputs.download }}
GITHUB_REPOSITORY: ${{ github.repository }}
IDENTIFIER: ${{ github.ref_name }}
run: |
chmod +x ../utils/download-and-process/main.sh
../utils/download-and-process/main.sh

- name: Comment artifact size metrics comparison
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const fs = require('node:fs')

// Read the artifact size metrics comparison
const comparison = fs.readFileSync('build/reports/metrics/artifact-analysis.md', 'utf8')

// Get PR ID
const { data: pullRequest } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number
})
const pullRequestId = pullRequest.node_id

// Add the comment
const addCommentResponse = await github.graphql(`
mutation {
addComment(input: {body: """${comparison}""", subjectId: "${pullRequestId}"}) {
commentEdge { node { id } }
}
}
`)

const commentId = addCommentResponse.addComment.commentEdge.node.id

// Minimize the comment
await github.graphql(`
mutation {
minimizeComment(input: {subjectId: "${commentId}", classifier: RESOLVED}) { }
}
`)
Comment on lines +52 to +57
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we always minimizing the comment now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we rarely have to actually look at the metrics. If we do, it's really easy to just un-minimize a comment.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aren't the artifact sizes logged in the CI output? Maybe we don't need the comment at all


- name: Large size increase?
if: ${{ !contains(github.event.pull_request.labels.*.name, 'acknowledge-artifact-size-increase') }}
shell: bash
run: |
if [ "$LARGE_DIFF" == "true" ]; then
echo "An artifact has increased in size by more than 5%.
If this is expected, please add the acknowledge-artifact-size-increase label to this pull request."
exit 1
fi
86 changes: 0 additions & 86 deletions .github/actions/artifact-size-metrics/show-results/action.yml

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Gets artifact size metrics from staging dir
calculateArtifactSizes() {
# Artifact staging dir
input_dir="build/m2"

# Create output_file
output_file="$1"
mkdir -p "$(dirname "$output_file")"
touch "$output_file"

# Write CSV header
echo "Artifact, Size (Bytes)" > "$output_file"

# Find all JARs (exclude sources and javadoc)
# TODO: Calculate KN artifacts sizes
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we have an internal task for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have an older task for it: SDK-KT-771

find "$input_dir" -type f -name "*.jar" ! -name "*-sources.jar" ! -name "*-javadoc.jar" | while read -r jar; do
size=$(stat -c%s "$jar")

# remove dir path, version, optional timestamp, and .jar
artifact=$(basename "$jar")
artifact=$(echo "$artifact" | sed -E 's/-[0-9].*\.jar$//')

# Add artifact size to CSV
echo "$artifact, $size" >> "$output_file"
done

# Print results for debugging
cat "$output_file"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Upload the artifact size metrics to cloudwatch
uploadToCloudwatch() {
metrics_file="$1"
metrics=()

# Read CSV
while IFS=',' read -r artifactName artifactSize; do
# Skip header
[[ "$artifactName" == "Artifact" ]] && continue

# Trim spaces
artifactName=$(echo "$artifactName" | xargs)
artifactSize=$(echo "$artifactSize" | xargs)

# Build metric JSON
metrics+=$(jq -n \
--arg name "$GITHUB_REPOSITORY-$artifactName" \
--arg value "$artifactSize" \
--arg project "$GITHUB_REPOSITORY" \
'{
MetricName: $name,
Timestamp: (now | todate),
Unit: "Bytes",
Value: ($value | tonumber),
Dimensions: [
{ Name: "Project", Value: $project }
]
}'
)
done < "$metrics_file"

namespace="Artifact Size Metrics"
chunk_size=1000

# Send metrics in chunks
for ((i=0; i<${#metrics[@]}; i+=chunk_size)); do
chunk=("${metrics[@]:i:chunk_size}")
aws cloudwatch put-metric-data \
--namespace "$namespace" \
--metric-data "$(printf '%s\n' "${chunk[@]}" | jq -s '.')"
done
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/bin/bash

# Bash script to calculate, and upload artifact size metrics

source "$(dirname "$0")/calculate_metrics.sh"
source "$(dirname "$0")/cloudwatch.sh"
source "$(dirname "$0")/../s3.sh"
source "$(dirname "$0")/../constants.sh"
source "$(dirname "$0")/../setup.sh"

setup

# Calculate size for artifacts in staging dir (build/m2) and save them to metrics_file
calculateArtifactSizes "$metrics_file" # see: constants.sh

# Upload metrics to S3/cloudwatch if required
if [ "$UPLOAD" == "true" ]; then
if [ "$RELEASE_METRICS" == "true" ]; then
# For record-keeping
uploadToMetricsBucket "$metrics_file" "$GITHUB_REPOSITORY"-v"$IDENTIFIER".csv
uploadToMetricsBucket "$metrics_file" "$GITHUB_REPOSITORY"-latest.csv

# For display in our OPS dashboard
uploadToCloudwatch "$metrics_file" "$GITHUB_REPOSITORY"
else
# For downstream consumption in pull requests
uploadToMetricsBucket "$metrics_file" [TEMP]"$GITHUB_REPOSITORY"-pull-request-"$IDENTIFIER".csv
fi
fi
10 changes: 10 additions & 0 deletions .github/actions/artifact-size-metrics/utils/constants.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash

# Where current metrics are stored
metrics_file="build/reports/metrics/artifact-size-metrics.csv"

# Where metrics from latest release are stored
latest_release_metrics_file="build/reports/metrics/latest-release-artifact-size-metrics.csv"

# Where the metrics comparison results are stored
metrics_comparison_file="build/reports/metrics/comparison.md"
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Compares artifact size metrics to ones from the latest available release,
# stores comparison as a markdown table,
# and returns "true" if a large diff was found (over 5%)
compareMetrics() {
local metrics_file="$1"
local latest_release_metrics_file="$2"
local metrics_comparison_file="$3"

# Title and table headers
{
echo "Affected Artifacts"
echo "="
echo "| Artifact | Pull Request (bytes) | Latest Release (bytes) | Delta (bytes) | Delta (percentage) |"
echo "|----------|----------------------|------------------------|---------------|--------------------|"
} > "$metrics_comparison_file"

large_diff=false

# Read CSV
while IFS=',' read -r artifact size; do
# Skip header
[ "$artifact" = "Artifact" ] && continue

# Trim spaces
artifact=$(echo "$artifact" | xargs)
size=$(echo "$size" | xargs)

# Find corresponding artifact size in release file or skip
latest_release_size=$(awk -F',' -v art="$artifact" 'NR>1 && $1==art {gsub(/ /,"",$2); print $2}' "$latest_release_metrics_file")
[ -z "$latest_release_size" ] && continue

# Find delta
delta=$((size - latest_release_size))
abs_delta=${delta#-}
percent=$((100 * abs_delta / latest_release_size))

# Add to file
echo "| $artifact | $size | $latest_release_size | $delta | ${percent}% |" >> "$metrics_comparison_file"

# Check for large diff
if [ "$percent" -gt 5 ]; then
large_diff=true
fi
Comment on lines +40 to +43
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we no longer using the significantChangeThresholdPercentage configured in the plugin?

/**
* The threshold for an acceptable artifact size increase (percentage)
*/
var significantChangeThresholdPercentage: Double = 5.0

Let's delete it there if it's no longer being used

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, forgot to delete all that. We never really changed the value from 5% so it doesn't seem necessary.

done < "$metrics_file"

# Print results for debugging
cat "$metrics_comparison_file"

$large_diff && echo "true"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/bin/bash

# Bash script to download, and compare artifact size metrics

source "$(dirname "$0")/compare.sh"
source "$(dirname "$0")/../s3.sh"
source "$(dirname "$0")/../constants.sh"
source "$(dirname "$0")/../setup.sh"

setup

if [ "$DOWNLOAD" == "true" ]; then
# Get metrics calculated in codebuild - otherwise metrics will already be here
downloadFromMetricsBucket [TEMP]"$GITHUB_REPOSITORY"-pull-request-"$IDENTIFIER".csv "$metrics_file" # see: constants.sh
fi

# Metrics from the latest release are never calculated here so we need to download them
downloadFromMetricsBucket "$GITHUB_REPOSITORY"-latest.csv "$latest_release_metrics_file" # see: constants.sh

# Compare metrics
export LARGE_DIFF=$(compareMetrics "$metrics_file" "$latest_release_metrics_file" "$metrics_comparison_file") # see: constants.sh

if [ "$LARGE_DIFF" == "true" ]; then
echo "Large diff found!"
fi
12 changes: 12 additions & 0 deletions .github/actions/artifact-size-metrics/utils/s3.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Owned by: aws-kotlin-sdk+ci
S3_ARTIFACT_SIZE_METRICS_BUCKET="artifact-size-metrics"

# Uploads metrics to the metrics bucket under the specified file name
uploadToMetricsBucket() {
aws s3 cp "$1" s3://"$S3_ARTIFACT_SIZE_METRICS_BUCKET"/"$2"
}

# Downloads metrics from the metrics bucket to the specified local file
downloadFromMetricsBucket() {
aws s3 cp s3://"$S3_ARTIFACT_SIZE_METRICS_BUCKET"/"$1" "$2"
}
6 changes: 6 additions & 0 deletions .github/actions/artifact-size-metrics/utils/setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Exit if non zero exit code or if env var is missing, and enable command tracing
setup() {
set -u
set -e
set -x
}
Loading
Loading