Skip to content
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
74 changes: 74 additions & 0 deletions .github/workflows/helm-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
name: Helm Chart Test

on:
push:
branches: [main]
paths:
- "helm/**"
- ".github/workflows/helm-test.yml"
pull_request:
branches: [main]
paths:
- "helm/**"
- ".github/workflows/helm-test.yml"

permissions:
contents: read

jobs:
test-helm-chart:
name: Test Helm Chart
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0

- name: Build Docker image
uses: docker/build-push-action@c382f710d39a5bb4e430307530a720f50c2d3318 # v6.0.0
with:
context: .
load: true
tags: toolhive-cloud-ui:latest
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Create Kind cluster
uses: helm/kind-action@92086f6be054225fa813e0a4b13787fc9088faab # v1.13.0

- name: Load image into Kind
run: |
kind load docker-image toolhive-cloud-ui:latest --name chart-testing

- name: Install Helm chart
run: |
helm upgrade --install toolhive-cloud-ui ./helm \
-f ./helm/values-dev.yaml \
--wait \
--timeout=5m

- name: Check deployment status
run: |
kubectl get pods -l app.kubernetes.io/name=toolhive-cloud-ui
kubectl get svc -l app.kubernetes.io/name=toolhive-cloud-ui

- name: Verify application is responding
run: |
kubectl wait --for=condition=ready pod -l app.kubernetes.io/name=toolhive-cloud-ui --timeout=120s
kubectl port-forward svc/toolhive-cloud-ui 8080:80 &
sleep 5
curl -f http://localhost:8080 || (kubectl logs -l app.kubernetes.io/name=toolhive-cloud-ui && exit 1)

- name: Run Helm tests (if any)
run: |
helm test toolhive-cloud-ui || echo "No tests defined"

- name: Show logs on failure
if: failure()
run: |
kubectl get all -l app.kubernetes.io/name=toolhive-cloud-ui
kubectl describe pods -l app.kubernetes.io/name=toolhive-cloud-ui
kubectl logs -l app.kubernetes.io/name=toolhive-cloud-ui --tail=100
42 changes: 42 additions & 0 deletions .github/workflows/lint-helm.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Lint Helm Chart

on:
push:
branches: [main]
paths:
- "helm/**"
- ".github/workflows/lint-helm.yml"
pull_request:
branches: [main]
paths:
- "helm/**"
- ".github/workflows/lint-helm.yml"

permissions:
contents: read

jobs:
lint-chart:
name: Lint Helm Chart
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
fetch-depth: 0

- name: Set up Helm
uses: azure/setup-helm@fe7b79cd5ee1e45176fcad797de68ecaf3ca4814 # v4.2.0
with:
version: "latest"

- name: Run Helm lint
run: |
helm lint ./helm
helm lint ./helm -f ./helm/values-dev.yaml

- name: Validate templates
run: |
helm template toolhive-cloud-ui ./helm --kube-version 1.28.0 --debug
helm template toolhive-cloud-ui ./helm -f ./helm/values-dev.yaml --kube-version 1.28.0 --debug
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,8 @@ yarn-error.log*
# typescript
*.tsbuildinfo
next-env.d.ts

