diff --git a/kubernetes/chart/.helmignore b/kubernetes/chart/.helmignore
new file mode 100644
index 00000000..0e8a0eb3
--- /dev/null
+++ b/kubernetes/chart/.helmignore
@@ -0,0 +1,23 @@
+# Patterns to ignore when building packages.
+# This supports shell glob matching, relative path matching, and
+# negation (prefixed with !). Only one pattern per line.
+.DS_Store
+# Common VCS dirs
+.git/
+.gitignore
+.bzr/
+.bzrignore
+.hg/
+.hgignore
+.svn/
+# Common backup files
+*.swp
+*.bak
+*.tmp
+*.orig
+*~
+# Various IDEs
+.project
+.idea/
+*.tmproj
+.vscode/
diff --git a/kubernetes/chart/Chart.yaml b/kubernetes/chart/Chart.yaml
new file mode 100644
index 00000000..67362bf6
--- /dev/null
+++ b/kubernetes/chart/Chart.yaml
@@ -0,0 +1,15 @@
+apiVersion: v2
+type: application
+name: sourcebot
+version: 0.1.0
+appVersion: ""
+description: The open source Sourcegraph alternative. Sourcebot gives you a powerful interface to search though all your repos and branches across multiple code hosts.
+icon: https://raw.githubusercontent.com/sourcebot-dev/sourcebot/ebf6721836b8f878d42bb8c1e844bdc7867a74fe/packages/web/public/logo_512.png
+keywords:
+ - code-search
+ - code-intelligence
+ - sourcebot
+home: https://sourcebot.dev/
+sources:
+ - https://github.com/sourcebot-dev/sourcebot
+ - https://github.com/sourcebot-dev/sourcebot/kubernetes/chart
diff --git a/kubernetes/chart/README.md b/kubernetes/chart/README.md
new file mode 100644
index 00000000..47861d5b
--- /dev/null
+++ b/kubernetes/chart/README.md
@@ -0,0 +1,92 @@
+# sourcebot
+
+ 
+
+The open source Sourcegraph alternative. Sourcebot gives you a powerful interface to search though all your repos and branches across multiple code hosts.
+
+**Homepage:**
+
+## Source Code
+
+*
+*
+
+## Values
+
+| Key | Type | Default | Description |
+|-----|------|---------|-------------|
+| additionalLabels | object | `{}` | Add extra labels to all resources. |
+| affinity | object | `{}` | Set affinity rules for pod scheduling. Defaults to soft anti-affinity if not set. See: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/ |
+| args | list | `[]` | Override the default arguments of the container. |
+| autoscaling | object | `{"enabled":false,"maxReplicas":3,"minReplicas":1,"targetCPUUtilizationPercentage":80,"targetMemoryUtilizationPercentage":80}` | Configure Horizontal Pod Autoscaler. |
+| autoscaling.enabled | bool | `false` | Enable or disable Horizontal Pod Autoscaler. |
+| autoscaling.maxReplicas | int | `3` | Maximum number of replicas. |
+| autoscaling.minReplicas | int | `1` | Minimum number of replicas. |
+| autoscaling.targetCPUUtilizationPercentage | int | `80` | Target CPU utilization percentage for autoscaling. |
+| autoscaling.targetMemoryUtilizationPercentage | int | `80` | Target memory utilization percentage for autoscaling. |
+| command | list | `[]` | Override the default command of the container. |
+| config | object | `{"$schema":"https://raw.githubusercontent.com/sourcebot-dev/sourcebot/main/schemas/v3/index.json","connections":{},"settings":{}}` | Configure Sourcebot-specific application settings. |
+| containerSecurityContext | object | `{}` | Set the container-level security context. |
+| database | object | `{}` | Configure the database secret. |
+| envSecrets | list | `[]` | Set environment variables from Kubernetes secrets. |
+| envs | list | `[]` | Set additional environment variables. |
+| fullnameOverride | string | `""` | Override the full name of the chart. |
+| image | object | `{"pullPolicy":"Always","repository":"ghcr.io/sourcebot-dev/sourcebot","tag":"latest"}` | Configure the container image. |
+| image.pullPolicy | string | `"Always"` | Image pull policy. |
+| image.repository | string | `"ghcr.io/sourcebot-dev/sourcebot"` | Container image repository. |
+| image.tag | string | `"latest"` | Container image tag. |
+| imagePullSecrets | list | `[]` | Configure image pull secrets for private registries. |
+| ingress | object | `{"annotations":{},"className":"","enabled":false,"hosts":[],"tls":[]}` | Configure ingress for Sourcebot. |
+| ingress.annotations | object | `{}` | Ingress annotations. |
+| ingress.className | string | `""` | Ingress class name. |
+| ingress.enabled | bool | `false` | Enable or disable ingress. |
+| ingress.hosts | list | `[]` | List of hostnames and paths for ingress rules. |
+| ingress.tls | list | `[]` | TLS settings for ingress. |
+| initContainers | list | `[]` | Configure init containers to run before the main container. |
+| license | object | `{}` | Configure the enterprise license key secret. |
+| livenessProbe | object | `{"failureThreshold":5,"httpGet":{"path":"/","port":"http"},"initialDelaySeconds":10,"periodSeconds":10}` | Liveness probe to check if the container is alive. |
+| livenessProbe.failureThreshold | int | `5` | Number of consecutive failures before marking the container as unhealthy. |
+| livenessProbe.httpGet | object | `{"path":"/","port":"http"}` | Http GET request to check if the container is alive. |
+| livenessProbe.httpGet.path | string | `"/"` | Path to check. |
+| livenessProbe.httpGet.port | string | `"http"` | Port to check. |
+| livenessProbe.initialDelaySeconds | int | `10` | Initial delay before the first probe. |
+| livenessProbe.periodSeconds | int | `10` | Frequency of the probe. |
+| nameOverride | string | `""` | Override the name of the chart. |
+| nodeSelector | object | `{}` | Set node selector constraints. See: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector |
+| podAnnotations | object | `{}` | Add annotations to the pod metadata. |
+| podDisruptionBudget | object | `{"enabled":true,"maxUnavailable":1,"minAvailable":1}` | Configure Pod Disruption Budget. |
+| podDisruptionBudget.enabled | bool | `true` | Enable Pod Disruption Budget. |
+| podDisruptionBudget.maxUnavailable | int | `1` | Maximum number of pods that can be unavailable. |
+| podDisruptionBudget.minAvailable | int | `1` | Minimum number of pods that must be available. |
+| podSecurityContext | object | `{}` | Set the pod-level security context. |
+| priorityClassName | string | `""` | Set the priority class name for pods. See: https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/ |
+| readinessProbe | object | `{"failureThreshold":5,"httpGet":{"path":"/","port":"http"},"initialDelaySeconds":10,"periodSeconds":10}` | Readiness probe to check if the container is ready to serve traffic. |
+| readinessProbe.failureThreshold | int | `5` | Number of consecutive failures before marking the container as not ready. |
+| readinessProbe.httpGet | object | `{"path":"/","port":"http"}` | Http GET request to check if the container is ready. |
+| readinessProbe.httpGet.path | string | `"/"` | Path to check. |
+| readinessProbe.httpGet.port | string | `"http"` | Port to check. |
+| readinessProbe.initialDelaySeconds | int | `10` | Initial delay before the first probe. |
+| readinessProbe.periodSeconds | int | `10` | Frequency of the probe. |
+| redis | object | `{}` | Configure the Redis secret. |
+| replicaCount | int | `1` | Set the number of replicas for the deployment. |
+| resources | object | `{}` | Configure resource requests and limits for the container. |
+| service | object | `{"annotations":{},"containerPort":3000,"port":3000,"type":"ClusterIP"}` | Configure the Sourcebot Kubernetes service. |
+| service.annotations | object | `{}` | Service annotations. |
+| service.containerPort | int | `3000` | Internal container port. |
+| service.port | int | `3000` | External service port. |
+| service.type | string | `"ClusterIP"` | Type of the Kubernetes service (e.g., ClusterIP, NodePort, LoadBalancer). |
+| serviceAccount | object | `{"annotations":{},"automount":false,"create":true,"name":""}` | Configure the ServiceAccount. |
+| serviceAccount.annotations | object | `{}` | Add annotations to the ServiceAccount. |
+| serviceAccount.automount | bool | `false` | Enable or disable automatic ServiceAccount mounting. |
+| serviceAccount.create | bool | `true` | Create a new ServiceAccount. |
+| serviceAccount.name | string | `""` | Use an existing ServiceAccount (if set). |
+| startupProbe | object | `{"failureThreshold":30,"httpGet":{"path":"/","port":"http"},"periodSeconds":30}` | Startup probe to check if the container has started successfully. |
+| startupProbe.failureThreshold | int | `30` | Number of seconds to wait before starting the probe. |
+| startupProbe.httpGet | object | `{"path":"/","port":"http"}` | Http GET request to check if the container has started. |
+| startupProbe.httpGet.path | string | `"/"` | Path to check. |
+| startupProbe.httpGet.port | string | `"http"` | Port to check. |
+| startupProbe.periodSeconds | int | `30` | Initial delay before the first probe. |
+| tolerations | list | `[]` | Set tolerations for pod scheduling. See: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ |
+| volumeMounts | list | `[]` | Define volume mounts for the container. |
+| volumes | list | `[]` | Define additional volumes. |
+
diff --git a/kubernetes/chart/templates/NOTES.txt b/kubernetes/chart/templates/NOTES.txt
new file mode 100644
index 00000000..2adfa79c
--- /dev/null
+++ b/kubernetes/chart/templates/NOTES.txt
@@ -0,0 +1,22 @@
+1. Get the application URL by running these commands:
+{{- if $.Values.ingress.enabled }}
+{{- range $host := $.Values.ingress.hosts }}
+ {{- range .paths }}
+ http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
+ {{- end }}
+{{- end }}
+{{- else if contains "NodePort" $.Values.service.type }}
+ export NODE_PORT=$(kubectl get --namespace {{ $.Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "sourcebot.fullname" $ }})
+ export NODE_IP=$(kubectl get nodes --namespace {{ $.Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
+ echo http://$NODE_IP:$NODE_PORT
+{{- else if contains "LoadBalancer" $.Values.service.type }}
+ NOTE: It may take a few minutes for the LoadBalancer IP to be available.
+ You can watch its status by running 'kubectl get --namespace {{ $.Release.Namespace }} svc -w {{ include "sourcebot.fullname" $ }}'
+ export SERVICE_IP=$(kubectl get svc --namespace {{ $.Release.Namespace }} {{ include "sourcebot.fullname" $ }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
+ echo http://$SERVICE_IP:{{ $.Values.service.port }}
+{{- else if contains "ClusterIP" $.Values.service.type }}
+ export POD_NAME=$(kubectl get pods --namespace {{ $.Release.Namespace }} -l "app.kubernetes.io/name={{ include "sourcebot.name" $ }},app.kubernetes.io/instance={{ $.Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
+ export CONTAINER_PORT=$(kubectl get pod --namespace {{ $.Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
+ echo "Visit http://127.0.0.1:3000 to use Sourcebot after forwarding"
+ kubectl --namespace {{ $.Release.Namespace }} port-forward $POD_NAME 3000:$CONTAINER_PORT
+{{- end }}
diff --git a/kubernetes/chart/templates/_helpers.tpl b/kubernetes/chart/templates/_helpers.tpl
new file mode 100644
index 00000000..7ff85c01
--- /dev/null
+++ b/kubernetes/chart/templates/_helpers.tpl
@@ -0,0 +1,78 @@
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "sourcebot.name" -}}
+{{- default $.Chart.Name $.Values.nameOverride | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Create a default fully qualified app name.
+We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
+If release name contains chart name it will be used as a full name.
+*/}}
+{{- define "sourcebot.fullname" -}}
+{{- if $.Values.fullnameOverride }}
+{{- $.Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- $name := default $.Chart.Name $.Values.nameOverride }}
+{{- if contains $name $.Release.Name }}
+{{- $.Release.Name | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- printf "%s-%s" $.Release.Name $name | trunc 63 | trimSuffix "-" }}
+{{- end }}
+{{- end }}
+{{- end }}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "sourcebot.chart" -}}
+{{- printf "%s-%s" $.Chart.Name $.Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Common labels
+*/}}
+{{- define "sourcebot.labels" -}}
+helm.sh/chart: {{ include "sourcebot.chart" $ }}
+{{ include "sourcebot.selectorLabels" $ }}
+{{- if $.Chart.AppVersion }}
+app.kubernetes.io/version: {{ $.Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ $.Release.Service }}
+{{- with $.Values.additionalLabels }}
+{{ toYaml . }}
+{{- end }}
+{{- end }}
+
+{{/*
+Selector labels
+*/}}
+{{- define "sourcebot.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "sourcebot.name" $ }}
+app.kubernetes.io/instance: {{ $.Release.Name }}
+{{- end }}
+
+{{/*
+Create the image to use for the container.
+*/}}
+{{- define "sourcebot.image" -}}
+{{- if $.Values.image.digest -}}
+"{{ $.Values.image.repository }}@{{ $.Values.image.digest }}"
+{{- else if $.Values.image.tag -}}
+"{{ $.Values.image.repository }}:{{ $.Values.image.tag }}"
+{{- else -}}
+"{{ $.Values.image.repository }}:{{ $.Chart.AppVersion }}"
+{{- end -}}
+{{- end }}
+
+{{/*
+Create the name of the service account to use
+*/}}
+{{- define "sourcebot.serviceAccountName" -}}
+{{- if $.Values.serviceAccount.create }}
+{{- default (include "sourcebot.fullname" $) $.Values.serviceAccount.name }}
+{{- else }}
+{{- default "default" $.Values.serviceAccount.name }}
+{{- end }}
+{{- end }}
diff --git a/kubernetes/chart/templates/config.yaml b/kubernetes/chart/templates/config.yaml
new file mode 100644
index 00000000..43cbf16e
--- /dev/null
+++ b/kubernetes/chart/templates/config.yaml
@@ -0,0 +1,10 @@
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: {{ include "sourcebot.fullname" $ }}
+ labels:
+ {{- include "sourcebot.labels" $ | nindent 4 }}
+data:
+ config.json: |
+ {{- toJson $.Values.config | nindent 4 }}
diff --git a/kubernetes/chart/templates/deployment.yaml b/kubernetes/chart/templates/deployment.yaml
new file mode 100644
index 00000000..584f1fa7
--- /dev/null
+++ b/kubernetes/chart/templates/deployment.yaml
@@ -0,0 +1,136 @@
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: {{ include "sourcebot.fullname" $ }}
+ labels:
+ {{- include "sourcebot.labels" $ | nindent 4 }}
+spec:
+ {{- if not $.Values.autoscaling.enabled }}
+ replicas: {{ $.Values.replicaCount }}
+ {{- end }}
+ selector:
+ matchLabels:
+ {{- include "sourcebot.selectorLabels" $ | nindent 6 }}
+ template:
+ metadata:
+ {{- with $.Values.podAnnotations }}
+ annotations:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ labels:
+ {{- include "sourcebot.labels" $ | nindent 8 }}
+ {{- with $.Values.podLabels }}
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ spec:
+ {{- with $.Values.imagePullSecrets }}
+ imagePullSecrets:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ serviceAccountName: {{ include "sourcebot.serviceAccountName" $ }}
+ {{- with $.Values.podSecurityContext }}
+ securityContext:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ containers:
+ - name: {{ .Chart.Name }}
+ {{- with $.Values.containerSecurityContext }}
+ securityContext:
+ {{- toYaml . | nindent 12 }}
+ {{- end }}
+ image: {{ include "sourcebot.image" $ }}
+ imagePullPolicy: {{ $.Values.image.pullPolicy }}
+ {{- with $.Values.command }}
+ command: {{ toYaml . | nindent 12 }}
+ {{- end }}
+ {{- with $.Values.args }}
+ args: {{ toYaml . | nindent 12 }}
+ {{- end }}
+ env:
+ - name: CONFIG_PATH
+ value: /etc/sourcebot/config.json
+ {{- if $.Values.license }}
+ - name: SOURCEBOT_EE_LICENSE_KEY
+ valueFrom:
+ secretKeyRef:
+ name: {{ $.Values.license.secretName }}
+ key: {{ $.Values.license.secretKey }}
+ {{- end }}
+ {{- if $.Values.database }}
+ - name: DATABASE_URL
+ valueFrom:
+ secretKeyRef:
+ name: {{ $.Values.database.secretName }}
+ key: {{ $.Values.database.secretKey }}
+ {{- end }}
+ {{- if $.Values.redis }}
+ - name: REDIS_URL
+ valueFrom:
+ secretKeyRef:
+ name: {{ $.Values.redis.secretName }}
+ key: {{ $.Values.redis.secretKey }}
+ {{- end }}
+ {{- range $.Values.envSecrets }}
+ - name: {{ .envName }}
+ valueFrom:
+ secretKeyRef:
+ name: {{ .secretName }}
+ key: {{ .secretKey }}
+ {{- end }}
+ {{- with $.Values.envs }}
+ {{- toYaml . | nindent 12 }}
+ {{- end }}
+ ports:
+ - name: http
+ containerPort: {{ $.Values.service.containerPort }}
+ protocol: TCP
+ {{- with $.Values.livenessProbe }}
+ livenessProbe:
+ {{- toYaml . | nindent 12 }}
+ {{- end }}
+ {{- with $.Values.readinessProbe }}
+ readinessProbe:
+ {{- toYaml . | nindent 12 }}
+ {{- end }}
+ {{- with $.Values.startupProbe }}
+ startupProbe:
+ {{- toYaml . | nindent 12 }}
+ {{- end }}
+ {{- with $.Values.resources }}
+ resources:
+ {{- toYaml . | nindent 12 }}
+ {{- end }}
+ volumeMounts:
+ - name: sourcebot-config
+ mountPath: /etc/sourcebot/config.json
+ subPath: config.json
+ readOnly: true
+ {{- with $.Values.volumeMounts }}
+ {{- toYaml . | nindent 12 }}
+ {{- end }}
+ {{- with $.Values.priorityClassName }}
+ priorityClassName: {{ . }}
+ {{- end }}
+ volumes:
+ - name: sourcebot-config
+ configMap:
+ name: {{ include "sourcebot.fullname" $ }}
+ items:
+ - key: config.json
+ path: config.json
+ {{- with $.Values.volumes }}
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ {{- with $.Values.nodeSelector }}
+ nodeSelector:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ {{- with $.Values.affinity }}
+ affinity:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ {{- with $.Values.tolerations }}
+ tolerations:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
diff --git a/kubernetes/chart/templates/hpa.yaml b/kubernetes/chart/templates/hpa.yaml
new file mode 100644
index 00000000..8079dc75
--- /dev/null
+++ b/kubernetes/chart/templates/hpa.yaml
@@ -0,0 +1,33 @@
+{{- if $.Values.autoscaling.enabled }}
+---
+apiVersion: autoscaling/v2
+kind: HorizontalPodAutoscaler
+metadata:
+ name: {{ include "sourcebot.fullname" $ }}
+ labels:
+ {{- include "sourcebot.labels" $ | nindent 4 }}
+spec:
+ scaleTargetRef:
+ apiVersion: apps/v1
+ kind: Deployment
+ name: {{ include "sourcebot.fullname" $ }}
+ minReplicas: {{ $.Values.autoscaling.minReplicas }}
+ maxReplicas: {{ $.Values.autoscaling.maxReplicas }}
+ metrics:
+ {{- if $.Values.autoscaling.targetCPUUtilizationPercentage }}
+ - type: Resource
+ resource:
+ name: cpu
+ target:
+ type: Utilization
+ averageUtilization: {{ $.Values.autoscaling.targetCPUUtilizationPercentage }}
+ {{- end }}
+ {{- if $.Values.autoscaling.targetMemoryUtilizationPercentage }}
+ - type: Resource
+ resource:
+ name: memory
+ target:
+ type: Utilization
+ averageUtilization: {{ $.Values.autoscaling.targetMemoryUtilizationPercentage }}
+ {{- end }}
+{{- end }}
diff --git a/kubernetes/chart/templates/ingress.yaml b/kubernetes/chart/templates/ingress.yaml
new file mode 100644
index 00000000..e0f563e7
--- /dev/null
+++ b/kubernetes/chart/templates/ingress.yaml
@@ -0,0 +1,44 @@
+{{- if $.Values.ingress.enabled -}}
+---
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: {{ include "sourcebot.fullname" $ }}
+ labels:
+ {{- include "sourcebot.labels" $ | nindent 4 }}
+ {{- with $.Values.ingress.annotations }}
+ annotations:
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+spec:
+ {{- with $.Values.ingress.className }}
+ ingressClassName: {{ . }}
+ {{- end }}
+ {{- if $.Values.ingress.tls }}
+ tls:
+ {{- range $.Values.ingress.tls }}
+ - hosts:
+ {{- range .hosts }}
+ - {{ . | quote }}
+ {{- end }}
+ secretName: {{ .secretName }}
+ {{- end }}
+ {{- end }}
+ rules:
+ {{- range $.Values.ingress.hosts }}
+ - host: {{ .host | quote }}
+ http:
+ paths:
+ {{- range .paths }}
+ - path: {{ .path }}
+ {{- with .pathType }}
+ pathType: {{ . }}
+ {{- end }}
+ backend:
+ service:
+ name: {{ include "sourcebot.fullname" $ }}
+ port:
+ number: {{ $.Values.service.port }}
+ {{- end }}
+ {{- end }}
+{{- end }}
diff --git a/kubernetes/chart/templates/pdb.yaml b/kubernetes/chart/templates/pdb.yaml
new file mode 100644
index 00000000..307b98f7
--- /dev/null
+++ b/kubernetes/chart/templates/pdb.yaml
@@ -0,0 +1,18 @@
+{{- if and $.Values.podDisruptionBudget.enabled (gt (int $.Values.replicaCount) 1) }}
+apiVersion: {{ include "common.capabilities.policy.apiVersion" . }}
+kind: PodDisruptionBudget
+metadata:
+ name: {{ include "sourcebot.fullname" $ }}
+ labels:
+ {{- include "sourcebot.labels" $ | nindent 4 }}
+spec:
+ {{- if $.Values.podDisruptionBudget.minAvailable }}
+ minAvailable: {{ $.Values.podDisruptionBudget.minAvailable }}
+ {{- end }}
+ {{- if $.Values.podDisruptionBudget.maxUnavailable }}
+ maxUnavailable: {{ $.Values.podDisruptionBudget.maxUnavailable }}
+ {{- end }}
+ selector:
+ matchLabels:
+ {{- include "sourcebot.selectorLabels" $ | nindent 6 }}
+{{- end }}
diff --git a/kubernetes/chart/templates/service.yaml b/kubernetes/chart/templates/service.yaml
new file mode 100644
index 00000000..8c9c5bb0
--- /dev/null
+++ b/kubernetes/chart/templates/service.yaml
@@ -0,0 +1,16 @@
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ include "sourcebot.fullname" $ }}
+ labels:
+ {{- include "sourcebot.labels" $ | nindent 4 }}
+spec:
+ type: {{ $.Values.service.type }}
+ ports:
+ - port: {{ $.Values.service.port }}
+ targetPort: http
+ protocol: TCP
+ name: http
+ selector:
+ {{- include "sourcebot.selectorLabels" $ | nindent 4 }}
diff --git a/kubernetes/chart/templates/serviceaccount.yaml b/kubernetes/chart/templates/serviceaccount.yaml
new file mode 100644
index 00000000..fcf0a219
--- /dev/null
+++ b/kubernetes/chart/templates/serviceaccount.yaml
@@ -0,0 +1,14 @@
+{{- if $.Values.serviceAccount.create -}}
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: {{ include "sourcebot.serviceAccountName" . }}
+ labels:
+ {{- include "sourcebot.labels" . | nindent 4 }}
+ {{- with $.Values.serviceAccount.annotations }}
+ annotations:
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+automountServiceAccountToken: {{ $.Values.serviceAccount.automount }}
+{{- end }}
diff --git a/kubernetes/chart/values.schema.json b/kubernetes/chart/values.schema.json
new file mode 100644
index 00000000..3a8b10cf
--- /dev/null
+++ b/kubernetes/chart/values.schema.json
@@ -0,0 +1,469 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "Sourcebot Helm Chart Values Schema",
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "nameOverride": {
+ "type": "string"
+ },
+ "fullnameOverride": {
+ "type": "string"
+ },
+ "replicaCount": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "image": {
+ "type": "object",
+ "properties": {
+ "repository": {
+ "type": "string"
+ },
+ "tag": {
+ "type": "string"
+ },
+ "digest": {
+ "type": "string"
+ },
+ "pullPolicy": {
+ "type": "string",
+ "enum": [
+ "Always",
+ "IfNotPresent",
+ "Never"
+ ]
+ }
+ },
+ "required": [
+ "repository"
+ ]
+ },
+ "imagePullSecrets": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "command": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "args": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "database": {
+ "type": "object"
+ },
+ "redis": {
+ "type": "object"
+ },
+ "license": {
+ "type": "object"
+ },
+ "envSecrets": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "secretName": {
+ "type": "string"
+ },
+ "secretKey": {
+ "type": "string"
+ },
+ "envName": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "secretName",
+ "secretKey",
+ "envName"
+ ]
+ }
+ },
+ "envs": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "value": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "name",
+ "value"
+ ]
+ }
+ },
+ "config": {
+ "type": "object",
+ "properties": {
+ "connections": {
+ "type": "object"
+ },
+ "settings": {
+ "type": "object"
+ }
+ }
+ },
+ "serviceAccount": {
+ "type": "object",
+ "properties": {
+ "create": {
+ "type": "boolean"
+ },
+ "name": {
+ "type": "string"
+ },
+ "annotations": {
+ "type": "object"
+ },
+ "automount": {
+ "type": "boolean"
+ }
+ }
+ },
+ "podSecurityContext": {
+ "type": "object",
+ "properties": {
+ "runAsUser": {
+ "type": "integer"
+ },
+ "runAsGroup": {
+ "type": "integer"
+ },
+ "runAsNonRoot": {
+ "type": "boolean"
+ },
+ "fsGroup": {
+ "type": "integer"
+ }
+ }
+ },
+ "containerSecurityContext": {
+ "type": "object",
+ "properties": {
+ "allowPrivilegeEscalation": {
+ "type": "boolean"
+ },
+ "privileged": {
+ "type": "boolean"
+ },
+ "readOnlyRootFilesystem": {
+ "type": "boolean"
+ },
+ "runAsUser": {
+ "type": "integer"
+ },
+ "runAsGroup": {
+ "type": "integer"
+ },
+ "capabilities": {
+ "type": "object",
+ "properties": {
+ "drop": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "seccompProfile": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "RuntimeDefault",
+ "Unconfined",
+ "Localhost"
+ ]
+ }
+ }
+ }
+ }
+ },
+ "service": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "ClusterIP",
+ "NodePort",
+ "LoadBalancer",
+ "ExternalName"
+ ]
+ },
+ "containerPort": {
+ "type": "integer"
+ },
+ "port": {
+ "type": "integer"
+ },
+ "annotations": {
+ "type": "object"
+ }
+ }
+ },
+ "ingress": {
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "type": "boolean"
+ },
+ "className": {
+ "type": "string"
+ },
+ "annotations": {
+ "type": "object"
+ },
+ "hosts": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "host": {
+ "type": "string"
+ },
+ "paths": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "path": {
+ "type": "string"
+ },
+ "pathType": {
+ "type": "string",
+ "enum": [
+ "ImplementationSpecific",
+ "Exact",
+ "Prefix"
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "tls": {
+ "type": "object",
+ "properties": {
+ "secretName": {
+ "type": "string"
+ },
+ "hosts": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "required": [
+ "secretName",
+ "hosts"
+ ]
+ }
+ }
+ }
+ },
+ "initContainers": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "image": {
+ "type": "string"
+ },
+ "args": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "resources": {
+ "type": "object",
+ "properties": {
+ "limits": {
+ "type": "object",
+ "properties": {
+ "cpu": {
+ "type": "string"
+ },
+ "memory": {
+ "type": "string"
+ }
+ }
+ },
+ "requests": {
+ "type": "object",
+ "properties": {
+ "cpu": {
+ "type": "string"
+ },
+ "memory": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "livenessProbe": {
+ "$ref": "#/definitions/probe"
+ },
+ "readinessProbe": {
+ "$ref": "#/definitions/probe"
+ },
+ "startupProbe": {
+ "$ref": "#/definitions/probe"
+ },
+ "autoscaling": {
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "type": "boolean"
+ },
+ "minReplicas": {
+ "type": "integer"
+ },
+ "maxReplicas": {
+ "type": "integer"
+ },
+ "targetCPUUtilizationPercentage": {
+ "type": "integer"
+ },
+ "targetMemoryUtilizationPercentage": {
+ "type": "integer"
+ }
+ }
+ },
+ "volumes": {
+ "type": "array",
+ "items": {
+ "type": "object"
+ }
+ },
+ "volumeMounts": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "mountPath": {
+ "type": "string"
+ },
+ "readOnly": {
+ "type": "boolean"
+ }
+ }
+ }
+ },
+ "podDisruptionBudget": {
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "type": "boolean"
+ },
+ "minAvailable": {
+ "type": [
+ "integer",
+ "string"
+ ]
+ },
+ "maxUnavailable": {
+ "type": [
+ "integer",
+ "string"
+ ]
+ }
+ }
+ },
+ "podAnnotations": {
+ "type": "object"
+ },
+ "additionalLabels": {
+ "type": "object"
+ },
+ "nodeSelector": {
+ "type": "object"
+ },
+ "tolerations": {
+ "type": "array",
+ "items": {
+ "type": "object"
+ }
+ },
+ "affinity": {
+ "type": "object"
+ },
+ "priorityClassName": {
+ "type": "string"
+ }
+ },
+ "definitions": {
+ "probe": {
+ "type": "object",
+ "properties": {
+ "httpGet": {
+ "type": "object",
+ "properties": {
+ "path": {
+ "type": "string"
+ },
+ "port": {
+ "type": [
+ "string",
+ "integer"
+ ]
+ }
+ },
+ "required": [
+ "path",
+ "port"
+ ]
+ },
+ "initialDelaySeconds": {
+ "type": "integer",
+ "minimum": 0
+ },
+ "periodSeconds": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "timeoutSeconds": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "successThreshold": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "failureThreshold": {
+ "type": "integer",
+ "minimum": 1
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/kubernetes/chart/values.yaml b/kubernetes/chart/values.yaml
new file mode 100644
index 00000000..f9cb63af
--- /dev/null
+++ b/kubernetes/chart/values.yaml
@@ -0,0 +1,265 @@
+# -- Sourcebot Helm Chart Values
+
+# -- Override the name of the chart.
+nameOverride: ""
+
+# -- Override the full name of the chart.
+fullnameOverride: ""
+
+# -- Set the number of replicas for the deployment.
+replicaCount: 1
+
+# -- Configure the container image.
+image:
+ # -- Container image repository.
+ repository: ghcr.io/sourcebot-dev/sourcebot
+ # -- Container image tag.
+ tag: latest
+ # -- Container image digest (used instead of tag if set).
+ # digest: ""
+ # -- Image pull policy.
+ pullPolicy: Always
+
+# -- Configure image pull secrets for private registries.
+imagePullSecrets: []
+
+# -- Override the default command of the container.
+command: []
+
+# -- Override the default arguments of the container.
+args: []
+
+# -- Configure the database secret.
+database: {}
+# secretName: sourcebot-database-url
+# secretKey: url
+
+# -- Configure the Redis secret.
+redis: {}
+# secretName: sourcebot-redis-url
+# secretKey: url
+
+# -- Configure the enterprise license key secret.
+license: {}
+# secretName: sourcebot-ee-license-key
+# secretKey: key
+
+# -- Set environment variables from Kubernetes secrets.
+envSecrets: []
+# - secretName: sourcebot-github-token
+# secretKey: token
+# envName: GITHUB_TOKEN
+
+# -- Set additional environment variables.
+envs: []
+# - name: FOO
+# value: bar
+
+# -- Configure Sourcebot-specific application settings.
+config:
+ # Schema version of the Sourcebot configuration.
+ $schema: https://raw.githubusercontent.com/sourcebot-dev/sourcebot/main/schemas/v3/index.json
+ connections: {}
+ # github-repos:
+ # type: github
+ # token:
+ # env: GITHUB_TOKEN
+ # repos:
+ # - sourcebot/sourcebot
+ # - sourcebot/sourcebot-plugins
+ settings: {}
+ # reindexIntervalMs: 86400000
+ # enablePublicAccess: true
+
+# -- Configure the ServiceAccount.
+serviceAccount:
+ # -- Create a new ServiceAccount.
+ create: true
+ # -- Use an existing ServiceAccount (if set).
+ name: ""
+ # -- Add annotations to the ServiceAccount.
+ annotations: {}
+ # -- Enable or disable automatic ServiceAccount mounting.
+ automount: false
+
+# -- Set the pod-level security context.
+podSecurityContext: {}
+# runAsUser: 1000
+# runAsGroup: 1000
+# runAsNonRoot: true
+# fsGroup: 1000
+
+# -- Set the container-level security context.
+containerSecurityContext: {}
+# allowPrivilegeEscalation: false
+# privileged: false
+# readOnlyRootFilesystem: true
+# runAsUser: 1000
+# runAsGroup: 1000
+# capabilities:
+# drop:
+# - ALL
+# seccompProfile:
+# type: RuntimeDefault
+
+# -- Configure the Sourcebot Kubernetes service.
+service:
+ # -- Type of the Kubernetes service (e.g., ClusterIP, NodePort, LoadBalancer).
+ type: ClusterIP
+ # -- Internal container port.
+ containerPort: 3000
+ # -- External service port.
+ port: 3000
+ # -- Service annotations.
+ annotations: {}
+
+# -- Configure ingress for Sourcebot.
+ingress:
+ # -- Enable or disable ingress.
+ enabled: false
+ # -- Ingress class name.
+ className: ""
+ # -- Ingress annotations.
+ annotations: {}
+ # kubernetes.io/ingress.class: nginx
+ # kubernetes.io/tls-acme: "true"
+
+ # -- List of hostnames and paths for ingress rules.
+ hosts: []
+ # - host: chart-example.local
+ # paths:
+ # - path: /
+ # pathType: ImplementationSpecific
+
+ # -- TLS settings for ingress.
+ tls: []
+ # - hosts:
+ # - chart-example.local
+ # secretName: chart-example-tls
+
+# -- Configure init containers to run before the main container.
+initContainers: []
+# - name: sleeper
+# image: busybox
+# args:
+# - sleep
+# - "10"
+
+# -- Configure resource requests and limits for the container.
+resources: {}
+## It is recommended to set resources explicitly in production environments.
+# limits:
+# cpu: 100m
+# memory: 128Mi
+# requests:
+# cpu: 100m
+# memory: 128Mi
+
+# -- Liveness probe to check if the container is alive.
+livenessProbe:
+ # -- Http GET request to check if the container is alive.
+ httpGet:
+ # -- Path to check.
+ path: /
+ # -- Port to check.
+ port: http
+ # -- Initial delay before the first probe.
+ initialDelaySeconds: 10
+ # -- Frequency of the probe.
+ periodSeconds: 10
+ # -- Number of consecutive failures before marking the container as unhealthy.
+ failureThreshold: 5
+
+# -- Readiness probe to check if the container is ready to serve traffic.
+readinessProbe:
+ # -- Http GET request to check if the container is ready.
+ httpGet:
+ # -- Path to check.
+ path: /
+ # -- Port to check.
+ port: http
+ # -- Initial delay before the first probe.
+ initialDelaySeconds: 10
+ # -- Frequency of the probe.
+ periodSeconds: 10
+ # -- Number of consecutive failures before marking the container as not ready.
+ failureThreshold: 5
+
+# -- Startup probe to check if the container has started successfully.
+startupProbe:
+ # -- Http GET request to check if the container has started.
+ httpGet:
+ # -- Path to check.
+ path: /
+ # -- Port to check.
+ port: http
+ # -- Number of seconds to wait before starting the probe.
+ failureThreshold: 30
+ # -- Initial delay before the first probe.
+ periodSeconds: 30
+
+# -- Configure Horizontal Pod Autoscaler.
+autoscaling:
+ # -- Enable or disable Horizontal Pod Autoscaler.
+ enabled: false
+ # -- Minimum number of replicas.
+ minReplicas: 1
+ # -- Maximum number of replicas.
+ maxReplicas: 3
+ # -- Target CPU utilization percentage for autoscaling.
+ targetCPUUtilizationPercentage: 80
+ # -- Target memory utilization percentage for autoscaling.
+ targetMemoryUtilizationPercentage: 80
+
+# -- Define additional volumes.
+volumes: []
+# - name: foo
+# secret:
+# secretName: mysecret
+# optional: false
+
+# -- Define volume mounts for the container.
+volumeMounts: []
+# - name: foo
+# mountPath: "/etc/foo"
+# readOnly: true
+
+# -- Configure Pod Disruption Budget.
+podDisruptionBudget:
+ # -- Enable Pod Disruption Budget.
+ enabled: true
+ # -- Minimum number of pods that must be available.
+ minAvailable: 1
+ # -- Maximum number of pods that can be unavailable.
+ maxUnavailable: 1
+
+# -- Add annotations to the pod metadata.
+podAnnotations: {}
+# prometheus.io/scrape: "true"
+# prometheus.io/path: "/metrics"
+# prometheus.io/port: "9102"
+
+# -- Add extra labels to all resources.
+additionalLabels: {}
+# team: sourcebot
+
+# -- Set node selector constraints.
+# See: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector
+nodeSelector: {}
+
+# -- Set tolerations for pod scheduling.
+# See: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/
+tolerations: []
+# - effect: NoSchedule
+# key: "key"
+# operator: Equal
+# value: "value"
+
+# -- Set affinity rules for pod scheduling.
+# Defaults to soft anti-affinity if not set.
+# See: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/
+affinity: {}
+
+# -- Set the priority class name for pods.
+# See: https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/
+priorityClassName: ""