Skip to content

Commit

Permalink
Merge pull request #145 from DontShaveTheYak/develop
Browse files Browse the repository at this point in the history
Release v0.11.0
  • Loading branch information
shadycuz authored Nov 5, 2021
2 parents 1cd5cde + 5a0c6e3 commit 3d15c7d
Show file tree
Hide file tree
Showing 45 changed files with 1,873 additions and 74 deletions.
37 changes: 37 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
FROM jenkins/jenkins:latest-jdk11

# Install docker into the container
USER root
RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y \
wget \
git \
curl \
python3 \
python3-pip && \
python3 -m pip install --upgrade pip && \
rm -rf /var/lib/apt/lists/*

# Install and setup docker into the container
RUN groupadd -g 118 docker && curl -fsSL https://get.docker.com -o get-docker.sh && \
sh get-docker.sh && usermod -aG docker jenkins

USER jenkins

# Install pre-commit and dependencies
COPY tests/requirements.txt /tmp
RUN pip3 install --no-cache-dir -r /tmp/requirements.txt

## Plugins
COPY --chown=jenkins:jenkins docker/*-plugins.txt /usr/share/jenkins/ref/
RUN cat /usr/share/jenkins/ref/lib-plugins.txt >> /usr/share/jenkins/ref/runner-plugins.txt && \
jenkins-plugin-cli -f /usr/share/jenkins/ref/runner-plugins.txt && \
jenkins-plugin-cli --plugins job-dsl build-blocker-plugin

## Setup init scripts
COPY --chown=jenkins:jenkins .devcontainer/*.groovy docker/init_scripts/src/main/groovy/* /usr/share/jenkins/ref/init.groovy.d/

ENV JAVA_OPTS -Djenkins.install.runSetupWizard=false
ENV JENKINS_SLAVE_AGENT_PORT=
ENV JENKINS_OPTS="--httpPort=80"
ENV PATH="/var/jenkins_home/.local/bin:$PATH"
58 changes: 58 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.191.1/containers/docker-existing-dockerfile
{
"name": "jenkins-std-lib",
// Sets the run context to one level up instead of the .devcontainer folder.
"context": "..",
// Update the 'dockerFile' property if you aren't using the standard 'Dockerfile' filename.
"dockerFile": "../.devcontainer/Dockerfile",
// Set *default* container specific settings.json values on container create.
"settings": {
"editor.insertSpaces": true,
"editor.tabSize": 4,
"groovy.classpath": [
"/var/jenkins_home/pipeline-library/build/dependencies"
]
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"ms-azuretools.vscode-docker",
"dontshavetheyak.jenkins-extension-pack",
"eamodio.gitlens",
"ms-python.python"
],
// By default vscode sets the entrypoint to infinite sleep loop
"overrideCommand": false,
// Put the workspace in the jenkins home directory so it can be installed into the jenkins as a shared library.
"workspaceMount": "source=${localWorkspaceFolder},target=/var/jenkins_home/pipeline-library,type=bind,consistency=cached",
"workspaceFolder": "/var/jenkins_home/pipeline-library",
"containerEnv": {
"DIND_WORKSPACE": "${localWorkspaceFolder}"
},
// Set the build args
// "build": {
// "args": {
// "PRE_COMMIT_VERSION": "latest",
// "TERRAFORM_VERSION": "latest",
// "TERRAFORM_DOCS_VERSION": "latest",
// "TERRASCAN_VERSION": "latest",
// "TFLINT_VERSION": "latest",
// "TFSEC_VERSION": "latest"
// }
// },
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [8080, 50000],
"appPort": [
"5050:80"
],
// Uncomment the next line to run commands after the container is created - for example installing curl.
"postStartCommand": "./gradlew downloadJars",
// Uncomment when using a ptrace-based debugger like C++, Go, and Rust
// "runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined" ],
// Uncomment to use the Docker CLI from inside the container. See https://aka.ms/vscode-remote/samples/docker-from-docker.
"mounts": [
"source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind"
],
// Uncomment to connect as a non-root user if you've added one. See https://aka.ms/vscode-remote/containers/non-root.
// "remoteUser": "vscode"
}
27 changes: 27 additions & 0 deletions .devcontainer/disable-security.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!groovy
/* groovylint-disable NoDef, NoWildcardImports, UnnecessaryGetter, UnnecessarySetter, VariableTypeRequired */
import jenkins.model.*
import hudson.security.*
import hudson.util.*
import jenkins.install.*
import javaposse.jobdsl.plugin.GlobalJobDslSecurityConfiguration
import jenkins.model.GlobalConfiguration

// You should not actually do this on your real jenkins.
println('==== Disable Jenkins Security')

println('== Disable JobDSL Security')
GlobalConfiguration.all().get(GlobalJobDslSecurityConfiguration).useScriptSecurity = false
GlobalConfiguration.all().get(GlobalJobDslSecurityConfiguration).save()

final Jenkins jenkins = Jenkins.getInstance()

println('== Disable Setup Wizard')
jenkins.setInstallState(InstallState.INITIAL_SETUP_COMPLETED)

println('== Disable Authentication')
def strategy = new AuthorizationStrategy.Unsecured()
jenkins.setAuthorizationStrategy(strategy)

jenkins.save()
println('== Disable Security complete')
98 changes: 98 additions & 0 deletions .devcontainer/seed-job.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#!groovy
/* groovylint-disable GStringExpressionWithinString, JavaIoPackageAccess, NoDef, NoWildcardImports, UnnecessaryGetter, UnnecessaryObjectReferences, UnnecessarySetter, VariableTypeRequired */
import hudson.model.FreeStyleProject
import hudson.triggers.SCMTrigger
import javaposse.jobdsl.plugin.*
import jenkins.model.Jenkins
import hudson.plugins.filesystem_scm.FSSCM

println('==== Creating seed job')
final String jobName = 'seed-job'
final File jobsDir = new File('/var/jenkins_home/pipeline-library/jobs')

final String dslScript = '''\
import java.nio.file.Path
import java.nio.file.Files
import java.nio.file.Paths
Files.walk(Paths.get('/var/jenkins_home/pipeline-library/jobs')).findAll { Path item ->
item.toString().contains('.groovy')
}.forEach { Path item ->
final String fileName = item.getFileName()
final String jobName = fileName.replace('_', '-').replace('.groovy', '')
final File jenkinsFile = item.toFile()
println("Creating job for ${fileName}")
pipelineJob(jobName) {
definition {
cpsScm {
lightweight(true)
scm {
filesystem {
// The file path for the source code.
path(jenkinsFile.getParent())
// If true, the system will delete all existing files/sub-folders in workspace before checking-out.
clearWorkspace(false)
// If true, the system will copy hidden files and folders as well.
copyHidden(false)
filterSettings {
includeFilter(false)
}
}
}
scriptPath(fileName)
}
}
}
}
'''

final FSSCM fileScm = new FSSCM(jobsDir.getPath(), false, false, false, false, null)

final Jenkins jenkins = Jenkins.getInstance()

def existingJob = jenkins.items.find { def job ->
job.name == jobName
}

if (existingJob) {
println('== Existing seed job found, exiting')
return
}

final SCMTrigger scmTrigger = new SCMTrigger('* * * * *')
final ExecuteDslScripts dslBuilder = new ExecuteDslScripts()

// dslBuilder.setSandbox(true)
dslBuilder.setScriptText(dslScript)
dslBuilder.setUseScriptText(true)
dslBuilder.setIgnoreExisting(false)
dslBuilder.setIgnoreMissingFiles(false)
dslBuilder.setFailOnMissingPlugin(true)
dslBuilder.setRemovedJobAction(RemovedJobAction.DELETE)
dslBuilder.setRemovedViewAction(RemovedViewAction.DELETE)
dslBuilder.setLookupStrategy(LookupStrategy.JENKINS_ROOT)

dslProject = new FreeStyleProject(jenkins, jobName)
dslProject.scm = fileScm


dslProject.addTrigger(scmTrigger)
dslProject.createTransientActions()
dslProject.getPublishersList().add(dslBuilder)

println('== Adding Seed Job to Jenkins')
jenkins.add(dslProject, jobName)

println('== Triggering Seed Job polling')
scmTrigger.start(dslProject, true)

println('== Seed Job setup complete')
3 changes: 3 additions & 0 deletions .groovylintrc.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
{
"extends": "recommended",
"rules": {
"BlockEndsWithBlankLine": {
"enabled": false
},
"BlockStartsWithBlankLine": {
"enabled": false
},
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Changelog

This has been deprecated until I can automate it, for now please see the GitHub [releases](https://github.com/DontShaveTheYak/jenkins-std-lib/releases).

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
Expand Down
40 changes: 24 additions & 16 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,28 +37,36 @@ In general, we follow the ["fork-and-pull" Git workflow](https://github.com/susa
7. Open a PR in our repository so that we can efficiently review the changes.

### Code Style
We are using GroovyLint to create a consistent experience when reading code. Besides GroovyLint we also ask that Class contructors only take a single argument and thats the workflow script. If you need additional aruguments for your class please use a property/field instead. We prefer this because when using our library to create jobs the user will almost never have autocompletion and groovy has poor support for keyword arguments.

Example:
```groovy
// Don't do this
def myBook = new Book(this, 'A guide to Jenkins', 15)
// Do this
def myBook = new Book(this)
myBook.title = 'A guide to Jenkins'
myBook.chapters = 15
// This might also be okay but usually only in methods
def myBook = new Book(this, title: 'A guide to Jenkins', chapters: 15)
```
We are using GroovyLint to create a consistent experience when reading the source code. We do often ignore certain rules from GroovyLint like getter/setter rules so feel free to ignore a rule that you don't think applies.

### Setup
The testing of this library is a little quirky. We currently test the library by creating Jenkins jobs in the [jobs](./jobs) folder. The format is `jobs/${packageName}/${className}_example.groovy` and this serves a basic example for users on how to use the class. You can also create unit tests using this format `jobs/${packageName}/tests/test_${className}.groovy`

We then use pytest to call a docker image that will run the jenkins job and return the output of the job. Pytest files use the following format `tests/test_${packageName}/test_${className}.py`

#### Development environment
## Development environment

We highly recommend the development environment we have setup for [vscode](https://code.visualstudio.com/). This development environment contains all the tooling and dependencies you need to contribute to this project and will save you hours of time setting up these items manually.

### vscode

The requirements for using the vscode dev environment is to have the [remote-containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension installed.

When you first open this repository in vscode you will get a notification that this workspace contains a dev container. Click "**Reopen in Container**"

If you miss the notification you can manually open the workspace in a remote container by opening up the command palette `CTRL+SHIFT+P` and type `Open Workspace in Container`.

Note: The first time you open the workspace using the remote-container it will take 5-10mins to configure the development environment. The next time you use the remote-container it will open much faster.

Once opened in the dev container you can:
* Run linting with `pre-commit run -a`
* Open `http://localhost:5050` in your browser to access the Jenkins UI and run tests manually. When you click build on a job, it will automaticly use the latest job/library code.
* Run all the tests in Jenkins UI automaticlly with `pytest -s`

### Manual

If you are not using docker or vscode you can setup a development environment using the following steps:

1. Have python (we use 3.9) installed and you should probably setup a venv. [Pyenv Guide](https://switowski.com/blog/pyenv)
2. Install the python requirements.
```
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ You can support my efforts in any of the following ways:
* Star this repo! :star_struck:
* Follow me on [Twitter](https://twitter.com/DontShaveTheYak).
* Spread the word :grin:
* Contribute to this repo! (Guide coming soon...ish)
* Contribute to this repo using the [guide](./CONTRIBUTING.md)!
* Sponsor me on [GitHub](https://github.com/sponsors/shadycuz) :heart_eyes:
* Support me on [Patreon](https://www.patreon.com/DontShaveTheYak) :smiling_face_with_three_hearts:
## License
Expand Down
8 changes: 6 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,14 @@ repositories {
}
}

configurations {
contrib.extendsFrom compileOnly
}

dependencies {
// Use the latest Groovy version for building this library
compileOnly('org.codehaus.groovy:groovy-all:3.0.9')
compileOnly('org.jenkins-ci.main:jenkins-core:2.313')
compileOnly('org.jenkins-ci.main:jenkins-core:2.316')
compileOnly('com.cloudbees:groovy-cps:1.32')
}

Expand All @@ -140,6 +144,6 @@ task downloadJars(type: Copy) {

into "${buildDir}/dependencies"

from configurations.compileOnly
from configurations.contrib

}
9 changes: 6 additions & 3 deletions docker/init_scripts/src/main/groovy/PipelineLibrary.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,21 @@ final String repoBranch = 'master'
final LibraryConfiguration lc
final File file = new File('/var/jenkins_home/pipeline-library/src')

println('==== Setting up SharedLibray')

if (file.exists()) {
println("===== Adding local ${libName}")
println('== Adding local lib for development')

FSSCM scm = new FSSCM(file.getParent(), false, false, null)

lc = new LibraryConfiguration(libName, new SCMRetriever(scm))

} else {
println("===== Adding remote ${libName}")
println('== Adding remote lib for production use')

String repoURL = 'https://github.com/DontShaveTheYak/jenkins-std-lib'

println("===== Using the Pipeline library from ${repoURL}")
println("== Using the Pipeline library from ${repoURL}")

GitSCMSource libSource = new GitSCMSource(libName, "${repoURL}.git", null, null, null, false)

Expand All @@ -37,3 +39,4 @@ lc.with {
defaultVersion = repoBranch
}
GlobalLibraries.get().libraries.add(lc)
println('== SharedLibray setup complete')
11 changes: 9 additions & 2 deletions docker/init_scripts/src/main/groovy/System.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,17 @@ import jenkins.model.Jenkins
import jenkins.model.JenkinsLocationConfiguration
import hudson.tasks.Mailer

println('== Configuring the system...')
println('==== System Configuration')

// We do not wait for anything
Jenkins.instance.quietPeriod = 0

JenkinsLocationConfiguration.get().adminAddress = '[email protected]'
// get Jenkins location configuration
JenkinsLocationConfiguration config = JenkinsLocationConfiguration.get()

config.url = 'http://localhost:5050'
config.adminAddress = '[email protected]'
Mailer.descriptor().defaultSuffix = '@non.existent.email'

config.save()
println('== System Configuration complete')
3 changes: 1 addition & 2 deletions docker/lib-plugins.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
git:4.7.2
sshd:3.0.3
workflow-aggregator:2.6
1 change: 1 addition & 0 deletions docker/runner-plugins.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
configuration-as-code-groovy:1.1
filesystem_scm:2.1
jdk-tool:1.5
git
Loading

0 comments on commit 3d15c7d

Please sign in to comment.