Created
April 4, 2022 02:55
-
-
Save ndbroadbent/3b2c909432913d567680f2e683fbaaff to your computer and use it in GitHub Desktop.
run_failed_gitlab_pipeline_specs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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_RSPEC_JOB_COUNT=$(echo "$FAILED_PIPELINE_JOBS_RESPONSE" | \ | |
jq -r '. | map(select(.name | contains ("rspec"))) | map(.id) | length') | |
FAILED_RSPEC_JOB_IDS=$(echo "$FAILED_PIPELINE_JOBS_RESPONSE" | \ | |
jq -r '. | map(select(.name | contains ("rspec"))) | map(.id) | .[]') | |
FAILED_RUBYLINT_JOB_COUNT=$(echo "$FAILED_PIPELINE_JOBS_RESPONSE" | \ | |
jq -r '. | map(select(.name | contains ("ruby_lint"))) | map(.id) | length') | |
FAILED_RUBYLINT_JOB_IDS=$(echo "$FAILED_PIPELINE_JOBS_RESPONSE" | \ | |
jq -r '. | map(select(.name | contains ("ruby_lint"))) | map(.id) | .[]') | |
FAILED_SECURITY_JOB_COUNT=$(echo "$FAILED_PIPELINE_JOBS_RESPONSE" | \ | |
jq -r '. | map(select(.name | contains ("security"))) | map(.id) | length') | |
FAILED_SECURITY_JOB_IDS=$(echo "$FAILED_PIPELINE_JOBS_RESPONSE" | \ | |
jq -r '. | map(select(.name | contains ("security"))) | map(.id) | .[]') | |
echo "Found $FAILED_RSPEC_JOB_COUNT failed RSpec job(s)" | |
echo | |
if [ "$FAILED_RSPEC_JOB_COUNT" != "0" ]; then | |
echo "$FAILED_PIPELINE_JOBS_RESPONSE" | \ | |
jq -r '. | map(select(.name | contains ("rspec"))) | map(" * " + .web_url) | .[]' | |
echo | |
fi | |
echo "Found $FAILED_RUBYLINT_JOB_COUNT failed Ruby Lint job(s)" | |
echo | |
if [ "$FAILED_RUBYLINT_JOB_COUNT" != "0" ]; then | |
echo "$FAILED_PIPELINE_JOBS_RESPONSE" | \ | |
jq -r '. | map(select(.name | contains ("ruby_lint"))) | map(" * " + .web_url) | .[]' | |
echo | |
fi | |
echo "Found $FAILED_SECURITY_JOB_COUNT failed security job(s)" | |
echo | |
if [ "$FAILED_SECURITY_JOB_COUNT" != "0" ]; then | |
echo "$FAILED_PIPELINE_JOBS_RESPONSE" | \ | |
jq -r '. | map(select(.name | contains ("security"))) | map(" * " + .web_url) | .[]' | |
echo | |
fi | |
if [ "$FAILED_RSPEC_JOB_COUNT" == "0" ] && | |
[ "$FAILED_RUBYLINT_JOB_COUNT" == "0" ] && | |
[ "$FAILED_SECURITY_JOB_COUNT" == "0" ]; then | |
exit | |
fi | |
for JOB_ID in $FAILED_RSPEC_JOB_IDS; do | |
JOB_LOGS_FILE="$PIPELINE_CACHE_DIR/rspec_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 | |
for JOB_ID in $FAILED_RUBYLINT_JOB_IDS; do | |
HAS_FAILED_RUBOCOP_JOB=true | |
JOB_LOGS_FILE="$PIPELINE_CACHE_DIR/ruby_lint_job_$JOB_ID.txt" | |
if [ -f "$JOB_LOGS_FILE" ]; then | |
echo "Found logs for failed Ruby Lint job $JOB_ID in $JOB_LOGS_FILE" | |
else | |
echo "Fetching logs for failed Ruby Lint 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 | |
echo | |
if [ "$HAS_FAILED_RUBOCOP_JOB" == true ]; then | |
FAILING_RUBOCOP_FILES="$(ruby -e "puts Dir.glob(\"$PIPELINE_CACHE_DIR/ruby_lint_job_*.txt\").map { |f| | |
logs = File.read(f); | |
start_regex = /Offenses:/; | |
end_regex = /\d+ files? inspected, \d+ offenses? detected/; | |
match_regex = /^(.+):\d+:\d+:/; | |
next nil if !logs.match?(start_regex) || !logs.match?(end_regex); | |
logs. | |
split(start_regex)[1]. | |
split(end_regex)[0]. | |
scan(match_regex) | |
}.flatten.reject(&:nil?).map(&:strip). | |
select { |f| File.exist?(f) }.join(' ')")" | |
if [ -z "$FAILING_RUBOCOP_FILES" ]; then | |
echo "Could not find any Ruby files in the RuboCop output! Please check the logs manually." >&2 | |
else | |
echo "Running 'rubocop -a' to fix Rubocop errors..." | |
echo "=> bundle exec rubocop -a $FAILING_RUBOCOP_FILES" | |
bundle exec rubocop -a $FAILING_RUBOCOP_FILES | |
fi | |
fi | |
FAILING_SPECS=$(ruby -e "puts Dir.glob(\"$PIPELINE_CACHE_DIR/rspec_job_*.txt\").map { |f| | |
logs = File.read(f); | |
start_regex = /Failed examples?:/; | |
end_regex = /Randomized with seed/; | |
match_regex = /rspec '?([^'#]+)/; | |
next nil if !logs.match?(start_regex) || !logs.match?(end_regex); | |
logs. | |
split(start_regex)[1]. | |
split(end_regex)[0]. | |
scan(match_regex) | |
}.flatten.reject(&:nil?).map(&:strip).join(' ')") | |
# echo "FAILING_SPECS: '$FAILING_SPECS'" | |
if [ -z "$FAILING_SPECS" ]; then | |
echo "Could not find any failing specs in the RSpec output! Please check the logs manually." >&2 | |
else | |
echo "Running failed specs locally..." | |
echo "=> bundle exec ./bin/rspec $FAILING_SPECS" | |
bundle exec ./bin/rspec $FAILING_SPECS | |
fi | |
if [ "$FAILED_SECURITY_JOB_COUNT" != "0" ]; then | |
./scripts/security | |
fi | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment