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
31 changes: 31 additions & 0 deletions .github/workflows/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# GitHub Actions Workflows

This directory contains the GitHub Actions workflow definitions used for continuous integration and testing of Kubexit.

## Workflows

### Unit Tests (`unit-test.yaml`)
- **Triggers**: Pushes to `master` branch and all pull requests.
- **Description**: Executes unit tests using `make test-unit`. This ensures that the core logic remains correct with every change.
- **Environment**: `ubuntu-latest`, Go 1.22.0.

### Integration Tests (`integration-test.yaml`)
- **Triggers**: Pushes to `master` branch and pull requests targeting `master`.
- **Description**: Executes integration tests using `make test-integration`. These tests use a `kind` cluster to verify the interaction between kubexit and Kubernetes components in a real environment.
- **Environment**: `ubuntu-latest`, Go 1.22.0, Docker, `kind`.

### End-to-End Tests (`e2e-test.yaml`)
- **Triggers**: Pull requests targeting `master`.
- **Description**: Performs a more comprehensive test suite including:
- Linting the Go codebase via `make lint`.
- Building the Kubexit Docker image.
- Setting up a `kind` cluster.
- Running end-to-end test scripts located in `ci/e2e-test/`.
- **Environment**: `ubuntu-latest`, Docker, `kind`, `kubectl`, `kustomize`, `jq`.

## CI/CD Pipeline Overview

The CI pipeline is designed to catch regressions early by running a layered testing strategy:
1. **Unit Tests**: Fast feedback on logic changes.
2. **Integration Tests**: Verifies behavior within a Kubernetes-like environment (`kind`).
3. **E2E Tests**: Validates the full deployment and execution flow, including Docker image compatibility and cluster interaction.
40 changes: 26 additions & 14 deletions .github/workflows/e2e-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,40 +9,52 @@ on:
jobs:
lint:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.26'
- name: Install goimports
run: go install golang.org/x/tools/cmd/goimports@latest
- name: Add Go bin to PATH
run: echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
- name: Lint Go Code
run: make lint
e2e-test:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Build image
# https://help.github.com/en/actions/language-and-framework-guides/publishing-docker-images
# https://github.com/docker/build-push-action
uses: docker/build-push-action@v1
uses: docker/build-push-action@v6
with:
repository: karlkfi/kubexit
# Docker Automated Builds handle publishing
push: false
- name: Setup kube tools
id: setup
uses: yokawasa/action-setup-kube-tools@v0.1.0
uses: yokawasa/action-setup-kube-tools@v0.13.5
with:
kubectl: '1.18.2'
kustomize: '3.8.1'
kubectl: 'latest'
kustomize: 'latest'
jq: 'latest'
- name: Update path
run: |
echo "::add-path::$(dirname "${{steps.setup.outputs.kubectl-path}}")"
echo "::add-path::$(dirname "${{steps.setup.outputs.kustomize-path}}")"
echo "::add-path::$(dirname "${{steps.setup.outputs.jq-path}}")"
echo "$(dirname "${{steps.setup.outputs.kubectl-path}}")" >> $GITHUB_PATH
echo "$(dirname "${{steps.setup.outputs.kustomize-path}}")" >> $GITHUB_PATH
echo "$(dirname "${{steps.setup.outputs.jq-path}}")" >> $GITHUB_PATH
- name: Create kind cluster
uses: engineerd/setup-kind@v0.4.0
uses: engineerd/setup-kind@v0.6.2
with:
version: v0.8.1
version: v0.24.0
name: e2e-test
- name: Print Context
run: |
Expand All @@ -59,6 +71,6 @@ jobs:
run: ci/e2e-test/client-server/await-job.sh
- name: Delete job
run: ci/e2e-test/client-server/delete-job.sh
- name: Delete kind cluster
if: always()
run: kind delete cluster --name e2e-test
# - name: Delete kind cluster
# if: always()
# run: kind delete cluster --name e2e-test
40 changes: 40 additions & 0 deletions .github/workflows/integration-test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
name: Integration Tests

on:
push:
branches: [master]
pull_request:
branches: [master]

jobs:
test-integration:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: "1.26.0"

- name: Setup Docker
uses: docker/setup-buildx-action@v3

- name: Setup kind
uses: engineerd/setup-kind@v0.6.2
with:
version: v0.24.0
name: kubexit-test

# - name: Build and Load Image
# run: |
# docker build -f cmd/test-server/Dockerfile -t kubexit/test-server:latest .
# kind load docker-image kubexit/test-server:latest --name kubexit-test

- name: Run Integration Tests
run: make test-integration
env:
GOTMPDIR: ${{ runner.temp }}
KIND_CLUSTER_NAME: kubexit-test
18 changes: 18 additions & 0 deletions .github/workflows/unit-test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: Unit Tests

on:
push:
branches: [master]
pull_request:

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.22.0"
- run: make test-unit
env:
GOTMPDIR: ${{ runner.temp }}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@
.graveyard

.vscode
.claude
CLAUDE.md
177 changes: 177 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
# Contributing to Kubexit

Thank you for your interest in contributing! Below are guidelines to help you get started and ensure a smooth review process.

## Table of Contents

- [Getting Started](#getting-started)
- [Development Workflow](#development-workflow)
- [Coding Guidelines](#coding-guidelines)
- [Pull Requests](#pull-requests)
- [Testing](#testing)
- [Building](#building)
- [Docker Images](#docker-images)
- [Reporting Bugs](#reporting-bugs)
- [Asking Questions](#asking-questions)

## Getting Started

1. **Fork** the repository on GitHub.
2. **Clone** your fork locally:
```bash
git clone https://github.com/<your-username>/kubexit.git
cd kubexit
```
3. **Add the upstream remote** to stay in sync:
```bash
git remote add upstream https://github.com/karlkfi/kubexit.git
```
4. **Sync the workspace**:
```bash
go work sync && go mod download
```
This project uses a Go workspace (`go.work`) with three modules: root (`pkg/`), `cmd/kubexit`, and `cmd/test-server`. The `go work sync` command keeps replace directives in sync across all modules.

## Development Workflow

1. **Create a feature branch** from `master`:
```bash
git fetch upstream
git checkout -b feature/your-feature-name upstream/master
```
2. **Make your changes** following the coding guidelines below.
3. **Run the linters and tests** before committing:
```bash
make lint
make test
```
Both commands run across all modules in the workspace via `./...`.
4. **Commit** with a clear, descriptive message (see [Commit Messages](#commit-messages)).
5. **Push** and open a pull request against `upstream/master`.

## Coding Guidelines

### Go

- Format all code with `gofmt` (run `make fix` for auto-formatting including `goimports`).
- Run `go vet ./...` to catch common issues.
- Write a doc comment on every exported function, type, and package.
- Keep comments on private functions when the intent is non-obvious.
- Add tests for new functionality and updates when behavior changes. See [Testing](#testing).
- Don't add new dependencies unless necessary. If you must, prefer direct dependencies over transitive ones and note the rationale in the PR description.

### Commit Messages

- Use the imperative mood: "Add logging" not "Added logging".
- Keep the subject line under 72 characters.
- Include a body paragraph for non-trivial changes that explains the _why_, not the _what_.
- Reference related issues using `#<number>` when applicable.

### Pull Requests

- Keep PRs focused — one feature or fix per PR.
- Include a clear description of the problem and the approach.
- Reference any related issues.
- Ensure CI passes (unit tests, linting, and e2e tests) before requesting review.
- Respond to review comments promptly; push follow-up commits instead of amending (preserves review history).

## Testing

### Unit Tests

```bash
make test-unit
```

Unit tests run via Go's built-in test framework and are executed on every push and pull request through CI.

### Integration Tests

Integration tests deploy a test-server into a local kind cluster to verify watch behavior against the live Kubernetes API.

```bash
make test-integration
```

Integration tests verify the interaction with Kubernetes components using a `kind` cluster and are executed on every push and pull request through CI.

### End-to-End Tests

E2E tests deploy kubexit in a real Kubernetes cluster to verify behavior against the live Kubernetes API. They run against a [Kind](https://kind.sigs.k8s.io/) cluster in CI.

To run them locally (requires Docker, `kind`, and `kubectl` installed):

```bash
# Start a Kind cluster
kind create cluster --name kubexit

# Build the kubexit image and load it into the cluster
docker build -t kubexit:latest .
kind load docker-image kubexit:latest --name kubexit

# Run the tests
bash ci/e2e-test/client-server/apply-job.sh
bash ci/e2e-test/client-server/await-job.sh
bash ci/e2e-test/client-server/delete-job.sh

# Tear down the cluster
kind delete cluster --name kubexit
```

See [ci/e2e-test/README.md](ci/e2e-test/README.md) for details.

### Linting

```bash
make lint
```

This runs `golangci-lint` (requires [golangci-lint](https://golangci-lint.run/) installed locally; CI handles this automatically).

### Building

```bash
make bin
```

### Docker Images

There are two Docker images in the project:

| Image | Dockerfile | Purpose |
|-------|------------|---------|
| `kubexit` | `Dockerfile` | Main application binary |
| `kubexit/test-server` | `cmd/test-server/Dockerfile` | Test HTTP server for integration tests |

Both use a multi-stage build: a `golang:1.26-alpine` builder stage compiles the binary, and an `alpine:3.23` runtime stage ships the final artifact.

Build locally with:

```bash
# Main image
docker build -t kubexit:latest .

# Test server image
docker build -f cmd/test-server/Dockerfile -t kubexit/test-server:latest .
```

To load images into a Kind cluster for local testing:

```bash
kind load docker-image kubexit:latest --name kubexit
kind load docker-image kubexit/test-server:latest --name kubexit
```

## Reporting Bugs

Open an issue on GitHub with:

1. A clear title and description of the expected vs. actual behavior.
2. Steps to reproduce.
3. The kubexit version and Kubernetes cluster version.
4. Any relevant logs or configuration.

## Asking Questions

- Open a [GitHub Issue](https://github.com/karlkfi/kubexit/issues) for general questions or feature ideas.
- For proposed changes, sketch the approach in an issue before implementing to avoid wasted effort.
27 changes: 21 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MAKE_DIR:=$(strip $(shell dirname "$(realpath $(lastword $(MAKEFILE_LIST)))"))

.PHONY: help bin clean lint fix gomodules lint-gomodules gofmt lint-gofmt goimports lint-goimports lint-govet
.PHONY: help bin clean lint test test-unit test-integration fix gomodules lint-gomodules gofmt lint-gofmt goimports lint-goimports lint-govet

default: help

Expand All @@ -16,20 +16,35 @@ bin:
clean:
scripts/clean.sh

# run unit tests
test-unit:
go test -v ./...

# run integration tests
test-integration:
go test -v -tags=integration ./pkg/watch/...

# run all tests
test: test-unit test-integration

# run all linters
lint: lint-gomodules lint-gofmt lint-goimports lint-govet

# fix (some) lint violations
fix: gofmt goimports

# update and remove unused go modules
# update and remove unused go modules (all workspace modules)
gomodules:
go mod tidy
go mod vendor
for dir in $$(scripts/go-modules.sh); do \
(cd "$$dir" && go mod tidy); \
done
go work vendor

# check if any go modules need updating
# check if any go modules need updating (all workspace modules)
lint-gomodules:
go mod verify
for dir in $$(scripts/go-modules.sh); do \
(cd "$$dir" && go mod verify); \
done

# format go code
gofmt:
Expand Down
Loading
Loading