Merge "Add groovy script to (re-)create and rename branches"
diff --git a/branch-git-repos.groovy b/branch-git-repos.groovy
new file mode 100644
index 0000000..383dba0
--- /dev/null
+++ b/branch-git-repos.groovy
@@ -0,0 +1,135 @@
+#!groovy
+
+/**
+ * (Re-)Create git branches
+ *
+ * @param GIT_REPO_LIST   List of repositories to handle
+ *     Multiline text: '<name> <url> <src_obj>' (full format)
+ *                 or: '<url>' (assuming src_obj=='SUBS_SOURCE_REF')
+ * @param GIT_CREDENTIALS Credentials ID to use for the ALL given repositories
+ * @param BRANCH          New branch name
+ * @param SOURCE_REVISION Source object (commit/tag/branch) to apply to all repos
+ *     having empty src_obj or src_obj=='SUBS_SOURCE_REF'
+ *
+ * @see <a href="https://mirantis.jira.com/browse/PROD-17759">PROD-17759</a>
+ */
+
+// Get job environment to use as a map to get values with defaults
+Map jobEnv = env.getEnvironment().findAll { k, v -> v }
+
+// Prepare job parameters
+ArrayList gitRepoList   = jobEnv.get('GIT_REPO_LIST', '').readLines()
+String gitBranchNew     = jobEnv.get('BRANCH')
+String srcObj           = jobEnv.get('SOURCE_REVISION', 'master')
+String gitCredentialsId = jobEnv.get('GIT_CREDENTIALS')
+
+// Check if new branch name is given
+if (! gitBranchNew) {
+    error ('No new branch name is given')
+}
+
+/**
+ * Returns local path for the given URL constructed from hostname and repository
+ *
+ * @param  repoUrl git repository URL
+ * @return string representing local relative patch
+ */
+String getRepoLocalPath(String repoUrl) {
+    // Regex to split git repository URLs
+    String re = '^(?:(?<proto>[a-z]+)://)?(?:(?<creds>[^@]+)@)?(?<host>[^:/]+)(?::(?<port>[0-9]+)/|[:/])(?<repo>.+)$'
+
+    java.util.regex.Matcher urlMatcher = repoUrl =~ re
+    if (urlMatcher.matches()) {
+        return new File(
+            urlMatcher.group('host'),
+            urlMatcher.group('repo').replaceAll(/\.git$/,'')
+        ).toString()
+    } else {
+        return ''
+    }
+}
+
+// Variables to use as repo parameters
+String gitRepoName
+String gitRepoUrl
+String gitSrcObj
+
+// Store current commit SHA
+String gitCommit
+
+node() {
+    for (gitRepo in gitRepoList) {
+        (gitRepoName, gitRepoUrl, gitSrcObj) = gitRepo.trim().tokenize(' ')
+
+        if (gitRepoName.startsWith('#')){
+            echo ("Skipping repo '${gitRepo}'")
+            continue
+        }
+
+        if (! gitRepoUrl) {
+        // The only token is the git repo url
+            gitRepoUrl = gitRepoName
+            gitRepoName = getRepoLocalPath(gitRepoUrl)
+            gitSrcObj = srcObj
+        } else if (! gitSrcObj) {
+        // Two tokens - can't decide is gitRepoName or gitSrcObj given
+            error ("Wrong repository string format: '${gitRepo}'")
+        }
+
+        if (gitSrcObj.contains('SUBS_SOURCE_REF')) {
+            echo ("Replacing 'SUBS_SOURCE_REF' => ${SOURCE_REVISION}")
+            gitSrcObj.replace('SUBS_SOURCE_REF', srcObj)
+        }
+
+        // Remove preifix `origin/` from gitSrcObj
+        java.util.regex.Pattern reOrigin = ~'^origin/'
+        gitSrcObj = gitSrcObj - reOrigin
+
+        checkout([
+            $class: 'GitSCM',
+            branches: [
+                [name: 'FETCH_HEAD'],
+            ],
+            userRemoteConfigs: [
+                [url: gitRepoUrl, refspec: gitSrcObj, credentialsId: gitCredentialsId],
+            ],
+            extensions: [
+                [$class: 'PruneStaleBranch'],
+                [$class: 'RelativeTargetDirectory', relativeTargetDir: gitRepoName],
+                [$class: 'SubmoduleOption', disableSubmodules: true],
+                [$class: 'UserIdentity', name: 'MCP CI', email: 'ci+infra@mirantis.com'],
+            ],
+        ])
+
+        // Proceed branch creation
+        dir(gitRepoName) {
+            sshagent (credentials: [gitCredentialsId]) {
+                // FIXME: Ensure git has configured user and email
+                // See: https://issues.jenkins-ci.org/browse/JENKINS-46052
+                sh 'git config user.name "MCP CI"'
+                sh 'git config user.email "ci+infra@mirantis.com"'
+
+                // Update list of branches
+                sh 'git remote update origin --prune'
+
+                // Ensure there is no branch or tag with gitBranchNew name
+                sh "git branch -d '${gitBranchNew}' && git push origin ':${gitBranchNew}' || :"
+                sh "git tag    -d '${gitBranchNew}' && git push origin ':refs/tags/${gitBranchNew}' || :"
+
+                // Check if gitSrcObj is a branch
+                gitCommit = sh (script: "git ls-remote --heads --quiet origin '${gitSrcObj}' | awk '{print \$1}'",
+                                returnStdout: true).trim()
+                if (gitCommit) {
+                // Rename existing branch
+                    sh "git checkout -b '${gitSrcObj}' -t 'origin/${gitSrcObj}'" // Checkout old branch
+                    sh "git branch -m '${gitSrcObj}' '${gitBranchNew}'"          // ... rename it
+                    sh "git push origin ':${gitSrcObj}'"                         // ... remove old remote branch
+                } else {
+                // Create new branch
+                    sh "git checkout -b '${gitBranchNew}' '${gitSrcObj}'"        // Create new local branch
+                }
+                sh "git push origin '${gitBranchNew}'"                           // ... push new branch
+            }
+        }
+    }
+}