Skip to content

Instantly share code, notes, and snippets.

@ndbroadbent
Last active October 3, 2020 10:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ndbroadbent/9b5742e6b0835323d45e6e33dcce8d85 to your computer and use it in GitHub Desktop.
Save ndbroadbent/9b5742e6b0835323d45e6e33dcce8d85 to your computer and use it in GitHub Desktop.
Find all the failed RSpec examples in GitLab CI pipeline logs and run them all locally
#!/bin/bash
set -eo pipefail
CURRENT_DIR="$(realpath $(dirname "$0"))"
ROOT_DIR="$(realpath $CURRENT_DIR/..)"
# https://gitlab.com/docspring/docspring
PROJECT_ID="1908805"
GITLAB_TOKEN=$(cat $ROOT_DIR/.gitlab-api-token)
PIPELINE_ID="$1"
if [ -z "$PIPELINE_ID" ]; then
CURRENT_GIT_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
echo "Fetching latest failed pipeline ID for '$CURRENT_GIT_BRANCH'..."
ESCAPED_BRANCH=$(ruby -r cgi -e "puts CGI.escape('$CURRENT_GIT_BRANCH')")
LATEST_PIPELINE_RESPONSE=$(curl -s --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
"https://gitlab.com/api/v4/projects/$PROJECT_ID/pipelines?ref=$ESCAPED_BRANCH&status=failed&per_page=1&page=1")
PIPELINE_ID="$(echo $LATEST_PIPELINE_RESPONSE | jq -r '.[0].id')"
echo "Found latest failed pipeline ID: $PIPELINE_ID"
echo
echo $LATEST_PIPELINE_RESPONSE | jq -r '" * " + .[0].web_url'
echo
fi
PIPELINE_CACHE_DIR="$ROOT_DIR/tmp/gitlab_pipeline_results/$PIPELINE_ID"
mkdir -p "$PIPELINE_CACHE_DIR"
JOB_IDS_FILE="$PIPELINE_CACHE_DIR/job_ids.json"
if [ -f "$JOB_IDS_FILE" ]; then
echo "Found jobs for GitLab CI Pipeline $PIPELINE_ID in $JOB_IDS_FILE"
FAILED_PIPELINE_JOBS_RESPONSE="$(cat "$JOB_IDS_FILE")"
else
echo "Listing jobs for GitLab CI Pipeline $PIPELINE_ID..."
FAILED_PIPELINE_JOBS_RESPONSE="$(curl -s --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
"https://gitlab.com/api/v4/projects/$PROJECT_ID/pipelines/$PIPELINE_ID/jobs?scope[]=failed")"
echo "$FAILED_PIPELINE_JOBS_RESPONSE" > "$JOB_IDS_FILE"
fi
FAILED_PIPELINE_JOB_COUNT=$(echo "$FAILED_PIPELINE_JOBS_RESPONSE" | \
jq -r '. | map(select(.name | contains ("rspec"))) | map(.id) | length')
echo "Found $FAILED_PIPELINE_JOB_COUNT failed RSpec job(s):"
if [ "$FAILED_PIPELINE_JOB_COUNT" == "0" ]; then exit; fi
echo
echo "$FAILED_PIPELINE_JOBS_RESPONSE" | \
jq -r '. | map(select(.name | contains ("rspec"))) | map(" * " + .web_url) | .[]'
echo
FAILED_PIPELINE_JOB_IDS=$(echo "$FAILED_PIPELINE_JOBS_RESPONSE" | \
jq -r '. | map(select(.name | contains ("rspec"))) | map(.id) | .[]')
for JOB_ID in $FAILED_PIPELINE_JOB_IDS; do
JOB_LOGS_FILE="$PIPELINE_CACHE_DIR/job_$JOB_ID.txt"
if [ -f "$JOB_LOGS_FILE" ]; then
echo "Found logs for failed RSpec job $JOB_ID in $JOB_LOGS_FILE"
else
echo "Fetching logs for failed RSpec job $JOB_ID"
curl -s --location --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
"https://gitlab.com/api/v4/projects/$PROJECT_ID/jobs/$JOB_ID/trace" > "$JOB_LOGS_FILE"
fi
done
FAILING_SPECS=$(ruby -e "puts Dir.glob(\"$PIPELINE_CACHE_DIR/job_*.txt\").map{ |f|
File.read(f)
.split('Failed examples:')[1]
.split('Randomized with seed')[0]
.scan(/rspec ([^#]+)/) }.join(' ')")
echo "Running failed specs locally..."
set -x
./bin/rspec $FAILING_SPECS
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment