diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml new file mode 100644 index 0000000..3c39e4d --- /dev/null +++ b/.github/workflows/docker-publish.yml @@ -0,0 +1,62 @@ +name: Publish Docker Images + +on: + push: + branches: [main] + tags: + - "v*" + workflow_dispatch: + +jobs: + publish: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + strategy: + fail-fast: false + matrix: + image: + - name: funcatlas-api + dockerfile: apps/api/Dockerfile + - name: funcatlas-web + dockerfile: apps/web/Dockerfile + - name: funcatlas-migrations + dockerfile: services/parser/migrations/Dockerfile + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: Set lowercase registry owner + run: echo "OWNER_LC=${GITHUB_REPOSITORY_OWNER,,}" >> "$GITHUB_ENV" + + - uses: docker/setup-qemu-action@v3 + - uses: docker/setup-buildx-action@v3 + + - name: Log in to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract image metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ghcr.io/${{ env.OWNER_LC }}/${{ matrix.image.name }} + tags: | + type=ref,event=branch + type=ref,event=tag + type=sha + type=raw,value=latest,enable={{is_default_branch}} + + - name: Build and push + uses: docker/build-push-action@v6 + with: + context: . + file: ${{ matrix.image.dockerfile }} + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/README.md b/README.md index 7a10d64..7820d87 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,27 @@ Paste a public repository URL and explore it. `⌘K` finds any function by name. > this way on a server. Blank the value in `.env` to use real GitHub sign-in instead > ([`docs/RISKS.md`](docs/RISKS.md) R39). +### Run from published Docker images (no clone) + +You can run funcatlas directly from GHCR images: + +```bash +TAG=v1.2.3 +docker pull ghcr.io/arcoder181105/funcatlas-api:${TAG} +docker pull ghcr.io/arcoder181105/funcatlas-web:${TAG} +docker pull ghcr.io/arcoder181105/funcatlas-migrations:${TAG} +curl -fsSL https://raw.githubusercontent.com/ARCoder181105/funcatlas/${TAG}/docker-compose.images.yml -o docker-compose.images.yml +FUNCATLAS_IMAGE_TAG=${TAG} docker compose -f docker-compose.images.yml up +``` + +Then open . The compose file comes from the same `${TAG}` as the images, so a pinned run cannot drift onto a newer compose file. For the floating `latest` run, use `TAG=main`. + +Published images: + +- `ghcr.io/arcoder181105/funcatlas-api` +- `ghcr.io/arcoder181105/funcatlas-web` +- `ghcr.io/arcoder181105/funcatlas-migrations` + ### With real GitHub sign-in Blank `FUNCATLAS_SINGLE_USER` in `.env` and register an OAuth app at diff --git a/docker-compose.images.yml b/docker-compose.images.yml new file mode 100644 index 0000000..5ea3092 --- /dev/null +++ b/docker-compose.images.yml @@ -0,0 +1,82 @@ +services: + postgres: + image: postgres:16 + environment: + POSTGRES_USER: funcatlas + POSTGRES_PASSWORD: funcatlas + POSTGRES_DB: funcatlas + ports: + - "127.0.0.1:5432:5432" + volumes: + - pgdata:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U funcatlas"] + interval: 5s + timeout: 5s + retries: 5 + + redis: + image: redis:7 + ports: + - "127.0.0.1:6379:6379" + volumes: + - redisdata:/data + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 5s + timeout: 5s + retries: 5 + + migrate: + image: ghcr.io/arcoder181105/funcatlas-migrations:${FUNCATLAS_IMAGE_TAG:-latest} + command: + - -path=/migrations + - -database=postgres://funcatlas:funcatlas@postgres:5432/funcatlas?sslmode=disable + - up + depends_on: + postgres: + condition: service_healthy + restart: "no" + + api: &node + image: ghcr.io/arcoder181105/funcatlas-api:${FUNCATLAS_IMAGE_TAG:-latest} + environment: + NODE_ENV: production + PORT: 3000 + WEB_APP_URL: http://localhost:5173 + CORS_ORIGIN: http://localhost:5173 + DATABASE_URL: postgres://funcatlas:funcatlas@postgres:5432/funcatlas?sslmode=disable + REDIS_URL: redis://redis:6379 + QUEUE_NAME: funcatlas-parse + GITHUB_CLIENT_ID: ci-client-id + GITHUB_CLIENT_SECRET: ci-client-secret + GITHUB_REDIRECT_URI: http://localhost:3000/auth/callback + GITHUB_WEBHOOK_SECRET: local-webhook-secret + SESSION_SECRET: local-session-secret-change-me + FUNCATLAS_SINGLE_USER: funcatlas + PARSER_BIN: /usr/local/bin/funcatlas-parser + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + migrate: + condition: service_completed_successfully + ports: + - "127.0.0.1:3000:3000" + + worker: + <<: *node + command: ["./node_modules/.bin/tsx", "src/worker.ts"] + ports: [] + + web: + image: ghcr.io/arcoder181105/funcatlas-web:${FUNCATLAS_IMAGE_TAG:-latest} + depends_on: + - api + ports: + - "127.0.0.1:5173:80" + +volumes: + pgdata: + redisdata: diff --git a/services/parser/migrations/Dockerfile b/services/parser/migrations/Dockerfile new file mode 100644 index 0000000..6cf7730 --- /dev/null +++ b/services/parser/migrations/Dockerfile @@ -0,0 +1,3 @@ +FROM migrate/migrate:v4.18.1 + +COPY services/parser/migrations /migrations