Skip to content

Commit 22e3730

Browse files
pjt222claude
andcommitted
feat: add Hugging Face Spaces Docker deployment
Two-stage Dockerfile caches R package installation in a base layer so only app code changes trigger fast rebuilds (~1-2 min vs 15-20 min on shinyapps.io). GitHub Actions workflow auto-deploys on push to main. Existing shinyapps.io deployment remains untouched as fallback. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 665b6c8 commit 22e3730

5 files changed

Lines changed: 155 additions & 0 deletions

File tree

.Rbuildignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,6 @@
1919
^Rplots\.pdf$
2020
^LICENSE\.md$
2121
inst/shiny-app/\.rscignore$
22+
^Dockerfile$
23+
^\.dockerignore$
24+
^hf-spaces$

.dockerignore

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
.git
2+
.github
3+
.Rproj.user
4+
.claude
5+
renv/library
6+
renv/local
7+
renv/staging
8+
renv/sandbox
9+
renv/python
10+
tests/
11+
docs/
12+
quarto/
13+
output/
14+
man/
15+
vignettes/
16+
temp/
17+
hf-spaces/
18+
*.Rproj
19+
CLAUDE.md
20+
GEMINI.md
21+
CONTINUE_HERE.md
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
name: Deploy to Hugging Face Spaces
2+
3+
on:
4+
push:
5+
branches: [main]
6+
paths-ignore:
7+
- 'quarto/**'
8+
- 'docs/**'
9+
- 'tests/**'
10+
- '*.md'
11+
- '!hf-spaces/README.md'
12+
workflow_dispatch:
13+
14+
concurrency:
15+
group: hf-spaces-deploy
16+
cancel-in-progress: true
17+
18+
permissions:
19+
contents: read
20+
21+
jobs:
22+
deploy-hf:
23+
runs-on: ubuntu-latest
24+
timeout-minutes: 10
25+
steps:
26+
- name: Checkout repository
27+
uses: actions/checkout@v4
28+
with:
29+
fetch-depth: 0
30+
lfs: true
31+
32+
- name: Prepare HF Spaces deployment
33+
run: |
34+
# Replace README with HF Spaces version (YAML frontmatter for Docker SDK)
35+
cp hf-spaces/README.md README.md
36+
37+
- name: Push to Hugging Face Spaces
38+
env:
39+
HF_TOKEN: ${{ secrets.HF_TOKEN }}
40+
run: |
41+
git config user.name "GitHub Actions"
42+
git config user.email "actions@github.com"
43+
git add -A
44+
git commit -m "Deploy to HF Spaces" --allow-empty
45+
git push --force https://pjt222:${HF_TOKEN}@huggingface.co/spaces/pjt222/jigsawR main

Dockerfile

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# ===========================================================================
2+
# Stage 1: Dependencies (cached layer -- only rebuilds when DESCRIPTION changes)
3+
# ===========================================================================
4+
FROM rocker/r-ver:4.4.2 AS deps
5+
6+
# Headless rgl (no X11 display in Docker)
7+
ENV RGL_USE_NULL=TRUE
8+
9+
# System libraries needed by R packages
10+
RUN apt-get update && apt-get install -y --no-install-recommends \
11+
build-essential \
12+
libcurl4-openssl-dev \
13+
libssl-dev \
14+
libxml2-dev \
15+
libmagick++-dev \
16+
librsvg2-dev \
17+
libpng-dev \
18+
libgl1-mesa-dev \
19+
libglu1-mesa-dev \
20+
libfreetype6-dev \
21+
libharfbuzz-dev \
22+
libfribidi-dev \
23+
libfontconfig1-dev \
24+
libtiff5-dev \
25+
libjpeg-dev \
26+
libwebp-dev \
27+
zlib1g-dev \
28+
git \
29+
&& rm -rf /var/lib/apt/lists/*
30+
31+
# Copy only dependency-defining file for cache optimization
32+
COPY DESCRIPTION /tmp/pkg/DESCRIPTION
33+
34+
# Install all R packages (PPM binaries where available)
35+
RUN Rscript -e " \
36+
install.packages('remotes', repos='https://cloud.r-project.org'); \
37+
# Imports \
38+
install.packages(c('Rcpp', 'ggplot2', 'ggfx', 'viridis', 'config', 'cli', 'rlang'), \
39+
repos='https://cloud.r-project.org'); \
40+
# Shiny runtime dependencies \
41+
install.packages(c('shiny', 'bslib', 'bsicons', 'shinyjs', 'colourpicker', 'waiter', \
42+
'rsvg', 'magick', 'zip', 'scales', 'ambient', 'png', 'base64enc', \
43+
'deldir', 'snic', 'ggforce', 'data.table'), \
44+
repos='https://cloud.r-project.org'); \
45+
# GitHub-only packages \
46+
remotes::install_github('stla/RCDT'); \
47+
"
48+
49+
# ===========================================================================
50+
# Stage 2: Application (fast rebuild on code changes)
51+
# ===========================================================================
52+
FROM deps AS app
53+
54+
# Create app user (HF Spaces runs as uid 1000)
55+
RUN useradd -m -u 1000 appuser
56+
57+
# Copy package source and install (compiles Rcpp C++)
58+
COPY . /tmp/jigsawR-src
59+
RUN cd /tmp/jigsawR-src && \
60+
R CMD INSTALL --no-test-load . && \
61+
rm -rf /tmp/jigsawR-src
62+
63+
# Set up the Shiny app directory
64+
RUN mkdir -p /app/output
65+
COPY inst/shiny-app/ /app/
66+
COPY inst/config.yml /app/config.yml
67+
68+
RUN chown -R appuser:appuser /app
69+
70+
USER appuser
71+
WORKDIR /app
72+
73+
EXPOSE 7860
74+
75+
CMD ["Rscript", "-e", "shiny::runApp('/app', host='0.0.0.0', port=7860, launch.browser=FALSE)"]

hf-spaces/README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
title: jigsawR
3+
emoji: "\U0001F9E9"
4+
colorFrom: blue
5+
colorTo: green
6+
sdk: docker
7+
app_port: 7860
8+
pinned: false
9+
license: gpl-3.0
10+
short_description: Interactive jigsaw puzzle generator
11+
---

0 commit comments

Comments
 (0)