feat: add CI for backend
Some checks failed
Publish Docker Images / build-and-publish (push) Has been cancelled

This commit is contained in:
Lucien Cartier-Tilet 2025-11-05 02:07:36 +01:00
parent 9b5d6d87ed
commit 67142aceaa
5 changed files with 401 additions and 5 deletions

121
.github/workflows/README.md vendored Normal file
View File

@ -0,0 +1,121 @@
# GitHub Actions Workflows
## Docker Image Publishing
The `publish-docker.yml` workflow automatically builds and publishes Docker images for the backend service using Nix.
### Triggers and Tagging Strategy
| Event | Condition | Published Tags | Example |
|--------------|-----------------------------|------------------------|-------------------|
| Tag push | Tag pushed to `main` branch | `latest` + version tag | `latest`, `1.0.0` |
| Branch push | Push to `develop` branch | `develop` | `develop` |
| Pull request | PR opened or updated | `pr<number>` | `pr12` |
| Branch push | Push to `main` (no tag) | `latest` | `latest` |
### Required GitHub Secrets
Configure these secrets in your repository settings (`Settings``Secrets and variables``Actions`):
| Secret Name | Description | Example Value |
|---------------------|---------------------------------------------|-------------------------------------------------|
| `DOCKER_USERNAME` | Username for Docker registry authentication | `phundrak` (Docker Hub) or `phundrak` (ghcr.io) |
| `DOCKER_PASSWORD` | Password or token for Docker registry | Personal Access Token (PAT) or password |
| `CACHIX_AUTH_TOKEN` | (Optional) Token for Cachix caching | Your Cachix auth token |
#### For GitHub Container Registry (ghcr.io)
1. Create a Personal Access Token (PAT):
- Go to GitHub Settings → Developer settings → Personal access tokens → Tokens (classic)
- Click "Generate new token (classic)"
- Select scopes: `write:packages`, `read:packages`, `delete:packages`
- Copy the generated token
2. Add secrets:
- `DOCKER_USERNAME`: Your GitHub username
- `DOCKER_PASSWORD`: The PAT you just created
#### For Docker Hub
1. Create an access token:
- Go to Docker Hub → Account Settings → Security → Access Tokens
- Click "New Access Token"
- Set permissions to "Read, Write, Delete"
- Copy the generated token
2. Add secrets:
- `DOCKER_USERNAME`: Your Docker Hub username
- `DOCKER_PASSWORD`: The access token you just created
#### For Custom Registry (e.g., labs.phundrak.com)
1. Obtain credentials from your registry administrator
2. Add secrets:
- `DOCKER_USERNAME`: Your registry username
- `DOCKER_PASSWORD`: Your registry password or token
### Configuring the Docker Registry
The target registry is set via the `DOCKER_REGISTRY` environment variable in the workflow file. To change it:
1. Edit `.github/workflows/publish-docker.yml`
2. Modify the `env` section:
```yaml
env:
DOCKER_REGISTRY: ghcr.io # Change to your registry (e.g., docker.io, labs.phundrak.com)
IMAGE_NAME: phundrak/phundrak-dot-com-backend
```
Or set it as a repository variable:
- Go to `Settings``Secrets and variables``Actions``Variables` tab
- Add `DOCKER_REGISTRY` with your desired registry URL
### Image Naming
Images are published with the name: `${DOCKER_REGISTRY}/${IMAGE_NAME}:${TAG}`
For example:
- `ghcr.io/phundrak/phundrak-dot-com-backend:latest`
- `ghcr.io/phundrak/phundrak-dot-com-backend:1.0.0`
- `ghcr.io/phundrak/phundrak-dot-com-backend:develop`
- `ghcr.io/phundrak/phundrak-dot-com-backend:pr12`
### Local Testing
To test the Docker image build locally:
```bash
# Build the image with Nix
nix build .#backendDockerLatest
# Load it into Docker
docker load < result
# Run the container
docker run -p 3100:3100 localhost/phundrak/backend-rust:latest
```
### Troubleshooting
#### Authentication Failures
If you see authentication errors:
1. Verify your `DOCKER_USERNAME` and `DOCKER_PASSWORD` secrets are correct
2. For ghcr.io, ensure your PAT has the correct permissions
3. Check that the `DOCKER_REGISTRY` matches your credentials
#### Build Failures
If the Nix build fails:
1. Test the build locally first: `nix build .#backendDockerLatest`
2. Check the GitHub Actions logs for specific error messages
3. Ensure all dependencies in `flake.nix` are correctly specified
#### Image Not Appearing in Registry
1. Verify the workflow completed successfully in the Actions tab
2. Check that the registry URL is correct
3. For ghcr.io, images appear at: `https://github.com/users/USERNAME/packages/container/IMAGE_NAME`
4. Ensure your token has write permissions

121
.github/workflows/publish-docker.yml vendored Normal file
View File

