Skip to content

Instantly share code, notes, and snippets.

@aks
Last active May 11, 2020 16:04
Show Gist options
  • Select an option

  • Save aks/04856d7765217e4ff9ae76aaacfa06e9 to your computer and use it in GitHub Desktop.

Select an option

Save aks/04856d7765217e4ff9ae76aaacfa06e9 to your computer and use it in GitHub Desktop.
Script to trigger CircleCI builds
#!/usr/bin/env bash
# Adapted from https://discuss.circleci.com/t/branch-not-building/30499/10
# Usage:
#
# 1. set \$CIRCLE_CLI_TOKEN or set token in ~/.circle/cli.yml
# 2. run `./trigger-ci [[<account>] [[<oroject>] [<branch>]]]`
#
# Examples to trigger builds in different ways:
#
# trigger-ci # on the current branch
# trigger-ci my-cool-branch # on "my-cool-branch'
# trigger-ci fun-stuff new-thing # on "new-thing" in "funstuff" repo
# trigger-ci mylogin fun-stuff new-thing
PROG="${0##*/}"
DIR="${0%*/}"
talk() { echo "$*" 1>&2 ; }
vtalk() { (( verbose )) && talk "$*" ; }
error() { talk "$*" ; exit 1 ; }
usage() {
(( $# > 0 )) && talk "$*"
cat 1>&2 <<USAGE
usage: $PROG [options] ACCOUNT REPO BRANCH
or: $PROG [options] REPO BRANCH
or: $PROG [options] BRANCH
or: $PROG [options]
This script triggers a CircleCI build given the proper arguments above.
If BRANCH is not given, and the command is given within a repo directory, then
the current branch is used by default. However, the command is not
automatically triggered unless the -a (auto) is also given.
If ACCOUNT and REPO are not given, and the command is given within a repo
directory, the "git remote -v" output is used and parsed for the current
ACCOUNT and REPO values. However, the command will not proceed automatically
unless -a is given.
If the environment variable CIRCLE_CLI_TOKEN is not defined, the path
"$HOME/.circleci/cli.yml" is searched for a "token:" line, from which the
actual token is extracted into the variable.
Options:
-a automatically proceed
-h show this help
-n don't actually do anything; but show it
-v show the URL that triggers the build
USAGE
exit 1
}
run() {
if [[ -n "$norun" ]]; then
talk "(norun) $@"
else
safe_run "$@"
fi
return 0
}
safe_run() {
if [[ -n "$verbose$norun" ]]; then
talk ">> $@"
fi
if ! eval "$@" ; then
code=$?
return $code
fi
return 0
}
circle_cli_yml_file="$HOME/.circleci/cli.yml"
circle_cli_token() {
awk '/token:/ {print $2}' $circle_cli_yml_file 2>/dev/null
}
check_circle_ci_token() {
if [[ -z "$CIRCLE_CLI_TOKEN" ]] ; then
export CIRCLE_CLI_TOKEN=`circle_cli_token`
fi
[[ -n "$CIRCLE_CLI_TOKEN" ]] || error "CIRCLE_CLI_TOKEN is not defined!"
}
get_current_repo_info() {
declare -g account= project= branch=
if [[ -d .git ]] ; then
fetch_info=`git remote -v | awk '/origin.*push/{print $2}'`
if [[ "$fetch_info" =~ [^@]+@github.com:([^/]+)/([^/.]+)\.git ]] ; then
account=${BASH_REMATCH[1]}
project=${BASH_REMATCH[2]}
fi
branch=`git rev-parse --abbrev-ref HEAD`
fi
}
check_arg() {
[[ -n "$2" ]] || usage "$1 was not given!"
}
confirm_implicit_data() {
if [[ -n "$implicit" && -z "$autorun" ]] ; then
talk "Some (or all) of this information was discovered:"
talk " account: $account"
talk " project: $project"
talk " branch: $branch"
while true ; do
read -p "Proceed? [yN] " ans
case "${ans:-no}" in
yes|y) break ;;
no|n) error "Nothing done" ;;
*) talk "Please answer yes or no, or just <RETURN> (for no)" ;;
esac
done
fi
}
autorun= norun= verbose= implicit=
while getopts 'ahnv' opt ; do
case "$opt" in
a) autorun=1 ;;
h) usage ;;
n) norun=1 ;;
v) verbose=1 ;;
esac
done
shift $((OPTIND - 1))
check_circle_ci_token
get_current_repo_info
implicit=1
case "$#" in
0) ;;
1) branch="$1" ;;
2) project="$1" branch="$2" ;;
3) account="$1" project="$2" branch="$3" implicit= ;;
*)
talk "Too many arguments";
usage
;;
esac
check_arg account "$account"
check_arg project "$project"
check_arg branch "$branch"
confirm_implicit_data
circle_token=$CIRCLE_CLI_TOKEN
# Unofficial strict mode:
set -euo pipefail
IFS=$'\n\t'
talk "Triggering build of $account/$project ($branch)."
trigger_build_url="https://circleci.com/api/v1.1/project/github/${account}/${project}/build?circle-token=${circle_token}"
post_data="{ \"branch\": \"${branch}\"}"
cmd="curl -s --header 'Accept: application/json' --header 'Content-Type: application/json'"
cmd+=" --data '${post_data}'"
cmd+=" --request POST '${trigger_build_url}'"
run "$cmd"
talk ''
exit
@joe-sharp

joe-sharp commented Mar 31, 2020

Copy link
Copy Markdown

Seemed to work ok, I ran this with no arguments and it found the right data and triggered the jobs successfully. I did get an error from declare though:

/Users/joesharp/bin/trigger-ci: line 88: declare: -g: invalid option
declare: usage: declare [-afFirtx] [-p] [name[=value] ...]

Thanks for the script though, should be very useful!

@aks

aks commented Mar 31, 2020

Copy link
Copy Markdown
Author

I did get an error from declare though

Hi Joe -- this is because you are probably running this on a MacOS where your default bash is the system one, which is an older version. Apple is notorious for shipping older versions of bash. This is easily fixed by installing the latest bash:

brew install bash
export PATH=/usr/local/bin:$PATH
exec bash

You might also update your .bashrc to something like this to get the newer bash, in /usr/local/bin, by default.

export PATH=/usr/local/bin:$PATH

If it's important to keep using the "old" bash, you could also delete the declare statement from your copy of this script, and assign those variables earlier in the script flow, so they will be "global" by default. Let me know if you need any help.

@mckenziescarborough

mckenziescarborough commented May 11, 2020

Copy link
Copy Markdown

Thanks for the script! Had a ton of trouble with account was not given error and @joe-sharp figured it out. My git remote -v output was git@github.com:/procore/procore.git . I had an extra / before procore. Removing that did the trick.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment