Is it possible to disable queuing on builds in TeamCity? If a job is already running, I don't want another one to queue (for example, if started by a trigger). I've done some searching and do not see a way to prevent the queuing up.
If each is only one build configuration, you could run them on the same agent, so that way only one could run at the same time. But then, build 2 would run after build 1 finishes, which you don't want.
Here's how I solved this problem. It's kind of ugly, but it's simple, and generalizes to many build configurations:
Pick a specific server. Since this server will determine whether a build runs, we'll call it your gate server. We need a file location that doesn't exist now, nor will it be created by any other program. Say, for example, `/teamcity/.lock'
Make a build configuration with the following contents:
lockFileLocation="/teamcity/.lock"
if [ -f $lockFileLocation ];
then
echo "oops, we're already running a build."
exit 1
else
echo "No build is running. Let's lock it up!"
touch $lockFileLocation
fi
For Powershell, it's this:
$lockFileLocation = "C:\teamcity\lock"
if(Test-Path $lockFileLocation)
{
echo "oops, we're already running a build."
exit 1
}
else
{
echo "No build is running. Let's lock it up!"
echo "lock'd!" > $lockFileLocation
}
And make sure that build is set to run only on the gate agent. So this build will only succeed if it hasn't ever run. Not useful yet. Let's call this build lock. Make a new build configuration with the following contents:
lockFileLocation="/teamcity/.lock"
if [ -f $lockFileLocation ];
then
echo "Build's over. You don't have to do home, but you can't stay here"
rm $lockFileLocation
else
echo "No build is running. How did we get here?"
exit 1
fi
For Powershell:
$lockFileLocation = "C:\teamcity\lock"
if(Test-Path $lockFileLocation)
{
echo "Build's over. You don't have to do home, but you can't stay here"
rm "$lockFileLocation"
}
else
{
echo "No build is running. How did we get here?"
exit 1
}
Make sure that build is set to run only on gate, and that build will delete the file if it exists. Let's call the build unlock.
Cool, now we can run lock to write the file, and unlock to delete it. If you run lock twice without running unlock, the first run of lock will pass, and the second will fail. Nice.
But how does this help us? Let's say that your build is a single build configuration called work. Set a finish build trigger on work so that it runs after lock succeeds. Similarly, set a finish build trigger on unlock so that it runs after work finishes, whether it passes or fails. We want to unlock the build even if you committed bad code.
If your build is a set of build configurations, your build internally needs to be connected via snapshot dependencies, and not finish build triggers. Say your build is two build configurations: work-A and work-B. You want to run work-A first, then when it's done, work-B. Set a snapshot dependency from work-B to work-A as usual. Then, set a finish build trigger on unlock that triggers when lock passes. Set a snapshot dependency from unlock to work-B, set to "run build even if dependency has failed. Here's a drawing of the build, where downward arrows are finish build triggers, and upward arrows are snapshot dependencies:
+----+
|lock|
+----+ +------+
| |work-A|
| +------+
| ^
| |
| |
\ +------+
\ |work-B|
\ +------+
\ ^
\ |
v |
+------+
|unlock|
+------+
Now, when you hit "run" on lock, it will lock the build, trigger your build configurations, then unlock the build. Hit "run" a bunch of times, and see how neither work-A nor work-B gets queued up.
But that's only one set of build configurations. You have two. So set both of them up this way, making sure they look at the same file, and are both set to run only on the gate agent.
Yay! We're done! But wait, why do work-A and work-B need to be connected via snapshot dependencies? Well, let's say the build is as follows:
+----+
|lock|
+----+
|
|
v
+------+
|work-A|
+------+
|
|
v
+------+
|work-B|
+------+
|
|
v
+------+
|unlock|
+------+
Now, what if work-A fails? work-B won't run, and so neither will unlock.
Note: theoretically, you could run the build as follows:
+----+
|lock|
+----+ +------+
\ |work-A|
\ +------+
\ ^
\ |
v |
+------+
|work-B|
+------+
|
|
v
+------+
|unlock|
+------+
This should work, but I haven't tested it, so I can't give you all the settings.
I can't find a way to dynamically disable a trigger or conditionally run one build based on the status of another.
If these two jobs are unrelated to one another, perhaps you could configure them to run on separate agents? That way they could run without interfering with one another.
Related
I am fairly new to Robot Framework. I am trying to run the following code using Ride IDE but facing issues. Could someone kindly help me on how to get this done.
Code:
*** Settings ***
*** Variables ***
*** Test Cases ***
Setting Variables
#| Example of running a python script
${result}= run process | python | C:\Users\name\Desktop\hello.py
#| | Should be equal as integers | ${result.rc} | 0
#| | Should be equal as strings | ${result.stdout} | Hello World
*** Keywords ***
I still think you should include more details in your question, namely:
the content of hello.py
the error message you get
Nevertheless, I think your problem will be somewhere around these:
1/ Your Settings section is empty, but you need Process library in order to execute Run Process keyword.
2/ Your hello.py is wrong, doesn't return and print what you think it does.
3/ You absolute path is wrong, the python file resides somewhere else.
4/ You're missing some modules you need in order to execute RF scripts. Please search on this site, similar question about missing modules has been asked many times.
All in all, the whole runnable example (provided you have all the prerequisites installed) would be:
*** Settings ***
Library Process
*** Test Cases ***
Setting Variables
${result}= Run Process python hello.py
Should be equal as integers ${result.rc} 0
Should be equal as strings ${result.stdout} Hello World
It's a good practice not to use absolute paths, so I refer to hello.py differently. The content of the file is:
hello.py
print('Hello World')
Lets say I have a scenario in my demo.feature file
Scenario Outline: Gather and load all submenus
Given I will login using <username> and <password>
When I will click all links
Examples :
| username | password |
| user1 | pass1 |
| use2 | pass2 |
lets say i have a file called users.json
How can i get those usernames and passwords from that external file to my demo.feature ?
Can I catch the file by passing parameters to my npm script like below ?
npm run cucumber -- --params.environment.file=usernames.json
I recommend having the login step access that json file within the step definition. Just make sure not to check it into the repo and instead always expect it to be in a location but only locally and not in the repository.
Doing the above is useful for a couple of reasons:
- An engineer running your tests does not need to know that a param must be passed in from the command line
- The code is self-descriptive in that step as to how it logs in
- You can add better error handling
- You can use multiple user files if needs be by having hooks define paths etc based on tags
I have an iOS project written by Swift 3.0 with CocoaPods. I've configured Gitlab CI for this project and it works perfectly. This is my .gitlab-ci.yml file:
stages:
- build
build_project:
stage: build
script:
- rm -rf Pods;rm -rf MyProject.xcworkspace;rm -rf MyProject.xcodeproj/project.xcworkspace
- pod install
- xcodebuild clean -workspace MyProject.xcworkspace -scheme MyProject | xcpretty
- xcodebuild test -workspace MyProject.xcworkspace -scheme MyProject -destination 'platform=iOS Simulator,name=iPhone 7,OS=10.2' | xcpretty -s
tags:
- ios
- lunchdot
I can't see code coverage for this project in my Gitlab repo. At the moment a coverage column for all my builds is empty. I tried to set Test coverage parsing in CI/CD Pipelines Gitlab settings, but it hadn't any effect because I don't know regex for Swift. Is it possible to set up code coverage for Swift project in Gitlab CI? How can I do this?
So, I tried a million ways to do it and the issue turned out to be xcpretty. After I removed it I started getting consistent results with my gitlab ci coverage data. If you still do not want to get tons of data you do not care about, you can use -quiet in your gitlab yams file. I will post it all though, so keep reading.
One still needs an external tool for coverage analysis - xcov seems to not be available anymore so I used slather. Worked like a charm.
These are the steps:
1) Get slather.
2) Get your .slather.yml file straightened out. Mine looks like the following (YourApp is the name of your app obviously):
# .slather.yml
coverage_service: cobertura_xml
xcodeproj: ./YourApp.xcodeproj
workspace: ./YourApp.xcworkspace
scheme: YourApp
source_directory: ./YourApp
output_directory: path/to/xml_report
ignore:
- "**/Pods/*"
- "thirdparty/*"
- "./Scripts/*"
- "**/3rdParty/*"
- "../**/Developer/*"
- "**/libraries/*"
- "Module-Core/*"
- "Module-Components/*"
- "**/AppUnitTests/*"
You can get the test output as html, xml, in codecov.io, etc, totally up to you. Check out the slather GitHub page to see the possible ways of doing that. But for the current issue, all we need is slather reporting in the command line so gitlab can pick it up. That is where properly setting up the gitlab yaml file comes in.
3) Set up the .gitlab-ci.yml file. Mine looks like this:
stages:
- build
build_project_1:
stage: build
script:
- xcodebuild clean -workspace YourApp.xcworkspace -scheme YourApp -quiet
- xcodebuild test -workspace YourApp.xcworkspace -scheme YourApp -destination 'platform=iOS Simulator,name=iPhone 6,OS=10.3.1' -enableCodeCoverage YES -quiet
after_script:
- slather coverage -s
only:
- master
4) Next step is to:
Go to your gitlab page/profile or whatever you call it
Go to Settings and then Pipelines
Scroll down to Test coverage parsing and add this regex expression there: \d+\%\s*$
And that is it. All you need to do is invoke a build.
Since Xcode 9.3 Apple provides xccov, so here is a solution using this, that does not rely on third party dependencies (and does not care if you use xcpretty, -quiet etc.)
Overview of xccovreport and xccov
When your Scheme has test coverage enabled (or when you pass -enableCodeCoverage YES to xcodebuild), an .xccovreport file is created. It contains the coverage percentages that you can see in Xcode UI.
The file is located in:
(for Xcode 9)
/Users/somename/Library/Developer/Xcode/DerivedData/MyApp-airjvkmhmywlmehdusimolqklzri/Logs/Test/E387E6E7-0AE8-4424-AFBA-EF9FX71A7E46.xccovreport
(for Xcode 10)
/Users/somename/Library/Developer/Xcode/DerivedData/MyApp-airjvkmhmywlmehdusimolqklzri/Logs/Test/Test-MyApp-2018.10.12_20-13-43-+0100.xcresult/action.xccovreport
(unless you specify a different folder in xcodebuild via -derivedDataPath)
Note: In Xcode 10, the .xccovreport file location is printed out in console after test finishes, but Xcode 9 does not do this. In any case, relying on this is probably not a good idea, as it might be silenced (e.g. by xcpretty)
The file isn't a plain text and to view it you have to call:
xcrun xccov view <path_to_xccovreport_file>
Which will output the report.
(You can pass --json for JSON report)
What we need to do
We want to be able to parse the file and print out the total percentage (so then GitLab can pick this up and use it in the dashboard).
There are a couple of challenges:
- Firstly we need to find out the file path of the xccovreport which contains random strings (in two places)
- Then we need to parse the file (using some regular expressions) and extract the total percentage.
The script
Here's what I am using (any improvement suggestions welcome, as I am not a bash expert):
#!/bin/bash
#1
# Xcode 10
TEST_LOGS_DIR=`xcodebuild -project MyApp.xcodeproj -showBuildSettings | grep BUILD_DIR | head -1 | perl -pe 's/\s+BUILD_DIR = //' | perl -pe 's/\/Build\/Products/\/Logs\/Test/'`
TEST_RESULTS_DIR=`ls -t $TEST_LOGS_DIR | grep "xcresult" | head -1`
TEST_COV_REPORT_FILENAME=`ls "$TEST_LOGS_DIR/$TEST_RESULTS_DIR/1_Test" | grep "xccovreport"`
TEST_COV_REPORT_FULL_PATH="$TEST_LOGS_DIR/$TEST_RESULTS_DIR/1_Test/$TEST_COV_REPORT_FILENAME"
# Xcode 9
# TEST_LOGS_DIR=`xcodebuild -project MyApp.xcodeproj -showBuildSettings | grep BUILD_DIR | head -1 | perl -pe 's/\s+BUILD_DIR = //' | perl -pe 's/\/Build\/Products/\/Logs\/Test/'`
# TEST_COV_REPORT_FILENAME=`ls $TEST_LOGS_DIR | grep "xccovreport"`
# TEST_COV_REPORT_FULL_PATH="$TEST_LOGS_DIR/$TEST_COV_REPORT_FILENAME"
# More general recursive search. Perhaps less likely to fail on new Xcode versions. Relies on filepaths containing timestamps that sort alphabetically correctly in time
# TEST_LOGS_DIR=`xcodebuild -project MyApp.xcodeproj -showBuildSettings | grep BUILD_DIR | head -1 | perl -pe 's/\s+BUILD_DIR = //' | perl -pe 's/\/Build\/Products/\/Logs\/Test/'`
# TEST_COV_REPORT_FULL_PATH=`find $TEST_LOGS_DIR -name '*.xccovreport' | sort -r | head -1`
#2
TOTAL_XCTEST_COVERAGE=`xcrun xccov view $TEST_COV_REPORT_FULL_PATH | grep '.app' | head -1 | perl -pe 's/.+?(\d+\.\d+%).+/\1/'`
#3
echo "TOTAL_XCTEST_COVERAGE=$TOTAL_XCTEST_COVERAGE"
What it does
#1 - gets the BUILD_DIR and then manipulates the path to get to the xccovreport file. Comment / uncomment the block for your version of Xcode.
#2 - We start with the full report as text. grep '.app' takes only the lines that contain .app. This is guaranteed to exist, because there is a line that reports the total coverage and contains MyApp.app. There will be multiple matches, but the first match will always be the overall total codecov score. So we use head -1 to take that first line of the grep result.
Now we have a line that looks like this:
MyApp.app 12.34% (8/65)
We use a perl regex to take only the “12.34%” part.
#3 - We simply print out the result (together with the variable name to make it easier to locate later in GitLab CI)
How to use
Replace MyApp.xcodeproj with your correct value
Make sure the correct logic is applied in step #1 (Xcode 9 / Xcode 10 / Generalized recursive search)
Save to a printCodeCov.sh file in the root of your project.
Make the file executable chmod +x printCodeCov.sh
In your .gitlab-ci.yml file, add a line to the script that says - ./printCodeCov.sh
In your GitLab Pipeline Settings, set the Test coverage parsing to TOTAL_XCTEST_COVERAGE=(.+)%
Notes
This does not use the --json format of xccov. For that version, see below.
This solution might be fragile, because of multiple assumptions about folder locations and report format
I use perl instead of sed because the latter was too difficult (BSD/GNU differences, regex limitations etc).
JSON version
If you'd rather use the JSON report (from xccov), then in the script you need something like this:
# Xcode 10
COV_NUMBER_FRACTION=`xcrun xccov view --json $TEST_COV_REPORT_FULL_PATH | perl -pe 's/.+?\.app.+?"lineCoverage":([^,]+).+/\1/'`
# Xcode 9
# COV_NUMBER_FRACTION=`xcrun xccov view --json $TEST_COV_REPORT_FULL_PATH | perl -pe 's/.+"targets"[^l]+lineCoverage":([^,]+),.+/\1/'`
COV_NUMBER_PERCENTAGE=`bc <<< $COV_NUMBER_FRACTION*100`
TOTAL_XCTEST_COVERAGE=`printf "%0.2f%%\n" $COV_NUMBER_PERCENTAGE`
I have downloaded a copy of the 1.1.0-RELEASE tagged source code for Spring RESTdocs, but "gradlew build" is failing during the test phase. 273 of 502 tests are failing with variations on this error:
org.springframework.restdocs.request.RequestPartsSnippetTests > requestPartsWithOptionalColumn[Markdown] FAILED
java.lang.AssertionError:
Expected: is adoc snippetPart | Optional | Description
---- | -------- | -----------
a | true | one
b | false | two
but: was:Part | Optional | Description
---- | -------- | -----------
a | true | one
b | false | two
The problem looks to be that the string "adoc snippet" is prefixed to the start
of the expected output. I don't think that's right, although I can see in the AbstractContentSnippetMatcher.describeTo() why it's happening and it doesn't look very conditional so maybe it's the test's actual result that's wrong?
I have made no changes to the source code* but I don't see other people reporting this problem, so I'm mystified. I'm entirely new to gradle. Is there some kind of config I need to set up to make the tests pass? Should I be using a different target?
(OK... 1 teensy change: I removed the new-line-at-end-of-file check from the checkStyle - I'm downloading from Github onto a Windows PC.)
The problem is that the files in the zip have Unix-style line endings but, when run on Windows, Checkstyle and the tests expect Windows-style line endings.
Typically a Windows Git client will take care of this for you by converting the line endings when you check out the code. For example, the default configuration of Git for Windows is to check code out with Windows-style line endings but commit changes with Windows-style line endings.
You may be able to find a Windows utility that will batch-convert the line endings from LF to CRLF. Failing that, it's probably easiest to install a Git client (such as Git for Windows that I linked to above), ensure it's configure to perform line ending conversion, and then:
> git clone https://github.com/spring-projects/spring-restdocs
> cd spring-restdocs
> gradlew build
Is there a plugin to fail a build if a pattern occurs on the console output?
For example:
Build Action - success
Build Action - success
Build Action - error_pattern
Build Action - success
Let's assume that the Jenkins build process does not fail the build on error_pattern, I need to have an external fail trigger of some sort.
EDIT
Looking for a solution to fail the build during, not a post build task.
You should try the Post Build Task plugin.
You can search for a pattern and then launch a script.
edit:
There is also Text finder plugin, looks better for your problem
As an ugly workaround I do the following: in the build script redirect all the output to some resulting .log file, then you can grep through this file in the background the way you like (personally I do the freezing check additionally - calculate the checksum and compare with previous, if the same - start counting for timeout until threshold), etc...
Disadvantage is the output goes to some file instead of Jenkins console, but I guess you can do both using tee (I don't care, because my goal is to archive the log anyways and send it via email, - so I just gzip my resulting .log file and attach it as an artifact to the build record + to the email).
Advantage is you have full control on what happens in the build output and can interrupt the build using your own return code / message.
I've used this answer as the basis of a pipeline script. In the "Build" stage I have two parallel sub-stages - one of them is doing the actual build and outputting to a log, whilst the other sub-stage is grepping the same log. I've negated the exit code (! grep) so that it'll error when the "ERROR:" string is found. Thanks to the failFast setting, this will cause the whole "Build" stage to fail as soon as the string is found. There's an extra grep at the end of the first sub-stage, in case an error was produced right at the end.
I'm tracking the build status with a variable (BUILD_COMPLETE).
pipeline {
agent {
label 'master'
}
environment {
BUILD_COMPLETE = false
}
stages {
stage('Build') {
failFast true
parallel {
stage('Building') {
steps {
sh 'echo foo | tee output.log'
sleep 5
sh 'echo bar | tee -a output.log'
sleep 5
sh 'echo ERROR: baz | tee -a output.log'
sleep 5
sh 'echo qux | tee -a output.log'
sleep 5
sh '! grep "^ERROR:" output.log'
script {
BUILD_COMPLETE = true
}
}
}
stage('Monitoring the logs') {
steps {
script {
while (BUILD_COMPLETE != true) {
sh '! grep "^ERROR:" output.log'
sleep 1
}
}
}
}
}
}
}
}