Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
262 changes: 262 additions & 0 deletions fb/FBManager.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
#!/bin/bash

# Arguments
# 1: Configuration file JSON Format See help description
# 2: Action: create / delete Feature Branch
# 3: Feature Branch Name: word "feature/" will be added automatically in case of unset

# EXIT CODES
# 0 -- OK
# 1 -- Missing arguments or commands
# 2 -- Wrong provided argument
# 3 -- Missing mandatory information in the configuration file
# 4 -- Wrong provided information or insufficient privileges
# 5 -- Inability to perform action due to insufficient privileges
####
protected_branches_list_regex="^(master|develop|stable\/[0-9.-_a-zA-Z]+)$"
####

scrdir=$(dirname $(realpath $0))
. ${scrdir}/_functions.sh
SHORT=abchj
LONG=jira,config,action,featurebranch,help
PARSED=$(getopt --options $SHORT --longoptions $LONG --name "$0" -- "$@")
if [[ $? -ne 0 ]]; then
print_help
exit 0
fi
while true; do
case "$1" in
-h | --help)
print_help
exit 0
;;
-j | --jira)
jira_id="$2"
shift 2
;;
-c | --config)
config_file="$(realpath $2)"
shift 2
;;
-a | --action)
action="$2"
shift 2
;;
-b | --featurebranch)
featurebranch="$2"
shift 2
;;
"")
break
;;
*)
print_help
exit 0
;;
esac
done

#Check commands
assert_command git
assert_command jq
assert_command mvn

if [ -z "${jira_id}" ] || [[ ! "${jira_id}" =~ ^ITOP-[0-9]+$ ]]; then
echo_err "Jira ID is missing or invalid"
exit 1
fi

if [ -z "${config_file}" ] || [ ! -f "${config_file}" ]; then
echo_err "Config file is missing or invalid"
exit 1
fi
if ! validate_json ${config_file} >/dev/null; then #Suppress only plain message
echo_err "Config file is not a valid JSON file!"
exit 2
else
echo_ok "Config file \"${config_file}\" is a valid JSON file"
fi
if [[ ! "${action}" =~ ^(create|delete)$ ]]; then
echo_err "Wrong or Missing action! only create or delete are accepted!"
exit 2
else
echo_ok "Action \"${action}\" will be performed"
fi
if [ -z "${featurebranch}" ]; then
echo_err "Missing Feature Branch name!"
exit 2
fi
[[ "${featurebranch}" =~ ^(F|f)eature/ ]] || featurebranch="feature/${featurebranch}"

maventag=$(echo ${featurebranch} | sed -E 's|^(f\|F)eature/||g')

#Check for illegal characteres like / etc
if [[ ! "${maventag}" =~ ^[A-Za-z0-9_-]+$ ]]; then
echo_err "Feature branch \"${featurebranch}\" contains illegal characters!"
exit 3
fi
echo_ok "Feature Branch is \"${featurebranch}\""
start_time=$(date +%s)
rm -rf ${wkdir}* &>/dev/null #Cleanup
for el in $(cat ${config_file} | jq -c '.[]'); do
## Args Parsing
if ! eval $(echo $el | jq -r '. | to_entries | .[] | .key + "=\"" + .value + "\""') &>/dev/null; then
echo_err "Could not convert the followig JSON Object to Bash variables!"
echo $el | jq
exit 3
fi

## Args Common Checks
if [ -z "${git_organization}" ]; then
echo_err "Github organization is not specified!"
exit 3
fi

if [ -z "${git_repository}" ]; then
echo_err "Github repository is not specified!"
exit 3
fi

## Prepare repository
full_repo_name="${git_organization}/${git_repository}"
ssh_url="git@github.com:${full_repo_name}.git"

## Check Repository existance and access privileges
if ! valid_repo ${ssh_url}; then
echo_err "Repository ${full_repo_name} is not exist or insufficient privileges!"
exit 4
fi

## Clone Repository
echo_ok "Cloning ${full_repo_name}"
local_repo_path="${wkdir}/${full_repo_name}"
[ -e ${local_repo_path} ] && rm -rf ${local_repo_path} &>/dev/null #Cleanup
if ! git clone ${ssh_url} ${local_repo_path} &>/dev/null; then
echo_err "Could not clone ${full_repo_name} !"
exit_with_cleanup 4
fi

## Check if the repository is successfully cloned
if [ ! -d ${local_repo_path} ] || [ ! -d "${local_repo_path}/.git" ]; then
echo_err "Local repository ${full_repo_name} is not created !"
exit_with_cleanup 4
else
echo_ok "Repository ${full_repo_name} is successfully cloned !"
fi

## Function Live Definition Make code below more redeable
r_git() {
git --git-dir=${local_repo_path}/.git --work-tree=${local_repo_path} $*
}

## Check if update is unset if yes, use false as default value
[ -z "${update}" ] && update="false"

## Perform Feature Branch Creation
if [[ $action == "create" ]]; then

## Check if base branch is unset if yes, use default branch as base one
[ -z "${git_base_branch}" ] && git_base_branch=$(r_git symbolic-ref --short HEAD)

## Check if feature branch is already exist in the Git Repository [ Remote Check ]
if [ ! -z "$(r_git ls-remote --heads origin ${featurebranch})" ]; then
if [[ ${update} == "false" ]]; then
echo_err "Branch \"${featurebranch}\" already exist!"
fi
if [[ ${update} == "true" ]]; then
echo_warn "Update Mode is Enabled!"
else
exit_with_cleanup 5
fi
fi

current_branch=$(r_git rev-parse --abbrev-ref HEAD)
#Default branch protection
if [[ "${featurebranch}" == "${current_branch}" ]]; then
echo_err "Could not recreate the default branch \"${featurebranch}\"!"
exit_with_cleanup 4
fi
## Check if the current branch is the selected base branch if not, check out to it
if [[ "${git_base_branch}" != "${current_branch}" ]]; then
if ! r_git checkout ${git_base_branch} &>/dev/null; then
echo_err "Could not checkout to branch \"${git_base_branch}\" !"
exit_with_cleanup 5
fi
echo_ok "Checked out to base branch \"${git_base_branch}\""
else
echo_ok "Already on base branch \"${git_base_branch}\""
fi

# Add Force flag for the git push and remove branch as precaution
force_flag=""
[[ ${update} == "true" ]] && force_flag="-f"
r_git branch -D ${featurebranch} &>/dev/null

# Create feature branch locally and push to the remote
if r_git checkout -b "${featurebranch}" 2>/dev/null; then
echo_ok "Branch \"${featurebranch}\" has been created locally"
else
echo_err "Could not create branch \"${featurebranch}\"!"
exit_with_cleanup 5
fi

# Apply changes to Maven Project
if [ -f "${local_repo_path}/pom.xml" ]; then
project_artifactId=$(get_maven_property "${local_repo_path}" "project.artifactId")
project_groupId=$(get_maven_property "${local_repo_path}" "project.groupId")
project_version=$(get_maven_property "${local_repo_path}" "project.version")
new_project_version=$(echo ${project_version} | sed "s|-SNAPSHOT|-${maventag}-SNAPSHOT|g")
echo_ok "Maven Project Informations:"
echo "***"
echo " ArtifactId: ${project_artifactId}"
echo " GroupId: ${project_groupId}"
echo " Version: ${project_version}"
echo " New version: ${new_project_version}"
echo "***"
if change_maven_project_version "${local_repo_path}" ${project_groupId} ${project_artifactId} ${new_project_version}; then
echo_ok "Maven Project version changed to ${new_project_version}"
else
echo_err "Could not change project version to ${new_project_version}"
exit_with_cleanup 4
fi
r_git add $(find ${local_repo_path} -name pom.xml | xargs)
if ! echo "${jira_id}: Create Feature Branch ${featurebranch}" | r_git commit -F -; then
echo_err "Could not commit on the ${featurebranch} branch!"
exit_with_cleanup 4
fi
fi

if ! r_git push origin "${featurebranch}" ${force_flag} 2>/dev/null; then
echo_err "Could not push on the ${featurebranch} branch!"
exit_with_cleanup 4
else
echo_ok "Branch ${featurebranch} has been created"
fi

## Perform Feature Branch Deletion
elif [[ $action == "delete" ]]; then
# Default Branch Protection
current_branch=$(r_git rev-parse --abbrev-ref HEAD)
if [[ "${featurebranch}" == "${current_branch}" ]]; then
echo_err "Could not delete default branch \"${featurebranch}\"!"
exit_with_cleanup 4
fi
## Check if feature branch is already exist in the Git Repository [ Remote Check ]
if [ ! -z "$(r_git ls-remote --heads origin ${featurebranch})" ]; then
echo_ok "Branch \"${featurebranch}\" exist"
if r_git push origin :${featurebranch}; then
echo_ok "Branch \"${featurebranch}\" has been deleted!"
else
echo_err "Could not delete branch \"${featurebranch}\"!"
exit_with_cleanup 5
fi
else
echo_ok "Branch \"${featurebranch}\" does not exist"
fi
fi
## Mandatory Common cleanup process for the next iteration
rm -rf $(dirname ${local_repo_path}) &>/dev/null #Global Cleanup : dirname = organization folder
unset name git_base_branch git_organization git_repository update force_flag
done
echo_ok "Finished in $(date -ud "@$(($(date +%s) - $start_time))" +%T)."
68 changes: 68 additions & 0 deletions fb/_functions.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
wkdir="/tmp/fbmgnfactory"

echo_err() {
echo "$(date +'%d/%m/%y %H:%M:%S') | Error | $*" >>/dev/stderr
}

echo_ok() {
echo "$(date +'%d/%m/%y %H:%M:%S') | INFO | $*"
}

echo_warn() {
echo "$(date +'%d/%m/%y %H:%M:%S') | WARN | $*"
}

exit_with_cleanup() {
rm -rf $wkdir &>/dev/null
exit $1
}

validate_json() {
cat $1 | jq type
}

assert_command() {
if ! hash $1 &>/dev/null; then
echo_err "$1 is not installed !"
exit 1
fi
}

valid_repo() {
[ ! -z "$1" ] && [ ! -z "$(git ls-remote --heads $1 2>/dev/null)" ]
}

get_maven_property() {
mvn -f "$1/pom.xml" -o org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=$2 | grep -v '\[' 2>/dev/null
}

change_maven_project_version() {
mvn -f "$1/pom.xml" -q versions:set -DgenerateBackupPoms=false -DgroupId=$2 -DartifactId=$3 -DnewVersion=$4 &>/dev/null
}

print_help() {
cat <<EOF
**** Feature Branch Manager ******
** Created by eXo SWF / ITOP Team

Usage: $0 -j|--jira ITOP_XXXX -c|--config <configuration_file.json> -a|--action <create|delete> -b|--featurebranch <[Feature/]xxxxxxx>

Config File Sample:

[
{
"git_organization": "exo-xxxxx,
"git_repository": "eXo-Testing",
"git_base_branch": "stable/xxxxxx", // Optional, Default [create]: default branch
"update": "true or false" // Optional, Default: false, [Caution] overwrite remote branch
},
{
"git_organization": "exo-yyyyy,
....
....
}
]

Mandatory commands: git, jq, maven (mvn)
EOF
}