Vendor pinned prettier/format toolchain from prompts scaffold (closes #203)
Check / check (pull_request) Skipped
Check / check (pull_request) Skipped
Replace the unpinned `npx prettier --tab-width 4` in `script/fmt` with the canonical toolchain vendored from `sneak/prompts`: `.prettierrc` (tabWidth 4, proseWrap always), pinned `package.json` + `yarn.lock` (prettier 3.8.1), and a `.prettierignore` that unions the scaffold entries with the repo's `*.min.js` line. `script/bootstrap` now installs a pinned node/yarn via a hash-verified nvm release archive (never curl-pipe-sh), so prettier stops being an unpinned host tool. `script/fmt` runs the pinned prettier via `.prettierrc` over `static/js/*.js` and `**/*.md`, keeping gofmt/goimports. All existing markdown is reflowed to house style; `static/js/alpine.min.js` stays byte-identical. Model: opus-4-8
This commit is contained in:
@@ -1,12 +1,14 @@
|
||||
# µPaaS by [@sneak](https://sneak.berlin)
|
||||
|
||||
A simple self-hosted PaaS that auto-deploys Docker containers from Git repositories via webhooks from Gitea, GitHub, or GitLab.
|
||||
A simple self-hosted PaaS that auto-deploys Docker containers from Git
|
||||
repositories via webhooks from Gitea, GitHub, or GitLab.
|
||||
|
||||
## Features
|
||||
|
||||
- Single admin user with argon2id password hashing
|
||||
- Per-app SSH keypairs for read-only deploy keys
|
||||
- Per-app UUID-based webhook URLs with auto-detection of Gitea, GitHub, and GitLab
|
||||
- Per-app UUID-based webhook URLs with auto-detection of Gitea, GitHub, and
|
||||
GitLab
|
||||
- Branch filtering - only deploy on configured branch changes
|
||||
- Environment variables, labels, and volume mounts per app
|
||||
- CPU and memory resource limits per app
|
||||
@@ -95,9 +97,12 @@ chi Router ──► Middleware Stack ──► Handler
|
||||
|
||||
### Key Patterns
|
||||
|
||||
- **Closure-based handlers**: Handlers return `http.HandlerFunc` allowing one-time initialization
|
||||
- **Active Record models**: Models encapsulate database operations (`Save()`, `Delete()`, `Reload()`)
|
||||
- **Async deployments**: Webhook triggers deploy via goroutine with `context.WithoutCancel()`
|
||||
- **Closure-based handlers**: Handlers return `http.HandlerFunc` allowing
|
||||
one-time initialization
|
||||
- **Active Record models**: Models encapsulate database operations (`Save()`,
|
||||
`Delete()`, `Reload()`)
|
||||
- **Async deployments**: Webhook triggers deploy via goroutine with
|
||||
`context.WithoutCancel()`
|
||||
- **Embedded assets**: Templates and static files embedded via `//go:embed`
|
||||
|
||||
## Entrypoints
|
||||
@@ -105,12 +110,12 @@ chi Router ──► Middleware Stack ──► Handler
|
||||
This repository adheres to the
|
||||
[Scripts to Rule Them All](https://github.com/github/scripts-to-rule-them-all)
|
||||
standard: normalized scripts in `script/` are the entrypoints for the
|
||||
development workflow, and the Makefile targets are thin shims that call
|
||||
them. We provide:
|
||||
development workflow, and the Makefile targets are thin shims that call them. We
|
||||
provide:
|
||||
|
||||
- `script/bootstrap` — install all dependencies (idempotent)
|
||||
- `script/setup` — make a fresh clone ready for development
|
||||
(bootstrap, then install-precommit)
|
||||
- `script/setup` — make a fresh clone ready for development (bootstrap, then
|
||||
install-precommit)
|
||||
- `script/projectname` — output the project name ("upaas")
|
||||
- `script/test` — run the test suite
|
||||
- `script/lint` — run golangci-lint
|
||||
@@ -118,12 +123,12 @@ them. We provide:
|
||||
- `script/fmt-check` — check formatting (read-only)
|
||||
- `script/check` — run test, lint, and fmt-check
|
||||
- `script/docker` — build the Docker image tagged via `script/projectname`
|
||||
- `script/cibuild` — CI entrypoint: `docker build .` (the Dockerfile
|
||||
runs the checks, so a green build implies a green repo)
|
||||
- `script/cibuild` — CI entrypoint: `docker build .` (the Dockerfile runs the
|
||||
checks, so a green build implies a green repo)
|
||||
- `script/precommit` — pre-commit checks (`go mod tidy` guard, then
|
||||
`script/check`)
|
||||
- `script/install-precommit` — install the git pre-commit hook that
|
||||
runs `script/precommit`
|
||||
- `script/install-precommit` — install the git pre-commit hook that runs
|
||||
`script/precommit`
|
||||
|
||||
## Development
|
||||
|
||||
@@ -156,11 +161,11 @@ Before every commit:
|
||||
|
||||
1. **Format**: Run `make fmt` to format all code
|
||||
2. **Lint**: Run `make lint` and fix all errors/warnings
|
||||
- Do not disable linters or add nolint comments without good reason
|
||||
- Fix the code, don't hide the problem
|
||||
- Do not disable linters or add nolint comments without good reason
|
||||
- Fix the code, don't hide the problem
|
||||
3. **Test**: Run `make test` and ensure all tests pass
|
||||
- Fix failing tests by fixing the code, not by modifying tests to pass
|
||||
- Add tests for new functionality
|
||||
- Fix failing tests by fixing the code, not by modifying tests to pass
|
||||
- Add tests for new functionality
|
||||
4. **Verify**: Run `make check` to confirm everything passes
|
||||
|
||||
```bash
|
||||
@@ -174,6 +179,7 @@ git commit -m "Your message"
|
||||
```
|
||||
|
||||
The Docker build runs `make check` and will fail if:
|
||||
|
||||
- Code is not formatted
|
||||
- Linting errors exist
|
||||
- Tests fail
|
||||
@@ -185,17 +191,17 @@ This ensures the main branch always contains clean, tested, working code.
|
||||
|
||||
Environment variables:
|
||||
|
||||
| Variable | Description | Default |
|
||||
|----------|-------------|---------|
|
||||
| `PORT` | HTTP listen port | 8080 |
|
||||
| `UPAAS_DATA_DIR` | Data directory for SQLite and keys | `./data` (local dev only — use absolute path for Docker) |
|
||||
| `UPAAS_HOST_DATA_DIR` | Host path for DATA_DIR (when running in container) | *(none — must be set to an absolute path)* |
|
||||
| `UPAAS_DOCKER_HOST` | Docker socket path | unix:///var/run/docker.sock |
|
||||
| `UPAAS_PLAINTEXT_HTTP` | Set when µPaaS is reached over plain HTTP (no TLS-terminating proxy in front) so CSRF origin checks use `http://`. Leave unset behind a TLS-terminating reverse proxy. | false |
|
||||
| `DEBUG` | Enable debug logging | false |
|
||||
| `SENTRY_DSN` | Sentry error reporting DSN | "" |
|
||||
| `METRICS_USERNAME` | Basic auth for /metrics | "" |
|
||||
| `METRICS_PASSWORD` | Basic auth for /metrics | "" |
|
||||
| Variable | Description | Default |
|
||||
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
|
||||
| `PORT` | HTTP listen port | 8080 |
|
||||
| `UPAAS_DATA_DIR` | Data directory for SQLite and keys | `./data` (local dev only — use absolute path for Docker) |
|
||||
| `UPAAS_HOST_DATA_DIR` | Host path for DATA_DIR (when running in container) | _(none — must be set to an absolute path)_ |
|
||||
| `UPAAS_DOCKER_HOST` | Docker socket path | unix:///var/run/docker.sock |
|
||||
| `UPAAS_PLAINTEXT_HTTP` | Set when µPaaS is reached over plain HTTP (no TLS-terminating proxy in front) so CSRF origin checks use `http://`. Leave unset behind a TLS-terminating reverse proxy. | false |
|
||||
| `DEBUG` | Enable debug logging | false |
|
||||
| `SENTRY_DSN` | Sentry error reporting DSN | "" |
|
||||
| `METRICS_USERNAME` | Basic auth for /metrics | "" |
|
||||
| `METRICS_PASSWORD` | Basic auth for /metrics | "" |
|
||||
|
||||
## Running with Docker
|
||||
|
||||
@@ -217,35 +223,38 @@ TLS-terminating reverse proxy, drop that line.
|
||||
|
||||
```yaml
|
||||
services:
|
||||
upaas:
|
||||
build: .
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- ${HOST_DATA_DIR}:/var/lib/upaas
|
||||
environment:
|
||||
- UPAAS_HOST_DATA_DIR=${HOST_DATA_DIR}
|
||||
# Set when serving plain HTTP (no TLS-terminating proxy); drop behind one
|
||||
- UPAAS_PLAINTEXT_HTTP=true
|
||||
# Optional: uncomment to enable debug logging
|
||||
# - DEBUG=true
|
||||
# Optional: Sentry error reporting
|
||||
# - SENTRY_DSN=https://...
|
||||
# Optional: Prometheus metrics auth
|
||||
# - METRICS_USERNAME=prometheus
|
||||
# - METRICS_PASSWORD=secret
|
||||
upaas:
|
||||
build: .
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- ${HOST_DATA_DIR}:/var/lib/upaas
|
||||
environment:
|
||||
- UPAAS_HOST_DATA_DIR=${HOST_DATA_DIR}
|
||||
# Set when serving plain HTTP (no TLS-terminating proxy); drop behind one
|
||||
- UPAAS_PLAINTEXT_HTTP=true
|
||||
# Optional: uncomment to enable debug logging
|
||||
# - DEBUG=true
|
||||
# Optional: Sentry error reporting
|
||||
# - SENTRY_DSN=https://...
|
||||
# Optional: Prometheus metrics auth
|
||||
# - METRICS_USERNAME=prometheus
|
||||
# - METRICS_PASSWORD=secret
|
||||
```
|
||||
|
||||
**Important**: You **must** set `HOST_DATA_DIR` to an **absolute path** on the host before running
|
||||
`docker compose up`. This value is bind-mounted into the container and passed as `UPAAS_HOST_DATA_DIR`
|
||||
so that Docker bind mounts during builds resolve correctly. Relative paths (e.g. `./data`) will break
|
||||
container builds because the Docker daemon resolves paths relative to the host, not the container.
|
||||
**Important**: You **must** set `HOST_DATA_DIR` to an **absolute path** on the
|
||||
host before running `docker compose up`. This value is bind-mounted into the
|
||||
container and passed as `UPAAS_HOST_DATA_DIR` so that Docker bind mounts during
|
||||
builds resolve correctly. Relative paths (e.g. `./data`) will break container
|
||||
builds because the Docker daemon resolves paths relative to the host, not the
|
||||
container.
|
||||
|
||||
Example: `HOST_DATA_DIR=/srv/upaas/data docker compose up -d`
|
||||
|
||||
Session secrets are automatically generated on first startup and persisted to `$UPAAS_DATA_DIR/session.key`.
|
||||
Session secrets are automatically generated on first startup and persisted to
|
||||
`$UPAAS_DATA_DIR/session.key`.
|
||||
|
||||
## License
|
||||
|
||||
|
||||
Reference in New Issue
Block a user