From d82c627bb1bbe0dc6e73fe2522c203980cfcc0b3 Mon Sep 17 00:00:00 2001 From: XapcT Date: Sat, 11 Apr 2026 18:52:08 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9F=D0=BE=D0=B4=D0=B3=D0=BE=D1=82=D0=BE?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=BF=D0=BE=D0=B4=D0=B4=D0=B5?= =?UTF-8?q?=D1=80=D0=B6=D0=BA=D0=B0=20=D1=82=D0=B5=D1=81=D1=82=D0=BE=D0=B2?= =?UTF-8?q?=D1=8B=D1=85=20=D1=80=D0=B5=D0=BB=D0=B8=D0=B7=D0=BD=D1=8B=D1=85?= =?UTF-8?q?=20=D1=82=D0=B5=D0=B3=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/workflows/build.yml | 13 +++++++++- .github/workflows/build.yml | 39 ++++++++++++++++++++++++++--- AGENTS.md | 6 +++++ Mods/DnD 5.5e AIO Russian/meta.lsx | 2 +- scripts/build.ps1 | 26 +++++++++++++++---- scripts/set-version.ps1 | 40 +++++++++++++++++++++++------- 6 files changed, 106 insertions(+), 20 deletions(-) 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)')."