diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml
index 185ba33..4f61b32 100644
--- a/.gitea/workflows/build.yml
+++ b/.gitea/workflows/build.yml
@@ -40,6 +40,7 @@ jobs:
}
git -c "http.extraHeader=Authorization: Basic $authBasic" fetch --depth 1 origin $repoRef
+ git -c "http.extraHeader=Authorization: Basic $authBasic" fetch --force --tags origin
git checkout --force FETCH_HEAD
if (-not (Test-Path -LiteralPath "Mods\\DnD 5.5e AIO Russian\\Localization\\Russian\\russian.xml")) {
@@ -109,6 +110,7 @@ jobs:
throw "Release archive was not found at '$zipPath'."
}
+ $isPrerelease = $tagName -match '^v\d+\.\d+\.\d+-'
$owner = $repoParts[0]
$repo = $repoParts[1]
$apiBase = "$serverUrl/api/v1/repos/$owner/$repo"
@@ -137,10 +139,19 @@ jobs:
name = $tagName
target_commitish = "${{ gitea.sha }}"
draft = $false
- prerelease = $false
+ prerelease = $isPrerelease
} | ConvertTo-Json
$release = Invoke-RestMethod -Method Post -Uri "$apiBase/releases" -Headers $headers -ContentType "application/json" -Body $releaseBody
+ } elseif ($release.prerelease -ne $isPrerelease) {
+ $releaseBody = @{
+ tag_name = $tagName
+ target_commitish = "${{ gitea.sha }}"
+ draft = $false
+ prerelease = $isPrerelease
+ } | ConvertTo-Json
+
+ $release = Invoke-RestMethod -Method Patch -Uri "$apiBase/releases/$($release.id)" -Headers $headers -ContentType "application/json" -Body $releaseBody
}
$existingAsset = $null
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index c5b0660..0075959 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -43,10 +43,15 @@ jobs:
run: |
$ErrorActionPreference = "Stop"
$versionTag = ""
+ $isPrerelease = "false"
if ($env:GITHUB_REF -like "refs/tags/v*") {
$versionTag = $env:GITHUB_REF_NAME
+ if ($versionTag -match '^v\d+\.\d+\.\d+-') {
+ $isPrerelease = "true"
+ }
}
"version_tag=$versionTag" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
+ "is_prerelease=$isPrerelease" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
- name: Notify Telegram about build start
if: startsWith(github.ref, 'refs/tags/v')
@@ -113,6 +118,7 @@ jobs:
$ErrorActionPreference = "Stop"
$tagName = "${{ github.ref_name }}"
$zipPath = Join-Path $env:GITHUB_WORKSPACE "build\\DnD 5.5e AIO Russian $tagName.zip"
+ $isPrerelease = "${{ steps.vars.outputs.is_prerelease }}" -eq "true"
if (-not (Test-Path -LiteralPath $zipPath)) {
throw "Release archive was not found at '$zipPath'."
@@ -121,15 +127,40 @@ jobs:
gh release view $tagName --repo "${{ github.repository }}" *> $null
if ($LASTEXITCODE -ne 0) {
- gh release create $tagName $zipPath `
- --repo "${{ github.repository }}" `
- --title $tagName `
- --notes ""
+ $args = @(
+ "release", "create", $tagName, $zipPath,
+ "--repo", "${{ github.repository }}",
+ "--title", $tagName,
+ "--notes", ""
+ )
+
+ if ($isPrerelease) {
+ $args += "--prerelease"
+ }
+
+ gh @args
}
else {
gh release upload $tagName $zipPath `
--repo "${{ github.repository }}" `
--clobber
+
+ $releaseId = gh release view $tagName `
+ --repo "${{ github.repository }}" `
+ --json id `
+ --jq ".id"
+
+ $releaseBodyPath = Join-Path $env:RUNNER_TEMP "release-body.json"
+ @{
+ name = $tagName
+ prerelease = $isPrerelease
+ } | ConvertTo-Json -Compress | Set-Content -LiteralPath $releaseBodyPath -Encoding utf8
+
+ gh api `
+ --method PATCH `
+ -H "Accept: application/vnd.github+json" `
+ "/repos/${{ github.repository }}/releases/$releaseId" `
+ --input $releaseBodyPath
}
- name: Notify Telegram about build success
diff --git a/AGENTS.md b/AGENTS.md
index 8cf1938..e9f903f 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -122,6 +122,12 @@ Source of truth:
Rules:
- do not change `PublishVersion`
- tag MUST match version
+- tag formats:
+ - stable: `vX.Y.Z` -> `Version64 = X.Y.Z.0`
+ - suffixed: `vX.Y.Z-suffix` -> `Version64 = X.Y.Z.N`
+- for suffixed tags, suffix affects tag/release channel only and is NOT encoded in `Version64`
+- for suffixed tags on the same base version `X.Y.Z`, increment `build` (`N`) by counting prior released tags `vX.Y.Z-*`; current release uses the next value starting from `1`
+- stable tag without suffix always uses `build = 0`, even if suffixed releases for the same base version already existed
Before tag:
1. if version already changed → use it
diff --git a/Mods/DnD 5.5e AIO Russian/meta.lsx b/Mods/DnD 5.5e AIO Russian/meta.lsx
index 4eb227c..66f75ba 100644
--- a/Mods/DnD 5.5e AIO Russian/meta.lsx
+++ b/Mods/DnD 5.5e AIO Russian/meta.lsx
@@ -32,7 +32,7 @@
-
+
diff --git a/scripts/build.ps1 b/scripts/build.ps1
index 7304e46..0a784ba 100644
--- a/scripts/build.ps1
+++ b/scripts/build.ps1
@@ -20,7 +20,8 @@ $ErrorActionPreference = "Stop"
function Convert-VersionTagToVersion64 {
param(
[string]$Tag,
- [string]$FallbackVersion64
+ [string]$FallbackVersion64,
+ [string]$RepoPath
)
if (-not $Tag) {
@@ -32,16 +33,31 @@ function Convert-VersionTagToVersion64 {
$normalized = $normalized.Substring(1)
}
- if ($normalized -notmatch '^\d+(\.\d+){0,3}$') {
- return [int64]$FallbackVersion64
+ if ($normalized -notmatch '^(?\d+\.\d+\.\d+)(?:-(?[0-9A-Za-z][0-9A-Za-z.-]*))?$') {
+ throw "Version tag '$Tag' is invalid. Expected format: vX.Y.Z or vX.Y.Z-suffix"
}
- $parts = $normalized.Split(".")
+ $baseVersion = $Matches.base
+ $suffix = $Matches.suffix
+ $parts = $baseVersion.Split(".")
$numbers = @(0, 0, 0, 0)
for ($i = 0; $i -lt $parts.Length; $i++) {
$numbers[$i] = [int]$parts[$i]
}
+ if ($suffix) {
+ $resolvedRepoPath = [System.IO.Path]::GetFullPath($RepoPath)
+ $matchingTags = @()
+
+ try {
+ $matchingTags = @(git -C $resolvedRepoPath tag --list "v$baseVersion-*" 2>$null | Where-Object { $_ -and $_ -ne $Tag })
+ } catch {
+ $matchingTags = @()
+ }
+
+ $numbers[3] = $matchingTags.Count + 1
+ }
+
return ([int64]$numbers[0] -shl 55) -bor ([int64]$numbers[1] -shl 47) -bor ([int64]$numbers[2] -shl 31) -bor [int64]$numbers[3]
}
@@ -59,7 +75,7 @@ if ($VersionTag) {
}
$zipPath = Join-Path $buildPath "$archiveName.zip"
$infoJsonPath = Join-Path $buildPath "info.json"
-$resolvedVersion64 = Convert-VersionTagToVersion64 -Tag $VersionTag -FallbackVersion64 $ModVersion64
+$resolvedVersion64 = Convert-VersionTagToVersion64 -Tag $VersionTag -FallbackVersion64 $ModVersion64 -RepoPath $workspacePath
if (-not (Test-Path -LiteralPath $DivinePath)) {
$resolvedCommand = Get-Command $DivinePath -ErrorAction SilentlyContinue
diff --git a/scripts/set-version.ps1 b/scripts/set-version.ps1
index 0822393..3631abf 100644
--- a/scripts/set-version.ps1
+++ b/scripts/set-version.ps1
@@ -1,14 +1,16 @@
param(
[Parameter(Mandatory = $true)]
[string]$VersionTag,
- [string]$MetaPath = "Mods/DnD 5.5e AIO Russian/meta.lsx"
+ [string]$MetaPath = "Mods/DnD 5.5e AIO Russian/meta.lsx",
+ [string]$RepositoryPath = "."
)
$ErrorActionPreference = "Stop"
-function Convert-VersionTagToVersion64 {
+function Get-ReleaseVersionParts {
param(
- [string]$Tag
+ [string]$Tag,
+ [string]$RepoPath
)
$normalized = $Tag
@@ -16,17 +18,36 @@ function Convert-VersionTagToVersion64 {
$normalized = $normalized.Substring(1)
}
- if ($normalized -notmatch '^\d+(\.\d+){0,3}$') {
- throw "Version tag '$Tag' is invalid. Expected format: vX.Y.Z or X.Y.Z"
+ if ($normalized -notmatch '^(?\d+\.\d+\.\d+)(?:-(?[0-9A-Za-z][0-9A-Za-z.-]*))?$') {
+ throw "Version tag '$Tag' is invalid. Expected format: vX.Y.Z or vX.Y.Z-suffix"
}
- $parts = $normalized.Split(".")
+ $baseVersion = $Matches.base
+ $suffix = $Matches.suffix
+ $parts = $baseVersion.Split(".")
$numbers = @(0, 0, 0, 0)
for ($i = 0; $i -lt $parts.Length; $i++) {
$numbers[$i] = [int]$parts[$i]
}
- return ([int64]$numbers[0] -shl 55) -bor ([int64]$numbers[1] -shl 47) -bor ([int64]$numbers[2] -shl 31) -bor [int64]$numbers[3]
+ if ($suffix) {
+ $resolvedRepoPath = [System.IO.Path]::GetFullPath($RepoPath)
+ $matchingTags = @()
+
+ try {
+ $matchingTags = @(git -C $resolvedRepoPath tag --list "v$baseVersion-*" 2>$null | Where-Object { $_ -and $_ -ne $Tag })
+ } catch {
+ $matchingTags = @()
+ }
+
+ $numbers[3] = $matchingTags.Count + 1
+ }
+
+ return [pscustomobject]@{
+ BaseVersion = $baseVersion
+ Suffix = $suffix
+ Version64 = ([int64]$numbers[0] -shl 55) -bor ([int64]$numbers[1] -shl 47) -bor ([int64]$numbers[2] -shl 31) -bor [int64]$numbers[3]
+ }
}
$resolvedMetaPath = [System.IO.Path]::GetFullPath($MetaPath)
@@ -34,7 +55,8 @@ if (-not (Test-Path -LiteralPath $resolvedMetaPath)) {
throw "meta.lsx was not found: '$resolvedMetaPath'."
}
-$resolvedVersion64 = Convert-VersionTagToVersion64 -Tag $VersionTag
+$releaseVersion = Get-ReleaseVersionParts -Tag $VersionTag -RepoPath $RepositoryPath
+$resolvedVersion64 = $releaseVersion.Version64
$utf8Encoding = [System.Text.UTF8Encoding]::new($false)
$metaContent = [System.IO.File]::ReadAllText($resolvedMetaPath, $utf8Encoding)
[xml]$metaXml = $metaContent
@@ -60,4 +82,4 @@ $updatedMeta = [regex]::Replace(
[System.IO.File]::WriteAllText($resolvedMetaPath, $updatedMeta, $utf8Encoding)
-Write-Host "[set-version.ps1] Updated '$resolvedMetaPath' to Version64=$resolvedVersion64 (from tag '$VersionTag')."
+Write-Host "[set-version.ps1] Updated '$resolvedMetaPath' to Version64=$resolvedVersion64 (from tag '$VersionTag', base '$($releaseVersion.BaseVersion)')."