Published: Oct 13, 2023 by Isaac Johnson
I noted a couple weeks ago a TechCrunch Article about how Harness has released a free Git system called “Gitness”. The PR Newswire quoted the CEO Jyoti Bansal:
“Gitness marks a significant milestone for Harness and the software development community and represents our commitment to driving innovation and empowering developers worldwide. As the first significant release of an open source Git platform in nearly a decade, Gitness is equipped to provide all developers with the tools they need to streamline their workflows, collaborate effectively, and ensure code quality”
From what I can see, this is just a gifted free tool. So let’s check it out.
Setup
We start by going to gitness.com.
We can see the initial Getting Started page that shows how to run in docker
docker run -d \
-p 3000:3000 \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /tmp/gitness:/data \
--name gitness \
--restart always \
harness/gitness
This will launch as a background daemon on port 3000 and restart with the host. You can remove the “restart” and “-d” options if you want to try it locally without making a background container.
I went ahead and launched as a daemon (can always stop in Docker/Podman desktop)
builder@DESKTOP-QADGF36:~$ docker run -d \
> -p 3000:3000 \
> -v /var/run/docker.sock:/var/run/docker.sock \
> -v /tmp/gitness:/data \
> --name gitness \
> --restart always \
> harness/gitness
Unable to find image 'harness/gitness:latest' locally
latest: Pulling from harness/gitness
96526aa774ef: Pull complete
d4d14a1f5c94: Pull complete
f64b697cf540: Pull complete
ce6acd792289: Pull complete
1c0d819d2d83: Pull complete
602c0335f152: Pull complete
Digest: sha256:81508315971e915cd09634c064c7ed48fc1f0b2c08affe6efb46a09e92762463
Status: Downloaded newer image for harness/gitness:latest
4b36604209fec50f88db768c1e29ff1c27a3a64c1ce073f6803ed63f0b2e82a7
We now head to http://localhost:3000/signin
.
Depending on your screen width, you’ll see either
or
Ignore that Chrome decided to prefill gitea, We’ll click “Sign Up”.
This doesn’t require a confirmation out of the box, so we are launched right into Gitness
I double checked, and no confirmation email was sent (if it had, I would be curious what smtp service was built-in).
Projects
Let’s create a new project
I’ll give it a name and description
I now see it listed
From there I can create a new repository in the project
Let’s start with a Public repo and see we get
It initialized as I asked with a .gitignore, LICENSE and README.md on main (the other option for initial branch was master, or set your own).
In settings, we could switch it between Public and Private - so you are not locked in at create time.
I’ll click “Clone” to get an HTTP url I can use. To start, I will not generate credentials
Cloning worked just fine
builder@DESKTOP-QADGF36:~/Workspaces$ git clone http://localhost:3000/git/MyTestProject/MyFirstRepo.git
Cloning into 'MyFirstRepo'...
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 5 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (5/5), 6.42 KiB | 2.14 MiB/s, done.
builder@DESKTOP-QADGF36:~/Workspaces$ cd MyFirstRepo/
builder@DESKTOP-QADGF36:~/Workspaces/MyFirstRepo$ ls
LICENSE README.md
I’ll now make a change to an existing file
builder@DESKTOP-QADGF36:~/Workspaces/MyFirstRepo$ vi README.md
builder@DESKTOP-QADGF36:~/Workspaces/MyFirstRepo$ git diff README.md
diff --git a/README.md b/README.md
index 97ec28d..59acfb6 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,5 @@
# MyFirstRepo
-My First Repo
\ No newline at end of file
+My First Repo
+
+# Author
+Isaac
Then add and commit
builder@DESKTOP-QADGF36:~/Workspaces/MyFirstRepo$ git add README.md
builder@DESKTOP-QADGF36:~/Workspaces/MyFirstRepo$ git commit -m "Update Readme.md"
[main fd3a15b] Update Readme.md
1 file changed, 4 insertions(+), 1 deletion(-)
I could not push anonmyously
builder@DESKTOP-QADGF36:~/Workspaces/MyFirstRepo$ git push
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 16 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 297 bytes | 297.00 KiB/s, done.
Total 3 (delta 1), reused 0 (delta 0)
error: RPC failed; HTTP 401 curl 22 The requested URL returned error: 401
fatal: the remote end hung up unexpectedly
fatal: the remote end hung up unexpectedly
Everything up-to-date
builder@DESKTOP-QADGF36:~/Workspace
I’ll take a step back and get those GIT credentials
Trying to push again prompted me for creds which I used the credentials shown above
builder@DESKTOP-QADGF36:~/Workspaces/MyFirstRepo$ git push
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 16 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 297 bytes | 297.00 KiB/s, done.
Total 3 (delta 1), reused 0 (delta 0)
Username for 'http://localhost:3000': idjohnson
Password for 'http://idjohnson@localhost:3000':
remote:
remote: Create a new PR for branch 'main'
remote: http://localhost:3000/MyTestProject/MyFirstRepo/pulls/compare/main...main
remote:
To http://localhost:3000/git/MyTestProject/MyFirstRepo.git
b393190..fd3a15b main -> main
We can see the update now in gitness
We can see that even with “public” repos, we must auth for the WebUI
Pipelines
Let’s create a pipeline
We can give it a name and path
This brings up a rather clean in-line editor. For such a beta product, I was slightly impressed
I’ll quick create a Webhook in Discord for Gitness
I’ll use a custom icon (because I like pretty icons) and copy the webhook URL
It should be in the format https://discord.com/api/webhooks/WEBHOOKID/WEBHOOKTOKEN
I’ll now use that in the “Add discord step”
By default, that is going to put a real token into a “public” repo, probably not ideal.
I’ll test with this first to see if it works, then we will address that secret info. I click “Save and Run” in the upper right which prompts for a branch
And it kicks in the pipeline
And I see an update in my #monitoring channel
Secrets
Let’s try and sort out that secret.
We’ll create a new Secret in the Secrets section
I’ll give it a name, description and paste the value. Since the value is hidden, i first pasted into the description to check my clipboard contents
which confirms creation when we save
I’ll try using the standard harness syntax for accessing secrets first
and commit right to main
Since there is no CI trigger (yet), I’ll need to hop over to pipelines to manually run
It didn’t work. I tried a few other syntaxes
webhook_id: "1160907943923953715"
webhook_token: {{.Values.discordtoken | quote}}
generated a pipeline internal error and
webhook_id: "1160907943923953715"
webhook_token: {secrets.getValue("discordtoken")}
didn’t do anything (tho it did run). I also tried with $
at the start.
In the end, I tried
webhook_token: {{.Values.discordtoken | quote}}
webhook_token: ${{.Values.discordtoken | quote}}
webhook_token: {secrets.getValue("discordtoken")}
webhook_token: ${secrets.getValue("discordtoken")}
webhook_token: ${discordtoken}
webhook_token: <+secrets.getValue("discordtoken")>
At this point I’m out of ideas (and google searching and github searching found no good examples).
I tried an option from Bing
- type: plugin
configuration:
discordtoken:
type: SECRET
value: ${secrets.discordtoken}
spec:
name: discord
inputs:
message: PipelineDone2
tts: true
username: _isaacjohnson
webhook_id: "1160907943923953715"
webhook_token: "${discordtoken}"
Suffice to say, nothing I tried worked.
CI
So right now, the default trigger just runs on PRs
Here I’ll set it to run when a branch is updated
I think it might work, but there is nothing that let’s me scope to the main branch or shows that ‘branch updated’ setting on the right-hand side after saving
Webhooks
I’ll use webhook.site to do a quick webhook test
Now that the webhook is created
I’ll push a change to main
builder@DESKTOP-QADGF36:~/Workspaces/MyFirstRepo$ git pull
remote: Enumerating objects: 53, done.
remote: Counting objects: 100% (53/53), done.
remote: Compressing objects: 100% (39/39), done.
remote: Total 52 (delta 24), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (52/52), 4.66 KiB | 433.00 KiB/s, done.
From http://localhost:3000/git/MyTestProject/MyFirstRepo
fd3a15b..8480b91 main -> origin/main
Updating fd3a15b..8480b91
Fast-forward
.harness/MyFirstPipeline.yaml | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
create mode 100644 .harness/MyFirstPipeline.yaml
builder@DESKTOP-QADGF36:~/Workspaces/MyFirstRepo$ vi README.md
builder@DESKTOP-QADGF36:~/Workspaces/MyFirstRepo$ git diff README.md
diff --git a/README.md b/README.md
index 59acfb6..232ae25 100644
--- a/README.md
+++ b/README.md
@@ -2,4 +2,4 @@
My First Repo
# Author
-Isaac
+Isaac Johnson
builder@DESKTOP-QADGF36:~/Workspaces/MyFirstRepo$ git add README.md
builder@DESKTOP-QADGF36:~/Workspaces/MyFirstRepo$ git commit -m "minor change"
[main 5c701c8] minor change
1 file changed, 1 insertion(+), 1 deletion(-)
builder@DESKTOP-QADGF36:~/Workspaces/MyFirstRepo$ git push
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 16 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 303 bytes | 303.00 KiB/s, done.
Total 3 (delta 1), reused 0 (delta 0)
remote:
remote: Create a new PR for branch 'main'
remote: http://localhost:3000/MyTestProject/MyFirstRepo/pulls/compare/main...main
remote:
To http://localhost:3000/git/MyTestProject/MyFirstRepo.git
8480b91..5c701c8 main -> main
And see a branch_updated
event was pushed
I can see that it created a pipeline run, which validated the main trigger, but that itself didn’t push any new webhooks.
Neither did a subsequent manual run.
Kubernetes
There is no chart I can find published for Gitness.
So let’s make one!
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app.kubernetes.io/instance: gitness
app.kubernetes.io/name: gitness
name: gitness
namespace: default
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app.kubernetes.io/instance: gitness
app.kubernetes.io/name: gitness
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
app.kubernetes.io/instance: gitness
app.kubernetes.io/name: gitness
spec:
containers:
- image: harness/gitness:latest
imagePullPolicy: IfNotPresent
name: gitness
ports:
- containerPort: 3000
name: gitness
protocol: TCP
resources:
requests:
cpu: 250m
memory: 256Mi
securityContext:
runAsNonRoot: true
runAsUser: 1001
volumeMounts:
- mountPath: /data
name: data
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext:
fsGroup: 1001
serviceAccount: default
serviceAccountName: default
terminationGracePeriodSeconds: 30
volumes:
- name: data
persistentVolumeClaim:
claimName: gitness-data
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
labels:
app.kubernetes.io/instance: gitness
app.kubernetes.io/name: gitness
name: gitness-data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: managed-nfs-storage
---
apiVersion: v1
kind: Service
metadata:
annotations:
app.kubernetes.io/instance: gitness
app.kubernetes.io/name: gitness
labels:
app.kubernetes.io/instance: gitness
app.kubernetes.io/name: gitness
name: gitness
spec:
internalTrafficPolicy: Cluster
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- name: gitness
port: 3000
protocol: TCP
targetPort: gitness
selector:
app.kubernetes.io/instance: gitness
app.kubernetes.io/name: gitness
sessionAffinity: None
type: ClusterIP
We can now port-forward
$ kubectl port-forward svc/gitness 3000:3000
Forwarding from 127.0.0.1:3000 -> 3000
Forwarding from [::1]:3000 -> 3000
Handling connection for 3000
Handling connection for 3000
Handling connection for 3000
and create a new account
I’ll make a second project
And a repo inside of it
What we want to do next is double check the PVC really stores the data by deleting the running pod and logging in again
Upgrades
This is a free offering from Harness.io, but we can see they plan to add a “migrate to Harness Software Delivery platform” option in future versions:
Summary
If I can solve secrets in the pipelines, then I might have a very usable basic Gitea equivalent. Let’s be fair; there is no email or notifications setup outside of pipelines and webhooks, there are no frills; plugins, federated identity, etc. But it’s a very fast lightweight container-based tool.
When added with a protected drive (like using a NAS to host it) or using Helm and partnering with a PVC, this is actually a fairly usable product. We still need to explore a few more features such as PRs, but I’ll be keen to see where Harness takes this offering.