doc: templates #829

This commit is contained in:
jamesread 2026-06-18 12:25:17 +01:00
parent 03a9a05e38
commit a3413c0bc3
6 changed files with 154 additions and 5 deletions

View File

@ -79,6 +79,7 @@
** xref:args/input_textarea.adoc[Input: Textarea] ** xref:args/input_textarea.adoc[Input: Textarea]
** xref:args/suggestions.adoc[Suggestions] ** xref:args/suggestions.adoc[Suggestions]
** xref:args/env.adoc[Environment Variables] ** xref:args/env.adoc[Environment Variables]
** xref:args/templates.adoc[Templates]
* xref:dashboards/intro.adoc[Dashboards] * xref:dashboards/intro.adoc[Dashboards]
** xref:dashboards/examples.adoc[Examples] ** xref:dashboards/examples.adoc[Examples]
** xref:dashboards/actions.adoc[Actions (Linked)] ** xref:dashboards/actions.adoc[Actions (Linked)]

View File

@ -49,6 +49,6 @@ actions:
shellAfterCompleted: "apprise -t 'Backup on {{ .Env.HOSTNAME }}' -b '{{ output }}'" shellAfterCompleted: "apprise -t 'Backup on {{ .Env.HOSTNAME }}' -b '{{ output }}'"
---- ----
`.Env` uses the same Go template context as other action variables (e.g. `.Arguments`, `.CurrentEntity`, `.OliveTin`). The map is built from the process environment when OliveTin starts; values are read at template execution time. If a variable is missing, the template engine will report a missing-key error (with `missingkey=error`), so use defaulting when a variable might be unset, e.g. `{{ or .Env.OPTIONAL_VAR "default" }}`. `.Env` uses the same Go template context as other action variables (e.g. `.Arguments`, `.CurrentEntity`, `.OliveTin`). The map is built from the process environment when OliveTin starts; values are read at template execution time. If a variable is missing, the template engine will report a missing-key error (with `missingkey=error`), so use defaulting when a variable might be unset, e.g. `{{ or .Env.OPTIONAL_VAR "default" }}`. For template functions such as JSON encoding, see xref:args/templates.adoc#json-encoding[JSON encoding with Json].
This feature addresses the need to use environment variables in templates without changing the config loader (see link:https://github.com/OliveTin/OliveTin/issues/840[GitHub issue #840]). This feature addresses the need to use environment variables in templates without changing the config loader (see link:https://github.com/OliveTin/OliveTin/issues/840[GitHub issue #840]).

View File

@ -85,11 +85,11 @@ fi
To use the *process* environment (the environment OliveTin was started with) inside action template fields such as `shell` or `shellAfterCompleted`, use the `.Env` template variable: `{{ .Env.VAR_NAME }}`. This substitutes the value at execution time. See xref:advanced_configuration/config_envs.adoc#using-env-in-template-replacements[Using .Env in template replacements] for details and examples. To use the *process* environment (the environment OliveTin was started with) inside action template fields such as `shell` or `shellAfterCompleted`, use the `.Env` template variable: `{{ .Env.VAR_NAME }}`. This substitutes the value at execution time. See xref:advanced_configuration/config_envs.adoc#using-env-in-template-replacements[Using .Env in template replacements] for details and examples.
For other template features, including JSON encoding of argument and entity values, see xref:args/templates.adoc[Templates in actions].
== Notes == Notes
. Argument names are converted to uppercase for environment variables, `name: filename` becomes `FILENAME`. . Argument names are converted to uppercase for environment variables, `name: filename` becomes `FILENAME`.
. OliveTin sets `OLIVETIN=1` in the process environment for every action; see <<olivetin-env-var,The OLIVETIN environment variable>> above. . OliveTin sets `OLIVETIN=1` in the process environment for every action; see <<olivetin-env-var,The OLIVETIN environment variable>> above.
. The execution request variables are exposed as `OT_USERNAME` and `OT_EXECUTIONTRACKINGID` in the process environment; see <<execution-request-variables,Execution Request Variables>> above. . The execution request variables are exposed as `OT_USERNAME` and `OT_EXECUTIONTRACKINGID` in the process environment; see <<execution-request-variables,Execution Request Variables>> above.
. The environment variables are passed into the execution context which uses a shell (/bin/sh on Linux), so it is also possible to use them with the $ notation in the `shell` line, like this; `shell: echo $FILENAME` for example. . The environment variables are passed into the execution context which uses a shell (/bin/sh on Linux), so it is also possible to use them with the $ notation in the `shell` line, like this; `shell: echo $FILENAME` for example.

View File

@ -19,5 +19,5 @@ Now that you understand how arguments work, explore the different argument types
* xref:args/suggestions.adoc[Argument suggestions] - Add dynamic suggestions to help users * xref:args/suggestions.adoc[Argument suggestions] - Add dynamic suggestions to help users
* xref:args/regex.adoc[Input validation with regex] - Validate user input with regular expressions * xref:args/regex.adoc[Input validation with regex] - Validate user input with regular expressions
* xref:args/env.adoc[Environment variables] - Use arguments to set environment variables * xref:args/env.adoc[Environment variables] - Use arguments to set environment variables
* xref:args/templates.adoc[Templates] - Use Go templates in actions, including JSON encoding
* xref:action_examples/intro.adoc[See examples] - View real-world examples using arguments * xref:action_examples/intro.adoc[See examples] - View real-world examples using arguments

View File

@ -0,0 +1,70 @@
[#templates]
= Templates in actions
OliveTin uses https://pkg.go.dev/text/template[Go text/template] syntax in action fields such as `shell`, `shellAfterCompleted`, entity directory titles, and `enabledExpression`. Template placeholders are written as `{{ ... }}`.
In OliveTin 3k, use dotted names for template context variables:
* `{{ .Arguments.NAME }}` — argument values (see xref:args/env.adoc[Environment variables])
* `{{ .CurrentEntity.property }}` — entity properties (see xref:entities/intro.adoc[Entities])
* `{{ .Env.VAR_NAME }}` — process environment (see xref:advanced_configuration/config_envs.adoc#using-env-in-template-replacements[Using .Env in template replacements])
* `{{ .OliveTin.Build.Version }}` and related build/runtime fields
In OliveTin 2k, argument and execution-request placeholders used the shorter form (for example, `{{ message }}` instead of `{{ .Arguments.message }}`).
[#json-encoding]
== JSON encoding with `Json`
The `Json` template function encodes a value as a JSON string. Pipe a template value to it when you need structured data in a command — for example, passing argument or entity state to a script or HTTP client that expects JSON.
[source,yaml]
----
actions:
- title: curl my knx thing
shell: curl --json https://knx.example.com/v1/group/global_on/write -d '{{ .Arguments | Json }}'
entity: light
arguments:
- name: value
default: "true"
----
After template substitution, `{{ .Arguments | Json }}` becomes a JSON object containing all argument names and values for that execution (including execution-request variables such as `ot_username` and `ot_executionTrackingId`).
=== Examples
Encode a single argument value:
[source,yaml]
----
shell: echo {{ .Arguments.value | Json }}
----
If `value` is `hello`, the substituted command is `echo "hello"`.
Encode an entity field:
[source,yaml]
----
shell: curl -d {{ .CurrentEntity.foo.bar | Json }}
----
If `foo.bar` is the string `baz`, the substituted command is `curl -d "baz"`.
Encode a nested entity object:
[source,yaml]
----
shell: curl --json -d {{ .CurrentEntity.payload | Json }}
----
If `payload` is `{on: true}`, the substituted command is `curl --json -d {"on":true}`.
=== Notes
. `Json` uses Go's `encoding/json` package. Strings, numbers, booleans, objects, and arrays are encoded according to normal JSON rules.
. Argument values in templates are strings (`map[string]string`). A checkbox or boolean argument therefore appears in JSON as a string (for example, `"true"`), not a JSON boolean.
. If the piped value is missing or nil, `Json` produces `null`.
. When embedding JSON in a shell command, quote the substitution if the JSON may contain spaces or shell metacharacters. Prefer single-quoted YAML strings around the template when possible, as shown in the curl example above.
. For HTTP request bodies, pass one JSON-encoded value (or build the JSON structure you need in one template expression). Piping several values with spaces between them does not produce a single valid JSON document.
See link:https://github.com/OliveTin/OliveTin/issues/829[GitHub issue #829] for the original feature request.

View File

@ -0,0 +1,78 @@
# macOS release signing
Release builds can sign and notarize the `darwin` binaries using [quill](https://github.com/anchore/quill) via GoReleaser. This runs on the existing Linux CI runner; no macOS runner is required.
Signing is **optional**. If the GitHub secrets below are not all set, GoReleaser skips macOS signing and publishes unsigned binaries (the previous behaviour).
## Prerequisites
- An active [Apple Developer Program](https://developer.apple.com/programs/) membership.
- A **Developer ID Application** certificate (not "Apple Development" or "Mac App Distribution").
- An [App Store Connect API key](https://appstoreconnect.apple.com/access/integrations/api) with at least **Developer** access.
## One-time setup
### 1. Create the signing certificate
1. Open [Certificates, Identifiers & Profiles](https://developer.apple.com/account/resources/certificates/list).
2. Create a certificate of type **Developer ID Application**.
3. Download the `.cer` file and double-click it to add it to **Keychain Access** on a Mac.
4. In Keychain Access, export the certificate as a **Personal Information Exchange (`.p12`)** file. You will set an export password — remember it; this becomes `MACOS_SIGN_PASSWORD`.
### 2. Create the notarization API key
1. Open [App Store Connect → Users and Access → Integrations → App Store Connect API](https://appstoreconnect.apple.com/access/integrations/api).
2. Create a key with **Developer** role (or Admin).
3. Download the `.p8` file once (it cannot be downloaded again). Note the **Key ID** shown in the portal and the **Issuer ID** at the top of the API keys page.
### 3. Base64-encode the key files
Run on a machine that has the files (Linux or macOS):
```sh
base64 -w0 < ./Certificates.p12 # MACOS_SIGN_P12
base64 -w0 < ./AuthKey_XXXXXX.p8 # MACOS_NOTARY_KEY
```
On macOS without GNU coreutils, use `base64 -i file | tr -d '\n'`.
### 4. Add GitHub repository secrets
In **Settings → Secrets and variables → Actions**, create:
| Secret | Value |
|--------|-------|
| `MACOS_SIGN_P12` | Base64 contents of the `.p12` file |
| `MACOS_SIGN_PASSWORD` | Password used when exporting the `.p12` |
| `MACOS_NOTARY_KEY` | Base64 contents of the `.p8` file |
| `MACOS_NOTARY_KEY_ID` | Key ID from App Store Connect (e.g. `ABC123DEF4`) |
| `MACOS_NOTARY_ISSUER_ID` | Issuer UUID from App Store Connect |
All five must be present for signing to run. Any missing secret disables signing for that release.
## Renewal
| Item | Typical lifetime | What to do |
|------|------------------|------------|
| Developer ID Application certificate | ~5 years | Create a new certificate in the Apple portal, export a new `.p12`, update `MACOS_SIGN_P12` and `MACOS_SIGN_PASSWORD`. |
| App Store Connect API key | Does not expire, but can be revoked | Create a new key if compromised or lost; update `MACOS_NOTARY_KEY`, `MACOS_NOTARY_KEY_ID`, and optionally `MACOS_NOTARY_ISSUER_ID`. |
| Apple Developer Program | Annual subscription | Renew membership before it lapses; existing certificates stop working if the account is inactive. |
After updating secrets, the next release on `main` (via semantic-release) will use the new credentials automatically.
## Verifying a signed release
On a Mac, download a `OliveTin-darwin-*.tar.gz` release artifact and run:
```sh
tar -xzf OliveTin-darwin-arm64.tar.gz
spctl -a -vv -t execute OliveTin-darwin-arm64/OliveTin
```
A signed and notarized binary should report `accepted` with `source=Notarized Developer ID`.
## Configuration reference
- GoReleaser: `notarize.macos` in [`.goreleaser.yml`](.goreleaser.yml)
- CI secrets: [`.github/workflows/build-and-release.yml`](.github/workflows/build-and-release.yml) (`release` step)
- [GoReleaser notarization docs](https://goreleaser.com/customization/notarize/)