Skip to content
Open
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
63 changes: 63 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Docker ignore file for Samoyed
# Reduces build context size and improves build performance

# Git
.git/
.gitignore
.github/

# Rust build artifacts
target/
**/*.rs.bk
*.pdb

# IDE
.vscode/
.idea/
*.swp
*.swo
*~

# Documentation
README.md
CLAUDE.md
AGENTS.md
.docs/
.assets/

# Nix
flake.nix
flake.lock
result
result-*

# CI/CD (except workflows we might need)
.gitlab-ci.yml
.travis.yml

# Testing artifacts
.tarpaulin.toml
tarpaulin-report.html
cobertura.xml
lcov.info

# Temporary files
*.log
*.tmp
/tmp/

# Package files
*.deb
*.rpm
*.tar.gz

# macOS
.DS_Store

# Keep these for the build:
# - Cargo.toml
# - Cargo.lock
# - src/
# - assets/
# - clippy.toml
# - tests/integration/
50 changes: 50 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: Deploy Documentation

on:
push:
branches: ["main"]
paths:
- 'docs/**'
- '.github/workflows/docs.yml'
workflow_dispatch:

permissions:
contents: read
pages: write
id-token: write

concurrency:
group: "pages"
cancel-in-progress: false

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup mdBook
uses: peaceiris/actions-mdbook@v2
with:
mdbook-version: 'latest'

- name: Build book
run: |
cd docs
mdbook build

- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: './docs/book'

deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,9 @@ target/
# Claude Code local settings - user-specific configurations that should
# not be shared across development environments
.claude/settings.local.json

# ============================================================================
# Documentation Build Output
# ============================================================================
# mdBook generated HTML output directory
docs/book/
65 changes: 65 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Dockerfile for Samoyed integration tests
# Multi-stage build for efficient parallel testing

# Stage 1: Build Samoyed binary
FROM rust:1.83-slim AS builder

WORKDIR /build

# Install build dependencies
RUN apt-get update && \
apt-get install -y pkg-config libssl-dev && \
rm -rf /var/lib/apt/lists/*

# Copy dependency files first (better caching)
COPY Cargo.toml Cargo.lock ./
COPY src ./src
COPY assets ./assets
COPY clippy.toml ./

# Build release binary
RUN cargo build --release --verbose && \
strip target/release/samoyed

# Stage 2: Test runtime environment
FROM debian:bookworm-slim AS test-runner

# Install minimal dependencies for tests
RUN apt-get update && \
apt-get install -y \
git \
bash \
coreutils \
ca-certificates \
procps \
&& rm -rf /var/lib/apt/lists/*

# Configure git for tests (disable commit signing)
RUN git config --global commit.gpgsign false && \
git config --global user.email "test@samoyed.test" && \
git config --global user.name "Samoyed Test"

# Copy compiled binary from builder
COPY --from=builder /build/target/release/samoyed /usr/local/bin/samoyed

# Copy test suite
COPY tests/integration /tests/integration

# Set up test workspace (isolated per container)
WORKDIR /test-workspace

# Verify binary works
RUN samoyed --version

# Environment variables
ENV TEST_NAME=""
ENV SAMOYED_TEST_CONTAINER=1

# Default: run specific test passed via environment variable
CMD if [ -n "$TEST_NAME" ]; then \
exec /tests/integration/"$TEST_NAME"; \
else \
echo "ERROR: TEST_NAME environment variable not set"; \
echo "Usage: docker run -e TEST_NAME=01_default.sh samoyed-test"; \
exit 1; \
fi
73 changes: 73 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Makefile for Samoyed
# Provides convenient commands for building, testing, and development

.PHONY: help build test test-docker test-docker-parallel test-docker-compose clean

# Default target
help:
@echo "Samoyed - Git hooks manager"
@echo ""
@echo "Available targets:"
@echo " make build - Build release binary"
@echo " make test - Run unit tests"
@echo " make test-integration - Run integration tests (serial)"
@echo " make test-docker - Run integration tests in Docker (serial)"
@echo " make test-docker-parallel - Run integration tests in Docker (parallel)"
@echo " make test-docker-compose - Run integration tests via Docker Compose"
@echo " make clean - Clean build artifacts"
@echo " make fmt - Format code"
@echo " make clippy - Run Clippy linter"
@echo " make coverage - Generate test coverage report"

# Build release binary
build:
cargo build --release --verbose

# Run Rust unit tests
test:
cargo test --verbose -- --test-threads=1

# Run integration tests locally (serial)
test-integration: build
@echo "Running integration tests..."
@cd tests/integration && for test in [0-9]*.sh; do \
echo "Running $$test..."; \
./$$test || exit 1; \
done

# Build and test in Docker (serial)
test-docker:
docker build -t samoyed-test:latest -f Dockerfile .
@for test in tests/integration/[0-9]*.sh; do \
test_name=$$(basename $$test); \
echo "Running $$test_name in Docker..."; \
docker run --rm -e TEST_NAME=$$test_name samoyed-test:latest || exit 1; \
done

# Build and test in Docker (parallel)
test-docker-parallel:
@bash tests/integration/run-parallel-docker.sh

# Test using Docker Compose
test-docker-compose:
docker-compose -f docker-compose.test.yml build
docker-compose -f docker-compose.test.yml up --abort-on-container-exit --exit-code-from test-01-default
docker-compose -f docker-compose.test.yml down

# Clean build artifacts
clean:
cargo clean
rm -rf target/
rm -f *.log

# Format code
fmt:
cargo fmt --all

# Run Clippy linter
clippy:
cargo clippy --all-targets --all-features -- -D warnings

# Generate test coverage
coverage:
cargo tarpaulin -- --test-threads=1
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Samoyed

[![Crates.io Version](https://img.shields.io/crates/v/samoyed)](https://crates.io/crates/samoyed)
[![Documentation](https://img.shields.io/badge/docs-mdbook-blue)](https://nutthead.github.io/samoyed/)

> A single-binary, minimalist, ultra-fast Git hooks manager for every platform.

Expand Down
125 changes: 125 additions & 0 deletions docker-compose.test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
version: '3.8'

# Docker Compose configuration for parallel integration testing
# Usage: docker-compose -f docker-compose.test.yml up --abort-on-container-exit

services:
test-01-default:
build:
context: .
dockerfile: Dockerfile
container_name: samoyed-test-01-default
environment:
TEST_NAME: 01_default.sh

test-02-custom-dir:
build:
context: .
dockerfile: Dockerfile
container_name: samoyed-test-02-custom-dir
environment:
TEST_NAME: 02_custom_dir.sh

test-03-from-subdir:
build:
context: .
dockerfile: Dockerfile
container_name: samoyed-test-03-from-subdir
environment:
TEST_NAME: 03_from_subdir.sh

test-04-not-git-dir:
build:
context: .
dockerfile: Dockerfile
container_name: samoyed-test-04-not-git-dir
environment:
TEST_NAME: 04_not_git_dir.sh

test-05-git-not-found:
build:
context: .
dockerfile: Dockerfile
container_name: samoyed-test-05-git-not-found
environment:
TEST_NAME: 05_git_not_found.sh

test-06-command-not-found:
build:
context: .
dockerfile: Dockerfile
container_name: samoyed-test-06-command-not-found
environment:
TEST_NAME: 06_command_not_found.sh

test-07-strict-mode:
build:
context: .
dockerfile: Dockerfile
container_name: samoyed-test-07-strict-mode
environment:
TEST_NAME: 07_strict_mode.sh

test-08-samoyed-0:
build:
context: .
dockerfile: Dockerfile
container_name: samoyed-test-08-samoyed-0
environment:
TEST_NAME: 08_samoyed_0.sh

test-09-init:
build:
context: .
dockerfile: Dockerfile
container_name: samoyed-test-09-init
environment:
TEST_NAME: 09_init.sh

test-10-time:
build:
context: .
dockerfile: Dockerfile
container_name: samoyed-test-10-time
environment:
TEST_NAME: 10_time.sh

test-11-lfs-flags:
build:
context: .
dockerfile: Dockerfile
container_name: samoyed-test-11-lfs-flags
environment:
TEST_NAME: 11_lfs_flags.sh

test-12-lfs-subcommand:
build:
context: .
dockerfile: Dockerfile
container_name: samoyed-test-12-lfs-subcommand
environment:
TEST_NAME: 12_lfs_subcommand.sh

test-13-hooks-d:
build:
context: .
dockerfile: Dockerfile
container_name: samoyed-test-13-hooks-d
environment:
TEST_NAME: 13_hooks_d.sh

test-14-existing-hooks:
build:
context: .
dockerfile: Dockerfile
container_name: samoyed-test-14-existing-hooks
environment:
TEST_NAME: 14_existing_hooks.sh

test-15-combined-features:
build:
context: .
dockerfile: Dockerfile
container_name: samoyed-test-15-combined-features
environment:
TEST_NAME: 15_combined_features.sh
Loading
Loading