How to Create and Run A Job In Jenkins Using Jenkins Freestyle Project

As per the official Jenkins wiki information, a Jenkins freestyle project is a typical build job or task. This may be as simple as building or packaging an application, running tests, building or sending a report, or even merely running a few commands.

Collating data for tests can also be done by Jenkins. For instance, a real-world scenario could involve Jenkins allowing you to submit reports to log management at any specified stage concerning management, which may include details about artifacts or shipping application logs. In this Jenkins tutorial, we will dive deeper into how to create a job in Jenkins and eventually, a Jenkins freestyle project. Let’s find out more about Jenkins Build Job before we begin creating a Freestyle Project.

What Is a Build Job?

The build jobs are at the heart of any Jenkins build process. To put it plainly, imagine a Jenkins build job as a particular task or step in your entire build process. The task or step could involve merely compiling the source code and running your unit tests over. Or you can configure a build job to do other co-related tasks, such as:

  1. Measuring code coverage or code quality metrics
  2. Running your integration tests
  3. Generating technical documentation
  4. And even deploying the application to a web server

Generally, a real project requires many separate, but related build jobs in a CI or DevOps cycle. Let us first understand what the Jenkins Freestyle Project is and how we can create it.

What Is Jenkins Freestyle Project?

Jenkins supports different types of build jobs. The two most commonly used Jenkins build jobs are:

  1. Freestyle builds
  2. Maven 2/3 builds

The best part about the Jenkins Freestyle Project is that it allows you to configure just about any build job, thus making them highly flexible and configurable. The Maven 2/3 builds, on the other hand, understand the Maven project structure and let you set up Maven build jobs quickly with added features. In a Freestyle build job, you can break down your build job into several smaller build steps, making it easier to organize builds in separate stages. For example, in one step, a build might run a suite of functional tests and then tag the build in a second step if all functional tests are successful. 

It may be appropriate to invoke an Ant task or a Maven target or run a shell script in a technical terms build phase. Various other Jenkins plugins also let you use additional types of build steps. These involve Grails, Gant, Rake, Gradle, Ruby, MSBuild, etc. But what highlights a Jenkins Freestyle project is that it lets you create general-purpose build jobs with maximum flexibility. So the bottom line is that the Freestyle projects allow you to configure just about any build job. 

A Jenkins project involves steps and post-build actions and is a repeatable build job. There are limitations in the types of actions you can perform in a build step or post-build action. Within a Jenkins freestyle project, there are several standard plugins available to help you overcome this problem. These plugins allow you to configure build triggers and offer project-based security for the Jenkins project.

When to Use a Jenkins Freestyle Project

Any access to the shell or a batch environment propagates a high level of security access for the Jenkins Freestyle project. In Freestyle Project environments, it's convenient to create a script that instructs a Jenkins freestyle job to FTP a file from one server to another, compile a directory of Java code, or even run a SonarQube test. 

A Jenkins freestyle job can be as powerful and complex as any build job built with a Jenkins pipeline or a Groovy DSL. However, the only drawback to freestyle projects is that the user must know how to script all of these actions, and developers need to learn how to manage these scripts. Plugins such as Git, Maven, and SonarQube are the preferred way to access resources. Technologically, every developer can write a script to access those resources within a Jenkins freestyle project. 

However, it is recommended that every developer in the development team should follow the guided security best practices and inhibit from adapting a scripted approach.

Creating a Freestyle Build Job

To set up freestyle projects using Jenkins, we need to ensure that we have Jenkins installed and up and running. Also, it is mandatory to be authenticated as the "Admin." 

Once you have Jenkins up and ready, let us create a Jenkins freestyle job. 

Step 1

  1. Get logged on to your Jenkins dashboard through the Jenkins installation path.
  2. Unless you have defined a private host, it will be hosted on the localhost at http://localhost:8080.
  3. In case your Jenkins is installed in another path, make sure to use the appropriate URL to access the dashboard.

Enter user and password information, then click log in

Step 2

Go to the "New Item" option at the top left-hand side of your main dashboard. 

"New Item" optionStep 3

  1. Here, enter the name of the item you want to create. Let us use "Hello World.”
  2. Select Freestyle project as the option for this new item.
  3. Click OK.

Item name and select Freestyle projectWhen we hit Ok, Jenkins automatically takes us to the project configuration view, where we need to configure our project details. Additionally, we can provide intricate details through tab options. The first tab is the general details of the project. So the next step is to enter project details.

Step 4

Enter the project details in the General tab, including the name and description of the project that needs to be tested. 

Enter the project details in the General tab,

Next, let’s understand what the Source Code Management tab does. It checks out code from version control hosts, which implies that if your code is hosted on GitHub or any other repositories, you have to add the repository details. 

Jenkins will clone the repository. 

Source Code Management

The blue question mark icons present at the right-hand bottom side serve us with quick tips, and they can be very resourceful and provide more clarification at times. 

Step 5

Under the Source Code Management(SCM) tab:

  1. Select Git as a repository source and enter your Git Repository URL.
  2. In case you have your repository created locally, it is permissible to use a local repository.
  3. Suppose the GitHub repository you are using is private. In that case, Jenkins will validate the login credentials with GitHub, and upon successful validation, it will then pull the source code from your GitHub repository.

Repository URL After you have provided all the project and repo details, the next part is to build the code. You can manage the settings under the Build section to build the code at your desired time. You can even schedule the build to run periodically if needed. 

Step 6

Go to the Build section and click on the Add build step. 

Under the build section, click on the "Add build step."

Add build step

Then, "Execute Windows batch command" and add the commands you want to execute during the build process.

Execute Windows batch command

For example, Java compile batch commands:Execute Windows batch command

Step 7

When you have entered all the data:

  1. Click Apply.
  2. Save the project.

Step 8

On the left-hand side panel, click the Build Now button to build the source code. 

Build Now

Step 9

We can see the status of the build under Build History

Build History

Step 10

We can verify the history of the executed build under the Build History by clicking the build number. By clicking on the Build Number --> Console Output, it should show you a success or failure message depending on how the job ran. 

Console Output: Finished (Success)

To sum up, we ran a "Hello World" program on GitHub. Jenkins pulled up the source code from the remote repository and continuously built it at a frequency you define.

Jenkins Freestyle Project for Docker Container Images

The below demonstration is about creating a Jenkins Freestyle project that first builds a Docker image and then scans it for any vulnerabilities and compliance issues as a testover.

Enter Item Name

echo "Creating Dockerfile..."
echo "FROM imiell/bad-dockerfile:latest" > Dockerfile
docker build --no-cache -t test/test-image:0.1 .


Scan reports

Jenkins Freestyle Project for Serverless Functions

It is similar to the procedure for container images to set up Jenkins to scan serverless functions, except that you can use the Scan Prisma Cloud Functions construct step. 

Scan Prisma Cloud Functions construct step

Converting a Project From Jenkins Freestyle Project to a Declarative Pipeline

In Jenkins, managing freestyle jobs is cumbersome. Declarative Pipelines offer a more modern and suggested solution. It is time-consuming and error-prone, however, to try to convert Freestyle jobs to Declarative Pipelines manually. You can use the Migration Assistant Declarative Pipeline plugin to streamline this operation. 

During the conversion, the Declarative Pipeline Migration Assistant uses a best-effort approach: supported configurations are converted automatically in Freestyle projects, and placeholder stages are generated for plugins that are not yet supported. The Declarative Pipeline Migration Assistant's advantages include:

Generating a Jenkinsfile From a Project for Freestyle

A centralized configuration file, called a Jenkinsfile, is the basis for pipeline or multi-branch pipeline projects. In the text editor or GUI, a Jenkinsfile can be generated. The file is maintained either with the project code or, for example, a software configuration management (SCM) tool like Git in a separate repository. 

Using an SCM to store the file gives the configuration file a centralized location, enables code review, and provides an audit trail for the pipeline. To build an initial Jenkinsfile, the Declarative Pipeline Migration Assistant uses information from a Freestyle project. The Declarative Pipeline Migration Assistant is only accessible from the Jenkins UI and not from the Jenkins CLI. See Defining Pipeline for more information about pipelines. 

Prerequisites

Two plugins, namely:

Steps to generate a Jenkinsfile from a Freestyle project:

  1. Go to the --> Freestyle project.
  2. From the Freestyle project tab, choose To Declarative from the left navigation menu.

To Declarative


Conversion completed with warnings

The table below exhibits a list of the supported plugins.

Type Step
scm
git
step
shell step
step
batch step
step
Maven build step
build wrapper
Config File Provider plugin
build wrapper
secret (convert to credentials binding)
build wrapper
Build a timeout plugin
job property
Lockable Resources plugin
job property
build parameters
job property
build discarder configuration
build trigger
upstream projects trigger
build trigger
SCM pooling
build trigger
timer trigger
build environment
provide configuration files
build environment
use secret text(s) or file(s)
post-build action
JUnit plugin
post-build action
HTML Publisher plugin
post-build action
trigger another project
post-build action
mail notification
post-build action
Do not fail the build if archiving returns nothing
post-build action
archive artifacts only if the build is successful
post-build action
fingerprint all archived projects

Jenkinsfile Customization

After creating a Jenkinsfile from a Freestyle project, you have a few options.

  1. You can either copy-paste the Jenkinsfile into a text file.
  2. Or, you can download the provided text file and open it in the text editor.
  3. Then, to perform the same tasks performed by the Freestyle project, review the Jenkinsfile and edit as required for the new Pipeline project.

Jenkinsfile Customization

Creating a Pipeline Project in Jenkins and Adding a Jenkinsfile

The next move is to add the Jenkinsfile as the configuration file to a Pipeline or Multibranch Pipeline project after creating a Jenkinsfile from a Freestyle project and editing the Jenkinsfile. Creating the Jenkins pipeline project first. Then, by copying and pasting the Jenkinsfile into the Pipeline editor or storing it in an SCM like GitHub and linking the repository to the Pipeline project, add the Jenkinsfile to your project. Steps to create a Pipeline project and adding the Jenkinsfile:

Step 1

In Jenkins, create a pipeline project and copy and paste the Jenkinsfile text into the editor of the pipeline. 

Step 2

Store the Jenkinsfile in a repository for SCM such as GitHub and:

Extending the Declarative Pipeline Migration Assistant Plugin

A small number of plugins are currently supported by the Declarative Pipeline Migration Assistant plugin. For a list of plugins supported, see the table above. Beyond this list, if you want to add support for a particular plugin that is currently not supported, it involves attaching the API dependency to the converter and creating the extension. 

Adding the API Dependence of the Converter

The following code snippet illustrates how to add a dependency on the converter API:

      org.jenkins-ci.plugins.to-declarative
      declarative-pipeline-migration-assistant-api
      
    


Creating the Extension

The following code snippet is an illustration of how to create the extension:

```
@Extension
public class ShellConverter extends SingleTypedConverter
    @Override
    public boolean convert( ConverterRequest request, ConverterResult result, Object target )
    {
      Shell shell = (Shell) target;
      /* Do some work to generate a new stage . . . */
      ModelASTStage stage = new ModelASTStage( this );
      // use a utility method to add the stage to the pipeline model
      ModelASTUtils.addStage( request.getModelASTPipelineDef(), stage);

      // true for success, false for failure
      return true;
    }
```


Example Conversions

The abstract class SingleTypedConverter<T> defines the extension of the conversion.

Example Build Step Conversion

The following code snippet is an illustration of how to convert a Shell script Freestyle step using the API:

```
@Extension
public class ShellConverter extends SingleTypedConverter
{
  @Override
  public boolean convert (ConerterRequest request, ConverterRequest result, Object target )
    {
        Shell shell = (Shell) target;
        ModelASTStage stage = new ModelASTStage( this );
        int stageNumber = request.getAndIncrement( SHELL_NUMBER_KEY );  
        stage.setName( "Shell script " + stageNumber );
        ModelASTBranch branch = new ModelASTBranch( this );  
        stage.setBranches( Arrays.asList( branch ) );  
        ModelASTStep step = new ModelASTStep( this );  
        step.setName( "sh" );  
        ModelASTSingleArgument singleArgument = new ModelASTSingleArgument( this );
        singleArgument.setValue( ModelASTValue.fromConstant( shell.getCommand(), this ) ); 
        step.setArgs( singleArgument );
        ModelASTUtils.wrapBranch(result, step, branch); 
        ModelASTUtils.addStage(result.getModelASTPipelineDef(), stage); 
        return true;
    }
}
```


Example Build Wrapper Conversion

The following example converts the Config File Freestyle wrapper build using the API. This conversion uses a helper method to add a wrapper around all future build step conversions.

```
// This was to not have the config-file-provider plugin as a required dependency
// But you can use (as you use your plugin)
@OptionalExtension(requirePlugins = { "config-file-provider" })
public class ConfigFileBuildWrapperConverter extends SingleTypedConverter
{
    private Logger LOGGER = LoggerFactory.getLogger( ConfigFileBuildWrapperConverter.class );

    @Override
    public boolean convert(ConverterRequest request, ConverterResult result, Object target)
    {
        ConfigFileBuildWrapper configFileBuildWrapper = (ConfigFileBuildWrapper) target;
        if(configFileBuildWrapper.getManagedFiles() == null || configFileBuildWrapper.getManagedFiles().isEmpty() )
        {
            return true;
        }

        result.addWrappingTreeStep( () -> build( configFileBuildWrapper) ); 
        return true;
    }

    private ModelASTTreeStep build(ConfigFileBuildWrapper configFileBuildWrapper) {
        ModelASTTreeStep configFileProvider = new ModelASTTreeStep( this );

        configFileProvider.setName( "configFileProvider" );
        ModelASTSingleArgument singleArgument = new ModelASTSingleArgument( null );
        configFileProvider.setArgs( singleArgument );

        ManagedFile managedFile = configFileBuildWrapper.getManagedFiles().get( 0 ); 
        StringBuilder gstring = new StringBuilder( "[configFile(fileId:'" );
        gstring.append( managedFile.getFileId());
        gstring.append( "', targetLocation: '" );
        gstring.append( managedFile.getTargetLocation() );
        gstring.append( "')]" );
        singleArgument.setValue( ModelASTValue.fromGString( gstring.toString(), this ) );
        return configFileProvider;
    }
}
```


