Jenkins Groovy: how to extract specific number from parameter in method? - bash

I am quite new in Groovy and trying to extract find the best way to write a method that will extract the 3rd number in branch name which is passed as a parameter.
Standard gitBranchName looks like this release-1.2.3
Below is my method and I am wondering what to do with newestTagNumber:
#!/usr/bin/env groovy
def call(gitRepoName, gitBranchName) {
withCredentials([
string(credentialsId: 'jenkinsuser', variable: 'USER'),
string(credentialsId: 'jenkinssecret', variable: 'SECRET')]) {
def commitHash = sh(
script: 'git rev-parse --short HEAD',
/*script: 'git rev-parse --symbolic-full-name #{-1} && git rev-parse --abbrev-ref #{-1}' */
returnStdout: true).trim()
def repoUrl = "bitbucket.org/cos/${gitRepoName}"
/* newestTagNumber - this is 3rd number taken from gitBranchName */
def newestTagNumber = <what_to_add_here?>
/* nextTagNumber - incremented by 1 */
def nextTagNumber = newestTagNumber + 1
sh """
git config user.email "example#example.com"
git config user.name "jenkins"
git tag -a release-${nextTagNumber}.t -m 'Create tag release-${nextTagNumber}.t'
"""
sh('git push --tags https://${JT_USER}:${JT_SECRET}#' + repoUrl)
}
}
This is how it will probably work using Regex, but is there a prettier way to do it in Groovy?
[\d]*(\d$)
Thank you guys!

You can simply split the String by "." and get the last digit.
def parts = gitBranchName.split("\\.")
def newestTagNumber = parts[parts.size()-1]
If you are sure you will always get the branch name in this format with 3 decimal points(release-1.2.3) here is a one-liner.
def newestTagNumber = gitBranchName.split("\\.")[2]

#ycr solution is right, but I found even better option if you always want to change the last number (which is my case):
def newestTagNumber = gitBranchName.split("\\.").last()
Thanks!

Related

Get tripple dot diff with gitpython

I am getting the diff between two commits using gitpython in below way:
def get_inbetween_commit_diff(repo_path, commit_a, commit_b):
repo = Repo(repo_path)
uni_diff_text = repo.git.diff(
"{}".format(commit_a), "{}".format(commit_b), ignore_blank_lines=True, ignore_space_at_eol=True
)
return uni_diff_text
However, the default repo.git.diff shows the diff with double dot. Is there a way to achieve triple dot diff using gitpython?
Reference on double dot and triple dot diff: https://matthew-brett.github.io/pydagogue/git_diff_dots.html
repo.git.diff calls git directly, so I think you can just do this:
repo.git.diff(
"{}...{}".format(commit_a, commit_b), ignore_blank_lines=True, ignore_space_at_eol=True
)

Get all keys of Json as list directly from Git Repo

