Skip to content

Version Management

This document describes version management in Structyl.

Overview

Structyl maintains a single version for the entire project. All language implementations share this version, ensuring consistency across packages.

Version Source

The canonical version is stored in a single file:

VERSION

Contents (plain text, no newline required):

1.2.3

Leading and trailing whitespace (including newlines) is stripped before parsing.

Version Format

Structyl expects Semantic Versioning:

MAJOR.MINOR.PATCH[-PRERELEASE][+BUILD]

Examples:

  • 1.0.0
  • 2.1.3
  • 1.0.0-alpha
  • 1.0.0-beta.2
  • 2.0.0-rc.1+build.123

Error Conditions

ConditionExit CodeError Message
Version source file missing2version source file not found: {path}
Version source file empty2version source file is empty: {path}
Invalid version format2invalid version format in {path}: "{content}"
Version file not readable3cannot read version file: {path}: {error}

Version Commands

Get Current Version

bash
structyl version
# Output: 1.2.3

Set Version

bash
structyl version set 2.0.0

This:

  1. Updates the VERSION file
  2. Propagates to all configured files
  3. Regenerates documentation (if configured)

Bump Version

bash
structyl version bump patch   # 1.2.3 → 1.2.4
structyl version bump minor   # 1.2.3 → 1.3.0
structyl version bump major   # 1.2.3 → 2.0.0

Prerelease Versions

bash
structyl version set 2.0.0-alpha.1
structyl version bump prerelease  # 2.0.0-alpha.1 → 2.0.0-alpha.2

Prerelease Bump Edge Cases

Current VersionAfter bump prereleaseNotes
1.0.0ErrorCannot bump prerelease on release version
1.0.0-alpha1.0.0-alpha.1Adds .1 suffix
1.0.0-alpha.11.0.0-alpha.2Increments numeric suffix
1.0.0-alpha.91.0.0-alpha.10No digit limit
1.0.0-rc.11.0.0-rc.2Works with any prerelease tag
1.0.0-beta.2+build.51.0.0-beta.3+build.5Build metadata preserved

Error case:

bash
structyl version bump prerelease  # When VERSION contains "1.0.0"
# Error: cannot bump prerelease on release version "1.0.0"
# Exit code: 2

Version Propagation

Structyl updates version strings in language-specific files using regex patterns.

Regex Syntax

