Jenkinsfile to checkout different repo and update a file - jenkins

I have 2 repos A and B. At the end of build A, I want to update a properties file in repo B with the build number of A
How can I checkout the master branch of repo B in repo A's Jenkinfile just for this stage(which is last) ?
After checkout, can I follow the steps
mentioned below to update the file or is there any better way to
achieve it?
Jenkinsfile of repo A:
stage('Update properties file in repo B') {
steps {
script {
// how do I checkout master branch ofrepo B here?
sh "git config --global user.email jenkins#abc.com"
sh "git config --global user.name Jenkins"
sh(script: 'echo "repoA_VERSION=$BUILD_NUMBER" > version.properties', returnStdout: true).trim()
git add .
git commit -m "Updated version.properties file with ${env.BUILD_NUMBER}"
}
}
}

You just need to call git step:
E.g.
git branch: 'your_branch', credentialsId: 'your_credentials', url: 'your_repo'
If you don't know identifier for your credentials, you can go to:
your_jenkins_server:8080/job/job_name/pipeline-syntax/
where job_name is any job in your server, and you will access to Pipeline Syntax, you can then configure your git checkout and generate command:
For number 2,
the code must be within sh command:
sh """git add .
git commit -m "Updated version.properties file with ${env.BUILD_NUMBER}"
git push
"""
A final recommendation, avoid using git add ., and add files individually or with a wildcard.

Related

Automatic merge based on commit message

I am using Xcode Cloud with my iOS project. There are a few workflows based on branches and tags. Commonly one of them is finishing with app publication on the Test Flight.
My goal is to make an automation that will be run on develop branch every time when I will make some push. This automation will arise when script will find #promote tag inside commit message.
My first approach was to use post build script in Xcode Cloud as shown below:
#!/bin/sh
# ci_post_xcodebuild.sh
# BeforeDaily
#
# Created by Piotrek on 28/08/2022.
#
cd "$CI_WORKSPACE"
MESSAGE=$(git log -1 --oneline --format=%s | sed 's/^.*: //')
if [[ "$MESSAGE" == *"#promote"* ]]; then
echo "Merging develop into stage"
git fetch --all
git checkout --track -b stage origin/stage
git merge develop
git push origin stage
git checkout develop
echo "Done"
else
echo "There is nothing to do here..."
fi
This approach was promising but Xcode Cloud does not have write permissions on the Github project and it is not possible to change it. The result of the script is here:
2022-08-28T21:37:40.713643324Z Merging develop into stage
2022-08-28T21:37:42.747978838Z From http://github.com/<username>/<project_name>
2022-08-28T21:37:42.748494378Z * [new branch] develop -> origin/develop
2022-08-28T21:37:42.749001513Z * [new branch] main -> origin/main
2022-08-28T21:37:42.749224260Z * [new branch] stage -> origin/stage
2022-08-28T21:37:42.749514956Z Switched to a new branch 'stage'
2022-08-28T21:37:42.749752757Z branch 'stage' set up to track 'origin/stage'.
2022-08-28T21:37:42.750006530Z fatal: refusing to merge unrelated histories
2022-08-28T21:37:42.852059197Z remote: Write access to repository not granted.
2022-08-28T21:37:42.852480361Z fatal: unable to access 'http://github.com/piotrekjeremicz/beforedaily-swiftui-app.git/': The requested URL returned error: 403
2022-08-28T21:37:42.852854256Z Switched to branch 'develop'
2022-08-28T21:37:42.853020173Z Done
So the question is:
Is there any method that could provide me automatic merge based on commit message content?
I could not find any other solution than make a clean clone and work on fresh git repository. Everything is done in Xcode Cloud Workflow Here is a final ci_post_xcbuild.sh that makes a merge to stage if some message on develop contains #promote string.
#!/bin/sh
cd "$CI_WORKSPACE"
MESSAGE=$(git log -1 --oneline --format=%s | sed 's/^.*: //')
if [[ "$CI_BRANCH" == develop && "$MESSAGE" == *"#promote"* ]]; then
echo "Automerge develop branch into stage"
mkdir tempclone
cd tempclone
git clone https://x-access-token:$GITHUB_TOKEN#github.com/github_account/github_repo_name.git
cd beforedaily-swiftui-app
git config --global user.email "xcodecloud#jeremicz.com"
git config --global user.name "Xcode Cloud"
git checkout --track -b stage origin/stage
git merge origin/develop
git push origin stage
cd ../../
rm -r tempclone
else
echo "There is nothing to do here..."
fi
This script works with Github Token as an environment value that could be setup in Workflow settings.

Where Jenkins clone GIT repository?

I am trying to find out where Jenkins clone the GIT repo but I can't find it.
In my script in Jenkins pipeline I have:
stage('Do something'){
steps {
sh '''
#!/bin/bash
YAML_FILE="${JENKINS_HOME}/jobs/<JENKINS_JOB_NAME>/workspace/GIT_REPO_NAME/path/to/file.yaml"
...
However when I am trying to buid it, it can't find it in this path:
Error: open /efsmnt/jobs/<JENKINS_JOB_NAME>/workspace/GIT_REPO_NAME/path/to/file.yaml: no such file or directory
I also found that it could be in:
20:13:55 Error: open /home/jenkins/agent/workspace/<JENKINS_JOB_NAME>/GIT_REPO_NAME/path/to/file.yaml: no such file or directory
but with no luck.
The global environment WORKSPACE represents the job workspace where your repo will be clone into.
And Jenkins won't create GIT_REPO_NAME folder in job workspace when run git clone.
You can try below script
sh '''
pwd
ls -l
YAML_FILE="${WORKSPACE}/path/to/file.yaml"
'''
Use double quote in case job workspace path includes space when Jenkins job or Jenkins folder name includes space

libgit2sharp - How to checkout as "git checkout <commit_hash> ."

With git command, to replace the working directory with a commit, we will call:
git checkout <commit_hash> .
How can I implement that with libgit2sharp?

How do you specify additional trusted files with the Jenkins Github Branch Source plugin?

I've created a Jenkins Multibranch Pipeline with the GitHub Branch Source plugin. The Jenkinsfile essentially just calls a Cake Build script (build.ps1, build.cake) that contains all the build/deploy logic. This allows me to move to another CI service easily.
Unfortunately, I cannot seem to figure out how to add my Cake Build scripts as a trusted file so that PR's from forks will pull the files from the source repo instead. The Trust setting of the Discover pull requests from forks behavior seems to indicate that there can be other trusted files besides Jenkinsfile:
Nobody
Pull requests from forks will all be treated as untrusted. This means that where Jenkins requires a trusted file (e.g. Jenkinsfile) the contents of that file will be retrieved from the target branch on the origin repository and not from the pull request branch on the fork repository.
However, I cannot seem to find any documentation on adding other trusted files. The primary reason for this is to prevent a PR from a fork from accessing credentials from the Cake script. They wouldn't be able to change Jenkinsfile, but they could still change the Cake script to expose the credentials.
Is it actually possible to add other trusted files?
It seems like Jenkins does not support this. My solution is checking out the untrusted files manually from the base version instead. First getting the commit 's hash of the base version with:
def commit = sh(
script: 'git rev-parse HEAD',
returnStdout: true
).trim()
def base = sh(
script: "git rev-list --parents -n 1 ${commit}",
returnStdout: true
).trim().split('\\s+')[2]
git rev-list --parents -n 1 ${commit} will return the hash of current commit, which is a merge commit that was created by Jenkins; the latest commit of the PR and the latest commit of the target branch, separated by a space (e.g. 05e9322574ea03003f87dcbb44f172e6fa62581f b3f6ef892af9c645f490106757d7d05df3a26060 069ffd55ae36414a51b4de166aef86966f9447a8). Hence, we grab the hash of the latest commit of the target branch by trim().split('\\s+')[2].
Now we can do sh "git checkout ${base} FILE" on any file that we don't trust from the PR.
This does not works if the PR is already merged with the latest version of target branch. So what I did is something like this:
// revert untrusted files to the base version and backup it before we execute any untrusted code so the attacker
// don't have a chance to put a malicious content
def latest = sh(script: 'git rev-parse HEAD', returnStdout: true).trim()
sh "git checkout origin/${env.CHANGE_TARGET}"
def baseCompose = readFile('docker-compose.yml')
// switch back to latest commit
sh "git checkout ${latest}"
sh 'git clean -d -f -f -q -x'

Jenkins Pipeline building all branches simultaneously

I setup a simple Jenkinsfile that just echo a few steps.
I setup a new repo on Bitbucket (git) and two branches called master and develop.
When I commit something to master then both branches checkout and build in jenkins. Same behaviour on the develop branch.
Is it possible to limit only master to build in Jenkins once there is a commit to master branch? Similar behaviour to develop?
I think you can use a temporary text file to save last successful build SHA ($LAST_SUCCESSFUL_BUILD_SHA) of each branch. Then, when having a new commit from the repo, we'll check which branch the commit comes from.
CURRENT_SHA=$(git rev-parse HEAD)
if [ $FORCE_REBUILD = true ] || [ $CURRENT_SHA != $LAST_SUCCESSFUL_BUILD_SHA ]; then
echo "New commits available OR it was forced to build."
else
echo "Already up-to-date. Skip build."
curl -v -X POST --data "description=no changes, skip." ${JENKINS_BUILD_URL}submitDescription --user <username>:<password>
curl -v -X POST ${BUILD_URL}stop --user <username>:<password>
echo "Waiting for abort to take effect :D"
fi
If the new commit comes from another branch, it's good to use Jenkins open API to skip the build.
I have applied this for my freestyle jobs but haven't tried with Jenkinsfile.

Resources