Jenkins: how to make parameters required in a parameterized build? - continuous-integration

In Jenkins is there a plugin for parameterized builds to make the parameters required? The fields under the standard "This build is parameterized" option do not seem to provide that.
Clarification: by "required" I mean that the build will not execute until the field is populated with a value. This would obviously preclude automated triggers.

The accepted answer is no longer valid.
There was a plugin that did that but is no longer maintained.
There's an open bug to support it.
In the mean time what you can do is check if your parameter is present and if not throw an error like:
if (!params.SomeParam) {
error("Build failed because of this and that..")
}

This is the plugin i use to do this type of stuff: link...
You can set a regular expression to validate the input against

Couldn't comment to answer Miguel's question, so answering here:
To fail a build if a parameter is not set, one could do something like this:
stage('Checkout')
{
steps
{
checkout scm
script
{
if (params.myParam == '') { // and/or whatever condition you want
currentBuild.result = 'ABORTED'
error('myParam not set')
}
}
}
}

There's a plugin called "Validating String Parameter". When you install this plugin in your project, you see an additional option of Validating String Parameter while adding parameters. Using this option will show an additional column of Regular expression.
For non-empty string parameter write this inside Regular Expression field:
^(?!\s*$).+
This will finally make your string parameter mandatory.

Related

Why does Sonarqube mark try as a critical issue?

I'm currently facing an issue with some SonarQube's analysis being performed over some Kotlin code I wrote.
I'm trying to implement a method that connects to the database and returns accordingly to the query's result. I'm not sure how related this can be, but I added the following maven dependencies to my project:
Quarkus
Arrow
Ktorm
The code is the following:
#ApplicationScoped
class Repository(private val database: Database) {
override fun get(name: String): Either<Error, Brand> =
try {
database.brands.find { it.name eq name }.rightIfNotNull {
MissingBrandError("Missing brand")
}
} catch (e: Exception) {
Either.Left(DatabaseError(e.message))
}
}
class Error(val message: String)
class MissingUserError(val message: String) : Error(message)
class DatabaseError(val message: String? = null) : Error(message ?: "Some database error")
NOTE: Database object is of type org.ktorm.database.Database and brands is of type org.ktorm.entity.EntitySequence
The code is working and I also wrote unit tests for it that pass and give enough coverage (accordingly to the code coverage analysis tool), but at some point in my pipeline SonarQube marks the try as a critical issue with the following message:
Possible null pointer dereference in (...)Repository(String) due to return value of called method
I checked it online and I could find some related questions, but none of the provided answers worked for me. Amongst the many attempts these are the ones I can remember I tried without any success:
Not inlining any code (pretty much using Java style code)
Extracting the query result to a variable
Check with if/else statements for nullability instead (both with inlined try and without)
I'd also like to highlight that all I can see on Sonar is the generated report and CLI for the running build. I don't have access to any of its configuration or intended to change them (unless of course it comes down to that). The line I mentioned seems to be the only one affected by this problem according to Sonar's report, that's why this is the solo class I provided.
I hope I provided enough info and that any of you can help me with this. Thanks in advance.

Dynamically changing 'teamcity.build.branch'

I want to set the value of 'teamcity.build.branch' dynamically according to the result of another TC build configuration part of the build pipeline.
Is that even possible? It looks like the value is evaluated and used at the start of the build pipeline.
UseCase:
I am executing a TC build configuration that will generate a unique number
in the connected TC build configuration part of the same pipeline I want the number to be used in the 'teamcity.build.branch' - just for visualization purposes
I am already using message service to overwrite the parameter, but the change is not taken into account. It looks like the value is read in the very early stage of the build process.
Check below reference containing build number and git branch name
https://octopus.com/blog/teamcity-version-numbers-based-on-branches
You could overwrite the value of the parameter by using a simple script that emits a "set parameter" service message.
By using a dedicated service message in your build script, you can dynamically update build parameters of the build right from a build step (...)
With that approach, here are the steps that you need to perform:
In the first build config, define a custom build parameter and set its value to the unique number you're generating. Do this directly from the script that generates the unique number by writing something like this to STDOUT:
##teamcity[setParameter name='magicNumber' value='1234']
In the dependent build config, you now have access to that parameter. Using a second build script, you can overwrite the teamcity.build.branch with the same mechanism:
##teamcity[setParameter name='teamcity.build.branch' value='the new value']
Note 1: I recommend against overwriting the built-in parameters, because this might have strange side-effects. Rather, define a custom parameter in the second build config and use that for your visualization purposes.
Note 2: In case you decide to ignore Note 1, it may be necessary to overwrite the build parameters by setting the dependency property as outlined in the docs in section "Overriding Dependencies Properties":
##teamcity[setParameter name='reverse.dep.*.teamcity.build.branch' value='the new value']

Grails define custom error message for command object

I am writing a Grails (2.3.3 currently) application and have created a validateable command object similar to the following:
#Validateable
class MyCustomCommand {
String name
static constraints = {
name blank: false
}
}
In my i18n/messages.properties file I defined the following properties to override the default error messages.
MyCustomCommand.name.blank=Name must be provided.
MyCustomCommand.name.null=Name must be provided.
Which per the Grails documentation should be of the format [Class Name].[Property Name].[Constraint Code] as I have done. When I run my application if I leave the value blank I still get the default message for a null property.
I also tried following the example of the default messages and defining them a follows, but still get the default message.
MyCustomCommand.name.blank.message=Name must be provided.
MyCustomCommand.name.null.message=Name must be provided.
I am assuming that I am missing something simple here, but have yet to stumble upon what. Any suggestions on what I am doing incorrectly?
It is simple indeed. Message should look like:
myCustomCommand.name.blank=Name must be provided.
myCustomCommand.name.nullable=Name must be provided.
//className.propertyName.blank (camelCase with first letter of class name lower)
So, as I anticipated it was something simple. I was using the defaults as an example which used null where as what I really needed was nullable. Which does make sense as that matches the constraint name.
Therefore the correct version is:
myCustomCommand.name.blank=Name must be provided.
myCustomCommand.name.nullable=Name must be provided.

How do I use inputs.property on a Gradle task, but with a closure for a value?

I'm trying to add an installer builder to my build configuration and I'm having a little trouble getting task inputs set up properly. I have the configuration split into a separate .gradle file and I add it to my project by doing the following.
project.ext.i4jArgs = [ "--verbose" ]
apply from: rootProject.projectDir.absolutePath + "/gradle/install4j.gradle"
To build the installers I'm calling a command line tool via exec. Almost everything is based on convention, but I want to optionally add a couple arguments / switches to the command from my main build file. I do it using the project.ext.i4jArgs property (above).
If I set the project.ext.i4jArgs property before applying my install4j.gradle file, I can use the following for inputs and everything seems to work.
inputs.property("i4jArgs", project.ext.has('i4jArgs') ? project.ext.i4jArgs : null)
However, if I apply my install4j.gradle file first and set the project.ext.i4jArgs property second, the project.ext.i4jArgs property is always null when I'm declaring inputs in my task (obviously). The API for TaskInputs (here) says I can pass a closure as a value. Is there a way I can use a closure to delay the evaluation of the project.ext.i4jArgs long enough to guarantee it's been initialized? I though the following would work, but the closure never gets called.
inputs.property("i4jArgs", {
project.afterEvaluate {
println "has args ${project.ext.has('i4jArgs')}"
project.ext.has('i4jArgs') ? project.ext.i4jArgs : null
}
})
I know writing a plugin that supports all the configuration I want might be a better option for the specific example I've given, but I'd like to figure out what I'm misunderstanding here anyway.
I would remove project.afterEvaluate in the first closure. This is for adding a closure that gets executed after the project has been configured.
What is actually going on is when gradle resolves the inputs, it calls the first closure, which then calls project.afterEvaluate, which adds a closure to the list that will be called when the project is done configuring... which will never be called because it is now in the execution phase.

Jenkins - passing variables between jobs?

I have two jobs in jenkins, both of which need the same parameter.
How can I run the first job with a parameter so that when it triggers the second job, the same parameter is used?
You can use Parameterized Trigger Plugin which will let you pass parameters from one task to another.
You need also add this parameter you passed from upstream in downstream.
1.Post-Build Actions > Select ”Trigger parameterized build on other projects”
2.Enter the environment variable with value.Value can also be Jenkins Build Parameters.
Detailed steps can be seen here :-
https://itisatechiesworld.wordpress.com/jenkins-related-articles/jenkins-configuration/jenkins-passing-a-parameter-from-one-job-to-another/
Hope it's helpful :)
The accepted answer here does not work for my use case. I needed to be able to dynamically create parameters in one job and pass them into another. As Mark McKenna mentions there is seemingly no way to export a variable from a shell build step to the post build actions.
I achieved a workaround using the Parameterized Trigger Plugin by writing the values to a file and using that file as the parameters to import via 'Add post-build action' -> 'Trigger parameterized build...' then selecting 'Add Parameters' -> 'Parameters from properties file'.
I think the answer above needs some update:
I was trying to create a dynamic directory to store my upstream build artifacts so I wanted to pass my upstream job build number to downstream job I tried the above steps but couldn't make it work. Here is how it worked:
I copied the artifacts from my current job using copy artifacts plugin.
In post build action of upstream job I added the variable like "SOURCE_BUILD_NUMBER=${BUILD_NUMBER}" and configured it to trigger the downstream job.
Everything worked except that my downstream job was not able to get $SOURCE_BUILD_NUMBER to create the directory.
So I found out that to use this variable I have to define the same variable in down stream job as a parameter variable like in this picture below:
This is because the new version of jenkins require's you to define the variable in the downstream job as well. I hope it's helpful.
(for fellow googlers)
If you are building a serious pipeline with the Build Flow Plugin, you can pass parameters between jobs with the DSL like this :
Supposing an available string parameter "CVS_TAG", in order to pass it to other jobs :
build("pipeline_begin", CVS_TAG: params['CVS_TAG'])
parallel (
// will be scheduled in parallel.
{ build("pipeline_static_analysis", CVS_TAG: params['CVS_TAG']) },
{ build("pipeline_nonreg", CVS_TAG: params['CVS_TAG']) }
)
// will be triggered after previous jobs complete
build("pipeline_end", CVS_TAG: params['CVS_TAG'])
Hint for displaying available variables / params :
// output values
out.println '------------------------------------'
out.println 'Triggered Parameters Map:'
out.println params
out.println '------------------------------------'
out.println 'Build Object Properties:'
build.properties.each { out.println "$it.key -> $it.value" }
out.println '------------------------------------'
Just add my answer in addition to Nigel Kirby's as I can't comment yet:
In order to pass a dynamically created parameter, you can also export the variable in 'Execute Shell' tile and then pass it through 'Trigger parameterized build on other projects' => 'Predefined parameters" => give 'YOUR_VAR=$YOUR_VAR'. My team use this feature to pass npm package version from build job to deployment jobs
UPDATE: above only works for Jenkins injected parameters, parameter created from shell still need to use same method. eg. echo YOUR_VAR=${YOUR_VAR} > variable.properties and pass that file downstream
I faced the same issue when I had to pass a pom version to a downstream Rundeck job.
What I did, was using parameters injection via a properties file as such:
1) Creating properties in properties file via shell :
Build actions:
Execute a shell script
Inject environment variables
E.g : properties definition
2) Passing defined properties to the downstream job :
Post Build Actions :
Trigger parameterized build on other project
Add parameters : Current build parameters
Add parameters : predefined parameters
E.g : properties sending
3) It was then possible to use $POM_VERSION as such in the downstream Rundeck job.
/!\ Jenkins Version : 1.636
/!\ For some reason when creating the triggered build, it was necessary to add the option 'Current build parameters' to pass the properties.
Reading through the answers, I don't see another option that I like so will offer it as well. I love the parameterization of jobs, but it doesn't always scale well. If you have jobs which are not directly downstream of the first job but farther down the pipeline, you don't really want to parameterize every job in the pipeline so as to be able to pass the parameters all the way through. Or if you have a large number of parameters used by a variety of other jobs (especially those not necessarily tied to one parent or master job), again parameterization doesn't work.
In these cases, I favor outputting the values to a properties file and then injecting that in whatever job I need using the EnvInject plugin. This can be done dynamically, which is another way to solve the issue from another answer above where parameterized jobs were still used. This solution scales very well in many scenarios.
This could be done via groovy function:
upstream Jenkinsfile - param CREDENTIALS_ID is passed downsteam
pipeline {
stage {
steps {
build job: "my_downsteam_job_name",
parameters [string(name: 'CREDENTIALS_ID', value: 'other_credentials_id')]
}
}
}
downstream Jenkinsfile - if param CREDENTIALS_ID not passed from upsteam, function returns default value
def getCredentialsId() {
if(params.CREDENTIALS_ID) {
return params.CREDENTIALS_ID;
} else {
return "default_credentials_id";
}
}
pipeline {
environment{
TEST_PASSWORD = credentials("${getCredentialsId()}")
}
}
You can use Hudson Groovy builder to do this.
First Job in pipeline
Second job in pipeline
I figured it out!
With almost 2 hours worth of trial and error, i figured it out.
This WORKS and is what you do to pass variables to remote job:
def handle = triggerRemoteJob(remoteJenkinsName: 'remoteJenkins', job: 'RemoteJob' paramters: "param1=${env.PARAM1}\nparam2=${env.param2}")
Use \n to separate two parameters, no spaces..
As opposed to
parameters: '''someparams'''
we use
paramters: "someparams"
the " ... " is what gets us the values of the desired variables. (These are double quotes, not two single quotes)
the ''' ... ''' or ' ... ' will not get us those values. (Three single quotes or just single quotes)
All parameters here are defined in environment{} block at the start of the pipeline and are modified in stages>steps>scripts wherever necessary.
I also tested and found that when you use " ... " you cannot use something like ''' ... "..." ''' or "... '..'..." or any combination of it...
The catch here is that when you are using "..." in parameters section, you cannot pass a string parameter; for example This WILL NOT WORK:
def handle = triggerRemoteJob(remoteJenkinsName: 'remoteJenkins', job: 'RemoteJob' paramters: "param1=${env.PARAM1}\nparam2='param2'")
if you want to pass something like the one above, you will need to set an environment variable param2='param2' and then use ${env.param2} in the parameters section of remote trigger plugin step
You can also make a job write into a properties file somewhere and have another job read it. One of the way to do that is to inject variables via EnvInject plugin.

Resources