- build runs go build under a spinner on a terminal and ends with 'Built bin/<name> in <time>'; make:* print 'Created <path>' per file - make:*, plugin:add, new, parity:*, docs:build, docs:sync and every delegate get long help and examples; delegates note that global options pass through to the application binary - make:* failures (no summer.yaml, invalid plugin ID or name, existing artifact, unknown plugin) explain themselves and suggest a command - docs:build and docs:sync return bonfire.Reported after the problem list - TestCommandsDocumented covers the tool commands too - docs: Upgrading to 0.4, delegates and global options, make: results and hints, the checklist for a finished command
96 lines
13 KiB
Markdown
96 lines
13 KiB
Markdown
---
|
|
title: Upgrading
|
|
description: Move an application to a newer framework release, what the version numbers promise, and what to check before you take 0.2 and 0.4.
|
|
section: setup
|
|
order: 60
|
|
---
|
|
# Upgrading
|
|
|
|
An application created by `summer new` builds against a framework checkout next to it; the update script moves that checkout to the newest release tag, reinstalls the `summer` tool and rebuilds the application (see [Updating an application](installation.md#updating-an-application)). An application or plugin that requires a tagged framework version in its `go.mod` moves with the go command instead:
|
|
|
|
```sh
|
|
go get git.golem15.com/golem15/summercms@v0.2.0
|
|
go mod tidy
|
|
```
|
|
|
|
Then rebuild, run `migrate` with the new binary and restart it.
|
|
|
|
## Version numbers
|
|
|
|
SummerCMS is in the 0.x series, and the version tells you whether to read before you upgrade:
|
|
|
|
- The minor version (0.1 to 0.2) goes up when an upgrade can refuse a configuration that the previous release accepted, or changes a documented behaviour. Read the section for that version below before you deploy it.
|
|
- A patch version (0.2.0 to 0.2.1) is safe to take without reading: it fixes bugs and adds features, and an application that started on the previous patch starts on it too.
|
|
|
|
Applications pin exact versions, so a new release never reaches an application until it moves its `go.mod` or its checkout.
|
|
|
|
## Upgrading to 0.4
|
|
|
|
0.4 rebuilds the console: Artisan-style `list` and help with examples, global options on every command, a logging pipeline with daily files, startup summaries and shutdown reports. Plugins compile unchanged. After you move the framework version, run `summer build` to regenerate `main.go`: the new generated main sets up logging before the configuration is read, parses the global options and returns the exit codes below. Then run `bin/<app> list` once with the new binary: it boots every plugin and runs the checks below.
|
|
|
|
### Boot refusals
|
|
|
|
**Duplicate command names.** Two commands with the same name, from two plugins or from a plugin and the framework, stop the binary at start-up with `bonfire.ErrDuplicateCommand` naming the command. Remove or rename one of them; a plugin that appends `centrifugo.Commands` or `flare.Commands` must be the only one that does.
|
|
|
|
**Reserved flag names.** A command flag named like a global option (`verbose`, `quiet`, `ansi`, `no-ansi`, `no-interaction`, `env`, or the shorthands `v`, `q`, `n`) stops the binary with `bonfire.ErrReservedFlag`. Rename the flag.
|
|
|
|
### Behaviour changes
|
|
|
|
- **Daily log files.** Logs go to the console and, from warnings up, to `storage/logs/summer-YYYY-MM-DD.log`, kept for 14 days. The directory must be writable by the user that runs the binary; when it is not, the binary logs one warning and keeps logging to the console. To keep the old console-only behaviour, set `log.default` to `console` (`SUMMER_LOG__DEFAULT=console`). See [Logging](../services/logging.md).
|
|
- **Component loggers.** Every log record carries a `component` attribute. GORM's lines move to component `db` and record-not-found is no longer logged; River's lines to component `river` (warnings and up by default). Raise or lower a component with `log.components`, for example `components: {db: debug}`.
|
|
- **The request log is on by default.** Every request writes one Info record `http request` from component `http` with the route pattern (never the path), status, duration and `request_id`. Silence it with `components: {http: warn}` in `config/log.yaml`, or turn it off with `http.access_log: false`.
|
|
- **`serve` prints a startup summary.** On a terminal it is a block; off a terminal `serve` prints nothing on stdout and logs a `startup summary` record and a `listening on <addr>` record on stderr instead, so a script that waits for `listening on 127.0.0.1:<port>` in the combined output still finds it. Ctrl+C prints a shutdown report and exits 0; a failed drain exits 1. `queue:work` and `schedule:run` do the same.
|
|
- **Exit codes.** A failed command exits 1 and a usage error (an unknown command or flag, a wrong number of arguments) exits 2. Errors print as a block on stderr with a hint where the framework knows the fix, and `-v` shows the wrapped errors.
|
|
- **`-q` keeps data.** `-q` hides information and success lines, spinners and progress bars, but still prints what a command exists to produce: the token of `admin:token:create`, the key of `key:generate` and every `--json` output.
|
|
- **Production confirmation.** `migrate`, `migrate:rollback`, `deferred:purge` and `queue:clear` ask before they run when the environment is `production` and they run on an interactive terminal; `--force` skips the question. Off a terminal, as in deploy scripts over SSH, nothing changes.
|
|
- **`summer dev` runs `serve`.** It used to start the binary without a command, which printed the help and stopped; it now runs `bin/<app> serve` with the global options you give `summer dev`.
|
|
- **Result lines.** `summer build` ends with `Built bin/<app> in <time>`, the `make:` commands print `Created <path>` per file, `migrate` prints `Applied N migrations` or `Nothing to migrate`, and `queue:clear` prints `Cleared N jobs from <queue>`. Adjust scripts that matched the old lower-case lines.
|
|
|
|
## Upgrading to 0.2
|
|
|
|
0.2 tightens two configuration checks so that settings which leaked credentials stop the start-up instead. Most applications are not affected: the first concerns applications that load an `auth.cookie` block, the second applications that send credentialed CORS answers. Start the new binary once in each environment before you switch traffic to it; a refused configuration fails `serve` at start-up with an error that names the key.
|
|
|
|
### Boot refusals
|
|
|
|
**A token cookie that is not Secure in production.** In the production environment, `bouncer.LoadCookieConfig` refuses a token cookie whose `Secure` attribute resolves to false. That covers `auth.cookie.secure: false` and, since 0.2, an unset `auth.cookie.secure` with an http or empty `app.url`, from which the cookie inherited `Secure=false` before. The error names `auth.cookie.secure` and `app.url`.
|
|
|
|
It affects applications whose plugins load an `auth.cookie` block for a browser frontend (the cookie transport). To fix it, set `app.url` to the application's public https URL, or set `auth.cookie.secure: true` explicitly. See [Cookie transport](../services/authentication.md#cookie-transport).
|
|
|
|
**Credentialed CORS with a wildcard host or an unanchored pattern.** With `supports_credentials: true`, globally under `http.cors` or in any profile under `http.cors_profiles.<name>`, these entries now fail the start-up, and the error names the key with its index, such as `http.cors.allowed_origins[1]` or `http.cors_profiles.spa.allowed_origins_patterns[0]`:
|
|
|
|
- an `allowed_origins` entry with a `*` that is not the whole leftmost host label after a literal scheme, such as `https://*`, `*://*`, `https://*example.com` or `http*://www.example.com` (`https://*.example.com` stays valid);
|
|
- an `allowed_origins_patterns` entry not anchored with `^` and `$`, in every alternative of the expression;
|
|
- any origin rule that matches an origin outside the configured domains, such as `https://*.com` or `^https?://.*$`.
|
|
|
|
It affects applications that send credentialed CORS answers, to a browser frontend on another origin that calls the API with cookies. To fix it, list the frontend's exact origins, or write anchored patterns such as `^https://[a-z]+\.example\.com$`. Without credentials these entries load as before. See [CORS](../services/routing.md#cors) and [CORS profiles](../services/routing.md#cors-profiles).
|
|
|
|
### Behaviour changes
|
|
|
|
These need no configuration change, but a test or an operator may notice them:
|
|
|
|
- **Site-cache purges are queued.** After an admin save commits, the purge request to the site is queued and sent by a background worker, with at most one request in flight per purger; saves committed meanwhile collapse into one follow-up request. The save no longer waits for the site. A test that asserts a purge calls `cooler.SiteCachePurger.Wait` first, and `serve` drains the queue on shutdown. See [Site cache purge](../services/caching.md#site-cache-purge).
|
|
- **Protected uploads need a private bucket.** While `storage.uploads.public_url` is set, `attach.Store` refuses a protected (`is_public` false) upload with `attach.ErrProtectedNeedsPrivateBucket` before it writes anything, and `serve` logs one warning at start-up that the bucket must hold public files only. Keep protected relations on a bucket without `public_url`, or make the relation public. See [Public URL base](../services/storage.md#public-url-base).
|
|
- **The Journal plugin's purge keys are deprecated.** `golem15.journal.site_cache.purge_url` and `golem15.journal.site_cache.purge_token` still work as aliases of the framework's `site_cache.purge_url` and `site_cache.purge_token`, which win when both are set; the plugin logs a deprecation warning. Move the values to the `site_cache` keys.
|
|
- **Cookie defaults.** A `bouncer.CookieConfig` built by hand with every field zero writes `SameSite=Lax` and `Secure`; a config with any field set keeps its own `Secure` value.
|
|
- **The API documentation page** at `/api-docs` runs only scripts that carry the page's per-request nonce. See [API documentation page](../services/routing.md#api-documentation-page).
|
|
- **Turnstile without a secret.** When `turnstile.secret` is empty and routes name `turnstile:open` or `turnstile:closed`, the start-up logs one warning with the number of such routes. See [Turnstile](../services/authentication.md#turnstile).
|
|
- **CORS profile headers on every answer.** A route that names `cors:<profile>` carries the profile's headers on every response, including refusals from guards, throttle, Turnstile and the body limit, and recovered panics.
|
|
|
|
## What 0.2 adds since 0.1
|
|
|
|
The 0.1 series grew through many patch releases. These are the larger features that arrived after its first public releases, with the page that documents each:
|
|
|
|
- Caching with memory and Redis drivers, and a Redis store that shares `throttle` counters between instances: [Caching](../services/caching.md), [Rate limiting](../services/rate-limiting.md).
|
|
- The site-cache purge after admin saves, including reorder saves through `pact.ReorderAfterSave`: [Site cache purge](../services/caching.md#site-cache-purge).
|
|
- Token cookies with ready-made refresh and logout handlers, and Turnstile bot protection: [Cookie transport](../services/authentication.md#cookie-transport), [Turnstile](../services/authentication.md#turnstile).
|
|
- Credentialed CORS, per-route CORS profiles (`cors:<profile>`) and the opt-in API documentation page: [CORS](../services/routing.md#cors), [CORS profiles](../services/routing.md#cors-profiles), [API documentation page](../services/routing.md#api-documentation-page).
|
|
- Go build tags in `summer.yaml` (`build.tags`), S3 uploads buckets behind the `summercms_s3` tag and a public URL base for a bucket or CDN: [The summer.yaml manifest](../architecture/go-modules-and-workspaces.md#the-summeryaml-manifest), [S3 and S3-compatible buckets](../services/storage.md#s3-and-s3-compatible-buckets), [Public URL base](../services/storage.md#public-url-base).
|
|
- Serving uploads from the application and a per-request access log: [Serving files](../services/storage.md#serving-files), [Request log](../services/logging.md#request-log).
|
|
- Plugin-provided admin field types: [Plugin field types](../backend/field-types.md).
|
|
- Rich text, repeater, money, password and taglist fields, and dependent dropdowns: [Rich text](../backend/forms.md#rich-text), [Repeater](../backend/forms.md#repeater), [Money](../backend/forms.md#money), [Form-only fields](../backend/forms.md#form-only-fields), [Taglist](../backend/forms.md#taglist), [Dependent dropdowns](../backend/forms.md#dependent-dropdowns).
|
|
- Record reordering as a tree or a flat list: [Tree reorder](../backend/lists-and-filters.md#tree-reorder), [Flat reorder](../backend/lists-and-filters.md#flat-reorder).
|
|
- Singleton controllers, record actions and write-only settings secrets: [Singleton controllers](../backend/admin-controllers.md#singleton-controllers), [Record actions](../backend/admin-controllers.md#record-actions), [Write-only secrets](../backend/settings.md#write-only-secrets).
|
|
- Personal API tokens for administrators and the `admin:token:*` commands: [API tokens](../backend/users-and-permissions.md#api-tokens), [Admin accounts](../console/setup-and-maintenance.md#admin-accounts).
|
|
- Menu item types that content plugins register for menus and sitemaps: [Menu item types](../plugins/menu-item-types.md).
|
|
- New framework modules: [cooler](../../modules/cooler/README.md) (caches, shared counters and the site-cache purge), [seaglass](../../modules/seaglass/README.md) (the rich text sanitizer), [sieve](../../modules/sieve/README.md) (collection helpers) and [signpost](../../modules/signpost/README.md) (the menu item type registry).
|