Skip to content

Instantly share code, notes, and snippets.

@snordmann
Created October 6, 2021 14:24
Show Gist options
  • Select an option

  • Save snordmann/8a6358945dbd189be45274b08c3fca0f to your computer and use it in GitHub Desktop.

Select an option

Save snordmann/8a6358945dbd189be45274b08c3fca0f to your computer and use it in GitHub Desktop.
Infracost - Posting to BitBucket

Infracost Integration with BitBucket Server/Datacenter

Features

  • Can post comment on BitBucket PR
  • Can update PR comment
  • Does not comment when no changes in infrastructure is detected
  • Is integrated with infracost official ci scripts

I have no idea when I will tackle the open points.

Explanation

The script infracost.sh takes 1 argument, the path for infracost. It generates the files infracost_breakdown.html (contains infracost breakdown in html format) and output.txt (contains diff in markdown format for PR comment).

The script post_to_bitbucket.sh takes 1 argument, the name of the current branch. It posts a new or updates an existing comment to the PR, if it exists. Also the following environment variables must be set:

  • BB_ADDRESS The URL of the bitbucket instance (eg. https://bitbucket.example.com or https://example.com:8008/bitbucket)
  • BB_PROJECT The current project (not tested with the personal space)
  • BB_REPOSITORY The repository inside the project
  • BB_USER User used to authenticate with (must have "REPO_READ" permissions)
  • BB_PASSWORD Do I have to explain this?

Example

terraform plan -no-color -out=tf.plan
terraform show -json tf.plan > plan.json

./infracost.sh plan.json

withEnv(["BB_ADDRESS=https://bitbucket.example.com", "BB_PROJECT=test", "BB_REPOSITORY=infracost-demo"]) {
  withCredentials([usernamePassword(credentialsId: "bitbucket_creads", passwordVariable: 'BB_PASSWORD', usernameVariable: 'BB_USER')]) {
    sh("./post_to_bitbucket.sh ${current_branch}")
  }
}
#!/bin/bash
infracost breakdown --no-color --format json --path $1 > infracost_breakdown.json
infracost output --no-color --path infracost_breakdown.json --format diff > infracost_diff.txt
infracost output --no-color --path infracost_breakdown.json --format html > infracost_breakdown.html
past_total_monthly_cost=$(jq '[.projects[].pastBreakdown.totalMonthlyCost | select (.!=null) | tonumber] | add' infracost_breakdown.json)
total_monthly_cost=$(jq '[.projects[].breakdown.totalMonthlyCost | select (.!=null) | tonumber] | add' infracost_breakdown.json)
diff_cost=$(jq '[.projects[].diff.totalMonthlyCost | select (.!=null) | tonumber] | add' infracost_breakdown.json)
currency=$(jq -r '.currency | select (.!=null)' infracost_breakdown.json)
if [ "${currency}" = "" ] || [ "${currency}" = "USD" ]; then
currency="$"
elif [ "${currency}" = "EUR" ]; then
currency="€"
elif [ "${currency}" = "GBP" ]; then
currency="£"
else
currency="${currency} " # Space is needed so output is "INR 123"
fi
change_word="increase"
change_emoji="📈"
if [ "$(echo "${total_monthly_cost} < ${past_total_monthly_cost}" | bc -l)" = 1 ]; then
change_word="decrease"
change_emoji="📉"
fi
cat <<EOF >output.txt
💰 Infracost estimate: **monthly cost will ${change_word} by ${currency}${diff_cost}** ${change_emoji}
Previous monthly cost: ${currency}${past_total_monthly_cost}
New monthly cost: ${currency}${total_monthly_cost}
**Infracost output:**
\`\`\`
$(cat infracost_diff.txt)
\`\`\`
EOF
rm -rf infracost_diff.txt infracost_breakdown.json
#!/bin/bash
# Environment variables
# - BB_ADDRESS
# - BB_PROJECT
# - BB_REPOSITORY
# - BB_USER
# - BB_PASSWORD
BB_USER_DISPLAY_NAME="MYAPIUSER"
current_branch=$1
common_curl_args="-L -k -u ${BB_USER}:${BB_PASSWORD}"
bb_api="${BB_ADDRESS}/rest/api/1.0/projects/${BB_PROJECT}/repos/${BB_REPOSITORY}"
response=$(curl ${common_curl_args} --header "Content-Type: application/json" --request GET --url ${bb_api}/pull-requests?State=OPEN&at=refs/heads/${current_branch}&direction=OUTGOING)
pr_number=$(echo "${response}" | jq -r ".values[0].id")
if [ "${pr_number}" == "null" ]; then
echo "Not running in a Pull Request. Exiting script"
exit 0
fi
echo "Running in Pull Request. Posting comment"
# Read file and replace \n (line feeds) with \\n (string)
# See also https://stackoverflow.com/a/1252191
pr_text=$(sed ':a;N;$!ba;s/[\r\n]/\\n/g' output.txt)
# Discover existing PR comments
response=$(curl ${common_curl_args} --header "Content-Type: application/json" --request GET --url "${bb_api}/pull-requests/${pr_number}/activities")
existing_comment=$(echo "${response}" | jq -r ".values[] | select(.action == \"COMMENTED\" and .user.displayName == \"Jenkins TID\")")
if [ "${existing_comment}" == "null" ] || [ "${existing_comment}" == "" ]; then
echo "Posting new comment"
echo "{\"text\": \"${pr_text}\"}" | curl ${common_curl_args} --header "Content-Type: application/json" --request POST -d@- --url "${bb_api}/pull-requests/${pr_number}/comments"
exit 0
fi
echo "Updating existing comment"
existing_comment_id=$(echo "${response}" | jq -r ".values | map(select(.action == \"COMMENTED\" and .user.displayName == \"${BB_USER_DISPLAY_NAME}\"))[0].comment.id")
existing_comment_version=$(echo "${response}" | jq -r ".values | map(select(.action == \"COMMENTED\" and .user.displayName == \"${BB_USER_DISPLAY_NAME}\"))[0].comment.version")
echo "ID=${existing_comment_id}"
echo "VERSION=${existing_comment_version}"
echo "{\"text\": \"${pr_text}\", \"version\": \"${existing_comment_version}\"}" | curl ${common_curl_args} --header "Content-Type: application/json" --request PUT -d@- --url "${bb_api}/pull-requests/${pr_number}/comments/${existing_comment_id}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment