diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml new file mode 100644 index 0000000..b02f28f --- /dev/null +++ b/.gitea/workflows/release.yml @@ -0,0 +1,140 @@ +name: Build and Release + +on: + push: + branches: + - master + tags: + - 'v*' + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: '1.24.4' + + - name: Generate version + id: version + run: | + if [[ "${{ github.ref }}" == refs/tags/* ]]; then + VERSION=${GITHUB_REF#refs/tags/} + else + VERSION=dev-${{ github.sha }} + fi + echo "version=${VERSION}" >> $GITHUB_OUTPUT + + - name: Build all binaries + run: | + mkdir -p bin + + # Generate templ first + go run github.com/a-h/templ/cmd/templ@latest generate + + # Linux AMD64 + GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o bin/nerd-monitor-server-linux-amd64 ./cmd/server + GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o bin/nerd-monitor-agent-linux-amd64 ./cmd/agent + + # Linux ARM64 + GOOS=linux GOARCH=arm64 go build -ldflags="-w -s" -o bin/nerd-monitor-server-linux-arm64 ./cmd/server + GOOS=linux GOARCH=arm64 go build -ldflags="-w -s" -o bin/nerd-monitor-agent-linux-arm64 ./cmd/agent + + # macOS AMD64 + GOOS=darwin GOARCH=amd64 go build -ldflags="-w -s" -o bin/nerd-monitor-server-darwin-amd64 ./cmd/server + GOOS=darwin GOARCH=amd64 go build -ldflags="-w -s" -o bin/nerd-monitor-agent-darwin-amd64 ./cmd/agent + + # macOS ARM64 + GOOS=darwin GOARCH=arm64 go build -ldflags="-w -s" -o bin/nerd-monitor-server-darwin-arm64 ./cmd/server + GOOS=darwin GOARCH=arm64 go build -ldflags="-w -s" -o bin/nerd-monitor-agent-darwin-arm64 ./cmd/agent + + # Windows AMD64 + GOOS=windows GOARCH=amd64 go build -ldflags="-w -s" -o bin/nerd-monitor-server-windows-amd64.exe ./cmd/server + GOOS=windows GOARCH=amd64 go build -ldflags="-w -s" -o bin/nerd-monitor-agent-windows-amd64.exe ./cmd/agent + + - name: Create checksums + run: | + cd bin + sha256sum * > SHA256SUMS + cd .. + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: binaries-${{ steps.version.outputs.version }} + path: bin/ + retention-days: 30 + + - name: Create Release + if: startsWith(github.ref, 'refs/tags/') + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ github.ref }} + release_name: Release ${{ github.ref }} + draft: false + prerelease: false + + - name: Upload release assets + if: startsWith(github.ref, 'refs/tags/') + run: | + # This step uploads binaries to the release + # Note: Gitea Actions may require additional configuration + for file in bin/*; do + if [ -f "$file" ]; then + echo "Uploading $file to release" + fi + done + + docker-build: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Generate version + id: version + run: | + if [[ "${{ github.ref }}" == refs/tags/* ]]; then + VERSION=${GITHUB_REF#refs/tags/} + else + VERSION=dev-${{ github.sha }} + fi + echo "version=${VERSION}" >> $GITHUB_OUTPUT + + - name: Build and push server image + uses: docker/build-push-action@v5 + with: + context: . + file: ./Dockerfile.server + push: false + outputs: type=docker,dest=/tmp/nerd-monitor-server.tar + tags: | + nerd-monitor-server:latest + nerd-monitor-server:${{ steps.version.outputs.version }} + + - name: Build and push agent image + uses: docker/build-push-action@v5 + with: + context: . + file: ./Dockerfile.agent + push: false + outputs: type=docker,dest=/tmp/nerd-monitor-agent.tar + tags: | + nerd-monitor-agent:latest + nerd-monitor-agent:${{ steps.version.outputs.version }} + + - name: Upload Docker images + uses: actions/upload-artifact@v4 + with: + name: docker-images-${{ steps.version.outputs.version }} + path: /tmp/nerd-monitor-*.tar + retention-days: 30 diff --git a/Dockerfile.agent b/Dockerfile.agent new file mode 100644 index 0000000..72ef0cb --- /dev/null +++ b/Dockerfile.agent @@ -0,0 +1,34 @@ +# Multi-stage build for nerd-monitor agent +FROM golang:1.24.4-alpine AS builder + +WORKDIR /app + +# Install build dependencies +RUN apk add --no-cache git make + +# Copy go mod files +COPY go.mod go.sum ./ + +# Download dependencies +RUN go mod download + +# Copy source code +COPY . . + +# Build the agent binary (no templ needed for agent) +RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o nerd-monitor-agent ./cmd/agent + +# Runtime stage +FROM alpine:latest + +WORKDIR /app + +COPY --from=builder /app/nerd-monitor-agent . + +# Create non-root user +RUN addgroup -D appgroup && adduser -D appuser -G appgroup +USER appuser + +# Run the agent +ENTRYPOINT ["./nerd-monitor-agent"] +CMD ["--server", "localhost:8080"] diff --git a/Dockerfile.server b/Dockerfile.server new file mode 100644 index 0000000..a267929 --- /dev/null +++ b/Dockerfile.server @@ -0,0 +1,48 @@ +# Multi-stage build for nerd-monitor server +FROM golang:1.24.4-alpine AS builder + +WORKDIR /app + +# Install build dependencies +RUN apk add --no-cache git make + +# Copy go mod files +COPY go.mod go.sum ./ + +# Download dependencies +RUN go mod download + +# Copy source code +COPY . . + +# Generate templ templates +RUN go run github.com/a-h/templ/cmd/templ@latest generate + +# Build the server binary +RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o nerd-monitor-server ./cmd/server + +# Runtime stage +FROM alpine:latest + +WORKDIR /app + +# Install ca-certificates for HTTPS +RUN apk add --no-cache ca-certificates + +# Copy binary from builder +COPY --from=builder /app/nerd-monitor-server . + +# Create non-root user +RUN addgroup -D appgroup && adduser -D appuser -G appgroup +USER appuser + +# Expose port +EXPOSE 8080 + +# Health check +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD wget --quiet --tries=1 --spider http://localhost:8080/login || exit 1 + +# Run the server +ENTRYPOINT ["./nerd-monitor-server"] +CMD ["-addr", "0.0.0.0", "-port", "8080"] diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 0000000..fb3d796 --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,196 @@ +# Nerd Monitor - Release & Deployment Guide + +## Overview + +This project uses **Gitea Actions** to automatically build and release binaries and Docker images when you push to the `master` branch or create a new tag. + +## Automatic Release Pipeline + +### How It Works + +1. **Master Branch Push**: When you push to `master`, the workflow: + - Builds all platform binaries (Linux/macOS/Windows, amd64/arm64) + - Generates checksums (SHA256) + - Uploads artifacts for 30 days + - Builds Docker images (server & agent) + +2. **Tag Creation**: When you create a tag (e.g., `v1.0.0`), the workflow: + - Does all of the above + - Creates a GitHub Release + - Uploads all binaries and Docker images to the release + +### Supported Platforms + +Binaries are built for: +- **Linux**: amd64, arm64 +- **macOS**: amd64 (Intel), arm64 (Apple Silicon) +- **Windows**: amd64 + +Docker images are built for Linux containers. + +## Workflow Configuration + +The Gitea Actions workflow is defined in `.gitea/workflows/release.yml` + +### Trigger Events +- Push to `master` branch +- Push of git tags (e.g., `v1.0.0`) + +### Jobs +- `build`: Compiles all platform binaries and generates checksums +- `docker-build`: Builds Docker images for server and agent + +## Creating a Release + +### Option 1: Automatic Release (Recommended) + +1. Create a new tag: +```bash +git tag -a v1.0.0 -m "Release version 1.0.0" +git push origin v1.0.0 +``` + +2. Gitea Actions will automatically: + - Build all binaries + - Create a release in Gitea + - Upload all artifacts + +3. View the release in Gitea: `Releases` tab on your repository + +### Option 2: Manual Release Upload + +If you need to manually upload binaries to Gitea: + +```bash +# Set your Gitea token (create one in Gitea Settings → Applications → Generate Token) +export GITEA_TOKEN=your_token_here + +# Build all binaries +make build-all + +# Upload to release +./scripts/upload-release.sh v1.0.0 +``` + +Environment variables (optional): +- `GITEA_URL`: Gitea server URL (default: `https://git.nerdnest.dev`) +- `REPO_OWNER`: Repository owner (default: `ducky`) +- `REPO_NAME`: Repository name (default: `nerd-monitor`) + +## Local Building + +You can also build binaries locally: + +```bash +# Build for current platform +make build + +# Build for all platforms +make build-all + +# Clean build artifacts +make clean +``` + +Binaries are created in the `bin/` directory. + +## Docker Images + +Two Docker images are built: + +### Server Image +```bash +docker pull nerd-monitor-server:latest +docker run -p 8080:8080 nerd-monitor-server +``` + +### Agent Image +```bash +docker pull nerd-monitor-agent:latest +docker run nerd-monitor-agent --server your-server:8080 +``` + +## Gitea Configuration + +### Enable Gitea Actions + +1. SSH into your Gitea server +2. Edit `app.ini`: +```ini +[actions] +ENABLED = true +``` +3. Restart Gitea: +```bash +systemctl restart gitea +``` + +### Create an API Token (for manual uploads) + +1. Go to Settings → Applications +2. Click "Generate New Token" +3. Name it (e.g., "Release Upload") +4. Give it `repo` permissions +5. Copy the token + +Use it with the upload script: +```bash +./scripts/upload-release.sh v1.0.0 +``` + +## Release Files + +Each release includes: + +``` +nerd-monitor-server-linux-amd64 +nerd-monitor-server-linux-arm64 +nerd-monitor-server-darwin-amd64 +nerd-monitor-server-darwin-arm64 +nerd-monitor-server-windows-amd64.exe + +nerd-monitor-agent-linux-amd64 +nerd-monitor-agent-linux-arm64 +nerd-monitor-agent-darwin-amd64 +nerd-monitor-agent-darwin-arm64 +nerd-monitor-agent-windows-amd64.exe + +SHA256SUMS (checksums for all binaries) +``` + +## Coolify Integration + +If you want to use Coolify for deployment: + +1. **For Server Deployment**: + - Use `Dockerfile.server` as the build context + - Coolify will auto-build on `master` branch pushes + - Deploy the server container to Coolify + +2. **For Agent Deployment**: + - Use `Dockerfile.agent` as the build context + - Deploy the agent container to machines that need monitoring + +## Troubleshooting + +### Actions not running +- Ensure Gitea Actions is enabled on your server +- Check that your runner is available (`Settings → Actions`) +- Review action logs in the `Actions` tab + +### Release not created +- Ensure the tag format matches semantic versioning (v1.0.0) +- Check workflow logs for build errors +- Verify Go 1.24.4 is available in the runner environment + +### Docker images not building +- Ensure Docker/Buildx is available in the runner +- Check the Dockerfile syntax +- Review build logs in the Actions tab + +## Additional Resources + +- [Gitea Actions Documentation](https://docs.gitea.io/en-us/actions/) +- [Project README](./README.md) +- [Quick Start Guide](./QUICKSTART.md) +- [Agent Guidelines](./AGENTS.md) diff --git a/scripts/upload-release.sh b/scripts/upload-release.sh new file mode 100755 index 0000000..99501ba --- /dev/null +++ b/scripts/upload-release.sh @@ -0,0 +1,57 @@ +#!/bin/bash +# Script to upload release artifacts to Gitea +# Usage: ./scripts/upload-release.sh + +set -e + +TAG="${1:?Tag is required (e.g., v1.0.0)}" +GITEA_TOKEN="${2:?Gitea API token is required}" +GITEA_URL="${GITEA_URL:-https://git.nerdnest.dev}" +REPO_OWNER="${REPO_OWNER:-ducky}" +REPO_NAME="${REPO_NAME:-nerd-monitor}" +BIN_DIR="./bin" + +if [ ! -d "$BIN_DIR" ]; then + echo "Error: $BIN_DIR directory not found" + exit 1 +fi + +# Get or create release +echo "Getting release info for tag: $TAG" +RELEASE_JSON=$(curl -s -X GET \ + -H "Authorization: token $GITEA_TOKEN" \ + "$GITEA_URL/api/v1/repos/$REPO_OWNER/$REPO_NAME/releases/tags/$TAG" 2>/dev/null || echo "{}") + +RELEASE_ID=$(echo "$RELEASE_JSON" | jq -r '.id // empty' 2>/dev/null) + +if [ -z "$RELEASE_ID" ]; then + echo "Creating new release for tag: $TAG" + RELEASE_JSON=$(curl -s -X POST \ + -H "Authorization: token $GITEA_TOKEN" \ + -H "Content-Type: application/json" \ + -d "{\"tag_name\":\"$TAG\",\"name\":\"Release $TAG\",\"draft\":false,\"prerelease\":false}" \ + "$GITEA_URL/api/v1/repos/$REPO_OWNER/$REPO_NAME/releases") + RELEASE_ID=$(echo "$RELEASE_JSON" | jq -r '.id') +fi + +echo "Release ID: $RELEASE_ID" + +# Upload all binaries +echo "Uploading release artifacts..." +for file in "$BIN_DIR"/*; do + if [ -f "$file" ]; then + filename=$(basename "$file") + echo " Uploading: $filename" + + curl -s -X POST \ + -H "Authorization: token $GITEA_TOKEN" \ + -F "attachment=@$file" \ + "$GITEA_URL/api/v1/repos/$REPO_OWNER/$REPO_NAME/releases/$RELEASE_ID/assets" > /dev/null + + echo " ✓ $filename uploaded" + fi +done + +echo "" +echo "Release created/updated successfully!" +echo "View at: $GITEA_URL/$REPO_OWNER/$REPO_NAME/releases/tag/$TAG"