Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PR to Issue #227 #15

Merged
merged 12 commits into from
Jan 3, 2025
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
177 changes: 177 additions & 0 deletions .tekton/pr-differ.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
---
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
name: pr-differ
annotations:
# The event we are targeting as seen from the webhook payload
# this can be an array too, i.e: [pull_request, push]
pipelinesascode.tekton.dev/on-event: "[pull_request]"

# The branch or tag we are targeting (ie: main, refs/tags/*)
pipelinesascode.tekton.dev/on-target-branch: "[main,devel]"

# Fetch the git-clone task from hub, we are able to reference later on it
# with taskRef and it will automatically be embedded into our pipeline.
pipelinesascode.tekton.dev/task: "git-clone"

# Use maven task from hub
# pipelinesascode.tekton.dev/task-1: "[pre-commit]"

# You can add more tasks in here to reuse, browse the one you like from here
# https://hub.tekton.dev/
# example:
# pipelinesascode.tekton.dev/task-2: "[github-add-labels]"
pipelinesascode.tekton.dev/task-1: "[.tekton/task/github-add-comment.yaml]"

# How many runs we want to keep attached to this event
pipelinesascode.tekton.dev/max-keep-runs: "2"
spec:
params:
# The variable with brackets are special to Pipelines as Code
# They will automatically be expanded with the events from Github.
- name: repo_url
value: "{{ repo_url }}"
- name: revision
value: "{{ revision }}"
- name: pull_request_number
value: "{{ pull_request_number }}"
- name: git_auth_secret
value: "{{ git_auth_secret }}"
- name: source_branch
value: "{{source_branch}}"
- name: target_branch
value: "{{target_branch}}"

podTemplate:
nodeSelector:
kubernetes.io/arch: amd64
pipelineSpec:
params:
- name: repo_url
- name: revision
- name: pull_request_number
- name: git_auth_secret
workspaces:
- name: source
tasks:
- name: fetch-repository-pr
taskRef:
resolver: cluster
params:
- name: kind
value: task
- name: name
value: git-clone
- name: namespace
value: openshift-pipelines
workspaces:
- name: output
workspace: source
params:
- name: URL
value: $(params.repo_url)
- name: REVISION
value: $(params.revision)
- name: DEPTH
value: 0
- name: SUBDIRECTORY
value: pr

- name: fetch-repository-main
taskRef:
resolver: cluster
params:
- name: kind
value: task
- name: name
value: git-clone
- name: namespace
value: openshift-pipelines
workspaces:
- name: output
workspace: source
params:
- name: URL
value: $(params.repo_url)
- name: REVISION
value: 'main'
- name: DEPTH
value: 0
- name: SUBDIRECTORY
value: main

- name: differ
runAfter:
- fetch-repository-main
- fetch-repository-pr
workspaces:
- name: source
workspace: source
taskSpec:
workspaces:
- name: source
steps:
- name: differ
image: quay.io/stormshift/gitops-differ:202501031515
imagePullPolicy: Always
workingDir: $(workspaces.source.path)
securityContext:
runAsNonRoot: true
runAsUser: 65532
env:
- name: WORKSPACE
value: $(workspaces.source.path)
script: |
set -euxo pipefail

${WORKSPACE}/pr/helper/differ.sh ${WORKSPACE}/pr ${WORKSPACE}/main

cp -v /tmp/diff-overview.md ${WORKSPACE}/diff-overview.md

- name: notify-deployment
runAfter:
- differ
workspaces:
- name: comment-file
workspace: source
params:
- name: REQUEST_URL
value: "$(params.repo_url)/pull/$(params.pull_request_number)"
- name: PAC_GITHUB_SECRET
value: "$(params.git_auth_secret)"
- name: COMMENT_OR_FILE
value: "diff-overview.md"
taskRef:
name: github-add-comment
# finally:
# - name: notify-linter-on-failure
# workspaces:
# - name: comment-file
# workspace: source
# when:
# - input: $(tasks.pre-commit.status)
# operator: in
# values: ["Failed"]
# params:
# - name: REQUEST_URL
# value: "$(params.repo_url)/pull/$(params.pull_request_number)"
# - name: PAC_GITHUB_SECRET
# value: "$(params.git_auth_secret)"
# - name: COMMENT_OR_FILE
# value: "notify-linter-on-failure.txt"
# taskRef:
# name: github-add-comment

workspaces:
- name: source
volumeClaimTemplate:
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
# This workspace will inject secret to help the git-clone task to be able to
# checkout the private repositories

190 changes: 190 additions & 0 deletions .tekton/task/github-add-comment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
---
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: github-add-comment
labels:
app.kubernetes.io/version: "0.7"
annotations:
tekton.dev/categories: Git
tekton.dev/pipelines.minVersion: "0.17.0"
tekton.dev/tags: github
tekton.dev/displayName: "add github comment"
tekton.dev/platforms: "linux/amd64,linux/s390x,linux/ppc64le"
spec:
description: >-
This Task will add a comment to a pull request or an issue.

It can take either a filename or a comment as input and can
post the comment back to GitHub accordingly.

workspaces:
- name: comment-file
optional: true
description: The optional workspace containing comment file to be posted.

params:
- name: GITHUB_HOST_URL
description: |
The GitHub host, adjust this if you run a GitHub enteprise.
default: "api.github.com"
type: string

- name: API_PATH_PREFIX
description: |
The API path prefix, GitHub Enterprise has a prefix e.g. /api/v3
default: ""
type: string

