Skip to content

Commit b10c52c

Browse files
committed
Convert http(s) github urls to github ssh urls
To support private repositories cloning with public-private-key authentication, we're now converting the Github http(s) urls from the payload to github ssh urls.
1 parent eeba10b commit b10c52c

File tree

10 files changed

+106
-38
lines changed

10 files changed

+106
-38
lines changed

subprojects/listener/README.md

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,15 @@ Pipeline Listener
33

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

6-
This listener supports multiple providers, GitHub being the first.
6+
This listener supports the following provider:
7+
8+
- github.com
79

810
Usage
911
-----
1012

1113
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.
1214

13-
### GET /
14-
15-
Shows a simple overview page with:
16-
17-
- Loaded providers and their details
18-
- Queued notifications (with basic details)
19-
- Amount processed notifications since start-up
20-
2115
### POST /providers/github
2216

2317
GitHub provider, supports the GitHub WebHook format as explained on [Post-Receive Hooks](https://help.github.com/articles/post-receive-hooks)

subprojects/listener/listener.gradle

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,8 @@ dependencies {
1111
compile libraries.groovyJson
1212
testCompile libraries.spock
1313
testCompile libraries.dropwizardTesting
14-
15-
// this dropwizard dependency is needed due to http://issues.gradle.org/browse/GRADLE-2647
16-
// compile libraries.'jersey-client'
1714
}
1815

19-
//run {
20-
// args 'server', './src/dist/config/helloworld.yml'
21-
//}
16+
run {
17+
args 'server'
18+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package org.pipelinelabs.pipeline.listen.core.github
2+
3+
4+
class GithubUtils {
5+
6+
private static final String SSH_URL_FORMAT = '[email protected]:%s.git'
7+
8+
static String toGithubSshUrl(String uri) throws URISyntaxException {
9+
return toGithubSshUrl(new URI(uri))
10+
}
11+
12+
static String toGithubSshUrl(URI uri) {
13+
return String.format(SSH_URL_FORMAT, cleanUriPath(uri))
14+
}
15+
16+
private static String cleanUriPath(URI uri) {
17+
def path = uri.path
18+
return path.replaceAll(/\/+/, '/')
19+
}
20+
}

subprojects/listener/src/main/groovy/org/pipelinelabs/pipeline/listen/resources/GitHubWebHookResource.groovy

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import javax.ws.rs.core.Response
1111
import static javax.ws.rs.core.MediaType.APPLICATION_FORM_URLENCODED
1212
import static javax.ws.rs.core.MediaType.APPLICATION_JSON
1313
import static javax.ws.rs.core.Response.Status.BAD_REQUEST
14+
import static org.pipelinelabs.pipeline.listen.core.github.GithubUtils.toGithubSshUrl
1415

1516
@Slf4j
1617
@Path("/providers/github")
@@ -26,19 +27,19 @@ class GitHubWebHookResource {
2627

2728
@POST
2829
Response trigger(@FormParam('payload') String payload) {
29-
final slurper = new JsonSlurper()
30+
def slurper = new JsonSlurper()
3031
def info = slurper.parseText(payload)
3132
try {
3233
verifyRequest(info)
3334
} catch (AssertionError e) {
34-
log.warn("Received GitHub WebHook payload with unexpected format:\n{}", info)
35+
log.warn("Received GitHub WebHook payload with unexpected format:\n{}", e.message)
3536
return Response.status(BAD_REQUEST.statusCode).build()
3637
}
3738
return handleRequest(info)
3839
}
3940

4041
private Response handleRequest(request) {
41-
def event = new GitTriggerEvent(request.repository.url)
42+
def event = new GitTriggerEvent(toGithubSshUrl(request.repository.url))
4243
bus.post(event)
4344
Response.noContent().build()
4445
}
@@ -57,5 +58,14 @@ class GitHubWebHookResource {
5758
assert request.repository.private == true ||
5859
request.repository.private == false
5960
assert request.repository.url
61+
assertValidUri(request.repository.url)
62+
}
63+
64+
private assertValidUri(String uri) throws AssertionError {
65+
try {
66+
new URI(uri)
67+
} catch (URISyntaxException e) {
68+
throw new AssertionError(e.message, e)
69+
}
6070
}
6171
}

subprojects/listener/src/test/groovy/org/pipelinelabs/pipeline/listen/core/DeadEventHandlerSpec.groovy

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,9 @@ import spock.lang.Specification
99

1010
class DeadEventHandlerSpec extends Specification {
1111
private EventBus bus = Mock(EventBus)
12+
private DeadEventHandler worker = new DeadEventHandler(bus)
1213

1314
def 'Start registers itself to the event bus'() {
14-
given:
15-
def worker = new DeadEventHandler(bus)
16-
1715
when:
1816
worker.start()
1917

@@ -22,17 +20,14 @@ class DeadEventHandlerSpec extends Specification {
2220
}
2321

2422
def 'Stop unregisters itself from the event bus'() {
25-
given:
26-
def worker = new DeadEventHandler(bus)
27-
2823
when:
2924
worker.stop()
3025

3126
then:
3227
1 * bus.unregister(worker)
3328
}
3429

35-
def 'Work handles DeadEvent and is annotated with @Subscribe'() {
30+
def 'work() is the event handler of DeadEvent objects'() {
3631
def method = DeadEventHandler.getMethod("work", DeadEvent)
3732

3833
expect:

subprojects/listener/src/test/groovy/org/pipelinelabs/pipeline/listen/core/GitWorkerSpec.groovy

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,9 @@ import spock.lang.Specification
77

88
class GitWorkerSpec extends Specification {
99
private EventBus bus = Mock(EventBus)
10+
private GitWorker worker = new GitWorker(bus)
1011

1112
def 'Start registers itself to the event bus'() {
12-
given:
13-
def worker = new GitWorker(bus)
14-
1513
when:
1614
worker.start()
1715

@@ -20,26 +18,22 @@ class GitWorkerSpec extends Specification {
2018
}
2119

2220
def 'Stop unregisters itself from the event bus'() {
23-
given:
24-
def worker = new GitWorker(bus)
25-
2621
when:
2722
worker.stop()
2823

2924
then:
3025
1 * bus.unregister(worker)
3126
}
3227

33-
def 'Work handles GitTriggerEvent and is annotated with @Subscribe'() {
28+
def 'work() is the event handler of GitTriggerEvent objects'() {
3429
def method = GitWorker.getMethod("work", GitTriggerEvent)
3530

3631
expect:
3732
method.isAnnotationPresent(Subscribe)
3833
}
3934

40-
@Ignore('Needs to be testable somehow')
35+
@Ignore
4136
def 'Work clones the git repo and starts pipe-runner'() {
42-
def worker = new GitWorker(bus)
4337
final event = Mock(GitTriggerEvent)
4438

4539
expect:
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package org.pipelinelabs.pipeline.listen.core.github
2+
3+
import spock.lang.Specification
4+
import spock.lang.Unroll
5+
6+
7+
class GithubUtilsSpec extends Specification {
8+
9+
@Unroll
10+
def 'Convert new URI("#uri") to github ssh url "#expected"'() {
11+
expect:
12+
final actual = GithubUtils.toGithubSshUrl(new URI(uri))
13+
actual == expected
14+
15+
where:
16+
uri || expected
17+
'https://github.com/octokitty/testing' || '[email protected]:/octokitty/testing.git'
18+
'http://github.com/octokitty/testing' || '[email protected]:/octokitty/testing.git'
19+
'http://github.com//octokitty/testing' || '[email protected]:/octokitty/testing.git'
20+
'http://github.com/octokitty//testing' || '[email protected]:/octokitty/testing.git'
21+
}
22+
23+
@Unroll
24+
def 'Convert "#uri" to github ssh url "#expected"'() {
25+
expect:
26+
final actual = GithubUtils.toGithubSshUrl(uri)
27+
actual == expected
28+
29+
where:
30+
uri || expected
31+
'https://github.com/octokitty/testing' || '[email protected]:/octokitty/testing.git'
32+
'http://github.com/octokitty/testing' || '[email protected]:/octokitty/testing.git'
33+
'http://github.com//octokitty/testing' || '[email protected]:/octokitty/testing.git'
34+
'http://github.com/octokitty//testing' || '[email protected]:/octokitty/testing.git'
35+
}
36+
}

subprojects/listener/src/test/groovy/org/pipelinelabs/pipeline/listen/resources/GitHubWebHookResourceSpec.groovy

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import com.sun.jersey.api.client.WebResource
77
import com.sun.jersey.api.representation.Form
88
import com.yammer.dropwizard.testing.ResourceTest
99
import org.pipelinelabs.pipeline.listen.core.GitTriggerEvent
10+
import spock.lang.Ignore
1011
import spock.lang.Specification
1112
import spock.lang.Unroll
1213

@@ -21,7 +22,28 @@ class GitHubWebHookResourceSpec extends Specification {
2122
def eventBus = Mock(EventBus)
2223
TestResource resource = new TestResource(eventBus)
2324

24-
def 'Correct payload results in event on queue'() {
25+
@Ignore
26+
def 'Valid payload results in git event with github ssh url on queue'() {
27+
given:
28+
def form = new Form()
29+
form.add('payload', jsonFixture("github/samplePayload.json"))
30+
31+
when:
32+
def response = requestBuilder()
33+
.type(APPLICATION_FORM_URLENCODED_TYPE)
34+
.accept(APPLICATION_JSON_TYPE)
35+
.post(ClientResponse, form)
36+
37+
then:
38+
1 * eventBus.post(_ as GitTriggerEvent) >> { event ->
39+
assert event.url == '[email protected]:/octokitty/testing.git'
40+
}
41+
response.type == APPLICATION_JSON_TYPE
42+
response.clientResponseStatus == NO_CONTENT
43+
response.length == -1
44+
}
45+
46+
def 'Valid payload results in git event on queue'() {
2547
given:
2648
def form = new Form()
2749
form.add('payload', jsonFixture("github/samplePayload.json"))

subprojects/runner/runner.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ apply plugin: 'application'
33
apply from: script('cucumber')
44

55
applicationName = 'pipe-runner'
6-
description = 'pipe-runner --the pipeline runner, executes the project pipeline from the project.pipe configuration'
6+
description = 'pipe-runner --the pipeline runner, executes the project pipeline a pipeline configuration file'
77
mainClassName = 'org.pipelinelabs.pipeline.runner.cli.Pipeline'
88

99
dependencies {

subprojects/runner/src/main/groovy/org/pipelinelabs/pipeline/runner/cli/command/RunCommand.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@
1515

1616
@Parameters(
1717
commandNames = {RunCommand.NAME}
18-
, commandDescription = "Run, baby run!"
18+
, commandDescription = "Run pipeline"
1919
)
2020
public class RunCommand implements Command {
2121
public static final String NAME = "run";
2222

2323
@Parameter(
24-
description = ""
24+
description = "Pipeline configuration to run"
2525
, listConverter = FileConverter.class
2626
, required = true
2727
, arity = 1

0 commit comments

Comments
 (0)