Repository Name Templates
Repository names are configured with the optional top-level name key in a
distribution’s config.json. Divekit renders the template once for every group
in members.json. If name is omitted, the default is
{{distribution}}-{{uuid}}.
{
"name": "exercise-{{username}}"
}
Repository name templates use Go’s text/template syntax. This page documents
the data and functions that Divekit provides for this specific use case.
Common Examples
Use the first configured GitLab username as the complete repository name:
{
"name": "{{username}}"
}
Add a prefix and suffix:
{
"name": "exercise-{{username}}-submission"
}
Access the first member of a group explicitly. For a group with
"members": ["alice", "bob"], this renders team-alice:
{
"name": "team-{{index .Usernames 0}}"
}
Create stable, zero-padded exam repository names such as exam-01, exam-02,
and exam-03:
{
"name": "exam-{{printf \"%02d\" (index)}}"
}
Use a human-readable label, its normalized slug, or group metadata:
{
"name": "{{slug}}-{{metadata \"cohort\"}}"
}
For a group labeled Team 02 with metadata { "cohort": "B" }, this renders
team-02-B.
Tokens can be combined. This example includes the distribution, group, first member, and stable group number:
{
"name": "{{distribution}}-{{slug}}-{{username}}-{{printf \"%02d\" (index)}}"
}
Divekit Tokens and Functions
The following functions are available while the repository name is rendered:
| Expression | Result |
|---|---|
{{username}} | First value in the group’s configured members array. |
{{uuid}} | Stable group UUID. If no UUID is supplied to the renderer, a new UUID is generated. Distributed groups normally have a UUID. |
{{label}} | Trimmed group label. Falls back to the UUID when the label is empty. |
{{slug}} | Lowercase, GitLab-safe form of label. Falls back to a slug of the UUID. |
{{metadata "key"}} | String value from groups[].metadata. The key is trimmed; a missing key renders an empty string. |
{{index}} | Stable, one-based repository index for the group UUID. See Stable Repository Indexes. |
{{autoincrement}} | Compatibility alias for the stable index value. |
{{now "2006-01-02"}} | Current time using a Go time layout, fixed at the first now call in the CLI process. Repeated calls in that process use the same time. |
{{creation "2006-01-02"}} | Current time evaluated for every call. Two renders can therefore produce different values. |
{{hash "value"}} | Lowercase hexadecimal SHA-256 hash of the string. An empty string is replaced by a newly generated UUID before hashing, so the result is not stable. |
Go time layouts describe the desired format using the reference time
Mon Jan 2 15:04:05 MST 2006. For example, 2006-01-02 produces an ISO-style
date and 20060102-150405 produces a compact timestamp.
Template Data Fields
The same values are also available as direct template fields. Field names are case-sensitive:
| Field | Type | Notes |
|---|---|---|
.Usernames | list of strings | Configured GitLab usernames in member order. Use {{index .Usernames 0}} for the first one or {{len .Usernames}} for the group size. |
.Uuid | string | Group UUID. The spelling is .Uuid, not .UUID. |
.Index | integer | Same stable value as {{index}}; using this field opts the group into stable index allocation. |
.Label | string | Label with the same UUID fallback as {{label}}. |
.Slug | string | Normalized label with the same fallback as {{slug}}. |
.Metadata | map of strings | Complete metadata map. Identifier-like keys can be accessed as {{.Metadata.cohort}}; {{metadata "key"}} also supports keys that are not valid field identifiers. |
For portable config.json templates, use .Label, .Slug, and
.Metadata.key as standalone actions, as shown above. Normal distribution
resolves those group values before the provider renders the remaining
template; commands that render a name outside that path may receive the full
fields directly. The function forms {{label}}, {{slug}}, and
{{metadata "key"}} are the clearest choice for ordinary names.
The internal template data type also contains a .Group field, but repository
name rendering does not populate it. It is not a supported source of group
information; use .Uuid, .Label, .Slug, or .Metadata instead.
Application Placeholders
Some values are substituted by the surrounding command before the Go template is rendered. They are exact placeholders rather than template functions:
| Placeholder | Scope |
|---|---|
{{distribution}} | Distribution folder/name. Supported by normal distribution, name patching, and snapshot naming. |
{{target}} | Display target such as work or eval. Used by target-aware proposal and name-patching paths, but not provided by the repository-name renderer itself. |
{{groupId}} | Configured GitLab group ID for the target. Used by target-aware proposal and name-patching paths, but not provided by the repository-name renderer itself. |
Use {{distribution}} in portable config.json name templates. Do not rely on
{{target}} or {{groupId}} for repository creation: unlike the data fields
and functions above, they are not consistently available in every naming path.
Whitespace variants such as {{ target }} are not application placeholders.
Stable Repository Indexes
index has two deliberately different forms:
{{index .Usernames 0}}performs collection access and returns the first username. It does not request or allocate a repository index.{{index}}takes no arguments and returns the stable repository index for the group UUID.{{autoincrement}}and.Indexrefer to the same value.
Indexes start at 1. Divekit reuses an existing index for the same UUID and gives a new UUID the next number after the highest persisted index. The same UUID therefore keeps its number if member order changes and shares it across linked targets.
The index is stored with the UUID-to-project mapping in remotes.json, not
in individuals.json. Divekit allocates a new index only when the naming
template uses zero-argument index, autoincrement, or .Index. A collection
lookup such as {{index .Usernames 0}} does not trigger allocation.
Changing the naming template later does not delete previously assigned indexes.
Existing remotes.json entries retain them, even if the new template no longer
uses a repository index.
Go Template Syntax for Repository Names
Template actions are enclosed in {{ and }}. Literal text outside an action
is copied into the result. A leading dot selects a field from the current
repository data, and function arguments are separated by spaces:
exercise-{{.Slug}}-{{metadata "cohort"}}
JSON strings must escape double quotes used inside template actions. A template
written as {{metadata "cohort"}} therefore appears as follows in
config.json:
{
"name": "exercise-{{metadata \"cohort\"}}"
}
Parentheses group a nested function call. printf uses Go formatting rules;
%02d formats an integer with at least two digits and leading zeroes:
{
"name": "exam-{{printf \"%02d\" (index)}}"
}
The standard text/template helpers are also available:
- output:
print,printf, andprintln - data access:
len,slice, and Divekit’s extendedindex - logic:
and,or, andnot - comparisons:
eq,ne,lt,le,gt, andge - escaping and advanced use:
html,js,urlquery, andcall
Control actions such as if, with, and range, template variables, and
pipelines are supported by text/template. Keep repository names simple where
possible, because every rendered result is normalized for GitLab afterward.
Errors, Normalization, and Privacy
- Empty groups: repository creation requires at least one configured
username.
{{username}}fails for an empty group, and{{index .Usernames 0}}fails with an out-of-range error. - Groups with several members:
{{username}}always means the first value ingroups[].members. Reordering the array can therefore change the name. - GitLab-safe result: after rendering, Divekit transliterates German
umlauts, replaces runs of characters other than ASCII letters, digits, and
hyphens with a hyphen, collapses repeated hyphens, and removes leading or
trailing hyphens.
{{slug}}applies the same normalization and also converts the value to lowercase before it is combined with other tokens. - Visible usernames: a username included in a repository name is also normally reflected in its GitLab path and URL. Treat the resulting name as visible to everyone who can see or receive the project URL, and avoid a username-based pattern when that disclosure is not appropriate.
- Template failures: invalid syntax, unavailable functions, wrong argument types, and out-of-range collection access stop name generation for the group.
Related pages: