Code Monkey home page Code Monkey logo

ci-build-simulator's Introduction

ci-build-simulator

This repository contains a multi-project Gradle build which can be used to seed a Jenkins installation with executed jobs and their corresponding data.

CodeDay Labs

This project exists mainly for use by my CodeDay labs team to generate test data while they create a tool for Developer Productivity that could be used to view some basic analytics about builds.

Tools and Technologies

The main technologies that program makes use of are Gradle, Kotlin, Groovy, Git, and Jenkins, and the conventions are based on empathy and object-oriented thinking.

Please read these:

For Groovy, Kotlin, Git and Jenkins, Google is your friend.

Usage

Environment setup

Default

Install Java 11, and make sure your $JAVA_HOME variable is set to it correctly. If this setup doesn't work, or your machine setup is particularly special/unique, try using the Docker method, as described below.

Docker

To normalize environments so that all dependencies are included automatically without you needing to install anything (other than Docker), you can use Docker to run all the below commands from within a container. Install Docker Desktop from Docker's website. This is via a .dmg file and is pretty easy.

This option only makes sense if you're using SSH authentication for Git.

Here are the instructions for using this repository via Docker:

  1. Build the Docker image with ./docker/build-workspace.sh.
  2. Open the workspace with ./docker/open-workspace.sh. You will enter the shell of a Docker container, in which you can run any of the below-mentioned Gradle tasks. For example, you could try running ./gradlew :sleeper:test.

This works by using a bind mount into the repository's root directory. It basically means that you are really in the same directory, but you're running in an environment which has predefined dependencies and tools installed already.

Creating a simulation

A simulation is a self-perpetuating job which continuously creates builds. It would be pretty boring if the builds were all the same, so in every run, the build modifies the source code on each run, so that subsequent builds are a bit different, in a way that acts as a rudimentary simulation of developers making changes.

Correspondingly, there are two Gradle plugins,

These two Gradle plugins configure some Gradle tasks used for executing CI build simulations.

Gradle plugin: Jenkins

Configures Gradle tasks for managing simulation jobs on Jenkins.

These tasks accept command line arguments as project properties using the -P flag.

Running ./gradlew :sleeper:createSimulationJob -Pbranch=simulation/1 -Purl=http://13.229.56.106:8080 -Puser=jenkins -Ppassword=secret will log into the Jenkins instance running at http://13.229.56.106:8080 using the username jenkins and the password secret, and create a simulation job for the git branch simulation/1. It also creates the branch remotely if it doesn't already exist.

Running ./gradlew :sleeper:deleteSimulationJob -Pbranch=simulation/1 -Purl=http://13.229.56.106:8080 -Puser=jenkins -Ppassword=secret will use the same mechanism to delete the simulation job for this branch.

Simulations are Jenkins jobs with stages defined in the predefined, shared Jenkinsfile. In short, these Jenkins jobs will run the build, run the development simulation Gradle task, and finish by triggering another build if needed. By default, simulations create 5 builds. You can change this by editing the Jenkinsfile on the simulation branch.

Putting in the URL, username and password for Jenkins all the time would be a chore, so instead you can put them in the file buildSrc/src/main/resources/jenkins.properties, which is ignored from version control. For example,

url=http://13.229.56.106:8080
user=jenkins
password=secret

If this file is present, the tasks for this Gradle plugin will use them, and you won't have to supply them on the command line.

Assumptions made by the plugin

  • The indicated Jenkins installation needs to have some appropriate plugins in order to run the jobs correctly. Honestly I don't know what the minimal subset is, but it certainly is a subset (but not necessarily a proper subset) of those seen here.
  • The given branch starts with simulation/ and contains no underscores (_).

Gradle plugin: Simulate Development

Modifies source code for introducing some variety in the build.

For example, running ./gradlew :sleeper:simulateDevelopment will run the development simulation in the sleeper project, which should generate some code.

To configure this plugin, a project which applies it needs to supply an instance of DevelopmentSimulator, which is a functional interface for generating source and test code files. If no instance is supplied, the configured simulateDevelopment task will do nothing.

To pass in a custom implementation of DevelopmentSimulator, use the following code in the project's build.gradle.kts

simulator {
    instance.set( <Instance of your custom implementation here> )
}

Assumptions made by the plugin

  • Main and test sources are both written in Groovy, under the default groovy source set (i.e. src/main/groovy and src/test/groovy)
  • There is a base package ci.build.simulator.<project-name> for both the main and test sources, which is where the plugin will generate code. For example, ci.build.simulator.sleeper. The <project name> is the name of the subdirectory of this repo (i.e. the value within the 'include' call in settings.gradle.kts).
  • The Jenkins instance has a username/password credential configured, called GitHubPushAccess, which holds valid credentials for pushing to this repository's Git remote.

Extending this simulator

Different kinds of project

There are different kinds of projects, whose builds have different kinds of characteristics in terms of test duration, test flakiness, and in other ways too. You may want to generate data for different phases of the build, like creating different kinds of artefacts like JARs, executables, containers or something else. To do this, you'll need to be able to extend this simulator to cover whatever custom requirements you might have.

Let's say you wanted to create simulations for some new kind of build. Let's say you want to do a simulation for a SpringBoot API. I would suggest taking the following steps:

  • Create a new Gradle subproject, like springboot
  • Write code in the springboot subproject so that the API works, has basic tests and meets the assumptions of the above mentioned Gradle plugins.
  • Create a custom implementation of DevelopmentSimulator in buildSrc/src/main/kotlin under the ci.build.simulator.simulate.development.simulators package, called SpringBootDevelopmentSimulator and implement it however you like.
  • Configure the 'development simulation' plugin in springboot/build.gradle.kts so that it uses an instance of the SpringBootDevelopmentSimulator for generating code. Presumably this implementation generates some code that is specific to SpringBoot.
  • You should then be able to create your custom simulations on Jenkins.

Different CI tools

Jenkins is just one CI provider. It's a very popular one, especially at companies with poor developer productivity in my experience. There are many others that you might want to run tests on though. In that case, I would suggest taking the following steps:

  • Add a new Gradle plugin in buildSrc under the package ci.build.simulator.<ci provider name>.
  • Implement it to have the create and delete tasks for simulations, like the Jenkins Gradle plugin.
  • Make sure the simulations created by the plugin work.
  • Apply the plugin wherever you want.
  • You should then be able to create your simulations on the new CI provider.

Developer Productivity

Many excellent software organisations employ teams dedicated to developer productivity. Here are a few examples:

ci-build-simulator's People

Contributors

robmoore-i avatar

Stargazers

Roman avatar

Watchers

James Cloos avatar

Forkers

codeday-clarity

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.