Skip to content
Snippets Groups Projects
Select Git revision
  • a85b92bb79a6fb73f2c34de59675de1cafe0e3db
  • master default protected
  • jul25_patches
  • nightly_master
  • online_mvd_readconf_cleanup protected
  • online_much_readconf_cleanup protected
  • cleanup_rich_v25a
  • jul24_patches
  • nov23_patches
  • DC_2404
  • nighly_master
  • DC_Jan24
  • DC_Nov23
  • DC_Oct23
  • feb23_patches
  • L1Algo-dev9
  • dec21_patches protected
  • apr21_patches protected
  • RC2_jul25
  • dev_2025_46
  • dev_2025_45
  • dev_2025_44
  • dev_2025_43
  • dev_2025_42
  • dev_2025_41
  • dev_2025_40
  • dev_2025_39
  • dev_2025_38
  • dev_2025_37
  • dev_2025_36
  • dev_2025_35
  • dev_2025_34
  • dev_2025_33
  • dev_2025_32
  • dev_2025_31
  • dev_2025_30
  • RC_jul25
  • dev_2025_29
38 results

inform_codeowners.sh

Blame
  • Eoin Clerkin's avatar
    Eoin Clerkin authored
    Inserts the declaration on the 1st or 2nd line of scripts.
    
    EMPTY LINE
    
    Short license declarations for .sh files
    
    Inserts the declaration on the 1st or 2nd line of scripts.
    
    EMPTY LINE
    
    Revert "Short license declarations for .sh files"
    
    This reverts commit d3dd8608dead032b12bc71798a2bd97bfca95442.
    
    Uses SPDX identifier
    
    Modifies declaration to use SPDX license identifier syntax
    
    Corrects file
    
    Empty line before hashbang removed
    6f6619b0
    History
    inform_codeowners.sh 5.91 KiB
    #!/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 "$@"