Giter Club home page Giter Club logo

jervis's Introduction

Jervis: Jenkins as a service

Build Status Coverage Status Maven Central Release GH commits since latest release

  • Project status: released to maven central.
  • Currently Targeted platforms:
    • Jenkins server host: Linux and Mac OS X (Windows compatible)
    • Jobs on clients: Linux only (Multi-platform capable)
What is Jervis?

Documentation

The library API is also fully documented. To generate the latest developer docs execute the following command.

./gradlew groovydoc

The documentation can be found in build/docs/groovydoc.

Provided examples

More about Jervis

Jervis is a combination of some letters in the words Jenkins and Travis: JEnkins tRaVIS. Jenkins is a continuous integration tool which is typically installed on premises. Travis is a hosted, distributed continuous integration system used by many open source projects. Both Jenkins and Travis have paid and enterprise offerings.

Jervis uses Travis-like job generation using the Job DSL plugin and groovy scripts. It reads the .jervis.yml file of a project and generates a job in Jenkins based on it. If .jervis.yml doesn't exist then it will fall back to using the .travis.yml file.

For development planning and other documentation see the Jervis wiki. If you wish to stay up to date with the latest Jervis news then please feel free to watch this repository because I use the issue tracking and wiki for planning.

Why Jervis?

What is Jervis attempting to scale? Let's talk about some scale bottlenecks that have been overcome by Jenkins (formerly Hudson) and its community.

The scaling issue is a main bullet. The solution for the issue is in a sub-bullet.

  • Developers are challenged with integrating work, building often, and even deploying often.
    • Jenkins was invented.
  • Jenkins infrastructure is strained when too many agents are in one server and too many jobs are queued up on a daily basis. A single Jenkins server struggles to perform all requested builds in a timely manner. Jenkins also suffers from single point of failure as a lone server.
    • Multi-controller Jenkins was invented. This provides redundancy for the server. Throughput for daily build capacity is improved.
  • Jenkins jobs suffer from a lot of duplicate code. It is difficult to fix a bug in one job and have it propagate to other jobs.
    • Jenkins Job DSL plugin was invented. Configuration through code is now possible. Multiple jobs can be generated and regenerated with the same code using templates in a domain specific language.
  • Onboarding new projects in a Jenkins installation can be difficult. Typically engineers will get together and discuss the needs of the project and then configure a Jenkins job for the needs of the project. For enterprises with a very large number of projects it is typically hard to scale number of build engineers to match with the large number of projects which require onboarding into the build ecosystem.
    • Jervis is being invented. Job generation through convention over configuration. Scaling the onboarding for a project by creating and abiding by conventions in how jobs are generated. This is for large scale job generation and project onboarding. Jervis is taking lessons learned from a seasoned build engineer and attempting to fill this gap in the Jenkins ecosystem.

Set up

To include this library for use in your Job DSL plugin scripts you only need include it in your build tool.

Maven

<dependency>
  <groupId>net.gleske</groupId>
  <artifactId>jervis</artifactId>
  <version>2.0</version>
  <type>pom</type>
</dependency>

Gradle

Your Job DSL scripts should have a build.gradle file which has the following contents.

apply plugin: 'maven'

repositories {
    mavenCentral()
}


configurations {
    libs
}

dependencies {
    libs 'net.gleske:jervis:2.0'
    libs 'org.yaml:snakeyaml:2.0'
}

task cleanLibs(type: Delete) {
    delete 'lib'
}

task libs(type: Copy) {
    into 'lib'
    from configurations.libs
}

defaultTasks 'clean', 'libs'
clean.dependsOn cleanLibs

Then execute ./gradlew libs to assemble dependencies into the lib directory of the Jenkins workspace. Don't forget to add lib to the classpath. This must be done before you configure your Jenkins job to execute Job DSL scripts.

Interactive debugging

Groovy Console is built into the Gradle file.

./gradlew console

Other development commands

Generate code coverage reports.

./gradlew clean check jacocoTestReport

Build the jar file.

./gradlew clean jar

Sign build jars and sign archives.

./gradlew clean check signArchives

See also RELEASE.md.

Local SonarQube Analysis

See SonarQube README.

License

Copyright 2014-2024 Sam Gleske

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

jervis's People

Contributors

samrocketman avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jervis's Issues

Add GitHub API request header Accept

The GitHub API recommends setting the version of the API to interact with GitHub. They recommend setting it if you're building an application and care about stability.

Accept: application/vnd.github.v3+json

Matrix job support

Jervis needs to create matrix jobs from more complicated .jervis.yml files which test multiple things.

Generic class for string interpolation

See groovy example in #28 for interpolating ${jervis_toolchain_ivalue}.

import groovy.json.JsonSlurper
def file='/tmp/toolchains.json'
toolchains = new groovy.json.JsonSlurper().parse(new File(file).newReader())
ArrayList interpolate_ivalue(ArrayList cmds, String ivalue) {
    def z = []
    cmds.each{ z << it.replace('${jervis_toolchain_ivalue}',ivalue) }
    z
}
println interpolate_ivalue(toolchains['rvm']['*'],'2.1.5').join('\n')
//println toolchains['rvm']['*'].join('\n')

It will not be exactly that but along those lines... perhaps renaming the fileIO class to support more than just the readFile() command. It would be something akin to a helper class for extended .jervis.yml features.

Data structure for commands in supported languages

Generic format

This is the general description of the supported language format listing default commands. This will be used to generate default commands depending on the language and files detected in the repository.

{
    "language": {
        "defaultKey": "somekey",
        "somekey": {
            "fileExistsCondition": ["/root/path", "somefile"],
            "fallbackKey": "some other key",
            "before_install": "some command",
            "install": "some command",
            "before_script": "some command",
            "script": "some command",
            "after_success": "some command",
            "after_failure": "some command",
            "after_script": "some command",
        },
        "some other key": {
            "fileExistsCondition": ["/root/path", "somefile"],
        }
    }
}
  • "language" - is the language that the commands are set up for. e.g. groovy, python, ruby, java, etc. The language is the root key of the object and will be used to look up default commands for all of the different command generation cases. The following keys fall under the language. Validation: This key is required.
    • "defaultKey" - This is the default key which will be used to look up the default commands to be generated. Validation: This key is required. The value of this key must exist as another key in the same level as this key.
    • "somekey" - This key is one or more keys in which will, by convention, be named after the build tool the commands are related to. e.g. gradle, ant, maven, etc.

A more specific formatted example

Here's an example of our supported language key when we're supporting just the groovy language based on "Building a Groovy project" Travis CI Documentation.

{
    "groovy": {
        "defaultKey": "gradle",
        "gradle": {
            "fileExistsCondition": ["/", "build.gradle"],
            "fallbackKey": "maven",
            "before_install": "",
            "install": "gradle assemble",
            "before_script": "",
            "script": "gradle check",
            "after_success": "",
            "after_failure": "",
            "after_script": "",
        },
        "maven": {
            "fileExistsCondition": ["/", "pom.xml"],
            "fallbackKey": "ant",
            "install": "mvn install -DskipTests=true",
            "script": "mvn test",
        },
        "ant": {
            "fileExistsCondition": ["/", "pom.xml"],
            "install": "mvn install -DskipTests=true",
            "script": "mvn test",
        }
    }
}

If readFile(/somefile) is used then it should read the file from the filesystem relative to the root of the repository. That logic would look something like this...

x="readFile(/path/to/file.sh)"
if (x[0..8] == 'readFile(') {
    println "Read the file ${x[9..-2]}"
}
else {
    println "Handle the string as a script on a single line."
}

Add getFolderListing() to standard remotes api

This should return an ArrayList that is a simple list of folders and files. This way we can load the list of files into the lifecycleGenerator to be used to generate the shell code.

Secure field support

#16 implements support for RSA encrypted strings. Implement support for the secure: field in .jervis.yml files. Execution in Jenkins should look something like this.

set +x
echo "Executing secure section."
#some decrypted secure section execution
set -x
#normal execution

Note: this would generate the secure contents as plain text inside of the Jenkins job so only Jenkins administrators should be able to see the Job configuration.

Refactor securityIO class so that it is not using scmGit

securityIO class issuing git commands as part of it's instantiation causes issues when working with the Job DSL plugin. It should be refactored so it is no longer using scmGit and users of the library will have to be explicit about the paths of the keys being used.

Create a loadDefaults function which loads resources from the jervis library

http://stackoverflow.com/questions/574809/load-a-resource-contained-in-a-jar

Seems achievable if we treat the resources as streams and use the loadLifecyclesString and loadToolchainsString functions.

Then a user can simply call code like...

import jervis.lang.lifecycleGenerator
def generator = new lifecycleGenerator()
generator.loadDefaults()
generator.loadYamlString('language: ruby')

The generator.loadDefaults() function would call generator.loadLifecyclesString(java.lang.String) and generator.loadToolchainsString(java.lang.String) functions. More testing needed ๐ŸŽฏ

Better defined exceptions for Jervis classes

I would like better defined exceptions. For example,

throw new MissingKeyException(transNbr, originalException);

Rather than a simple,

throw new Exception("some message")

Exceptions should ideally extend from better defined exceptions from the default list of exceptions. An example where poorly defined exceptions are being used is the lifecycleValidator.

Get Jenkins Groovy version