- name: REQUEST_URL
description: |
The GitHub issue or pull request URL where we want to add a new
comment.
type: string

- name: COMMENT_OR_FILE
description: |
The actual comment to add or the filename containing comment to post.
type: string

- name: PAC_GITHUB_SECRET
description: |
The name of the Kubernetes Secret that contains the GitHub token.
type: string

- name: PAC_GITHUB_SECRET_KEY
description: |
The key within the Kubernetes Secret that contains the GitHub token.
type: string
default: .git-credentials

- name: AUTH_TYPE
description: |
The type of authentication to use. You could use the less secure "Basic" for example
type: string
default: Bearer

- name: COMMENT_TAG
description: |
An invisible tag to be added into the comment. The tag is made
invisible by embedding in an an HTML comment. The tag allows for later
retrieval of the comment, and it allows replacing an existing comment.
type: string
default: ""

- name: REPLACE
description: |
When a tag is specified, and `REPLACE` is `true`, look for a comment
with a matching tag and replace it with the new comment.
type: string
default: "false" # Alternative value: "true"

steps:
- name: post-comment
workingDir: $(workspaces.comment-file.path)
env:
- name: GIT_CREDENTIALS
valueFrom:
secretKeyRef:
name: $(params.PAC_GITHUB_SECRET)
key: $(params.PAC_GITHUB_SECRET_KEY)

image: registry.access.redhat.com/ubi8/ubi-minimal:8.2
script: |
#!/usr/libexec/platform-python
import json
import os
import http.client
import sys
import urllib.parse

bearer = urllib.parse.urlparse(os.environ["GIT_CREDENTIALS"])

authHeader = "$(params.AUTH_TYPE) " + bearer.password

split_url = urllib.parse.urlparse(
"$(params.REQUEST_URL)").path.split("/")

# This will convert https://github.com/foo/bar/pull/202 to
# api url path /repos/foo/issues/
api_url = "{base}/repos/{package}/issues/{id}".format(
base="$(params.API_PATH_PREFIX)", package="/".join(split_url[1:3]), id=split_url[-1])

# Only support FILE on my case
commentParamValue = """$(params.COMMENT_OR_FILE)"""

# check if workspace is bound and parameter passed is a filename or not
if "$(workspaces.comment-file.bound)" == "true" and os.path.exists(commentParamValue):
commentParamValue = open(commentParamValue, "r").read()

else:
commentParamValue = """ 😱 An unexpected error has occurred, please check log files."""

# If a tag was specified, append it to the comment
if "$(params.COMMENT_TAG)":
commentParamValue += "<!-- {tag} -->".format(tag="$(params.COMMENT_TAG)")

data = {
"body": commentParamValue,
}

# This is for our fake github server
if "$(params.GITHUB_HOST_URL)".startswith("http://"):
conn = http.client.HTTPConnection("$(params.GITHUB_HOST_URL)".replace("http://", ""))
else:
conn = http.client.HTTPSConnection("$(params.GITHUB_HOST_URL)")

# If REPLACE is true, we need to search for comments first
matching_comment = ""
if "$(params.REPLACE)" == "true":
if not "$(params.COMMENT_TAG)":
print("REPLACE requested but no COMMENT_TAG specified")
sys.exit(1)
r = conn.request(
"GET",
api_url + "/comments",
headers={
"User-Agent": "TektonCD, the peaceful cat",
"Authorization": authHeader,
})

resp = conn.getresponse()
if not str(resp.status).startswith("2"):
print("Error: %d" % (resp.status))
print(resp.read())
sys.exit(1)
print(resp.status)

comments = json.loads(resp.read())
print(comments)
# If more than one comment is found take the last one
matching_comment = [x for x in comments if '$(params.COMMENT_TAG)' in x['body']][-1:]
if matching_comment:
matching_comment = matching_comment[0]['url']

if matching_comment:
method = "PATCH"
target_url = urllib.parse.urlparse(matching_comment).path
else:
method = "POST"
target_url = api_url + "/comments"

print("Sending data to GitHub with {} ".format(method))
# Don't print anymore...
# print(data)
r = conn.request(
method,
target_url,
body=json.dumps(data),
headers={
"User-Agent": "TektonCD, the peaceful cat",
"Authorization": authHeader,
})
resp = conn.getresponse()
if not str(resp.status).startswith("2"):
print("Error: %d" % (resp.status))
print(resp.read())
sys.exit(1)
else:
print("a GitHub comment has been {} to $(params.REQUEST_URL)".format(
"updated" if matching_comment else "added"))
20 changes: 8 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,15 @@ Rollout via OpenShift GitOps / ArgoCD and Red Hat Advances Cluster Manager.



## Seal secrets
# Build differ image

```bash
kubeseal \
--controller-name sealed-secret-controller-sealed-secrets \
--controller-namespace sealed-secrets \
--fetch-cert
export VERSION=$(date +%Y%m%d%H%M)
export IMAGE="quay.io/stormshift/gitops-differ:${VERSION}"

podman build --platform linux/amd64,linux/arm64 \
-f gitops-differ.Containerfile \
--manifest ${IMAGE} .
podman manifest push ${IMAGE}

kubeseal \
--controller-name sealed-secret-controller-sealed-secrets \
--controller-namespace sealed-secrets \
--format yaml \
< <(oc create secret generic test --from-literal=key1=supersecret --dry-run=client -o yaml)

```
```
Loading