Commit 3aa2f571 authored by Administrator's avatar Administrator
Browse files

Add CodeOwners functionality

Inform responsible persons about merge requests in their directories.
parent 31996f3c
Pipeline #13727 passed with stages
in 1 minute and 21 seconds
stages:
- checkRepository
- checkFormat
- finalise
RebaseCheck:
stage: checkRepository
......@@ -79,3 +80,20 @@ FileFormatCheck:
- ci_scripts/connect_upstream_repo.sh $CI_MERGE_REQUEST_PROJECT_URL
- git fetch upstream
- ci_scripts/check-file-format.sh upstream
InformCodeOwners:
stage: finalise
tags:
- Code_Owners
only:
refs:
- merge_requests
variables:
- $CI_MERGE_REQUEST_PROJECT_PATH == "CbmSoft/cbmroot_parameter" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"
script:
# Get the upstream repository manually. I did not find any other way to have it for
# comparison
- apk update && apk add git bash
- ci_scripts/connect_upstream_repo.sh $CI_MERGE_REQUEST_PROJECT_URL
- git fetch upstream
- ci_scripts/inform_codeowners.sh upstream
# Ending a path in a `/` will specify the code owners for every file
# nested in that directory, on any level
/ @f.uhlig @p.-a.loizeau @d.emschermann
## Detectors
# TRD
/trd/ @praisig
# PSD
#/psd/ @karpushkin_AT_inr.ru
# MUCH
/much/ @v.singhal
# TOF
/tof/ @n.herrmann @i.deppner
# RICH
/rich/ @s.lebedev
# STS
/sts/ @v.friese @a.toia
# MVD
/mvd/ @c.muentz @m.deveaux
#!/bin/bash
# Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
# SPDX-License-Identifier: GPL-3.0-only
# First commited by Florian Uhlig
main () {
# get passead parameters
# 1. git name of the official repo
if [[ ! $# -eq 1 ]]; then
echo "Pass the name of the upstream repository as argument"
exit 1
fi
# Since bash only supports dictionaries from version 4
# the dictionary is implemented as list. The values in
# the list are the directory (key) and the list of users owning
# this directory separated by a colon. If there is more than one
# user owning a directory the list of users is separated by a
# semicolon.
# An example of such an entry is "/macro/:f.uhlig;v.friese"
declare -a dictionary
declare -a unique_users
parse_codeowners_file
#declare -p dictionary
CHANGED_FILES=""
generate_file_list "$1"
ALL_USERS=""
generate_codeowners_list "$CHANGED_FILES"
generate_comment
}
# Add a key value pair to the dictionary
function add_hash () {
dictionary+=("$1":"$2")
}
# extract the directory (key) from the passed string
function get_key () {
dir="${1%%:*}"
}
# extract the user list (value) from the passed string
function get_value () {
users="${1##*:}"
}
# Parse the CODEOWNERS file and store the information of owned directories
# in a dictionray with the directory as key and the code owners as value
# read a file line by line
# Parse the remaining lines, split them at the first blank
# First entry of the array is the directory, all other entries
# are the list of people to inform
# We have to check that the CODEOWNERS file is properly formated since the
# used parser is very simply
function parse_codeowners_file () {
while read line; do
# exclude commented and empty lines
if [[ $line =~ ^\# || $line =~ ^$ ]]; then
dummy=$line
else
# split the line at blank characters and store the results in an array
IFS=' ' read -ra my_array <<< "$line"
# first entry is the directory
directory="${my_array[0]}"
# in case of two entries the second is the user
if [[ ${#my_array[@]} -eq 2 ]]; then
users="${my_array[1]}"
# in case of more entries the entries from the second to the last are a list of users
# Add the users to a semicolon separated list and store the list in the user array
else
arr2=("${my_array[@]:1:${#my_array[@]}}")
newUserList=""
for i in "${arr2[@]}"; do
newUserList="$newUserList;$i"
done
newUserList="${newUserList:1}"
users="$newUserList"
fi
add_hash "$directory" "$users"
fi
done < CODEOWNERS
}
function generate_codeowners_list () {
CHANGED_FILES=$1
all_users=""
for file in $CHANGED_FILES; do
# echo $file
file="/$file"
inform_users=""
longest_match=0
for entry in "${dictionary[@]}"; do
get_key $entry
if [[ $file =~ ^$dir ]]; then
get_value $entry
# echo "The length of the match is ${#dir}"
if [[ ${#dir} -gt $longest_match ]]; then
inform_users=$users
fi
fi
done
# echo "We have to inform user $inform_users for file $file"
all_users="$all_users;$inform_users"
done
ALL_USERS="${all_users:1}"
# remove duplications from string
IFS=';'
read -ra users <<< "$ALL_USERS"
for user in "${users[@]}"; do # access each element of array
if [[ ! " ${unique_users[@]} " =~ " ${user} " ]]; then
unique_users+=("$user")
fi
done
OWNERS_LIST=${unique_users[@]}
echo "We have to inform the following users about the code ownership: $OWNERS_LIST"
}
function generate_file_list() {
if [[ $# -eq 1 ]]; then
UPSTREAM=$1
else
if [ -z $UPSTREAM ]; then
UPSTREAM=$(git remote -v | grep git.cbm.gsi.de[:/]computing/cbmroot | cut -f1 | uniq)
if [ -z $UPSTREAM ]; then
echo "Error: Name of upstream repository not provided and not found by automatic means"
echo 'Please provide if by checking your remotes with "git remote -v" and exporting UPSTREAM'
echo "or passing as an argument"
exit -1
fi
fi
fi
echo "Upstream name is :" $UPSTREAM
# Rebase the MR to extract the changed files properly
# If upstream/master was changed while the pipline was running one would otherwise get
# a wrong list of files
git rebase $UPSTREAM/master
BASE_COMMIT=$UPSTREAM/master
CHANGED_FILES=$(git diff --name-only $BASE_COMMIT)
}
function generate_comment() {
# Get Information about the MR in JSON format
# Check if the returned string contains the signature that the CodeOwners label is set
# Only create GitLab comment if there is no comment yet (CodeOwners label not set)
MRInfo=$(curl -s --request GET --header "PRIVATE-TOKEN: $COMMENT_TOKEN" "https://git.cbm.gsi.de/api/v4/projects/$CI_MERGE_REQUEST_PROJECT_ID/merge_requests/$CI_MERGE_REQUEST_IID" | grep labels.*\\[.*CodeOwners.*\\])
if [[ -z $MRInfo ]]; then
comment="Dear "
for user in "${unique_users[@]}"; do
comment="$comment $user,"
done
comment="$comment
you have been identified as code owner of at least one file which was changed with this merge request.
Please check the changes and approve them or request changes."
# Add a comment to the merge request which informs code owners about their duty to review
curl -s --request POST \
-d "body=$comment" \
--header "PRIVATE-TOKEN: $COMMENT_TOKEN" \
"https://git.cbm.gsi.de/api/v4/projects/$CI_MERGE_REQUEST_PROJECT_ID/merge_requests/$CI_MERGE_REQUEST_IID/notes"
# On first call set a label which can be checked later on to avoid sending the comment over and over again
curl -s --request PUT \
--header "PRIVATE-TOKEN: $COMMENT_TOKEN" \
"https://git.cbm.gsi.de/api/v4/projects/$CI_MERGE_REQUEST_PROJECT_ID/merge_requests/$CI_MERGE_REQUEST_IID?add_labels=CodeOwners"
else
echo "Information message already exits, so there is no need to create another one."
fi
}
main "$@"
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment