diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..925971c --- /dev/null +++ b/.dockerignore @@ -0,0 +1,20 @@ +.git +.github +.review-sandboxes +.claude +.agents +.DS_Store +.venv +venv +__pycache__ +*.py[cod] +archive +docs +tmp +bin +dist +node_modules +web/static/dist +.air.log +*.md +!README.md diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..472733e --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,108 @@ +name: build + +on: + push: + branches: + - main + pull_request: + +permissions: + contents: read + +jobs: + test: + runs-on: ubuntu-latest + env: + TAILWIND_VERSION: v3.4.17 + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + + - name: Install templ + run: go install github.com/a-h/templ/cmd/templ@v0.3.1001 + + - name: Install tailwindcss standalone + run: | + curl -fsSL -o /usr/local/bin/tailwindcss \ + "https://github.com/tailwindlabs/tailwindcss/releases/download/${TAILWIND_VERSION}/tailwindcss-linux-x64" + chmod +x /usr/local/bin/tailwindcss + + - name: Build assets + run: | + mkdir -p web/static/dist + templ generate ./... + tailwindcss -c tailwind.config.js -i web/static/src/app.css -o web/static/dist/app.css --minify + + - name: Vet + run: go vet ./... + + - name: Test + run: go test -race ./... + + - name: Build + run: | + mkdir -p bin + CGO_ENABLED=0 go build -trimpath \ + -ldflags="-s -w -X github.com/fserg/md-to-html/internal/version.Version=$(cat VERSION)" \ + -o bin/md-to-html ./cmd/md-to-html + + cross-compile: + needs: test + runs-on: ubuntu-latest + env: + TAILWIND_VERSION: v3.4.17 + + strategy: + matrix: + include: + - goos: linux + goarch: amd64 + - goos: linux + goarch: arm64 + - goos: darwin + goarch: arm64 + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + + - name: Install templ + run: go install github.com/a-h/templ/cmd/templ@v0.3.1001 + + - name: Install tailwindcss standalone + run: | + curl -fsSL -o /usr/local/bin/tailwindcss \ + "https://github.com/tailwindlabs/tailwindcss/releases/download/${TAILWIND_VERSION}/tailwindcss-linux-x64" + chmod +x /usr/local/bin/tailwindcss + + - name: Build assets + run: | + mkdir -p web/static/dist + templ generate ./... + tailwindcss -c tailwind.config.js -i web/static/src/app.css -o web/static/dist/app.css --minify + + - name: Cross-compile + env: + GOOS: ${{ matrix.goos }} + GOARCH: ${{ matrix.goarch }} + CGO_ENABLED: "0" + run: | + mkdir -p bin + go build -trimpath \ + -ldflags="-s -w -X github.com/fserg/md-to-html/internal/version.Version=$(cat VERSION)" \ + -o "bin/md-to-html-${GOOS}-${GOARCH}" \ + ./cmd/md-to-html + + - uses: actions/upload-artifact@v4 + with: + name: md-to-html-${{ matrix.goos }}-${{ matrix.goarch }} + path: bin/md-to-html-${{ matrix.goos }}-${{ matrix.goarch }} + retention-days: 7 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..282fdb9 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,79 @@ +name: release + +on: + push: + tags: + - "v*" + +permissions: + contents: write + packages: write + +jobs: + release: + runs-on: ubuntu-latest + env: + TAILWIND_VERSION: v3.4.17 + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + + - name: Install templ + run: go install github.com/a-h/templ/cmd/templ@v0.3.1001 + + - name: Install tailwindcss standalone + run: | + curl -fsSL -o /usr/local/bin/tailwindcss \ + "https://github.com/tailwindlabs/tailwindcss/releases/download/${TAILWIND_VERSION}/tailwindcss-linux-x64" + chmod +x /usr/local/bin/tailwindcss + + - name: Build assets + run: | + mkdir -p web/static/dist + templ generate ./... + tailwindcss -c tailwind.config.js -i web/static/src/app.css -o web/static/dist/app.css --minify + + - name: Cross-compile binaries + run: | + mkdir -p dist + for target in "linux amd64" "linux arm64" "darwin arm64"; do + set -- $target + GOOS=$1 GOARCH=$2 CGO_ENABLED=0 go build -trimpath \ + -ldflags="-s -w -X github.com/fserg/md-to-html/internal/version.Version=$(cat VERSION)" \ + -o "dist/md-to-html-${1}-${2}" \ + ./cmd/md-to-html + done + + - name: Log in to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - uses: docker/setup-qemu-action@v3 + + - uses: docker/setup-buildx-action@v3 + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + push: true + platforms: linux/amd64,linux/arm64 + tags: | + ghcr.io/${{ github.repository }}:${{ github.ref_name }} + ghcr.io/${{ github.repository }}:latest + + - name: Create GitHub Release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh release create "${{ github.ref_name }}" \ + --title "${{ github.ref_name }}" \ + --notes-file CHANGELOG.md \ + dist/* diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..cc641d3 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,62 @@ +# syntax=docker/dockerfile:1.7 + +FROM debian:bookworm-slim AS tailwind + +RUN apt-get update \ + && apt-get install -y --no-install-recommends ca-certificates curl \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /src + +ARG TARGETARCH +ARG TAILWIND_VERSION=v3.4.17 + +RUN case "$TARGETARCH" in \ + amd64) tailwind_arch='x64' ;; \ + arm64) tailwind_arch='arm64' ;; \ + *) echo "unsupported TARGETARCH: $TARGETARCH" >&2; exit 1 ;; \ + esac \ + && curl -fsSL -o /usr/local/bin/tailwindcss \ + "https://github.com/tailwindlabs/tailwindcss/releases/download/${TAILWIND_VERSION}/tailwindcss-linux-${tailwind_arch}" \ + && chmod +x /usr/local/bin/tailwindcss + +COPY tailwind.config.js ./ +COPY web/ ./web/ +COPY internal/ui/ ./internal/ui/ + +RUN mkdir -p web/static/dist \ + && tailwindcss \ + -c tailwind.config.js \ + -i web/static/src/app.css \ + -o web/static/dist/app.css \ + --minify + +FROM golang:1.24-alpine AS build + +WORKDIR /src + +RUN apk add --no-cache ca-certificates git +RUN go install github.com/a-h/templ/cmd/templ@v0.3.1001 + +COPY go.mod go.sum ./ +RUN go mod download + +COPY . . +COPY --from=tailwind /src/web/static/dist/app.css ./web/static/dist/app.css + +RUN templ generate ./... \ + && CGO_ENABLED=0 GOOS=linux go build \ + -trimpath \ + -ldflags="-s -w -X github.com/fserg/md-to-html/internal/version.Version=$(cat VERSION)" \ + -o /out/md-to-html \ + ./cmd/md-to-html + +FROM gcr.io/distroless/static-debian12:nonroot + +COPY --from=build /out/md-to-html /md-to-html + +EXPOSE 8080 + +USER nonroot + +ENTRYPOINT ["/md-to-html", "serve"]