chore: import upstream snapshot with attribution
docmd CI verification / verify (push) Failing after 0s
docmd CI verification / verify (push) Failing after 0s
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
# --------------------------------------------------------------------
|
||||
# docmd : the minimalist, zero-config documentation generator.
|
||||
#
|
||||
# @package @docmd/core (and ecosystem)
|
||||
# @website https://docmd.io
|
||||
# @repository https://github.com/docmd-io/docmd
|
||||
# @license MIT
|
||||
# @copyright Copyright (c) 2025-present docmd.io
|
||||
#
|
||||
# [docmd-source] - Please do not remove this header.
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
# Dependencies
|
||||
node_modules
|
||||
packages/*/node_modules
|
||||
packages/plugins/*/node_modules
|
||||
packages/engines/*/node_modules
|
||||
|
||||
# Build outputs
|
||||
dist
|
||||
*.tsbuildinfo
|
||||
packages/*/dist
|
||||
packages/plugins/*/dist
|
||||
packages/engines/*/dist
|
||||
|
||||
# Generated sites
|
||||
site
|
||||
packages/*/site
|
||||
packages/plugins/*/site
|
||||
public
|
||||
|
||||
# Development files
|
||||
.git
|
||||
.gitignore
|
||||
.github
|
||||
.vscode
|
||||
.idea
|
||||
*.md
|
||||
!README.md
|
||||
|
||||
# Test and playground files
|
||||
packages/_playground
|
||||
temp-*
|
||||
*.log
|
||||
*.tsbuildinfo
|
||||
|
||||
# Native build artifacts (will be downloaded at runtime)
|
||||
packages/engines/rust-binaries/native/target
|
||||
|
||||
# Documentation
|
||||
docs
|
||||
*.md
|
||||
!README.md
|
||||
!LICENSE
|
||||
|
||||
# CI/CD files
|
||||
.github
|
||||
.travis.yml
|
||||
.circleci
|
||||
|
||||
# Editor files
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
.DS_Store
|
||||
|
||||
# Environment files
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
|
||||
# Test files
|
||||
test
|
||||
tests
|
||||
__tests__
|
||||
coverage
|
||||
.nyc_output
|
||||
|
||||
# Misc
|
||||
*.tgz
|
||||
*.bak
|
||||
tmp
|
||||
temp
|
||||
@@ -0,0 +1,236 @@
|
||||
# Docker Image for docmd
|
||||
|
||||
Official Docker image for docmd - the minimalist, zero-config documentation generator.
|
||||
|
||||
## Quick Start
|
||||
|
||||
> The examples below use `:latest` so you can copy-paste and run them immediately.
|
||||
> **For production, CI, and any reproducible build**, replace `:latest` with the specific version you want — see [Available Tags](#available-tags).
|
||||
|
||||
### Pull the Image
|
||||
|
||||
```bash
|
||||
# Pull from GitHub Container Registry (GHCR)
|
||||
docker pull ghcr.io/docmd-io/docmd:latest
|
||||
```
|
||||
|
||||
### Run Demo Site
|
||||
|
||||
The image ships with a demo template in `/template`. When you run the container with no volume mount, the entrypoint copies `/template` into `/docs` on first start, so the demo site comes up immediately.
|
||||
|
||||
```bash
|
||||
# Start with built-in demo site — works out of the box
|
||||
docker run -p 3000:3000 ghcr.io/docmd-io/docmd:latest
|
||||
|
||||
# Visit http://localhost:3000
|
||||
```
|
||||
|
||||
### Initialize New Project
|
||||
|
||||
```bash
|
||||
# Create and initialize a new project
|
||||
mkdir my-docs && cd my-docs
|
||||
docker run -v $(pwd):/workspace ghcr.io/docmd-io/docmd:latest init
|
||||
|
||||
# Start dev server
|
||||
docker run -v $(pwd):/workspace -p 3000:3000 ghcr.io/docmd-io/docmd:latest dev
|
||||
```
|
||||
|
||||
### Use Existing Docs
|
||||
|
||||
Mounting your own docs into `/docs` always wins — the entrypoint only seeds the demo template when `/docs` is completely empty, so your content is never overwritten.
|
||||
|
||||
```bash
|
||||
# Mount your docs and start dev server
|
||||
docker run -v $(pwd)/docs:/docs -p 3000:3000 ghcr.io/docmd-io/docmd:latest
|
||||
|
||||
# Build static site
|
||||
docker run -v $(pwd)/docs:/docs -v $(pwd)/site:/site ghcr.io/docmd-io/docmd:latest build
|
||||
```
|
||||
|
||||
## Available Tags
|
||||
|
||||
The image is published with two tags per release:
|
||||
|
||||
| Tag | Description | When to use |
|
||||
|-----|-------------|-------------|
|
||||
| `latest` | Floating alias for the most recent stable release | Quick start, local exploration, throwaway CI |
|
||||
| `<X.Y.Z>` | Pinned stable release (substitute the version you want) | Production, CI/CD, anything that must be reproducible |
|
||||
|
||||
> **Pin a specific version in production.** The examples below use `:latest` so you can copy-paste and run them immediately. For any pipeline whose output must be reproducible (or whose contracts you don't want silently changing), replace `:latest` with the specific version you want (e.g. `0.8.7`). Check the [package versions page](https://github.com/orgs/docmd-io/packages/container/docmd/versions) for the full list.
|
||||
|
||||
## Multi-Platform Support
|
||||
|
||||
The image is built for multiple architectures:
|
||||
|
||||
- `linux/amd64` - Standard x86_64 servers
|
||||
- `linux/arm64` - ARM-based servers (AWS Graviton, Raspberry Pi, Apple Silicon)
|
||||
|
||||
Docker automatically pulls the correct image for your platform.
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Docker Compose
|
||||
|
||||
```yaml
|
||||
# Replace `:latest` with a specific version (e.g. `0.8.7`) for reproducible
|
||||
# production builds. See the GitHub releases page for available versions.
|
||||
services:
|
||||
docmd:
|
||||
image: ghcr.io/docmd-io/docmd:latest
|
||||
ports:
|
||||
- "3000:3000"
|
||||
volumes:
|
||||
- ./docs:/docs
|
||||
- ./site:/site
|
||||
# The dev server defaults to 127.0.0.1 (loopback). For LAN access from
|
||||
# other devices, set DOCMD_HOST=0.0.0.0 or pass --host 0.0.0.0 explicitly.
|
||||
command: dev
|
||||
```
|
||||
|
||||
### GitHub Actions CI/CD
|
||||
|
||||
```yaml
|
||||
name: Build Docs
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Build documentation
|
||||
# Pin to a specific version (replace `:latest`) for reproducible CI runs.
|
||||
run: |
|
||||
docker run --rm \
|
||||
-v ${{ github.workspace }}/docs:/docs \
|
||||
-v ${{ github.workspace }}/site:/site \
|
||||
ghcr.io/docmd-io/docmd:latest \
|
||||
build
|
||||
|
||||
- name: Deploy to GitHub Pages
|
||||
uses: peaceiris/actions-gh-pages@v3
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: ./site
|
||||
```
|
||||
|
||||
### Kubernetes Deployment
|
||||
|
||||
```yaml
|
||||
# Replace `:latest` with a specific version (e.g. `0.8.7`) for reproducible
|
||||
# production deploys. Update the tag when you upgrade.
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: docmd-server
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: docmd
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: docmd
|
||||
spec:
|
||||
containers:
|
||||
- name: docmd
|
||||
image: ghcr.io/docmd-io/docmd:latest
|
||||
ports:
|
||||
- containerPort: 3000
|
||||
volumeMounts:
|
||||
- name: docs
|
||||
mountPath: /docs
|
||||
# The dev server defaults to 127.0.0.1. For LAN access, set
|
||||
# DOCMD_HOST=0.0.0.0 or pass --host 0.0.0.0 explicitly.
|
||||
command: ["docmd", "dev"]
|
||||
volumes:
|
||||
- name: docs
|
||||
configMap:
|
||||
name: docs-content
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
| Variable | Description | Default |
|
||||
|----------|-------------|---------|
|
||||
| `NODE_ENV` | Node environment | `production` |
|
||||
| `DOCMD_CONTAINER` | Container mode flag | `true` |
|
||||
|
||||
## Building Locally
|
||||
|
||||
```bash
|
||||
# Clone the repository
|
||||
git clone https://github.com/docmd-io/docmd.git
|
||||
cd docmd
|
||||
|
||||
# Build the image
|
||||
docker build -t docmd:local -f docker/Dockerfile .
|
||||
|
||||
# Test the build
|
||||
docker run --rm -v $(pwd)/docs:/docs docmd:local --version
|
||||
```
|
||||
|
||||
## Security Features
|
||||
|
||||
- Runs as non-root user (`docmd`)
|
||||
- Minimal Alpine Linux base image
|
||||
- Multi-stage build reduces attack surface
|
||||
- SBOM (Software Bill of Materials) included
|
||||
- OCI provenance attestation
|
||||
|
||||
## Health Check
|
||||
|
||||
The image includes a health check that verifies the dev server is running:
|
||||
|
||||
```bash
|
||||
# Check container health
|
||||
docker inspect --format='{{.State.Health.Status}}' <container-id>
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Permission Issues
|
||||
|
||||
The entrypoint automatically remaps to the uid:gid of the mounted directory, so files are always owned by the correct host user. If you hit permission issues, verify the mounted path exists and is writable on the host.
|
||||
|
||||
The dev server defaults to 127.0.0.1 (loopback only). To expose it to the LAN
|
||||
from inside a container, pass the host flag explicitly:
|
||||
|
||||
```bash
|
||||
# Loopback only (default) — access via http://localhost:3000 from the host
|
||||
docker run -p 3000:3000 ghcr.io/docmd-io/docmd:latest dev
|
||||
|
||||
# LAN access — the dev server binds to 0.0.0.0 inside the container, and
|
||||
# the port mapping makes it reachable from other devices on the host's network.
|
||||
docker run -p 3000:3000 ghcr.io/docmd-io/docmd:latest dev --host 0.0.0.0
|
||||
```
|
||||
|
||||
> **Security**: when you bind to 0.0.0.0, every host that can reach the
|
||||
> container's port can connect. Only do this on trusted networks. The dev
|
||||
> server's WebSocket requires an Origin that matches the bind host
|
||||
> (defence against CSWSH, CWE-1385), but loopback-only is the safer default.nsure you're binding to 0.0.0.0
|
||||
docker run -p 3000:3000 ghcr.io/docmd-io/docmd:latest dev --host 0.0.0.0
|
||||
```
|
||||
|
||||
### Memory Issues
|
||||
|
||||
```bash
|
||||
# For large documentation sites
|
||||
docker run --memory=2g -v $(pwd)/docs:/docs ghcr.io/docmd-io/docmd:latest build
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT License - see [LICENSE](../LICENSE) for details.
|
||||
|
||||
## Support
|
||||
|
||||
- **Issues**: [GitHub Issues](https://github.com/docmd-io/docmd/issues)
|
||||
- **Documentation**: [docs.docmd.io](https://docs.docmd.io)
|
||||
- **Website**: [docmd.io](https://docmd.io)
|
||||
@@ -0,0 +1,185 @@
|
||||
# --------------------------------------------------------------------
|
||||
# docmd : the minimalist, zero-config documentation generator.
|
||||
#
|
||||
# @package @docmd/core (and ecosystem)
|
||||
# @website https://docmd.io
|
||||
# @repository https://github.com/docmd-io/docmd
|
||||
# @license MIT
|
||||
# @copyright Copyright (c) 2025-present docmd.io
|
||||
#
|
||||
# [docmd-source] - Please do not remove this header.
|
||||
# --------------------------------------------------------------------
|
||||
#
|
||||
# Multi-stage Dockerfile for docmd
|
||||
# Creates a minimal production image with docmd CLI pre-installed
|
||||
#
|
||||
# Usage:
|
||||
# Quick Start (with demo site):
|
||||
# docker run -p 3000:3000 docmd:latest
|
||||
#
|
||||
# Initialize new project in current directory:
|
||||
# docker run -v $(pwd):/workspace docmd:latest init
|
||||
#
|
||||
# Run dev server with your docs:
|
||||
# docker run -v $(pwd)/my-docs:/docs -p 3000:3000 docmd:latest dev
|
||||
#
|
||||
# Build static site:
|
||||
# docker run -v $(pwd)/docs:/docs -v $(pwd)/site:/site docmd:latest build
|
||||
#
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Stage 1: Build stage - compiles TypeScript and prepares the application
|
||||
# -----------------------------------------------------------------------------
|
||||
FROM node:20-alpine AS builder
|
||||
|
||||
# Install build dependencies for native modules
|
||||
RUN apk add --no-cache \
|
||||
python3 \
|
||||
make \
|
||||
g++ \
|
||||
git \
|
||||
curl
|
||||
|
||||
# Install pnpm directly — avoids corepack version resolution issues in CI.
|
||||
# Bump the pinned version here whenever the monorepo's packageManager field changes.
|
||||
RUN npm install -g pnpm@10.33.2
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy everything (excluding files via .dockerignore)
|
||||
COPY . .
|
||||
|
||||
# Install dependencies
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
# Stub out packages that can't build in Docker before running the full build:
|
||||
# - engine-rust-binaries: requires cargo; pre-built .node files are in the repo
|
||||
# - _playground: dev sandbox, not part of the production image
|
||||
RUN sh tools/docker-prebuild.sh
|
||||
|
||||
# Build all packages
|
||||
RUN pnpm -r run build
|
||||
|
||||
# Resolve workspace:* deps to real version numbers for standalone use
|
||||
RUN node tools/resolve-ws-deps.js
|
||||
|
||||
# Pack all packages into tarballs (mimics npm publish)
|
||||
RUN pnpm -r pack --pack-destination /tarballs
|
||||
|
||||
# Generate a package.json listing every external (non-@docmd) runtime dep of
|
||||
# @docmd/core's transitive tree. The production stage installs from this file
|
||||
# instead of a hand-rolled list in the Dockerfile, so adding a dep to any
|
||||
# @docmd/* package automatically propagates to the Docker image.
|
||||
RUN node tools/print-okf-runtime-deps.js --emit-pkg=/tarballs/runtime-deps.json
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Stage 2: Production stage - minimal image with only runtime dependencies
|
||||
# -----------------------------------------------------------------------------
|
||||
FROM node:20-alpine AS production
|
||||
|
||||
# Install runtime dependencies
|
||||
RUN apk add --no-cache \
|
||||
git \
|
||||
curl \
|
||||
bash \
|
||||
su-exec
|
||||
|
||||
# Create non-root user for security
|
||||
RUN addgroup -g 1001 -S docmd && \
|
||||
adduser -S -D -H -u 1001 -h /app -s /bin/bash -G docmd -g docmd docmd
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy packed tarballs from builder
|
||||
COPY --from=builder /tarballs /tarballs
|
||||
|
||||
# Install only @docmd/* packages (the transitive deps of @docmd/core).
|
||||
# We extract each docmd-*.tgz tarball into /usr/local/lib/node_modules/@docmd/<name>.
|
||||
# This bypasses npm/pnpm registry lookups (packages aren't published yet at
|
||||
# build time). Legacy wrappers (doc.md, @mgks/docmd) and the monorepo root
|
||||
# tarball are excluded by only matching the docmd-* prefix.
|
||||
RUN mkdir -p /usr/local/lib/node_modules && \
|
||||
for tarball in /tarballs/docmd-*.tgz; do \
|
||||
fname=$(basename "$tarball" .tgz) && \
|
||||
pkg="${fname%-*}" && \
|
||||
scoped="@docmd/${pkg#docmd-}" && \
|
||||
mkdir -p "/usr/local/lib/node_modules/$scoped" && \
|
||||
tar -xzf "$tarball" -C "/usr/local/lib/node_modules/$scoped" --strip-components=1; \
|
||||
done
|
||||
|
||||
# Install external deps from the auto-generated runtime-deps.json produced by
|
||||
# the builder stage. We extract the dep list with node and pass it straight to
|
||||
# `npm install -g`, which puts packages into /usr/local/lib/node_modules —
|
||||
# exactly where Node's global resolution path looks. No hand-rolled list in the
|
||||
# Dockerfile: adding a dep to any @docmd/* package propagates automatically on
|
||||
# the next build because the builder stage regenerates runtime-deps.json fresh.
|
||||
RUN node -e "\
|
||||
const p=JSON.parse(require('fs').readFileSync('/tarballs/runtime-deps.json','utf8')); \
|
||||
const args=Object.entries(p.dependencies).map(([k,v])=>k+'@'+v); \
|
||||
const {execFileSync}=require('child_process'); \
|
||||
execFileSync('npm',['install','-g','--omit=dev','--no-audit','--no-fund',...args],{stdio:'inherit'}); \
|
||||
"
|
||||
|
||||
# Symlink the docmd CLI onto PATH (chmod +x on the script too — some
|
||||
# base images strip the executable bit during COPY).
|
||||
RUN ln -sf /usr/local/lib/node_modules/@docmd/core/dist/bin/docmd.js /usr/local/bin/docmd \
|
||||
&& chmod +x /usr/local/bin/docmd /usr/local/lib/node_modules/@docmd/core/dist/bin/docmd.js
|
||||
|
||||
# Clean up tarballs to reduce image size
|
||||
RUN rm -rf /tarballs
|
||||
|
||||
# Create directories for user content
|
||||
RUN mkdir -p /docs /site && chown -R docmd:docmd /docs /site
|
||||
|
||||
# Seed the default template by running docmd init non-interactively.
|
||||
# This ensures the image ships exactly what a real `docmd init` produces.
|
||||
#
|
||||
# Build does NOT fail on init failure: the image still publishes (so users
|
||||
# who mount their own /docs are unaffected), but the demo experience is
|
||||
# degraded and a clear warning is printed. Full stderr from `docmd init`
|
||||
# is in the build log above this block for diagnosis.
|
||||
RUN mkdir -p /template && \
|
||||
cd /template && \
|
||||
if docmd init --yes; then \
|
||||
if [ ! -f /template/docmd.config.json ]; then \
|
||||
printf '\n[docmd-docker] WARNING: docmd init exited 0 but /template/docmd.config.json is missing.\n' >&2; \
|
||||
printf '[docmd-docker] Demo seeding will not work. Mount your own /docs.\n' >&2; \
|
||||
fi; \
|
||||
else \
|
||||
printf '\n[docmd-docker] WARNING: docmd init failed during image build.\n' >&2; \
|
||||
printf '[docmd-docker] The `docker run` demo experience will not work. Mount your own /docs.\n' >&2; \
|
||||
printf '[docmd-docker] Full error from docmd init is in the build log above this block.\n' >&2; \
|
||||
fi
|
||||
|
||||
# Install entrypoint + healthcheck scripts (see docker/docker-entrypoint.sh
|
||||
# and docker/docker-healthcheck.sh). The entrypoint seeds /docs from
|
||||
# /template when /docs is empty, so `docker run` with no volume mount
|
||||
# still works out of the box. The healthcheck probes a port range because
|
||||
# `docmd dev` may auto-increment past 3000 if the port is already taken.
|
||||
COPY docker/docker-entrypoint.sh /usr/local/bin/docmd-entrypoint.sh
|
||||
COPY docker/docker-healthcheck.sh /usr/local/bin/docmd-healthcheck.sh
|
||||
RUN chmod +x /usr/local/bin/docmd-entrypoint.sh /usr/local/bin/docmd-healthcheck.sh
|
||||
|
||||
# Set environment variables
|
||||
ENV NODE_ENV=production
|
||||
ENV DOCMD_CONTAINER=true
|
||||
|
||||
# Run as root so the entrypoint can inspect /docs ownership and use
|
||||
# su-exec to re-exec as the correct uid:gid. The entrypoint never stays
|
||||
# as root — it always drops to the detected uid before exec-ing docmd.
|
||||
# This is the same pattern used by postgres, redis, and other official images.
|
||||
|
||||
# Set working directory to docs (where user content will be mounted)
|
||||
WORKDIR /docs
|
||||
|
||||
# Expose default port (dev server may pick a higher one if 3000 is in use)
|
||||
EXPOSE 3000
|
||||
|
||||
# Health check — probes 3000-3005 to follow the dev server's actual port
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 CMD ["/usr/local/bin/docmd-healthcheck.sh"]
|
||||
|
||||
# Default command — entrypoint detects /docs uid, drops privileges, then
|
||||
# seeds /docs if empty and execs the supplied command.
|
||||
ENTRYPOINT ["/usr/local/bin/docmd-entrypoint.sh"]
|
||||
CMD ["dev", "--host", "0.0.0.0"]
|
||||
@@ -0,0 +1,67 @@
|
||||
#!/bin/sh
|
||||
# docmd Docker entrypoint
|
||||
#
|
||||
# Handles two cases:
|
||||
#
|
||||
# 1. No volume / empty /docs → seeds the demo template so `docmd dev`
|
||||
# works out of the box with no arguments.
|
||||
#
|
||||
# 2. Host-mounted volume → detects the uid:gid that owns /docs and
|
||||
# re-execs as that identity (via su-exec), so file writes from any
|
||||
# subcommand — including `docmd init` — land with the correct host
|
||||
# ownership without needing `-u $(id -u):$(id -g)` from the caller.
|
||||
#
|
||||
# This mirrors the pattern used by official images (postgres, redis, etc.).
|
||||
set -e
|
||||
|
||||
FIRST_ARG="${1:-}"
|
||||
|
||||
# ── uid remapping ────────────────────────────────────────────────────────────
|
||||
# If we are currently running as root (the entrypoint is exec'd as root so it
|
||||
# can inspect /docs ownership), detect the uid:gid of /docs and re-exec as
|
||||
# that user. This lets `docmd init` and `docmd dev` write to host-mounted
|
||||
# volumes without permission errors regardless of the host user's uid.
|
||||
if [ "$(id -u)" = "0" ] && [ -d /docs ]; then
|
||||
DOCS_UID=$(stat -c '%u' /docs 2>/dev/null || echo "1001")
|
||||
DOCS_GID=$(stat -c '%g' /docs 2>/dev/null || echo "1001")
|
||||
|
||||
# If /docs is owned by root (uid 0) on the host, fall back to the docmd
|
||||
# user — writing as root inside the container is a security anti-pattern.
|
||||
if [ "$DOCS_UID" = "0" ]; then
|
||||
DOCS_UID="1001"
|
||||
DOCS_GID="1001"
|
||||
fi
|
||||
|
||||
# ── writability check (N-18) ───────────────────────────────────────────
|
||||
# Catch read-only volume mounts early with a clear message instead of
|
||||
# letting docmd crash mid-build with a cryptic EROFS / EACCES error.
|
||||
# Only applies to write commands — `dev`, `build`, `init`.
|
||||
# Read-only mounts are valid for `validate`, `mcp`, etc.
|
||||
case "$FIRST_ARG" in
|
||||
dev|build|init)
|
||||
if ! touch /docs/.docmd_write_test 2>/dev/null; then
|
||||
printf '\n[docmd] ERROR: /docs is read-only (or not writable by uid %s).\n' "$DOCS_UID" >&2
|
||||
printf '[docmd] Mount a writable directory:\n' >&2
|
||||
printf '[docmd] docker run -v $(pwd)/docs:/docs ghcr.io/docmd-io/docmd\n' >&2
|
||||
printf '[docmd] Or check directory permissions on the host.\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
rm -f /docs/.docmd_write_test
|
||||
;;
|
||||
esac
|
||||
|
||||
# Seed demo template before dropping privileges (root can always write).
|
||||
if [ "$FIRST_ARG" != "init" ] && \
|
||||
[ -z "$(ls -A /docs 2>/dev/null)" ] && \
|
||||
[ -d /template ]; then
|
||||
echo "[docmd] /docs is empty — seeding demo template from /template"
|
||||
cp -r /template/. /docs/
|
||||
chown -R "$DOCS_UID:$DOCS_GID" /docs 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Re-exec as the detected uid:gid so all subsequent writes are correctly owned.
|
||||
exec su-exec "$DOCS_UID:$DOCS_GID" "$0" "$@"
|
||||
fi
|
||||
|
||||
# ── already the right user (re-exec path lands here) ────────────────────────
|
||||
exec docmd "$@"
|
||||
@@ -0,0 +1,12 @@
|
||||
#!/bin/sh
|
||||
# docmd Docker healthcheck
|
||||
#
|
||||
# The dev server may auto-increment its port (3000, 3001, ...) if the
|
||||
# default port is in use, so we probe a small range instead of hard-
|
||||
# coding a single port. Returns 0 as soon as any port responds.
|
||||
for port in 3000 3001 3002 3003 3004 3005; do
|
||||
if curl -fs --connect-timeout 2 "http://127.0.0.1:${port}/" >/dev/null 2>&1; then
|
||||
exit 0
|
||||
fi
|
||||
done
|
||||
exit 1
|
||||
Reference in New Issue
Block a user