Skip to content

Instantly share code, notes, and snippets.

@leoxlin
Last active June 9, 2022 14:42
Show Gist options
  • Save leoxlin/c10902285626b3b22a12044b390aa861 to your computer and use it in GitHub Desktop.
Save leoxlin/c10902285626b3b22a12044b390aa861 to your computer and use it in GitHub Desktop.

Bitbucket Pipeline Watcher (OSX)

Watch bitbucket pipelines until it completes or the first step fails.

Uses OSX osascript for notifications so it only works on OSX.

Requirements

Requires app password: https://bitbucket.org/account/settings/app-passwords/

  1. Create an app password with at least 'Pipeline Read' permissions
  2. Set BITBUCKET_USERNAME and BITBUCKET_APP_PASSWORD in your bashrc

Usage

You can paste in the URI of the pipeline from the UI

./bitbucket_pipeline_watcher.sh 'https://bitbucket.org/workspace/repo/addon/pipelines/home#!/results/1234'

You can specify which workspace, repo and pipeline to watch

./bitbucket_pipeline_watcher.sh [workspace] [repo] [pipeline]

You can choose to alert on failure if even a single step fails

STRICT=1 ./bitbucket_pipeline_watcher.sh [workspace] [repo] [pipeline]
#!/bin/bash
WORKSPACE=$1
REPO=$2
export BRANCH=$3
ACTION=$4
export PIPELINE=$5
export PIPELINE_VARIABLES=$6
to_json() {
python3 -c 'import sys, yaml, json; y=yaml.safe_load(sys.stdin.read()); print(json.dumps(y))'
}
to_yaml() {
python3 -c 'import sys, yaml, json; j=json.loads(sys.stdin.read()); print(yaml.dump(j))'
}
list_pipelines() {
curl -s \
--user "$BITBUCKET_USERNAME:$BITBUCKET_APP_PASSWORD" \
--request GET \
--url "https://api.bitbucket.org/2.0/repositories/$WORKSPACE/$REPO/src/$BRANCH/bitbucket-pipelines.yml" | \
to_json | \
jq -r '.pipelines.custom | keys[]' | sort
}
show_pipeline() {
echo "${PIPELINE}:"
curl -s \
--user "$BITBUCKET_USERNAME:$BITBUCKET_APP_PASSWORD" \
--request GET \
--url "https://api.bitbucket.org/2.0/repositories/$WORKSPACE/$REPO/src/$BRANCH/bitbucket-pipelines.yml" | \
to_json | \
jq -r ".pipelines.custom | to_entries[] | select(.key == \"$PIPELINE\") | .value" |
to_yaml
}
run_pipeline() {
PAYLOAD=$(python3 -c '
import os, json
branch=os.environ["BRANCH"]
pipeline=os.environ["PIPELINE"]
variables=os.environ["PIPELINE_VARIABLES"]
vmap=[{"key":f.split("=", 1)[0],"value": f.split("=", 1)[1]} for f in variables.split(",") if "=" in f]
payload={
"target": {
"type": "pipeline_ref_target",
"ref_type": "branch",
"ref_name": branch,
"selector": {
"type": "custom",
"pattern": pipeline
}
},
"variables": vmap
}
print(json.dumps(payload))
')
curl -X POST -s --user "$BITBUCKET_USERNAME:$BITBUCKET_APP_PASSWORD" -H 'Content-Type: application/json' \
https://api.bitbucket.org/2.0/repositories/$WORKSPACE/$REPO/pipelines/ -d "$PAYLOAD"
}
if [[ "$ACTION" == "list" ]];then
list_pipelines
elif [[ "$ACTION" == "show" ]];then
show_pipeline
elif [[ "$ACTION" == "run" ]];then
run_pipeline
fi
#!/bin/bash
if [ $# -gt 1 ]; then
WORKSPACE=$1
REPO=$2
PIPELINE=$3
else
WORKSPACE=$(echo $1 | cut -d / -f 4)
REPO=$(echo $1 | cut -d / -f 5)
PIPELINE=$(echo $1 | cut -d / -f 10)
fi
get_pipeline() {
curl -s \
--user "$BITBUCKET_USERNAME:$BITBUCKET_APP_PASSWORD" \
--request GET \
--url "https://api.bitbucket.org/2.0/repositories/$WORKSPACE/$REPO/pipelines/$PIPELINE" \
--header 'Accept: application/json'
}
list_steps() {
curl -s \
--user "$BITBUCKET_USERNAME:$BITBUCKET_APP_PASSWORD" \
--request GET \
--url "https://api.bitbucket.org/2.0/repositories/$WORKSPACE/$REPO/pipelines/$PIPELINE/steps/?pagelen=200" \
--header 'Accept: application/json'
}
start=$(date -u +%s)
max_wait=14400
while true; do
now=$(date -u +%s)
if [ $(($now-$start)) -gt $max_wait ]; then
osascript -e "display notification \"$WORKSPACE/$REPO pipeline $PIPELINE running too long\" with title \"PIPELINE DEADLINE\""
exit
fi
if [ -n "$STRICT" ]; then
steps_info=$(list_steps)
failed_step=$(echo $steps_info | jq -r '.values | .[] | (.name + " " + .state.result.name)' | grep FAILED | head -n 1)
if [ -n "$failed_step" ]; then
osascript -e "display notification \"$WORKSPACE/$REPO pipeline $PIPELINE step $failed_step\" with title \"PIPELINE STEP FAILED\""
exit
fi
fi
pipeline_info=$(get_pipeline)
state=$(echo $pipeline_info | jq -r '.state.name')
stage=$(echo $pipeline_info | jq -r '.state.stage.name')
result=$(echo $pipeline_info | jq -r '.state.result.name')
if [[ "$state" == "COMPLETED" ]]; then
osascript -e "display notification \"$WORKSPACE/$REPO pipeline $PIPELINE completed with $result\" with title \"PIPELINE COMPLETED\""
exit
fi
if [[ "$state" != "IN_PROGRESS" ]]; then
osascript -e "display notification \"$WORKSPACE/$REPO pipeline $PIPELINE unknown issue\" with title \"PIPELINE UNKNOWN ISSUE\""
echo "Pipeline is not completed or failed and not in progress. See pipeline info below:"
echo $pipeline_info
exit
fi
echo "$WORKSPACE/$REPO pipeline $PIPELINE is still running fine"
sleep 15
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment