Create CI/CD pipeline with TeamCity and Sonarqube
Configure Continuous Integration (CI) build
Configure version control system
A version control system (VCS) is configured as a GIT repository. TeamCity automatically detects Microsoft DevOps server.

During repository detection, TeamCity checks credentials and network connection to the repository. After the test passes successfully, configure the default branch.


To use several default branches, configure a branch pattern. The pattern is written as a regular expression:
- "+" means using the pattern.
- "-" means excluding branches.
Configure build steps
Maven
The package build step is configured with the default TeamCity Maven plugin. The goal for Maven is clean package.

You can also configure code coverage analysis. In that case, choose a proper runner. The files to process are configured like branches. The symbol "." means that the plugin checks the whole project.

Sonarqube
To configure a Sonarqube check, follow the steps below:
- Create another Maven-based build step with the goal sonar:sonar.
- Specify the Sonar project key, host, and token for SonarQube as additional Maven parameters.

Configure package deployment
Deployment is implemented through a basic command-line build step. The package is uploaded with curl via Nexus REST API.
curl -v -u login:password -X POST https://nexus_url/service/rest/v1/components?repository=cicd-test -F "raw.directory=/" -F "raw.asset1=@repo_id/target/package.zip" -F "raw.asset1.filename=package.zip"

Define build parameters
Parameters are transferred to the build as environment variables and can be predefined with default values.

In Build steps, parameters are decorated with "{}".

Configure CD pipeline
The Continuous Delivery (CD) pipeline is configured with a single command-line build step.


The step runs the script that pushes the package from a Nexus repository to Control Tower:
#!/bin/bash
rm *.zip
wget --user username --password ... https://nexus_url/repository/repo_id/package.zip
bundleFile="package.zip"
resolutionStrategy=REPLACE
statusAttemptLimit=300
#delay is in seconds
statusDelay=1
hostname="https://ct_url"
username='apibot'
password='...'
timestamp() {
date +%Y-%m-%d_%H-%M-%S-%3N
}
writeOutputToFile() {
echo $1 >bundle-import-$2.json
}
if [[ -z "$bundleFile" ]]; then
echo 'Please, pass the path to bundle as first parameter'
exit 1
fi
if [[ -z "$hostname" ]]; then
echo 'Please, pass the hostname as second parameter'
exit 1
fi
if [[ -z "$username" ]]; then
echo 'Please pass username as third parameter'
exit 1
fi
if [[ -z "$password" ]]; then
echo 'Please pass password as fourth parameter'
exit 1
fi
if [ ! -f "$bundleFile" ]; then
echo 'The given bundle file does not seem to exist (possible typo?)'
exit 1
fi
#calculate checksum
checksum=$(md5sum "$bundleFile" | cut -d ' ' -f1)
#if absolute path with escaping (\\) is passed, need to cut '\'
if [[ $checksum == \\* ]]; then
checksum="${checksum:1}"
fi
cookie_file=$(mktemp --suffix=_bunle_import_cookie)
#login
loginResponse=$(
curl -s --request POST \
--url $hostname/workfusion/api/dologin \
--header 'Accept: */*' \
--header 'Cache-Control: no-cache' \
--header 'Connection: keep-alive' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'accept-encoding: gzip, deflate' \
--data "j_username=$username&j_password=$password" \
--cookie-jar $cookie_file \
--insecure
)
#extract token
token=$(echo $loginResponse | grep -Po '"csrfToken":.*?[^\\]",' | grep -Po ':".*"' | sed 's/:"//g' | sed 's/"//g')
if [[ -z "$token" ]]; then
echo "Login failed"
writeOutputToFile "$loginResponse" "$(timestamp)"
exit 1
fi
echo 'Login successful'
#call bundle import
importResponse=$(
curl --request POST \
--url $hostname/workfusion/api/v1/bundle-import/ \
--header 'Accept: */*' \
--header 'Cache-Control: no-cache' \
--header 'Connection: keep-alive' \
--header "X-CSRF-TOKEN: $token" \
--header 'accept-encoding: gzip, deflate' \
--header 'cache-control: no-cache' \
--form "bundleFile=@$bundleFile" \
--form "checksum=$checksum;type=text/plain" \
--form "conflictResolutions={\"conflictResolutionStrategy\": \"$resolutionStrategy\"};type=application/json" \
--cookie $cookie_file \
--insecure
)
#if verification failed, script is stopped
uuid=$(echo $importResponse | grep -Po '"uuid":.*?[^\\]",' | grep -Po ':".*"' | sed 's/:"//g' | sed 's/"//g')
validationStatus=$(echo $importResponse | grep -Po '"importStatus":.*?[^\\]",' | grep -Po ':".*"' | sed 's/:"//g' | sed 's/"//g')
if [[ (-z "$uuid") || ("$validationStatus" != 'ACCEPTED') ]]; then
currTimestamp=$(timestamp)
echo "Import failed, see bundle-import-$currTimestamp.json for details"
writeOutputToFile "$importResponse" "$currTimestamp"
exit 1
fi
echo 'Asset Package accepted'
#checking status in a cycle
isFinished=0
attempt=1
while [ $isFinished -eq 0 ]; do
#stop script if number of retries exceeded
if [[ $attempt -ge $statusAttemptLimit ]]; then
echo "Attempt limit ($statusAttemptLimit) is exceeded"
writeOutputToFile "Attempt limit ($statusAttemptLimit) is exceeded" "$(timestamp)"
exit 1
fi
sleep $statusDelay
statusResponse=$(
curl -s --request GET \
--url $hostname/workfusion/api/v1/bundle-import/$uuid \
--header 'Accept: */*' \
--header 'Cache-Control: no-cache' \
--header 'Connection: keep-alive' \
--header "X-CSRF-TOKEN: $token" \
--header 'accept-encoding: gzip, deflate' \
--header 'cache-control: no-cache' \
--cookie $cookie_file \
--insecure
)
status=$(echo $statusResponse | grep -Po -m1 '{"status":.*?[^\\]",' | head -1 | grep -Po ':".*"' | sed 's/:"//g' | sed 's/"//g')
if [ -z "$status" ]; then
currTimestamp=$(timestamp)
echo "Import failed, see bundle-import-$currTimestamp.json for details"
writeOutputToFile "$status" "$currTimestamp"
exit 1
fi
echo "Import in progress, attempt $attempt"
((attempt++))
if [[ "$status" == 'SUCCEEDED' ]]; then
isFinished=1
echo "Import succeeded"
fi
if [[ "$status" == 'FAILED' ]]; then
isFinished=1
currTimestamp=$(timestamp)
echo "Import failed, see bundle-import-$currTimestamp.json for details"
writeOutputToFile "$statusResponse" "$currTimestamp"
fi
done
exit