Brain Phrye

code cooking diy fiction personal photos politics reviews tools 


Git Pipeline Status (redux)

[ Listen to article ]

So yesterday I wrote…

Annoyingly I can’t really generalise this script very easily. I could drive it off some settings in ~/.gitconfig but haven’t gotten around to it. For now you’ll have to add the GitLab servers you care about.

Yeah, this was way easier to do than I thought. You need to run these four commands for each gitlab server:

1
2
3
4
git config --global pipeline-status.0.gitlab site1
git config --global pipeline-status.0.prefix https://gitlab.site1.com/
git config --global pipeline-status.1.gitlab site1
git config --global pipeline-status.1.prefix ssh://git@gitlab.site1.com:2200/

The gitlab var holds the shortname of your python-gitlab config name. The url var holds the part of the url before the path of the project. If you always clone with ssh urls (they either start with ssh:// or git@) then just put that part in and skip the https urls.

And then you can add more sites - just increment that number after pipeline-status. They have to be sequential - the script will stop looking after the first gap.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#!/usr/bin/env bash

# Documentation:
#
# Need to install python-gitlab and jq.  To configure python-gitlab
# you need a config file named ~/.python-gitlab.cfg with these contents:
#
#   [global]
#   default = titanhq
#   ssl_verify = true
#   timeout = 5
#
#   [titanhq]
#   url = https://gitlab.titanhq.com/
#   private_token = TOKEN
#   api_version = 4
#
# Replace TOKEN with your gitlab private token - give it the read_api
# scope.

if [[ ! -f ~/.python-gitlab.cfg ]]; then
    echo "?"
  exit
fi

export TZ=UTC

url="$(git config \
           remote."$(git for-each-ref --format='%(upstream:remotename)' \
                                      "$(git symbolic-ref -q HEAD)")".url)"

gitlab=(gitlab -o json -g)
i=0
while :; do
  prefix=$(git config --global pipeline-status.$i.prefix)
  if [[ -z "$prefix" ]]; then
    echo "πŸ‘½"
    exit
  fi
  if [[ "$url" =~ ^$prefix ]]; then
    url="${url#$prefix}"
    gitlab+=( $(git config --global pipeline-status.$i.gitlab) )
    break
  fi
  i=$(( i + 1 ))
done

project="$(git config pipeline-status.project)"
if [[ -z "$project" ]]; then
  url="${url%.git}"
  url="${url//\//%2F}"
  project="$("${gitlab[@]}" project get --id "$url" | jq -r '.id')"
  if [[ -z "$project" ]]; then
    echo "πŸ”­"
    exit
  fi
  git config pipeline-status.project "$project"
fi

conf="branch.$(git rev-parse --verify --abbrev-ref HEAD 2> /dev/null)"

hash="$(git rev-parse HEAD)"
cache_hash="$(git config "$conf".pipeline-cache-hash)"
if [[ "$hash" == "$cache_hash" ]]; then
  git config "$conf".pipeline-cache-status && exit
else
  git config "$conf".pipeline-cache-hash "$hash"
  git config --unset "$conf".pipeline-cache-status
  git config --unset "$conf".pipeline-cache-update
fi

cache-update() {
  local update

  update="$("${gitlab[@]}" project-pipeline list \
                             --project-id "$1" --sha "$2" \
            | jq -r '.[] | .updated_at' | sort | tail -1)"
  if [[ -z "$update" ]]; then
    if [[ -n "$3" ]]; then
      return
    fi
    update="$(date +%s)"
  else
    # Won't work on FreeBSD - date does not take a -d flag.
    # Need to parse time in this format: 2020-09-11T10:38:04.394Z
    if [[ "$OSTYPE" == linux-gnu ]]; then
      update="$(date +%s -d "$update")"
    else
      update="$(date -j -f '%FT%H:%M:%S' "${update%.*}" +%s)"
    fi
  fi
  git config "$conf".pipeline-cache-update "$update"
}

cache_update=$(git config "$conf".pipeline-cache-update)
cache-update "$project" "$hash" "$cache_update"
cache_update=$(git config "$conf".pipeline-cache-update)

if git config "$conf".pipeline-cache-status; then
  exit
fi

status="$("${gitlab[@]}" project-pipeline list \
                           --project-id "$project" --sha "$hash" \
          | jq -r '.[] | "\(.updated_at) \(.status)"' \
          | sort | tail -1 | cut '-d ' -f2)"

# NOTE: The pending and skipped emoji do not seem to provide
#       double width hints so don't align properly w/o a training dot.
case "$status" in
  created)              status="πŸŒ…"                         ;;
  waiting_for_resource) status="🚚"                         ;;
  preparing)            status="πŸ—οΈ"                         ;;
  pending)              status="⏸️."                         ;;
  running)              status="πŸš€"                         ;;
  success)              status="πŸŽ‰"                         ;;
  failed)               status="πŸ”₯"                         ;;
  canceled)             status="πŸ›‘"                         ;;
  skipped)              status="⏭️."                         ;;
  manual)               status="πŸ‘‹"                         ;;
  scheduled)            status="⏰"                         ;;
  "")                   status="πŸ’”"                         ;;
  *)                    status="-unknown-status-${status}-" ;;
esac

if [[ $(( $(date +%s) - cache_update )) -gt 600 ]]; then
  git config "$conf".pipeline-cache-status "$status"
fi

echo "$status"