ci: publish container image to GHCR
Build and publish container / Test, lint, and build (push) Canceled after 0s
Build and publish container / Build and publish image (push) Canceled after 0s

This commit is contained in:
2026-07-23 02:33:50 +03:00
parent 2c19b7a427
commit 2958752fba
5 changed files with 170 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
.git
.github
node_modules
dist
coverage
*.log
.env
.env.*
+90
View File
@@ -0,0 +1,90 @@
name: Build and publish container
on:
push:
branches:
- main
tags:
- 'v*'
pull_request:
branches:
- main
workflow_dispatch:
concurrency:
group: container-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
packages: write
jobs:
quality:
name: Test, lint, and build
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 24
cache: npm
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Run ESLint
run: npm run lint
- name: Build application
run: npm run build
container:
name: Build and publish image
needs: quality
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GHCR
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Generate image metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository }}
tags: |
type=raw,value=latest,enable={{is_default_branch}}
type=ref,event=branch
type=ref,event=tag
type=sha,prefix=sha-
- name: Build and publish image
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
+19
View File
@@ -0,0 +1,19 @@
FROM docker.io/library/node:24-alpine AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM docker.io/nginxinc/nginx-unprivileged:1.29-alpine AS runtime
COPY --chmod=644 nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 5120
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget -q -O /dev/null http://127.0.0.1:5120/ || exit 1
+19
View File
@@ -41,6 +41,25 @@ npm run lint
npm run build
```
## Container
Run the published image on the default port `5120`:
```bash
docker run --rm -p 5120:5120 ghcr.io/kr0sh512/pomodoro:latest
```
Or build it locally:
```bash
docker build -t pomodoro:local .
docker run --rm -p 5120:5120 pomodoro:local
```
GitHub Actions tests the project and publishes multi-architecture images for `linux/amd64` and
`linux/arm64` to GHCR on pushes to `main` and version tags. Published tags include `latest`,
`main`, version tags, and `sha-<commit>`.
## Architecture
- React and TypeScript for the interface and timer state
+34
View File
@@ -0,0 +1,34 @@
server {
listen 5120;
listen [::]:5120;
server_name _;
root /usr/share/nginx/html;
index index.html;
charset utf-8;
gzip on;
gzip_types text/css application/javascript application/json image/svg+xml;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
location /assets/ {
try_files $uri =404;
expires 1y;
add_header Cache-Control "public, immutable";
add_header X-Content-Type-Options "nosniff" always;
}
location / {
try_files $uri $uri/ /index.html;
}
location = /index.html {
add_header Cache-Control "no-cache";
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
}
}