@ -0,0 +1,121 @@
name: Publish Docker Images
on:
push:
branches:
- main
- develop
tags:
- 'v*.*.*'
pull_request:
types: [opened, synchronize, reopened]
env:
DOCKER_REGISTRY: labs.phundrak.com # Override in repository settings if needed
IMAGE_NAME: phundrak/phundrak-dot-com-backend
jobs:
build-and-publish:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write # Required for pushing to Phundrak Labs registry
pull-requests: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Nix
uses: cachix/install-nix-action@v27
with:
nix_path: nixpkgs=channel:nixos-unstable
- name: Setup Cachix
uses: cachix/cachix-action@v15
with:
name: devenv
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
skipPush: true
- name: Build Docker image with Nix
run: |
echo "Building Docker image..."
nix build .#backendDockerLatest --print-build-logs
- name: Load Docker image
run: |
echo "Loading Docker image into Docker daemon..."
docker load < result
- name: Log in to Docker Registry
run: |
echo "${{ secrets.DOCKER_PASSWORD }}" | docker login ${{ env.DOCKER_REGISTRY }} -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
- name: Determine tags and push images
run: |
set -euo pipefail
REGISTRY="${{ env.DOCKER_REGISTRY }}"
IMAGE_NAME="${{ env.IMAGE_NAME }}"
# The locally built image from Nix
LOCAL_IMAGE="localhost/phundrak/backend-rust:latest"
echo "Event: ${{ github.event_name }}"
echo "Ref: ${{ github.ref }}"
echo "Ref type: ${{ github.ref_type }}"
# Determine which tags to push based on the event
if [[ "${{ github.event_name }}" == "push" && "${{ github.ref_type }}" == "tag" ]]; then
# Tag push on main branch → publish 'latest' and versioned tag
echo "Tag push detected"
TAG_VERSION="${{ github.ref_name }}"
# Remove 'v' prefix if present (v1.0.0 → 1.0.0)
TAG_VERSION="${TAG_VERSION#v}"
echo "Tagging and pushing: ${REGISTRY}/${IMAGE_NAME}:latest"
docker tag "${LOCAL_IMAGE}" "${REGISTRY}/${IMAGE_NAME}:latest"
docker push "${REGISTRY}/${IMAGE_NAME}:latest"
echo "Tagging and pushing: ${REGISTRY}/${IMAGE_NAME}:${TAG_VERSION}"
docker tag "${LOCAL_IMAGE}" "${REGISTRY}/${IMAGE_NAME}:${TAG_VERSION}"
docker push "${REGISTRY}/${IMAGE_NAME}:${TAG_VERSION}"
elif [[ "${{ github.event_name }}" == "push" && "${{ github.ref }}" == "refs/heads/develop" ]]; then
# Push on develop branch → publish 'develop' tag
echo "Push to develop branch detected"
echo "Tagging and pushing: ${REGISTRY}/${IMAGE_NAME}:develop"
docker tag "${LOCAL_IMAGE}" "${REGISTRY}/${IMAGE_NAME}:develop"
docker push "${REGISTRY}/${IMAGE_NAME}:develop"
elif [[ "${{ github.event_name }}" == "pull_request" ]]; then
# Pull request → publish 'pr<number>' tag
echo "Pull request detected"
PR_NUMBER="${{ github.event.pull_request.number }}"
echo "Tagging and pushing: ${REGISTRY}/${IMAGE_NAME}:pr${PR_NUMBER}"
docker tag "${LOCAL_IMAGE}" "${REGISTRY}/${IMAGE_NAME}:pr${PR_NUMBER}"
docker push "${REGISTRY}/${IMAGE_NAME}:pr${PR_NUMBER}"
elif [[ "${{ github.event_name }}" == "push" && "${{ github.ref }}" == "refs/heads/main" ]]; then
# Push to main branch (not a tag) → publish 'latest'
echo "Push to main branch detected"
echo "Tagging and pushing: ${REGISTRY}/${IMAGE_NAME}:latest"
docker tag "${LOCAL_IMAGE}" "${REGISTRY}/${IMAGE_NAME}:latest"
docker push "${REGISTRY}/${IMAGE_NAME}:latest"
else
echo "Unknown event or ref, skipping push"
exit 1
fi
- name: Log out from Docker Registry
if: always()
run: docker logout ${{ env.DOCKER_REGISTRY }}
- name: Image published successfully
run: |
echo "✅ Docker image(s) published successfully to ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}"

View File

@ -80,35 +80,68 @@ To disable rate limiting, set `rate_limit.enabled: false` in your configuration.
### Prerequisites
**Option 1: Native Development**
- Rust (latest stable version recommended)
- Cargo (comes with Rust)
**Option 2: Nix Development (Recommended)**
- [Nix](https://nixos.org/download) with flakes enabled
- All dependencies managed automatically
### Running the Server
To start the development server:
**With Cargo:**
```bash
cargo run
```
**With Nix development shell:**
```bash
nix develop .#backend
cargo run
```
The server will start on the configured port (default: 3100).
### Building
For development builds:
**With Cargo:**
For development builds:
```bash
cargo build
```
For optimized production builds:
```bash
cargo build --release
```
The compiled binary will be at `target/release/backend`.
**With Nix:**
Build the backend binary:
```bash
nix build .#backend
# Binary available at: ./result/bin/backend
```
Build Docker images:
```bash
# Build versioned Docker image (e.g., 0.1.0)
nix build .#backendDocker
# Build latest Docker image
nix build .#backendDockerLatest
# Load into Docker
docker load < result
# Image will be available as: localhost/phundrak/backend-rust:latest
```
The Nix build ensures reproducible builds with all dependencies pinned.
## Testing
Run all tests:
@ -266,6 +299,126 @@ The contact form supports multiple SMTP configurations:
The `SmtpTransport` is built dynamically from `EmailSettings` based on
TLS/STARTTLS configuration.
## Docker Deployment
### Using Pre-built Images
Docker images are automatically built and published via GitHub Actions to the configured container registry.
Pull and run the latest image:
```bash
# Pull from Phundrak Labs (labs.phundrak.com)
docker pull labs.phundrak.com/phundrak/phundrak-dot-com-backend:latest
# Run the container
docker run -d \
--name phundrak-backend \
-p 3100:3100 \
-e APP__APPLICATION__PORT=3100 \
-e APP__EMAIL__HOST=smtp.example.com \
-e APP__EMAIL__PORT=587 \
-e APP__EMAIL__USER=user@example.com \
-e APP__EMAIL__PASSWORD=your_password \
-e APP__EMAIL__FROM="Contact Form <noreply@example.com>" \
-e APP__EMAIL__RECIPIENT="Admin <admin@example.com>" \
labs.phundrak.com/phundrak/phundrak-dot-com-backend:latest
```
### Available Image Tags
The following tags are automatically published:
- `latest` - Latest stable release (from tagged commits on `main`)
- `<version>` - Specific version (e.g., `1.0.0`, from tagged commits like `v1.0.0`)
- `develop` - Latest development build (from `develop` branch)
- `pr<number>` - Pull request preview builds (e.g., `pr12`)
### Building Images Locally
Build with Nix (recommended for reproducibility):
```bash
nix build .#backendDockerLatest
docker load < result
docker run -p 3100:3100 localhost/phundrak/backend-rust:latest
```
Build with Docker directly:
```bash
# Note: This requires a Dockerfile (not included in this project)
# Use Nix builds for containerization
```
### Docker Compose Example
```yaml
version: '3.8'
services:
backend:
image: labs.phundrak.com/phundrak/phundrak-dot-com-backend:latest
ports:
- "3100:3100"
environment:
APP__APPLICATION__PORT: 3100
APP__EMAIL__HOST: smtp.example.com
APP__EMAIL__PORT: 587
APP__EMAIL__USER: ${SMTP_USER}
APP__EMAIL__PASSWORD: ${SMTP_PASSWORD}
APP__EMAIL__FROM: "Contact Form <noreply@example.com>"
APP__EMAIL__RECIPIENT: "Admin <admin@example.com>"
APP__EMAIL__STARTTLS: true
APP__RATE_LIMIT__ENABLED: true
APP__RATE_LIMIT__BURST_SIZE: 10
APP__RATE_LIMIT__PER_SECONDS: 60
restart: unless-stopped
```
## CI/CD Pipeline
### Automated Docker Publishing
GitHub Actions automatically builds and publishes Docker images based on repository events:
| Event Type | Trigger | Published Tags |
|-----------------|------------------------------|-------------------------------|
| Tag push | `v*.*.*` tag on `main` | `latest`, `<version>` |
| Branch push | Push to `develop` | `develop` |
| Pull request | PR opened/updated | `pr<number>` |
| Branch push | Push to `main` (no tag) | `latest` |
### Workflow Details
The CI/CD pipeline (`.github/workflows/publish-docker.yml`):
1. **Checks out the repository**
2. **Installs Nix** with flakes enabled
3. **Builds the Docker image** using Nix for reproducibility
4. **Authenticates** with the configured Docker registry
5. **Tags and pushes** images based on the event type
### Registry Configuration
Images are published to the registry specified by the `DOCKER_REGISTRY` environment variable in the workflow (default: `labs.phundrak.com`).
To use the published images, authenticate with the registry:
```bash
# For Phundrak Labs (labs.phundrak.com)
echo $GITHUB_TOKEN | docker login labs.phundrak.com -u USERNAME --password-stdin
# Pull the image
docker pull labs.phundrak.com/phundrak/phundrak-dot-com-backend:latest
```
### Required Secrets
The workflow requires these GitHub secrets:
- `DOCKER_USERNAME` - Registry username
- `DOCKER_PASSWORD` - Registry password or token
- `CACHIX_AUTH_TOKEN` - (Optional) For Nix build caching
See [.github/workflows/README.md](../.github/workflows/README.md) for detailed setup instructions.
## License
AGPL-3.0-only - See the root repository for full license information.

View File

@ -34,8 +34,8 @@ in
cargo-watch
flyctl
just
marksman
tombi # TOML lsp server
vscode-langservers-extracted
];
services.mailpit = {

View File

@ -18,6 +18,7 @@ inputs.devenv.lib.mkShell {
packages = with pkgs; [
# LSP
marksman
nodePackages."@tailwindcss/language-server"
vscode-langservers-extracted
vue-language-server