- modules/sunrise/new.sh: curl | bash installer wrapped in main(), checks Go 1.27+/git/Docker, clones or fast-forwards the framework at the newest release tag (SUMMERCMS_REPO/DIR/REF overrides), installs summer and runs summer new next to the checkout, prints the cd line and a PATH hint - sunrise.Script() returns a fresh copy of the embedded script - smoke, shape, truncation and gated end-to-end tests; README and modules row
92 lines
4.3 KiB
Markdown
92 lines
4.3 KiB
Markdown
# sunrise
|
|
|
|
Bootstrap script that installs the summer CLI and creates a new SummerCMS application in one command, embedded so it is versioned with the framework.
|
|
|
|
`import "git.golem15.com/golem15/summercms/modules/sunrise"`
|
|
|
|
## Overview
|
|
|
|
`sunrise` holds `new.sh`, the script behind the one-liner served at https://summercms.io/new:
|
|
|
|
```sh
|
|
curl -fsSL https://summercms.io/new | bash -s -- blog
|
|
```
|
|
|
|
The script checks for Go 1.27 or newer, git and Docker, clones the framework into `./summercms` at its newest release tag (or moves an existing release checkout forward to it), installs the `summer` CLI with `go install ./cmd/summer` and runs `summer new blog --framework <checkout>` next to the checkout, which writes `./sm-blog-app`. `summer new` prints the next steps; the script adds the `cd` line and, when the Go install directory is not on `PATH`, an `export PATH=...` hint.
|
|
|
|
The script lives inside this package so `//go:embed` can reach it, and a web server serves the bytes of the framework release it was built against. `sunrise.Script` returns them.
|
|
|
|
## Features
|
|
|
|
- Truncation-safe: everything is a function definition and the last line is `main "$@"`, so a download cut short runs nothing.
|
|
- Prerequisites first: Go older than 1.27 or missing, or a missing git, stops the script with an install hint before anything is cloned; a missing Docker or compose plugin is only a warning.
|
|
- Release tags: a fresh clone is checked out detached at the newest `vX.Y.Z` tag, or at `SUMMERCMS_REF` when set.
|
|
- Fast-forward-only updates: an existing checkout is fetched (tags are never force-updated) and moved only when its `HEAD` is an ancestor of the target.
|
|
- Refusals that protect local work: an existing directory that is not a git repository, whose `go.mod` is not the framework module, that has changes to tracked files, or that is on a branch is left untouched and the script stops with a message.
|
|
- Early name check: a name that is not lower-case letters and digits starting with a letter, or an existing `sm-<name>-app`, stops the script before any clone or install.
|
|
- No privilege escalation and no dynamic code; only bash builtins plus `git`, `go` and `docker` are run, with stdin closed and `GIT_TERMINAL_PROMPT=0` so nothing waits for input.
|
|
|
|
## Usage
|
|
|
|
Run the script from the directory that should hold the framework checkout and the application:
|
|
|
|
```sh
|
|
curl -fsSL https://summercms.io/new | bash -s -- blog
|
|
```
|
|
|
|
`bash -s -- <name>` passes the application name to the piped script; `-h` or `--help` prints the usage. A local copy runs the same way with `bash new.sh blog`.
|
|
|
|
Serving the script from a Go handler:
|
|
|
|
```go
|
|
package acme
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"git.golem15.com/golem15/summercms/modules/sunrise"
|
|
)
|
|
|
|
func newScript(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
|
w.Header().Set("X-Content-Type-Options", "nosniff")
|
|
_, _ = w.Write(sunrise.Script())
|
|
}
|
|
```
|
|
|
|
## API reference
|
|
|
|
| Identifier | Description |
|
|
|------------|-------------|
|
|
| `sunrise.Script` | Returns a fresh copy of the embedded `new.sh` bytes on every call. |
|
|
|
|
## Configuration
|
|
|
|
The script reads three environment variables. It never reads or sets `SUMMER_`-prefixed variables, which the framework reads as configuration.
|
|
|
|
| Variable | Default | Purpose |
|
|
|----------|---------|---------|
|
|
| `SUMMERCMS_REPO` | `https://git.golem15.com/golem15/summercms` | Repository to clone. |
|
|
| `SUMMERCMS_DIR` | `summercms` (relative to the current directory) | Framework checkout directory; the application is created next to it. |
|
|
| `SUMMERCMS_REF` | newest `vX.Y.Z` tag | Tag or commit to check out instead of the newest release. |
|
|
|
|
## Dependencies
|
|
|
|
- SummerCMS modules: none.
|
|
- Third-party: none.
|
|
- Standard library: `bytes`, `embed`.
|
|
|
|
## Testing
|
|
|
|
```sh
|
|
go test ./modules/sunrise/...
|
|
```
|
|
|
|
The default run checks the embedded bytes, the script's shape and syntax (`bash -n`), and runs every line-boundary prefix and every byte prefix of the final line against stub commands to prove a truncated download invokes nothing.
|
|
|
|
```sh
|
|
SUMMERCMS_BOOTSTRAP_CHECK=1 go test ./modules/sunrise/ -run TestBootstrapEndToEnd -timeout 20m
|
|
```
|
|
|
|
The gated run serves the script from a local HTTP server, pipes it through `curl | bash` with `SUMMERCMS_REPO` set to this repository and `SUMMERCMS_REF` to its `HEAD`, and builds the generated application. It needs bash, curl, git, Go and access to the Go module proxy.
|