From 00e6852863f05519baf31d1216ee1b71a8d37ac1 Mon Sep 17 00:00:00 2001 From: Aculix Technologies Date: Fri, 14 Aug 2026 14:36:18 +0530 Subject: [PATCH] ci: publish multi-arch image to GHCR; move status port to 4733 GitHub Actions builds linux/amd64 and linux/arm64 on every push to main and pushes a single :latest tag to ghcr.io, so the container can be run without cloning or building. Tests gate the publish step. --- .env.example | 2 +- .github/workflows/docker.yml | 49 +++++++++++++++++++++++++++++++++ Dockerfile | 2 +- README.md | 53 ++++++++++++++++++++++++++++++++---- compose.yaml | 6 ++-- src/config.js | 2 +- 6 files changed, 103 insertions(+), 11 deletions(-) create mode 100644 .github/workflows/docker.yml diff --git a/.env.example b/.env.example index 6d2ae01..3a43a34 100644 --- a/.env.example +++ b/.env.example @@ -45,7 +45,7 @@ CURRENCY=₹ # ── Runtime ─────────────────────────────────────────────────────────────────── STATE_PATH=./state.json # Docker image defaults this to /data/state.json -PORT=8080 # status endpoint (--loop mode only) +PORT=4733 # status endpoint (--loop mode only) # Routes only the site checks through a SOCKS5 proxy; notifications stay direct. # Needed on datacenter hosts, whose IPs the site's WAF is likely to block. diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000..5cd8afc --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,49 @@ +name: docker + +on: + push: + branches: [main] + workflow_dispatch: + +concurrency: + group: docker-${{ github.ref }} + cancel-in-progress: true + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + - run: npm ci + - run: npm test + + publish: + needs: test + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - uses: actions/checkout@v4 + + # QEMU lets this amd64 runner build the arm64 half of the manifest. + - uses: docker/setup-qemu-action@v3 + - uses: docker/setup-buildx-action@v3 + + - uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - uses: docker/build-push-action@v6 + with: + context: . + platforms: linux/amd64,linux/arm64 + push: true + tags: ghcr.io/${{ github.repository }}:latest + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/Dockerfile b/Dockerfile index 27bf6d5..278a056 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,7 +8,7 @@ COPY src/ src/ ENV STATE_PATH=/data/state.json VOLUME /data -EXPOSE 8080 +EXPOSE 4733 # --env-file-if-exists so the container works with plain env vars when no .env is mounted. CMD ["node", "--env-file-if-exists=.env", "src/index.js", "--loop"] diff --git a/README.md b/README.md index 89cd1ed..910b116 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # ticket-monitoring +[![docker](https://github.com/aculix/ticket-monitoring/actions/workflows/docker.yml/badge.svg)](https://github.com/aculix/ticket-monitoring/actions/workflows/docker.yml) + Watches [district.in](https://www.district.in) showtimes and sends a max-priority push to your phone the second tickets go on sale for the movie, date, format and cinema you care about. @@ -36,18 +38,53 @@ Shows added later still get through. The [ntfy app](https://ntfy.sh/#subscribe-phone) on your phone, and either Docker or Node.js 22+. -## Quick start with Docker +## Quickest start: run the published image + +A prebuilt image is published to GitHub Container Registry on every push to `main`, for both +`linux/amd64` and `linux/arm64`. It runs as-is on a normal server, an Apple Silicon Mac or a +Raspberry Pi, with nothing to clone and nothing to build. + +Grab [`.env.example`](.env.example), save it as `.env`, fill it in using "Finding your IDs" below, +then: + +```bash +docker run -d --name ticket-monitoring \ + --restart unless-stopped \ + --env-file .env \ + -p 4733:4733 \ + -v ticket-monitoring-data:/data \ + ghcr.io/aculix/ticket-monitoring:latest +``` + +```bash +docker logs -f ticket-monitoring +``` + +You want to see `tick: closed failures: 0` scrolling past once a minute. + +The volume is what stops it re-alerting you about shows it already found, so keep it around across +restarts. Drop the `-p` flag if you don't want the status endpoint reachable. To update, pull the +image again and recreate the container: + +```bash +docker pull ghcr.io/aculix/ticket-monitoring:latest +docker rm -f ticket-monitoring # then re-run the docker run command above +``` + +Only `:latest` is published, so that's always the current build of `main`. + +## Quick start with Docker Compose + +Handy if you'd rather keep the config in a file you can edit in place: ```bash git clone https://github.com/aculix/ticket-monitoring.git cd ticket-monitoring cp .env.example .env # edit it, see "Finding your IDs" below -docker compose up -d --build +docker compose up -d # add --build to build locally instead of pulling docker compose logs -f ``` -You want to see `tick: closed failures: 0` scrolling past once a minute. - ## Quick start without Docker ```bash @@ -110,17 +147,21 @@ Everything is environment variables. `.env` is only a convenient place to put th | `CURRENCY` | `₹` | Price prefix | | `EXPIRY_UTC` | *auto* | When to retire. Defaults to local midnight after `TARGET_DATE`. | | `STATE_PATH` | `./state.json` | Where dedupe state lives, `/data/state.json` in Docker | -| `PORT` | `8080` | Status endpoint | +| `PORT` | `4733` | Status endpoint | | `PROXY_URL` | | SOCKS5 proxy for the site checks, see below | ## Status endpoint -While running continuously it serves JSON on `PORT`: +While running continuously it serves JSON on `PORT`, which defaults to 4733: - `/` gives you state, `lastTick` and `proxied` - `/?force=1` adds a live check right now, with no notifications and no state changes - `/healthz` returns `{"ok":true}` +```bash +curl -s localhost:4733/ | jq +``` + Watch `lastTick.at`. If it's more than a couple of minutes old, the loop is stuck. ## Troubleshooting diff --git a/compose.yaml b/compose.yaml index e510aa8..1310812 100644 --- a/compose.yaml +++ b/compose.yaml @@ -1,11 +1,13 @@ services: monitor: + # Pulls the prebuilt multi-arch image. Run `docker compose up --build` instead + # to build from this checkout; the result gets tagged with the same name. + image: ghcr.io/aculix/ticket-monitoring:latest build: . - image: ticket-monitoring container_name: ticket-monitoring restart: unless-stopped env_file: .env ports: - - "8080:8080" # status endpoint; drop this line to keep it private + - "4733:4733" # status endpoint; drop this line to keep it private volumes: - ./data:/data # state survives restarts, so you aren't re-alerted diff --git a/src/config.js b/src/config.js index 4166ed5..40af006 100644 --- a/src/config.js +++ b/src/config.js @@ -55,7 +55,7 @@ export function loadConfig() { // runtime statePath: process.env.STATE_PATH || "./state.json", - port: num("PORT", 8080), + port: num("PORT", 4733), proxyUrl: process.env.PROXY_URL || "", dispatcher: null, // set by attachProxy() when PROXY_URL is present };