forked from tektoncd/plumbing
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Setup a mario bot to build images on demand
Define an event-listener that can handle GitHub webhooks, using an interceptor "mario" service. The interceptor will: - validate the event with the shared secret - filter new comment events only - filter comments that start with "/mario" only - for now only accept the syntax "/mario build [contextPath] - return a body with the minimal content for the trigger binding A tekton tasks build the request images and triggers a cloud event. The pull request URL is attached to the taskrun with a label, that is sent via the cloud event. Define an event listener that receives the cloud event, and triggers something (TBD) that posts back to GitHub a comment with: - a link to the logs app to see the build logs - a link to the built image with the sha - a random picture of mario from the talk
- Loading branch information
Showing
9 changed files
with
552 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../../../LICENSE |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../../../OWNERS |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
/* | ||
Copyright 2019 The Tekton Authors | ||
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. | ||
*/ | ||
|
||
package main | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"log" | ||
"net/http" | ||
"os" | ||
"strconv" | ||
"strings" | ||
|
||
"github.com/google/go-github/github" | ||
"github.com/google/uuid" | ||
) | ||
|
||
const ( | ||
// Environment variable containing GitHub secret token | ||
envSecret = "GITHUB_SECRET_TOKEN" | ||
) | ||
|
||
type triggerPayload struct { | ||
BuildUUID string `json:"buildUUID,omitempty"` | ||
GitRepository string `json:"gitRepository,omitempty"` | ||
GitRevision string `json:"gitRevision,omitempty"` | ||
ContextPath string `json:"contextPath,omitempty"` | ||
TargetImage string `json:"targetImage,omitempty"` | ||
PullRequestID string `json:"pullRequestID,omitempty"` | ||
} | ||
|
||
func main() { | ||
errorMessage := "" | ||
secretToken := os.Getenv(envSecret) | ||
if secretToken == "" { | ||
log.Fatalf("No secret token given") | ||
} | ||
|
||
http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) { | ||
//TODO: We should probably send over the EL eventID as a X-Tekton-Event-Id header as well | ||
payload, err := github.ValidatePayload(request, []byte(secretToken)) | ||
id := github.DeliveryID(request) | ||
if err != nil { | ||
log.Printf("Error handling Github Event with delivery ID %s : %q", id, err) | ||
http.Error(writer, fmt.Sprint(err), http.StatusBadRequest) | ||
} | ||
event, err := github.ParseWebHook(github.WebHookType(request), payload) | ||
if err != nil { | ||
log.Printf("Error handling Github Event with delivery ID %s : %q", id, err) | ||
http.Error(writer, fmt.Sprint(err), http.StatusBadRequest) | ||
} | ||
switch event := event.(type) { | ||
case *github.IssueCommentEvent: | ||
if event.GetAction() == "created" { | ||
eventBody := event.GetComment().GetBody() | ||
if strings.HasPrefix(eventBody, "/mario") { | ||
log.Printf("Handling Mario command with delivery ID: %s; Comment: %s", id, eventBody) | ||
commandParts := strings.Fields(eventBody) | ||
command := commandParts[1] | ||
if command == "build" { | ||
// No validation here. Anything beyond commandParts[3] is ignored | ||
prID := strconv.Itoa(int(event.GetIssue().GetNumber())) | ||
triggerBody := triggerPayload{ | ||
BuildUUID: uuid.New().String(), | ||
GitRepository: "github.com/" + event.GetRepo().GetFullName(), | ||
GitRevision: "pull/" + prID + "/head", | ||
ContextPath: commandParts[2], | ||
TargetImage: "us.icr.io/knative/" + commandParts[3], | ||
PullRequestID: prID, | ||
} | ||
tPayload, err := json.Marshal(triggerBody) | ||
if err != nil { | ||
log.Printf("Failed to marshal the trigger body. Error: %q", err) | ||
} | ||
n, err := writer.Write(tPayload) | ||
if err != nil { | ||
log.Printf("Failed to write response for Github event ID: %s. Bytes writted: %d. Error: %q", id, n, err) | ||
} | ||
} else { | ||
errorMessage = "Unknown Mario command" | ||
} | ||
} else { | ||
errorMessage = "Not a Mario command" | ||
} | ||
} else { | ||
errorMessage = "Only new comments are supported" | ||
} | ||
default: | ||
errorMessage = "Event type not supported" | ||
} | ||
if errorMessage != "" { | ||
log.Printf(errorMessage) | ||
http.Error(writer, fmt.Sprint(errorMessage), http.StatusBadRequest) | ||
} | ||
}) | ||
|
||
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", 8080), nil)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# Copyright 2019 The Tekton Authors | ||
# | ||
# 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. | ||
|
||
apiVersion: v1 | ||
kind: Namespace | ||
metadata: | ||
name: mario |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# Copyright 2019 The Tekton Authors | ||
# | ||
# 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. | ||
|
||
apiVersion: v1 | ||
kind: ServiceAccount | ||
metadata: | ||
name: mario-bot | ||
namespace: mario |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
# Copyright 2019 The Tekton Authors | ||
# | ||
# 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 | ||
# | ||
# https://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. | ||
|
||
apiVersion: apps/v1 | ||
kind: Deployment | ||
metadata: | ||
name: mario | ||
namespace: mario | ||
spec: | ||
replicas: 1 | ||
selector: | ||
matchLabels: | ||
app: mario | ||
template: | ||
metadata: | ||
labels: | ||
app: mario | ||
spec: | ||
serviceAccountName: mario-bot | ||
containers: | ||
- name: mario-interceptor | ||
image: github.com/tektoncd/plumbing/cmd/mario | ||
env: | ||
- name: GITHUB_SECRET_TOKEN | ||
valueFrom: | ||
secretKeyRef: | ||
name: mario-github-secret | ||
key: secret-token | ||
--- | ||
apiVersion: v1 | ||
kind: Service | ||
metadata: | ||
name: mario | ||
namespace: mario | ||
spec: | ||
type: ClusterIP | ||
selector: | ||
app: mario | ||
ports: | ||
- protocol: TCP | ||
port: 80 | ||
targetPort: 8080 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
apiVersion: tekton.dev/v1alpha1 | ||
kind: TriggerBinding | ||
metadata: | ||
name: trigger-to-comment-github | ||
spec: | ||
params: | ||
- name: pullRequestID | ||
value: $(body.taskRun.metadata.labels.mario\.bot/pull-request-id) | ||
- name: buildUUID | ||
value: $(body.taskRun.metadata.labels.prow\.k8s\.io/build-id) | ||
- name: gitURL | ||
value: $(body.taskRun.spec.inputs.resources.#(name=="source").resourceSpec.params.#(name=="url").value) | ||
- name: gitRevision | ||
value: $(body.taskRun.spec.inputs.resources.#(name=="source").resourceSpec.params.#(name=="revision").value) | ||
- name: targetImageResourceName | ||
value: $(body.taskRun.spec.outputs.resources.#(name=="image").resourceRef.name) | ||
- name: passedOrFailed | ||
value: $(body.taskRun.status.conditions.#(type=="Succeeded").status) | ||
--- | ||
apiVersion: tekton.dev/v1alpha1 | ||
kind: EventListener | ||
metadata: | ||
name: github-feedback-trigger | ||
spec: | ||
serviceAccountName: mario-listener | ||
triggers: | ||
- name: trigger | ||
binding: | ||
name: trigger-to-comment-github | ||
template: | ||
name: mario-comment-github | ||
--- | ||
apiVersion: tekton.dev/v1alpha1 | ||
kind: TriggerTemplate | ||
metadata: | ||
name: mario-comment-github | ||
spec: | ||
params: | ||
- name: pullRequestID | ||
description: The pullRequestID to comment to | ||
- name: buildUUID | ||
description: The buildUUID for the logs link | ||
- name: gitURL | ||
description: The URL of the git repo | ||
- name: gitRevision | ||
description: The git revision | ||
- name: targetImageResourceName | ||
description: The name of the target image pipelineresource | ||
- name: passedOrFailed | ||
description: Whether the triggering event was successful or not | ||
resourcetemplates: | ||
- apiVersion: tekton.dev/v1alpha1 | ||
kind: PipelineResource | ||
metadata: | ||
name: pr-$(uid) | ||
spec: | ||
type: pullRequest | ||
params: | ||
- name: url | ||
value: $(params.gitURL)/pull/$(params.pullRequestID) | ||
secrets: | ||
- fieldName: githubToken | ||
secretName: mario-github-token | ||
secretKey: GITHUB_TOKEN | ||
- apiVersion: tekton.dev/v1alpha1 | ||
kind: TaskRun | ||
metadata: | ||
generateName: mario-comment-github-$(uid)- | ||
spec: | ||
serviceAccountName: mario-listener | ||
taskSpec: | ||
inputs: | ||
resources: | ||
- name: source | ||
type: git | ||
- name: pr | ||
type: pullRequest | ||
outputs: | ||
resources: | ||
- name: image | ||
type: image | ||
- name: pr | ||
type: pullRequest | ||
steps: | ||
- name: copy-pr-to-output | ||
image: busybox | ||
script: | | ||
#!/bin/sh | ||
mkdir -p $(outputs.resources.pr.path) | ||
cp -r $(inputs.resources.pr.path)/* $(outputs.resources.pr.path)/ | ||
- name: setup-comment | ||
image: python:3-alpine | ||
script: | | ||
#!/usr/bin/env python | ||
import json | ||
import random | ||
marios_pics_root = 'https://storage.googleapis.com/mario-bot/pics' | ||
ok_pics = ['mario', 'luigi', 'tekton'] | ||
failed_pics = ['goomba'] | ||
logs_url = 'http://35.222.249.224/?buildid=%s&namespace=mario' | ||
successful = ($(params.passedOrFailed) == "True") | ||
# Service Image | ||
comment_template = ( | ||
'<img width="200" alt="{pic_alt}" src="{pic_src}">' | ||
' at your service! </p>' | ||
) | ||
if successful: | ||
chosen_pic = random.choice(ok_pics) | ||
else: | ||
chosen_pic = random.choice(failed_pics) | ||
pic_url = "/".join([marios_pics_root, chosen_pic]) + '.png' | ||
comment_params = dict(pic_alt=chosen_pic, pic_src=pic_url) | ||
if successful: | ||
comment_template += ( | ||
'Here is the image you requested: ' | ||
'<a href="https://{imageurl}">built image</a>|' | ||
) | ||
comment_params['imageurl'] = '$(outputs.resources.image.url)' | ||
else: | ||
comment_template += ( | ||
'Cloud not build the requested image. Please check the ' | ||
) | ||
comment_template += ( | ||
'<a href="http://35.222.249.224/?buildid={buildid}&' | ||
'namespace=mario">build logs</a>' | ||
) | ||
comment_params['buildid'] = '$(params.buildUUID)' | ||
new_comment_path = "$(outputs.resources.pr.path)/comments/new.json" | ||
comment_body = dict(body=comment_template.format(**comment_params)) | ||
with open(new_comment_path, "w") as comment: | ||
json.dump(comment_body, comment) | ||
inputs: | ||
resources: | ||
- name: source | ||
resourceSpec: | ||
type: git | ||
params: | ||
- name: revision | ||
value: $(params.gitRevision) | ||
- name: url | ||
value: $(params.gitURL) | ||
- name: pr | ||
resourceRef: | ||
name: pr-$(uid) | ||
outputs: | ||
resources: | ||
- name: image | ||
resourceRef: | ||
name: $(params.targetImageResourceName) | ||
- name: pr | ||
resourceRef: | ||
name: pr-$(uid) |
Oops, something went wrong.