# helm
*.tgz
helm/charts/
helm/*.lock
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ RUN corepack enable && corepack prepare [email protected] --activate

WORKDIR /app

# Install dependencies based on the preferred package manager
# Install dependencies
COPY package.json pnpm-lock.yaml* ./
RUN pnpm install --frozen-lockfile

Expand Down
73 changes: 71 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,31 @@ IMAGE_NAME := toolhive-cloud-ui
IMAGE_TAG := latest
CONTAINER_NAME := toolhive-cloud-ui
PORT := 3000
RELEASE_NAME := toolhive-cloud-ui

## Show this help message
help:
@echo "Available commands:"
@grep -E '^## ' $(MAKEFILE_LIST) | sed 's/## //' | awk 'NR%2==1{printf "\033[36m%-15s\033[0m ",$$1} NR%2==0{print}'
@echo "ToolHive Cloud UI - Available Commands"
@echo ""
@echo "Docker (Local Development):"
@echo " make build - Build production Docker image"
@echo " make start - Start Docker container"
@echo " make stop - Stop Docker container"
@echo " make logs - View container logs"
@echo " make clean - Remove container and image"
@echo " make rebuild - Clean and rebuild"
@echo ""
@echo "Kind (Kubernetes):"
@echo " make kind-setup - Create cluster and deploy (first time)"
@echo " make kind-create - Create Kind cluster"
@echo " make kind-deploy - Build and deploy to Kind"
@echo " make kind-port-forward - Port-forward to localhost:8080"
@echo " make kind-logs - View application logs"
@echo " make kind-uninstall - Uninstall from Kind"
@echo " make kind-delete - Delete Kind cluster"
@echo ""
@echo "Development:"
@echo " make dev - Run Next.js dev server"

## Build the production docker image
build:
Expand Down Expand Up @@ -51,3 +71,52 @@ shell:
rebuild: clean build
@echo "Rebuild complete"

## Create Kind cluster
kind-create:
@echo "Creating Kind cluster..."
@kind create cluster --name toolhive || echo "Cluster already exists"
@kubectl cluster-info --context kind-toolhive
@echo "Kind cluster ready!"

## Delete Kind cluster
kind-delete:
@echo "Deleting Kind cluster..."
@kind delete cluster --name toolhive
@echo "Cluster deleted"

## Build and load image into Kind
kind-build:
@echo "Building Docker image..."
@docker build -t $(IMAGE_NAME):$(IMAGE_TAG) .
@echo "Loading image into Kind cluster..."
@kind load docker-image $(IMAGE_NAME):$(IMAGE_TAG) --name toolhive
@echo "Image loaded successfully"

## Deploy to Kind with Helm
kind-deploy: kind-build
@echo "Deploying to Kind..."
@helm upgrade --install $(RELEASE_NAME) ./helm -f ./helm/values-dev.yaml --wait --timeout=5m
@echo "Deployment complete!"
@echo ""
@echo "To access the application, run:"
@echo " make kind-port-forward"
@echo "Then open: http://localhost:8080"

## Uninstall from Kind
kind-uninstall:
@helm uninstall $(RELEASE_NAME) || true
@echo "Uninstalled from Kind"

## View logs
kind-logs:
@kubectl logs -f deployment/$(RELEASE_NAME)

## Port-forward to localhost
kind-port-forward:
@echo "Forwarding to http://localhost:8080"
@kubectl port-forward svc/$(RELEASE_NAME) 8080:80

## Full setup: create cluster and deploy
kind-setup: kind-create kind-deploy
@echo "Setup complete!"

50 changes: 50 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,59 @@ make clean

# Rebuild from scratch
make rebuild
```

The application will be available at [http://localhost:3000](http://localhost:3000).

## Kubernetes / Kind Deployment

This project includes a complete Helm chart for deploying to Kubernetes (optimized for Kind).

### Quick Start with Kind

```bash
# Create cluster and deploy (first time)
make kind-setup

# Or step by step:
# 1. Create Kind cluster
make kind-create

# 2. Deploy application
make kind-deploy

# 3. Access the application
make kind-port-forward
# Then open: http://localhost:8080

# View logs
make kind-logs

# Uninstall
make kind-uninstall

# Delete cluster
make kind-delete
```

### Helm Chart

The Helm chart is located in the `helm/` directory and includes:

- Deployment with configurable replicas
- Service (ClusterIP/NodePort/LoadBalancer)
- Horizontal Pod Autoscaler (optional)
- Configurable resource limits
- Health checks (startup, liveness and readiness probes)
- Security contexts following Pod Security Standards

### CI/CD

The chart is automatically tested on every push using GitHub Actions with Kind:

- **Helm Lint**: Validates chart syntax and best practices
- **Integration Test**: Deploys to Kind cluster and verifies the app responds

## Learn More

To learn more about Next.js, take a look at the following resources:
Expand Down
24 changes: 24 additions & 0 deletions helm/.helmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# 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/

15 changes: 15 additions & 0 deletions helm/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
apiVersion: v2
name: toolhive-cloud-ui
description: A Helm chart for ToolHive Cloud UI - Next.js application
type: application
version: 0.1.0
appVersion: "0.1.0"
keywords:
- nextjs
- react
- frontend
- ui
home: https://github.com/stacklok/toolhive-cloud-ui
sources:
- https://github.com/stacklok/toolhive-cloud-ui
kubeVersion: ">=1.24.0-0"
63 changes: 63 additions & 0 deletions helm/templates/_helpers.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "toolhive-cloud-ui.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Create a default fully qualified app name.
*/}}
{{- define "toolhive-cloud-ui.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 "toolhive-cloud-ui.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Common labels
*/}}
{{- define "toolhive-cloud-ui.labels" -}}
helm.sh/chart: {{ include "toolhive-cloud-ui.chart" . }}
{{ include "toolhive-cloud-ui.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/component: frontend
app.kubernetes.io/part-of: toolhive
{{- end }}

{{/*
Selector labels
*/}}
{{- define "toolhive-cloud-ui.selectorLabels" -}}
app.kubernetes.io/name: {{ include "toolhive-cloud-ui.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

{{/*
Create the name of the service account to use
*/}}
{{- define "toolhive-cloud-ui.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "toolhive-cloud-ui.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}

Loading