Repository Name Templates

Reference for repository name data, tokens, functions, and formatting.

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:

ExpressionResult
{{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:

FieldTypeNotes
.Usernameslist of stringsConfigured GitLab usernames in member order. Use {{index .Usernames 0}} for the first one or {{len .Usernames}} for the group size.
.UuidstringGroup UUID. The spelling is .Uuid, not .UUID.
.IndexintegerSame stable value as {{index}}; using this field opts the group into stable index allocation.
.LabelstringLabel with the same UUID fallback as {{label}}.
.SlugstringNormalized label with the same fallback as {{slug}}.
.Metadatamap of stringsComplete 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:

PlaceholderScope
{{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 .Index refer 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, and println
  • data access: len, slice, and Divekit’s extended index
  • logic: and, or, and not
  • comparisons: eq, ne, lt, le, gt, and ge
  • escaping and advanced use: html, js, urlquery, and call

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 in groups[].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: