Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Read [Why a new CD tool][1] for the reason and focus points behind this CD tool.
State of the project
--------------------
This project is currently in a very early state of development.
[Tricode](http://www.tricode.nl) Sponsors developer-time and resources

Building Pipeline
--------------
Expand Down
23 changes: 22 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
apply from: script('requireJavaVersion7')
apply from: script('dependencies')
apply plugin: 'distribution'

description = 'Pipeline --the Continuous Delivery (CD) tool, which we and all stakeholders of the CD pipeline love to use'
group = 'org.pipelinelabs.pipeline'
Expand All @@ -16,10 +17,30 @@ subprojects {
version = rootProject.version
}

distributions {
main {
contents {
into('bin') {
from { project(':listener').startScripts.outputs.files }
from { project(':runner').startScripts.outputs.files }
fileMode = 0755
}
into('lib') {
def libs = []
libs << project(':listener').configurations.runtime - project(':runner').configurations.runtime
libs << project(':runner').configurations.runtime
from libs
from project(':listener').jar
from project(':runner').jar
}
}
}
}

String createProjectGroupId(Project root, Project project) {
root.group << '.' << project.name.replaceAll('-', '.')
}

File script(String name) {
project.file("gradle/${name}.gradle")
}
}
4 changes: 3 additions & 1 deletion gradle/cucumber.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ configurations {

dependencies {
testCompile group: 'info.cukes', name: 'cucumber-groovy', version: '1.1.2'
testCompile group: 'info.cukes', name: 'cucumber-junit', version: '1.1.2'
testCompile group: 'info.cukes', name: 'cucumber-junit', version: '1.1.2', {
exclude group: 'junit', module: 'junit'
}

cucumberRuntime files("${jar.archivePath}")
}
Expand Down
41 changes: 35 additions & 6 deletions gradle/dependencies.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,43 @@ ext {
}

libraries += [
'maven-shared-utils': 'org.apache.maven.shared:maven-shared-utils:0.3',
groovy: 'org.codehaus.groovy:groovy:2.1.6:indy',
mavenSharedUtils: 'org.apache.maven.shared:maven-shared-utils:0.3',
groovy: 'org.codehaus.groovy:groovy:2.1.7:indy',
groovyJson: 'org.codehaus.groovy:groovy-json:2.1.7:indy',

junit: 'junit:junit:4.11',
asm: 'org.ow2.asm:asm:4.1',
hamcrest: 'org.hamcrest:hamcrest-library:1.3',
jcommander: 'com.beust:jcommander:1.30',
dropwizardTesting: 'com.yammer.dropwizard:dropwizard-testing:0.6.2',
]

libraries.dropwizard = ['com.yammer.dropwizard:dropwizard-core:0.6.2',
'com.sun.jersey:jersey-client:1.17.1',
]

libraries.spock = ['org.spockframework:spock-core:0.7-groovy-2.0',
libraries.groovy,
'org.objenesis:objenesis:2.0',
'cglib:cglib-nodep:2.2'
]

libraries.spock = dependencies.module('org.spockframework:spock-core:0.7-groovy-2.0') {
exclude group: 'org.codehaus.groovy', module: 'groovy-all'
exclude group: 'junit', module: 'junit-dep'
libraries.groovy
allprojects {
configurations.all {
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
def req = details.requested
// Replace groovy-all with groovy
if (req.name == 'groovy-all' || req.name == 'groovy') {
details.useTarget libraries.groovy
}
// Replace junit-dep with junit
if (req.name == 'junit-dep') {
details.useTarget libraries.junit
}
// Change old groupId of asm to new groupId, for correct dependency handling
if (req.group == 'asm') {
details.useTarget group: 'org.ow2.asm', name: req.name, version: req.version
}
}
}
}
4 changes: 2 additions & 2 deletions settings.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
include 'pipe'
include 'pipe-listener'
include 'runner'
include 'listener'

rootProject.name = 'pipeline'
rootProject.children.each { project ->
Expand Down
17 changes: 17 additions & 0 deletions subprojects/listener/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
Pipeline Listener
=================

Receives and queues service hook notifications, like `push` events from GitHub.

This listener supports the following provider:

- github.com

Usage
-----

Pipeline Listener (`pipe-listener`) provides a HTTP REST API that providers like GitHub can notify. The API is non-blocking, after basic verification of the notification message, the API will return a success (HTTP 204) or failure (HTTP 422) status. The notification message will be queued for processing a.s.a.p. by its processor.

### POST /providers/github

GitHub provider, supports the GitHub WebHook format as explained on [Post-Receive Hooks](https://help.github.com/articles/post-receive-hooks)
18 changes: 18 additions & 0 deletions subprojects/listener/listener.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
apply plugin: 'groovy'
apply plugin: 'application'

applicationName = 'pipe-listen'
description = 'pipe-listen --the listener for pipeline triggers'
mainClassName = 'org.pipelinelabs.pipeline.listen.Main'

dependencies {
compile libraries.dropwizard
compile libraries.groovy
compile libraries.groovyJson
testCompile libraries.spock
testCompile libraries.dropwizardTesting
}

run {
args 'server'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.pipelinelabs.pipeline.listen

import com.yammer.dropwizard.Service

class Main {

static void main(String... args) {
new Main().createService().run(args)
}

Service createService() {
new PipeListenService()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.pipelinelabs.pipeline.listen

import com.yammer.dropwizard.config.Configuration

class PipeListenConfiguration extends Configuration {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package org.pipelinelabs.pipeline.listen

import com.google.common.eventbus.AsyncEventBus
import com.yammer.dropwizard.Service
import com.yammer.dropwizard.config.Bootstrap
import com.yammer.dropwizard.config.Environment
import org.pipelinelabs.pipeline.listen.core.DeadEventHandler
import org.pipelinelabs.pipeline.listen.core.GitWorker
import org.pipelinelabs.pipeline.listen.resources.GitHubWebHookResource

import static java.util.concurrent.TimeUnit.SECONDS

class PipeListenService extends Service<PipeListenConfiguration> {

@Override
void initialize(Bootstrap<PipeListenConfiguration> bootstrap) {
}

@Override
void run(PipeListenConfiguration config, Environment env) throws Exception {
def bus = createEventBus(env)
env.manage(new DeadEventHandler(bus))
env.manage(new GitWorker(bus));
env.addResource(new GitHubWebHookResource(bus))
}

private createEventBus(Environment env) {
final corePoolSize = 2
final maxPoolSize = 6
final keepAliveTimeInSeconds = 30
new AsyncEventBus(
env.managedExecutorService(
"eventbus-worker-%s",
corePoolSize,
maxPoolSize,
keepAliveTimeInSeconds, SECONDS
)
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.pipelinelabs.pipeline.listen.core

import com.google.common.eventbus.DeadEvent
import com.google.common.eventbus.EventBus
import com.google.common.eventbus.Subscribe
import com.yammer.dropwizard.lifecycle.Managed
import groovy.util.logging.Slf4j

@Slf4j
class DeadEventHandler implements Managed {

private final EventBus bus

DeadEventHandler(EventBus bus) {
this.bus = bus
}

@Override
void start() throws Exception {
bus.register(this)
}

@Override
void stop() throws Exception {
bus.unregister(this)
}

@Subscribe
void work(DeadEvent event) {
log.error("No event handler available for event [{}]", event.event)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.pipelinelabs.pipeline.listen.core


class GitTriggerEvent {

final String url

GitTriggerEvent(String url) {
this.url = url
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package org.pipelinelabs.pipeline.listen.core

import com.google.common.eventbus.EventBus
import com.google.common.eventbus.Subscribe
import com.yammer.dropwizard.lifecycle.Managed
import groovy.util.logging.Slf4j

import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths

@Slf4j
class GitWorker implements Managed {

private final EventBus bus

GitWorker(EventBus bus) {
this.bus = bus
}

@Override
void start() throws Exception {
bus.register(this)
}

@Override
void stop() throws Exception {
bus.unregister(this)
}

@Subscribe
void work(GitTriggerEvent event) {
log.info('Received event [{}]', event)
def dir = Files.createTempDirectory("pipeline")
log.debug('Created pipeline directory [{}]', dir)

def workDirName = "work"
def workDir = Paths.get(dir.toString(), workDirName)
List envProps = null

def gitCommand = "git clone ${event.url} ${workDirName}"
executeCommand(gitCommand, dir, envProps)

def runnerCommand = "pipe-runner run project.pipeline"
executeCommand(runnerCommand, workDir, envProps)
}

private void executeCommand(String command, Path workDir, List envProps) {
log.info('Executing command [{}] in pipeline directory [{}]', command, workDir)
def runnerProc = command.execute(envProps, workDir.toFile())
def runnerExitStatus = runnerProc.waitFor()
log.info('Command [{}] exitted with status [{}]', command, runnerExitStatus)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.pipelinelabs.pipeline.listen.core.github


class GithubUtils {

private static final String SSH_URL_FORMAT = 'git@github.com:%s.git'

static String toGithubSshUrl(String uri) throws URISyntaxException {
return toGithubSshUrl(new URI(uri))
}

static String toGithubSshUrl(URI uri) {
return String.format(SSH_URL_FORMAT, cleanUriPath(uri))
}

private static String cleanUriPath(URI uri) {
def path = uri.path
return path.replaceAll(/\/+/, '/')
}
}
Loading