Patterns use RE2 syntax (Go's standard regex engine). Notable characteristics:

  • .*? performs non-greedy matching
  • [\s\S] matches any character including newlines
  • Capture groups use $1, $2, etc. in replacement strings
  • No backreferences within patterns
  • No lookahead or lookbehind assertions

Patterns are matched against the entire file content. Use anchors or capture groups to avoid unintended matches (e.g., matching dependency versions instead of package versions).

Match Cardinality

By default, each pattern MUST match exactly once per file:

Matches FoundBehaviorExit Code
0Error: pattern not found in {path}2
1Replace the match0
>1Error: pattern matched {n} times in {path} (expected 1)2

To replace all occurrences, set replace_all: true:

json
{
  "path": "docs/version.txt",
  "pattern": "v\\d+\\.\\d+\\.\\d+",
  "replace": "v{version}",
  "replace_all": true
}

With replace_all: true:

Matches FoundBehaviorExit Code
0Error: pattern not found in {path}2
≥1Replace all matches0

Configuration

json
{
  "version": {
    "source": "VERSION",
    "files": [
      {
        "path": "cs/Directory.Build.props",
        "pattern": "<Version>.*?</Version>",
        "replace": "<Version>{version}</Version>"
      },
      {
        "path": "py/pyproject.toml",
        "pattern": "version = \".*?\"",
        "replace": "version = \"{version}\""
      }
    ]
  }
}

Fields

FieldDescription
pathFile path relative to project root
patternRegex pattern to match version string
replaceReplacement with {version} placeholder

Pattern Examples

C# (Directory.Build.props)

xml
<Version>1.2.3</Version>
json
{
  "path": "cs/Directory.Build.props",
  "pattern": "<Version>.*?</Version>",
  "replace": "<Version>{version}</Version>"
}

Python (pyproject.toml)

toml
version = "1.2.3"
json
{
  "path": "py/pyproject.toml",
  "pattern": "version = \".*?\"",
  "replace": "version = \"{version}\""
}

Python (init.py)

python
__version__ = "1.2.3"
json
{
  "path": "py/mypackage/__init__.py",
  "pattern": "__version__ = \".*?\"",
  "replace": "__version__ = \"{version}\""
}

Rust (Cargo.toml)

toml
[package]
name = "mypackage"
version = "1.2.3"
json
{
  "path": "rs/mypackage/Cargo.toml",
  "pattern": "(name = \"mypackage\"[\\s\\S]*?)version = \".*?\"",
  "replace": "$1version = \"{version}\""
}

Note: Rust pattern uses capture group to avoid matching dependency versions.

TypeScript (package.json)

json
{
  "name": "mypackage",
  "version": "1.2.3"
}
json
{
  "path": "ts/package.json",
  "pattern": "\"version\": \".*?\"",
  "replace": "\"version\": \"{version}\""
}

Go (go.mod)

Go uses git tags for versioning. No file modification needed, but you can update a constant:

go
const Version = "1.2.3"
json
{
  "path": "go/version.go",
  "pattern": "const Version = \".*?\"",
  "replace": "const Version = \"{version}\""
}

Kotlin (build.gradle.kts)

kotlin
version = "1.2.3"
json
{
  "path": "kt/build.gradle.kts",
  "pattern": "version = \".*?\"",
  "replace": "version = \"{version}\""
}

R (DESCRIPTION)

Version: 1.2.3
json
{
  "path": "r/mypackage/DESCRIPTION",
  "pattern": "Version: .*",
  "replace": "Version: {version}"
}

Release Workflow

Manual Release

bash
# 1. Set version
structyl version set 2.0.0

# 2. Review changes
git diff

# 3. Commit
git add -A
git commit -m "Release v2.0.0"

# 4. Tag
git tag v2.0.0

# 5. Push
git push origin main --tags

Automated Release Command

bash
structyl release 2.0.0 [--push]

This command:

  1. Sets version in VERSION file
  2. Propagates version to all files
  3. Regenerates documentation
  4. Creates git commit: "Release v2.0.0"
  5. Creates git tag: v2.0.0
  6. (with --push) Pushes to origin remote

The --push flag always pushes to the origin remote. To push to a different remote, use manual git commands after structyl release.

Go Module Tag

Go modules require a special tag format. Configure additional tags:

bash
structyl release 2.0.0 --push
# Creates: v2.0.0, go/v2.0.0

Validation

Check Version Consistency

bash
structyl version check

Verifies all configured files contain the expected version:

VERSION: 2.0.0
cs/Directory.Build.props: 2.0.0 ✓
py/pyproject.toml: 2.0.0 ✓
rs/mypackage/Cargo.toml: 1.9.0 ✗ (expected 2.0.0)

Exit code 1 if any mismatch found. This is a runtime check of project state (not a configuration error), consistent with exit code 1 semantics for "expected runtime failure."

Configuration Reference

json
{
  "version": {
    "source": "VERSION",
    "files": [
      {
        "path": "path/to/file",
        "pattern": "regex pattern",
        "replace": "replacement with {version}",
        "replace_all": false
      }
    ]
  }
}
FieldDefaultDescription
source"VERSION"Version file path
files[]Files to update
files[].pathRequiredFile path
files[].patternRequiredRegex to match
files[].replaceRequiredReplacement string
files[].replace_allfalseReplace all matches (vs. require exactly one)

CLI Version Pinning

Each Structyl project pins the CLI version in .structyl/version. This ensures reproducible builds across different machines and CI environments.

Version File

The .structyl/version file contains a single line with the pinned CLI version:

1.2.3

This file is created by structyl init and should be committed to version control.

Upgrade Command

Usage: structyl upgrade [version] [--check]
       structyl upgrade --check
CommandDescription
structyl upgradeUpgrade to latest stable version
structyl upgrade <version>Upgrade to specific version (e.g., 1.2.3, nightly)
structyl upgrade --checkShow current vs latest version without changing

Version Types

TypeValidationCache CheckInstall Prompt
Stable (e.g., 1.2.3)Semver validationCheck ~/.structyl/versions/Only if not installed
NightlySkip validationSkipAlways prompt

GitHub API Integration

The upgrade command fetches the latest version from:

https://api.github.com/repos/AndreyAkinshin/structyl/releases/latest

Response parsing:

  • Extract tag_name field
  • Strip v prefix (e.g., v1.2.31.2.3)
  • 10-second HTTP timeout
  • User-Agent header required

Exit Codes

CodeMeaning
0Success
1Runtime error (network failure, file I/O, not in project)
2Usage error (invalid version format, unknown flag)

Output Examples

Upgrade to latest:

Upgraded from 1.1.0 to 1.2.3

Run '.structyl/setup.sh' to install version 1.2.3.

Check mode:

  Current CLI version:  1.2.0
  Pinned version:       1.1.0
  Latest stable:        1.2.3

A newer version is available. Run 'structyl upgrade' to update.

Nightly upgrade:

Upgraded from 1.1.0 to nightly

Run '.structyl/setup.sh' to install the nightly build.

Already on version:

Already on version 1.2.3

Released under the MIT License.