Example Publisher Conversion

The following example converts the ArtifactArchiver Freestyle post-build step using the API. This conversion modifies the model to add some build conditions.

```
@Extension
public class ArtifactArchiverConverter extends SingleTypedConverter {
    @Override
    public boolean convert(ConverterRequest request, ConverterResult result, Object target) {
        ArtifactArchiver artifactArchiver = (ArtifactArchiver) target;
        ModelASTBuildCondition buildCondition;
        if(artifactArchiver.isOnlyIfSuccessful()) { 
            buildCondition = ModelASTUtils.buildOrFindBuildCondition( result.getModelASTPipelineDef(), "success" );
        } else {
            buildCondition = ModelASTUtils.buildOrFindBuildCondition( result.getModelASTPipelineDef(), "always" );
        }
        ModelASTStep archiveArtifacts = ModelASTUtils.buildGenericStep(artifactArchiver, this);
        ModelASTUtils.addStep(buildCondition, archiveArtifacts); 
        return true;
    }
}
```


Depending on which condition the artifact needs to be executed, we add the step to the build condition. 

Example SCM Conversion 

The following example converts the Git SCM Freestyle stage using the API. This conversion adds a stage to the Pipeline model.

```
@OptionalExtension(requirePlugins = { "git"})
public class GitScmConverter extends SingleTypedConverter
{
  @Override
  public boolean convert(ConverterRequest request, ConverterResult result, Object target)
    {
        List repoList = ( (GitSCM) target ).getUserRemoteConfigs();
        if(repoList.isEmpty()){
            return true;
        }
        ModelASTStage stage = new ModelASTStage( this ); 
        stage.setName( "Checkout Scm" );
        List steps = new ArrayList<>(); 
        // a step will be created per remote repository
        for( UserRemoteConfig userRemoteConfig : repoList) 
        {
            ModelASTStep git = new ModelASTStep( null ); 
            git.setName( "git" );

            Map args = new HashMap<>();
            {
                ModelASTKey url = new ModelASTKey( this ); 
                url.setKey( "url" );
                ModelASTValue urlValue = ModelASTValue.fromConstant( userRemoteConfig.getUrl(), this );
                args.put( url, urlValue );
            } 

            ...

            ModelASTNamedArgumentList stepArgs = new ModelASTNamedArgumentList( null);  
            stepArgs.setArguments( args );
            git.setArgs( stepArgs );
            steps.add( git );
        }

        ModelASTBranch branch = new ModelASTBranch( this ); 
        branch.setSteps(steps);
        stage.setBranches( Arrays.asList( branch ) );
        ModelASTUtils.addStage(result.getModelASTPipelineDef(), stage ); 
        return true;
    }
}
```


  1. Create a new stage.
  2. Steps will be generated as: - git url: "", branch: '', changelog: '', credentialsId: '', pool: ''
  3. A step is created based on each remote repository.
  4. Create the Git step.
  5. Add parameters - URL.
  6. In the original code, add more parameters.
  7. Configure args of the step.
  8. Create a branch for the stage.
  9. Use a utility method to add the stage to the Pipeline model.

Example Build Trigger Conversion

Using the API, the following example transforms the cron trigger. The pipeline mode is changed by this conversion to add a trigger property through a utility process.

@Extension
public class TimerTriggerConverter extends SingleTypedConverter
{
    @Override
    public boolean convert(ConverterRequest request, ConverterResult result, Object target)
    {
        TimerTrigger timerTrigger = (TimerTrigger) target;

        String cronValue = timerTrigger.getSpec();
        ModelASTTrigger modelASTTrigger = new ModelASTTrigger( this ); 
        modelASTTrigger.setName( "cron" );
        modelASTTrigger.setArgs( Arrays.asList(ModelASTValue.fromConstant( cronValue, this )) );

        ModelASTUtils.addTrigger( result.getModelASTPipelineDef(), modelASTTrigger );  
        return true;
    }
}


That’s how you can create your very own pipeline projects! 

Wrapping Up!

In this blog, we saw the central feature of Jenkins learning how to create a job in Jenkins, Jenkins build jobs, and creating pipeline projects. Through the Jenkins Freestyle Project, you can build your project, and combine any SCM with any build system. We also saw a few extensions of Freestyle projects like the Docker container images.

The conversion of freestyle projects into Declarative Pipelines offers a more modern and suggested solution. Let us know what you feel about this blog in the comments below. Try reproducing the steps for Jenkins to create and build a job to learn on the go. 

Happy testing!

 

 

 

 

Top