Get version of groovy in Jenkins. Visit Manage Jenkins > Manage Nodes > master > Script Console. Then execute the following code.

println GroovySystem.version

Jenkins ver. 1.590 is running Groovy 1.8.9. All unit tests should be tested with Groovy 1.8.9 until they update it.

Improve groovydoc support

Must be able to generate Jervis api docs using groovydoc in gradle.

gradle groovydoc

It currently generates the groovydoc. However, the documentation is pretty horrible. This will need to be improved.

ruby support

Jervis needs to support building ruby projects.

Plugin detection

Jervis needs to allow a core and recommended Jenkins plugins to co-exist. As recommended plugins are installed then Jenkins provides more features automaticaly. e.g. virus scanning of artifacts when the ClamAV plugin is installed.

plugins = []
default_plugins = ["Plugin:pam-auth", "Plugin:antisamy-markup-formatter", "Plugin:maven-plugin", "Plugin:cvs", "Plugin:external-monitor-job", "Plugin:credentials", "Plugin:mailer", "Plugin:subversion", "Plugin:translation", "Plugin:matrix-project", "Plugin:ssh-credentials", "Plugin:ant", "Plugin:ldap", "Plugin:junit", "Plugin:javadoc", "Plugin:windows-slaves", "Plugin:matrix-auth", "Plugin:ssh-slaves", "Plugin:scm-api", "Plugin:mapdb-api"]
installed_plugins = []
hudson.model.Hudson.instance.pluginManager.plugins.each {
    plugins << it.toString()
}
println "Installed plugins:"
plugins.each {
    if(!(it in default_plugins)) {
        installed_plugins << it
    }
}
installed_plugins.each { println it }
null

loadYaml vs loadYamlString

loadYaml currently takes a String which is the contents of a YAML file. However, loadToolchains and loadLifecycles arguments are a String that is a file path to read the contents of a file. loadToolchainsString and loadLifecyclesString uses a String which contains the contents of the respective files.

Therefore, loadYaml should be renamed to loadYamlString. loadYamlString will take a String which is the contents of a YAML file.

loadYaml will now be a file path to read the contents of a file.

Toolchain support

Need a nifty way of storing toolchains that are easy to extend similar to how lifecycles was done.

Parse YAML file

Tested in Jenkins ver. 1.590. Tried this after reading JENKINS-19401. This is how I will parse the .travis.yml.

@Grab(group='org.yaml', module='snakeyaml', version='1.14')
import org.yaml.snakeyaml.Yaml

def my_yaml = "language: ruby\nrvm:\n - 1.9.3\n - 2.0.0\n - 2.1.1"

println my_yaml

Yaml yaml = new Yaml()
def build_info = yaml.load(my_yaml)
//print all the versions of ruby in rvm to test
build_info.rvm.each {
  println build_info.language + " " + it
}
println build_info

Cobertura code coverage falsely fails with Groovy 2.1.X and later

This issue has already been tracked in the upstream project cobertura/cobertura#184. Code coverage drastically goes down when performing code coverage on Groovy 2.1.X and later. This is a bug in cobertura.

This issue is simply to link the upstream issue as a known issue. This is not currently an issue for Jervis because Jenkins embeds Groovy 1.8.9. However, if the Groovy runtime in Jenkins is upgraded this will definitely become an issue.

NullPointer Exception bug filed with Groovy project

This issue is to track a bug report opened with the Groovy project.

Passing Groovy versions:

1.8.9, 2.0.8, 2.1.9, 2.2.2, 2.3.0

Affects Groovy Version/s:

2.3.1, 2.3.2, 2.3.3, 2.3.4, 2.3.5, 2.3.6, 2.3.7, 2.3.8, 2.3.9, 2.4.0-rc-1

Testing Environments:

OS: Ubuntu 14.04 LTS
Java: JDK 1.7.0_65, vendor: Oracle Corporation 24.65-b04
Gradle 2.2.1

OS: Ubuntu 12.04 LTS
Java version: JDK 1.7.0_72, vendor: Oracle Corporation
Gradle 2.2.1

Description

When traversing a HashMap that was created from a parsed JSON file my unit tests start failing on Groovy versions 2.3.1 and later. There seems to be some sort of regression introduced.

To explore and debug this problem you may view my travis builds testing the latest versions of Groovy from 1.8.9 through 2.4.0-rc-1.

https://travis-ci.org/samrocketman/jervis/builds/45633511

If you would like to check out and debug the problem yourself you can do the following:

git clone https://github.com/samrocketman/jervis.git
cd jervis
git checkout 2590bf2be5f8f2aaa1a25bcd63912506059da8c7
#passing build
GROOVY_VERSION="2.3.0" ./gradlew check
#first failing build
GROOVY_VERSION="2.3.1" ./gradlew check

gradlew check will automatically download Gradle 2.2.1, download the version of Groovy requested, assemble dependencies, compile, and execute unit tests.

Current Assessment

This is not much of a problem for me now because Jenkins CI embeds Groovy 1.8.9. However, future looking I think it would be good to address this.

groovy support

Jervis needs to support generating groovy jobs... After all, Jervis is groovy :)

Research automatically downloading Jenkins plugins

It would be preferable to automatically install plugins via groovy script. It is easy to detect what plugins are installed (or not installed).

It is not very easy to install the plugins when it is known one is missing.

Research Job DSL modifying root Jenkins config.xml file

I know the Job DSL plugin can configure the config.xml for jobs. However, it would be nice if it can configure some of the root settings in config.xml of $JENKINS_HOME. This would be useful during initial setup where Jervis can prompt for some settings and, if necessary, apply sane defaults.

80% test coverage

There must be at least 80% test coverage for Jervis before the first stable release. Check coverage:

./gradlew coberturaCheck test

./gradlew check will generate a cobertura report in build/reports/cobertura.

Ugly exceptions to clean up

Double Exception

YAML

language: python
python: 2.6

Throws an unfriendly exception when the user should be using

language: python
python: "2.6"

This should definitely be handled because user input can create this exception.

Calling keySet() on null object

Calling toolchainValidator.supportedTool("derpy", "derp") gives unfriendly exception when it is actually a problem with that function not throwing a more friendly exception on the fact that "derpy" does not exist as a toolchain in the toolchains file. Do we really care? I can't think of where a user would actually use this. Remains to be seen. For now it is documented in groovydoc.

This really only affects developers developing Jervis and not end users so not sure I care too much about this. Don't care...

Support for after_success, after_failure, and after_script.

In order to support after_success, after_failure, and after_script the following plugins need to be installed.

  • Plugin:flexible-publish
  • Plugin:postbuildscript

For more information see the Build overview wiki entry.

config.xml

The parent structure is:

<project>
  <publishers>
  </publishers>
</project>

The following XML describes the behavior of post-build actions of after_success, after_failure, and after_script.

  <publishers>
    <org.jenkins__ci.plugins.flexible__publish.FlexiblePublisher plugin="[email protected]">
      <publishers>
        <org.jenkins__ci.plugins.flexible__publish.ConditionalPublisher>
          <condition class="org.jenkins_ci.plugins.run_condition.core.AlwaysRun" plugin="[email protected]"/>
          <publisherList>
            <org.jenkinsci.plugins.postbuildscript.PostBuildScript plugin="[email protected]">
              <buildSteps>
                <hudson.tasks.Shell>
                  <command>echo &apos;after_success commands&apos;</command>
                </hudson.tasks.Shell>
              </buildSteps>
              <scriptOnlyIfSuccess>true</scriptOnlyIfSuccess>
              <scriptOnlyIfFailure>false</scriptOnlyIfFailure>
              <markBuildUnstable>false</markBuildUnstable>
            </org.jenkinsci.plugins.postbuildscript.PostBuildScript>
            <org.jenkinsci.plugins.postbuildscript.PostBuildScript plugin="[email protected]">
              <buildSteps>
                <hudson.tasks.Shell>
                  <command>echo &apos;after_failure commands&apos;</command>
                </hudson.tasks.Shell>
              </buildSteps>
              <scriptOnlyIfSuccess>false</scriptOnlyIfSuccess>
              <scriptOnlyIfFailure>true</scriptOnlyIfFailure>
              <markBuildUnstable>false</markBuildUnstable>
            </org.jenkinsci.plugins.postbuildscript.PostBuildScript>
            <org.jenkinsci.plugins.postbuildscript.PostBuildScript plugin="[email protected]">
              <buildSteps>
                <hudson.tasks.Shell>
                  <command>echo &apos;after_script commands&apos;</command>
                </hudson.tasks.Shell>
              </buildSteps>
              <scriptOnlyIfSuccess>false</scriptOnlyIfSuccess>
              <scriptOnlyIfFailure>false</scriptOnlyIfFailure>
              <markBuildUnstable>false</markBuildUnstable>
            </org.jenkinsci.plugins.postbuildscript.PostBuildScript>
          </publisherList>
          <runner class="org.jenkins_ci.plugins.run_condition.BuildStepRunner$Fail" plugin="[email protected]"/>
        </org.jenkins__ci.plugins.flexible__publish.ConditionalPublisher>
      </publishers>
    </org.jenkins__ci.plugins.flexible__publish.FlexiblePublisher>
  </publishers>

java support

Jervis needs to support building java projects.

Research GVM

Research GVM to test against multiple versions of groovy. Perhaps that's a better method.

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.