Skip to content

Commit 2cec184

Browse files
authored
Add an example how to run services as an oc plugin, fix for user.Name and user.Email (#84)
* Add plugin docs, Dockerfile and script * Set git config user and email * readme fix
1 parent 142c6ae commit 2cec184

File tree

14 files changed

+117
-92
lines changed

14 files changed

+117
-92
lines changed

README.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,6 @@ $ export GITHUB_TOKEN=<paste in GitHub access token>
2121
$ ./services promote --from https://github.com/organisation/first-environment.git --to https://github.com/organisation/second-environment.git --service service-a --commit-name <User to commit as> --commit-email <Email to commit as>
2222
```
2323

24-
If the `commit-name` and `commit-email` are not provided, it will attempt to find them in `~/.gitconfig`, otherwise it will fail.
25-
26-
2724
This will _copy_ all files under `/services/service-a/base/config/*` in `first-environment` to `second-environment`, commit and push, and open a PR for the change.
2825

2926

@@ -87,3 +84,13 @@ See the [tekton-example](./tekton-example/README.md) directory for more on using
8784
## Release process
8885

8986
When a new tag is pushed with the `v` prefix, a GitHub release will be created with binaries produced for 64-bit Linux, and Mac automatically.
87+
88+
## Experimental plugin section
89+
90+
Inside of the `plugin` folder you'll see documentation and other files related to using the `services` binary as a plugin to `oc`. This has been tested with the following version on OpenShift 4.3:
91+
92+
```
93+
Client Version: openshift-clients-4.3.13-202004121622
94+
Server Version: 4.3.13
95+
Kubernetes Version: v1.16.2
96+
```

automerge-example/README.md

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,6 @@ This example is for more advanced users. Start with the [tekton-example](../tekt
1818

1919
Our samples currently work with GitHub. They use the `hub` CLI to create a merge commit that when pushed, will merge the associated Pull Request. See [here](https://hub.github.com/hub-merge.1.html) for more details.
2020

21-
## gitconfig
22-
23-
Since we are creating git commits within the Tekton tasks, we need to know the username and email address to associate with them, as in our ['tekton-example'](../tekton-example/README.md). So, edit `gitconfig` and
24-
25-
```sh
26-
kubectl create configmap promoteconfigmap --from-file=gitconfig
27-
```
2821

2922
## Dockerfile
3023

@@ -86,7 +79,7 @@ Set up your Service Account and Secret as per the guide above. In this case you
8679
- A ServiceAccount configured for use by Tekton.
8780
- A Tekton-compatible Secret patched onto that that ServiceAccount containing your GitHub token.
8881

89-
This secret is used in two related ways. We check the source repository out using a Tekton Git PipelineResource. This sets up `~/.gitconfig` with the credentials needed for `git push` to work. It gets these credentials from the `accessToken` field of the relevant secret patched onto the ServiceAccount running the Tekton Task. We then extract the same field and export it into the `GITHUB_TOKEN` environment variable to make `hub merge` work. Instructions for creating this secret are in the Getting Started document linked above. You should have resources of the form,
82+
This secret is used in two related ways. We check the source repository out using a Tekton Git PipelineResource. This sets up Git with the credentials needed for `git push` to work. It gets these credentials from the `accessToken` field of the relevant secret patched onto the ServiceAccount running the Tekton Task. We then extract the same field and export it into the `GITHUB_TOKEN` environment variable to make `hub merge` work. Instructions for creating this secret are in the Getting Started document linked above. You should have resources of the form,
9083

9184
```yaml
9285
---

automerge-example/standalone/templates/automerge-task.yaml

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,15 @@ metadata:
44
name: automerge-task
55
spec:
66
params:
7-
- name: github-config
7+
- name: commit-name
88
type: string
9-
description: configmap name of the gitconfig file that has user name, user e-mail. The key name is gitconfig. It can be created by "kubectl create configmap <configmap name> --from-file=gitconfig"
9+
description: GitHub name to author the commit with
10+
- name: commit-email
11+
type: string
12+
description: GitHub email to author the commit with
1013
- name: github-secret
1114
type: string
1215
description: Name of the secret containing an access token for Github. Expects Tekton format, 'username' and 'password' keys.
13-
volumes:
14-
- name: gitconfig
15-
configMap:
16-
name: $(params.github-config)
17-
items:
18-
- key: gitconfig
19-
path: gitconfig
2016
inputs:
2117
resources:
2218
- name: git-source
@@ -31,13 +27,8 @@ spec:
3127
kubectl apply -k git-source/environments/dev/env --dry-run=client
3228
- name: merge-pr
3329
image: YOUR_DOCKER_HUB_ID/hub-test
34-
volumeMounts:
35-
- name: gitconfig
36-
mountPath: /root
3730
script: |
3831
#!/bin/bash -x
39-
40-
cat /root/gitconfig >> $HOME/.gitconfig
4132
fullPRLink=$(yq r pull-request/pr.json 'Link')
4233
prURL=${fullPRLink%.diff}
4334

automerge-example/webhooks/templates/automerge-task.yaml

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@ metadata:
44
name: automerge-task
55
spec:
66
params:
7-
- name: github-config
8-
type: string
9-
description: configmap name of the gitconfig file that has user name, user e-mail. The key name is gitconfig. It can be created by "kubectl create configmap <configmap name> --from-file=gitconfig"
10-
- name: github-secret
7+
- name: github-secret
118
type: string
129
description: Name of the secret containing an access token for Github. Expects Tekton format, 'username' and 'password' keys.
1310
- name: event-type
@@ -19,13 +16,6 @@ spec:
1916
- name: pull-request-url
2017
type: string
2118
description: The URL of the pull request, where applicable
22-
volumes:
23-
- name: gitconfig
24-
configMap:
25-
name: $(params.github-config)
26-
items:
27-
- key: gitconfig
28-
path: gitconfig
2919
inputs:
3020
resources:
3121
- name: git-source
@@ -38,9 +28,6 @@ spec:
3828
kubectl apply -k git-source/env --dry-run=client
3929
- name: merge-pr
4030
image: YOUR_DOCKER_HUB_ID/hub-test
41-
volumeMounts:
42-
- name: gitconfig
43-
mountPath: /root
4431
script: |
4532
#!/bin/bash -x
4633
@@ -52,12 +39,11 @@ spec:
5239
echo "do nothing"
5340
fi
5441
elif [ $(params.event-type) = "pull_request" ]; then
55-
56-
cat /root/gitconfig >> $HOME/.gitconfig
5742
# GHE requires some extra config
5843
# Replace `YOUR_GHE` with your GitHub Enterprise domain e.g. `github.ibm.com`
5944
git config --global --add hub.host YOUR_GHE
60-
45+
git config --global user.name $(params.commit-name)
46+
git config --global user.email $(params.commit-email)
6147
cd git-source
6248
export HUB_VERBOSE=true
6349
hub merge $(params.pull-request-url)

pkg/git/mock/mock.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,6 @@ func (m *Repository) AssertBranchNotCreated(t *testing.T, from, name string) {
203203
// AssertFileCopiedInBranch asserts the filename was copied from and to in a
204204
// branch.
205205
func (m *Repository) AssertFileCopiedInBranch(t *testing.T, branch, from, name string) {
206-
fmt.Printf("copied: %s\n", m.copiedFiles)
207206
if !hasString(key(branch, from, name), m.copiedFiles) {
208207
t.Fatalf("file %s was not copied from %s to branch %s", name, from, branch)
209208
}

pkg/git/repository.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,30 @@ func (r *Repository) StageFiles(filenames ...string) error {
158158
}
159159

160160
// Commit does the git commit -m with the msg & author
161+
// after first running git config commands for the user.name and user.email
162+
// these are intentionally *not* global settings because we don't want to touch a user's $HOME/.gitconfig
163+
// This means the settings only apply inside of our local repository cache.
161164
func (r *Repository) Commit(msg string, author *Author) error {
165+
_, err := r.execGit(r.repoPath(), envFromAuthor(author), "status")
166+
if err != nil {
167+
return fmt.Errorf("could not set name, err: %w", err)
168+
}
169+
170+
command := fmt.Sprintf("config user.name \"%s\"", author.Name)
171+
commandAsArgs := strings.Split(command, " ")
172+
_, err = r.execGit(r.repoPath(), envFromAuthor(author), commandAsArgs...)
173+
if err != nil {
174+
return fmt.Errorf("could not set name, err: %w", err)
175+
}
176+
command = fmt.Sprintf("config user.email \"%s\"", author.Email)
177+
commandAsArgs = strings.Split(command, " ")
178+
_, err = r.execGit(r.repoPath(), envFromAuthor(author), commandAsArgs...)
179+
if err != nil {
180+
return fmt.Errorf("could not set email, err: %w", err)
181+
}
182+
162183
args := []string{"commit", "-m", msg}
163-
_, err := r.execGit(r.repoPath(), envFromAuthor(author), args...)
184+
_, err = r.execGit(r.repoPath(), envFromAuthor(author), args...)
164185
return err
165186
}
166187

@@ -214,6 +235,7 @@ func envFromAuthor(a *Author) []string {
214235
sf := func(k, v string) string {
215236
return fmt.Sprintf("%s=%s", k, v)
216237
}
238+
217239
return []string{
218240
sf("GIT_AUTHOR_NAME", a.Name),
219241
sf("GIT_AUTHOR_EMAIL", a.Email)}

plugin/Dockerfile

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
FROM ubuntu AS oc-base
2+
3+
# Install curl
4+
RUN apt-get update
5+
RUN apt-get install -y curl
6+
7+
# Install oc
8+
RUN curl -O https://mirror.openshift.com/pub/openshift-v4/clients/oc/4.3/linux/oc.tar.gz
9+
10+
RUN tar xvf oc.tar.gz
11+
RUN chmod +x ./oc
12+
RUN cp ./oc /usr/local/bin/
13+
14+
# Build services binary, rename and add to path
15+
FROM golang:latest AS build
16+
COPY . /go/build
17+
WORKDIR /go/build
18+
19+
RUN CGO_ENABLED=0 GOOS=linux go build ./cmd/services
20+
21+
FROM registry.access.redhat.com/ubi8/ubi-minimal
22+
RUN microdnf install git
23+
WORKDIR /root/
24+
COPY --from=build /go/build/services /usr/local/bin/oc-services
25+
COPY --from=oc-base /usr/local/bin/oc /usr/local/bin/
26+
ENTRYPOINT ["/usr/local/bin/oc"]

plugin/README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
This folder contains an example script that will compile the services binary and name it in such a way that it can be used as a plugin to `oc` - using `oc services promote ...` for example.
2+
3+
A Dockerfile is also provided that will pull in `oc` and copy the built plugin binary into that image. You could then push that image to your own testing place on Dockerhub for use later - be it as a standalone container or as part of a Tekton Task.
4+
5+
Build it with the following command from the main `services` folder:
6+
7+
`docker build -f plugin/Dockerfile -t <dockerusername>/oc-services-plugin-experiment .`
8+
9+
You can then do
10+
11+
`docker run -e GITHUB_TOKEN=<mytoken> <dockerusername>/oc-services-plugin-experiment:latest services promote --from https://github.com/myorg/myrepo --to https://github.com/myorg/myotherrepo --service myservicename --commit-name=<mygitname> --commmit-email=<mygitemail>`
12+
13+
and that's using `promote` but from being an `oc plugin` - useful for seeing if anything breaks.

plugin/make-plugin.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/bin/bash -ex
2+
3+
go build ./cmd/services
4+
mv ./services ./oc-services
5+
chmod +x ./oc-services
6+
sudo mv ./oc-services /usr/local/bin/
7+
oc services --help

tekton-example/README.md

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ Creation of a TaskRun (using `promote-run.yaml`) will then further promote from
1414
- `service-promote-pipeline.yaml`: Creates a pipeline that executes `build-task.yaml` and `service-promote.yaml`
1515
- `promote.yaml`: Creates a pull request from one repository to another repository
1616
- `build-task.yaml`: This task builds a git source into a docker image and pushes to a docker registry
17-
- `gitconfig`: Data file for the configmap - includes a GitHub user ID and email address
1817

1918
## Pre-requisites
2019

@@ -47,23 +46,19 @@ kubectl apply -f resources
4746
```shell
4847
kubectl apply -f templates
4948
```
50-
- Edit `gitconfig` to contain your GitHub username and email address
51-
52-
- Create a configmap:
53-
```shell
54-
kubectl create configmap promote-configmap --from-file=gitconfig
55-
```
56-
This will store your GitHub username and email address in key-value pairs that can be used in the PipelineRun.
5749

5850
## Execute Pipeline
5951

6052
The PipelineRun you will create is designed to build your microservice from its development repository and then promote the new configuration to a GitOps repository (representing a different environment, for example development, staging, test or production).
6153

6254
- To create the PipelineRun, use:
6355
```shell
64-
tkn pipeline start service-promote-pipeline --resource git-source=git-app-repo --resource docker-image=docker-app-image--param commitID=v1 --param github-secret=promote-secret --param github-config=promote-configmap --param to=https://github.com/<github username>/<github repo>.git --workspace name=repo-space,claimName=repopvc,subPath=dir -s demo --showlog
56+
tkn pipeline start service-promote-pipeline --resource git-source=git-app-repo --resource docker-image=docker-app-image--param commitId=v1 --param github-secret=promote-secret --param commit-name=<yourgitname> --param commit-email=<yourgitemail> --param to=https://github.com/<github username>/<github repo>.git --param service=promote-demo --workspace name=repo-space,claimName=repopvc,subPath=dir -s demo --showlog
6557
```
6658

59+
This example promotes from the `promote-demo` repository, containing a service with the same name.
60+
61+
6762
- This creates a PipelineRun that executes the `service-promote-pipeline`, which will build the code and promote it to a repository you have specified
6863
- The logs will be outputted to your console, and you can also view its progress in the Tekton Dashboard.
6964

@@ -72,9 +67,9 @@ tkn pipeline start service-promote-pipeline --resource git-source=git-app-repo -
7267
Optionally, you can run a subsequent promote from one GitOps repository to another (e.g staging to prod) after merging the pull request on your first GitOps repository. For this you will need a third repository, and for this you can fork: https://github.com/rhd-gitops-example/gitops-example-staging
7368

7469
- To do this second promote, you will need to create a TaskRun that executes a task promoting from a testing repository to a production repository
75-
- To create the TaskRun, use:
70+
- To create the TaskRun (again this uses a service called `promote-demo`), use:
7671
```shell
77-
tkn task start promote --param github-secret=promote-secret--param from=https://github.com/<github username>/<github repo> --param from=https://github.com/<github username>/<github repo>.git --param github-config=promote-configmap --param service=service-a -s demo --showlog
72+
tkn task start promote --param github-secret=promote-secret --param from=https://github.com/<yourorg>/<yourdevrepo>.git --param to=https://github.com/<yourorg>/<yourstagingrepo>.git --param commit-name=<yourgitname> --param commit-email=<yourgitemail> --param service=promote-demo -s demo --showlog
7873
```
7974
This will start the TaskRun and output its logs, and you can also view its progress in the Tekton Dashboard.
8075

0 commit comments

Comments
 (0)