For my Jenkins pipeline I want to populate all the keys in Json which is in GitRepo as Extended Choice parameters.
[$class: 'ChoiceParameter', choiceType: 'PT_SINGLE_SELECT', description: 'Select an option', name: 'Option', randomName: 'choice-parameter-112', script: [$class: 'GroovyScript', fallbackScript: [classpath: [], sandbox: false, script: ''], script: [classpath: [], sandbox: false,
script: '''
//What should I write here in this block?
return keys
''']]]
Basically all I need is a curl call that I can make from the above block to get single file from Git using the Git Credential ID(I've stored my user name and password as credential id in Git)
This is a frequent case which boils down to this:
You can't issue a call to sh unless you have a node. To have a node, you need to run a pipeline. To run a pipeline, you need to figure out the parameters. To figure out this parameter, you need to issue a call to sh. See the problem?
To overcome the problem, you can cheat the system by running another (small) pipeline before the main one, e.g.
node('master') {
stage('read file') {
def file_contents = sh (returnStdout: true, script: "curl myrepo/myfile.json")
def parsed_data = readJSON text: file_contents
}
}
and then
properties([
parameters([
[$class: 'ChoiceParameter',
etc.

Is there any way to pass variables from bash script to Jenkinsfile without using extra plugins

I'm trying to use variables declared in bash script in my Jenkinsfile (jenkins pipeline) without using extra plugins like EnvInject plugin
please help, any idea will be appreciated
you need to output those variables to a file like Property/Yaml file. Then use pipeline step readProperties / readYaml to read into Map in Jenkinsfile.
steps {
sh'''
...
AA=XXX
BB=YYY
set > vars.prop
'''
script {
vars = readProperties file: 'vars.prop'
env << vars // merge vars into env
echo 'AA='+ env['AA']
}
}
I have done it with something like this, you can store the variables inside Shell into a file inside workspace and then you are out of shell block, read the file in groovy to load the key value pair into your environment
Something like:
def env_file = "${WORKSPACE}/shell_env.txt"
echo ("INFO: envFileName = ${env_file}")
def read_env_file = readFile env_file
def lines = read_env_file.readLines()
lines.each { String line ->
def object = line.split("=")
env.object[0] = object[1]
}

Checking if an object is in a repo in gitpython

I'm working on a program that will be adding and updating files in a git repo. Since I can't be sure if a file that I am working with is currently in the repo, I need to check its existence - an action that seems to be harder than I thought it would be.
The 'in' comparison doesn't seem to work on non-root levels on trees in gitpython. Ex.
>>> repo = Repo(path)
>>> hct = repo.head.commit.tree
>>>> 'A' in hct['documents']
False
>>> hct['documents']['A']
<git.Tree "8c74cba527a814a3700a96d8b168715684013857">
So I'm left to wonder, how do people check that a given file is in a git tree before trying to work on it? Trying to access an object for a file that is not in the tree will throw a KeyError, so I can do try-catches. But that feels like a poor use of exception handling for a routine existence check.
Have I missed something really obvious? How does once check for the existence of a file in a commit tree using gitpython (or really any library/method in Python)?
Self Answer
OK, I dug around in the Tree class to see what __contains__ does. Turns out, when searching in sub folders, one has to check for existence of a file using the full relative path from the repo's root. So a working version of the check I did above is:
>>> 'documents/A' in hct['documents']
True
EricP's answer has a bug. Here's a fixed version:
def fileInRepo(repo, filePath):
'''
repo is a gitPython Repo object
filePath is the full path to the file from the repository root
returns true if file is found in the repo at the specified path, false otherwise
'''
pathdir = os.path.dirname(filePath)
# Build up reference to desired repo path
rsub = repo.head.commit.tree
for path_element in pathdir.split(os.path.sep):
# If dir on file path is not in repo, neither is file.
try :
rsub = rsub[path_element]
except KeyError :
return False
return(filePath in rsub)
Usage:
file_found = fileInRepo(repo, 'documents/A')
This is very similar to EricP's code, but handles the case where the folder containing the file is not in the repo. EricP's function raises a KeyError in that case. This function returns False.
(I offered to edit EricP's code but was rejected.)
Expanding on Bill's solution, here is a function that determines whether a file is in a repo:
def fileInRepo(repo,path_to_file):
'''
repo is a gitPython Repo object
path_to_file is the full path to the file from the repository root
returns true if file is found in the repo at the specified path, false otherwise
'''
pathdir = os.path.dirname(path_to_file)
# Build up reference to desired repo path
rsub = repo.head.commit.tree
for path_element in pathdir.split(os.path.sep):
rsub = rsub[path_element]
return(path_to_file in rsub)
Example usage:
file_found = fileInRepo(repo, 'documents/A')
If you want to omit catch try you can check if object is in repo with:
def fileInRepo(repo, path_to_file):
dir_path = os.path.dirname(path_to_file)
rsub = repo.head.commit.tree
path_elements = dir_path.split(os.path.sep)
for el_id, element in enumerate(path_elements):
sub_path = os.path.join(*path_elements[:el_id + 1])
if sub_path in rsub:
rsub = rsub[element]
else:
return False
return path_to_file in rsub
or you can iterate through all items in repo, but it will be for sure slower:
def isFileInRepo(repo, path_to_file):
rsub = repo.head.commit.tree
for element in rsub.traverse():
if element.path == path_to_file:
return True
return False
There already exists a method of Tree that will do what fileInRepo re-implements in Lucidity's answer .
The method is Tree.join:
https://gitpython.readthedocs.io/en/3.1.29/reference.html#git.objects.tree.Tree.join
A less redundant implementation of fileInRepo is:
def fileInRepo(repo, filePath):
try:
repo.head.commit.tree.join(filePath)
return True
except KeyError:
return False

Grit commit_diff shows reverse diff

I'm trying to do a very simple thing: Read a diff from a git repo via the ruby gem Grit. I'm creating a file and adding the line "This is me changing the first file". Now I do this to get the diff:
r = Grit::Repo.new("myrepo")
c = r.commits.first
d = r.commit_diff(c.id).first
puts d.first.diff
The output of this is:
--- a/First-File.asciidoc
+++ b/First-File.asciidoc
## -1,2 +1 ##
-This is me changing the first file
See that minus in front of the added line? Why would a commit_diff show in reverse? I know that git reverses the diff if I reverse the commit shas, but this is a Grit library call that only gives the commit diff?
Any clues?
Let me answer that question. The commit shows up in correct form, if you do this insteas:
r = Grit::Repo.new("myrepo")
c = r.commits.first
d = c.diffs.first
puts d.first.diff
Not sure what the difference would be between Commit.diff and Repo.commit_diff.

Resources