Skip to content

Commit f4c19b4

Browse files
committed
Скрипты автоматизации публикации новых версий
1 parent 3c8c30d commit f4c19b4

File tree

7 files changed

+350
-3
lines changed

7 files changed

+350
-3
lines changed

.scripts/dependencies.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
..\MathCore.WPF
2+
..\MathCore.DSP
3+
..\MathCore.AI

.scripts/nuget-ver-remote.cs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
#!/usr/local/share/dotnet/dotnet run
2+
// Файл file-based app скрипта для определения текущей версии NuGet пакета из удаленного репозитория.
3+
// Использование: dotnet run .scripts/nuget-ver-remote.cs <package-name>
4+
5+
#nullable enable
6+
7+
#:package NuGet.Protocol@7.0.1
8+
#:package NuGet.Configuration@7.0.1
9+
10+
using System;
11+
using System.Linq;
12+
using System.Threading;
13+
using System.Threading.Tasks;
14+
using NuGet.Common;
15+
using NuGet.Configuration;
16+
using NuGet.Protocol;
17+
using NuGet.Protocol.Core.Types;
18+
using NuGet.Versioning;
19+
20+
if (args.Length < 1)
21+
{
22+
Console.Error.WriteLine("Usage: dotnet run .scripts/nuget-ver-remote.cs <package-name>");
23+
Environment.Exit(1);
24+
}
25+
26+
var package_name = args[0]; // имя пакета из аргумента
27+
if (string.IsNullOrWhiteSpace(package_name))
28+
{
29+
Console.Error.WriteLine("Package name is empty");
30+
Environment.Exit(1);
31+
}
32+
33+
try
34+
{
35+
// Создадим репозиторий NuGet (v3 API)
36+
var source_repo = Repository.Factory.GetCoreV3("https://api.nuget.org/v3/index.json");
37+
38+
// Получим ресурс метаданных пакета
39+
using var cache = new SourceCacheContext();
40+
var logger = NullLogger.Instance;
41+
var resource = await source_repo.GetResourceAsync<PackageMetadataResource>().ConfigureAwait(false);
42+
43+
// Запросим все метаданные по пакету (включая pre-release), не включая unlisted
44+
var metadata = await resource.GetMetadataAsync(package_name, includePrerelease: true, includeUnlisted: false, cache, logger, CancellationToken.None).ConfigureAwait(false);
45+
46+
var metadata_list = metadata?.ToList() ?? new System.Collections.Generic.List<IPackageSearchMetadata>();
47+
if (metadata_list.Count == 0)
48+
{
49+
Console.Error.WriteLine($"Package not found: {package_name}");
50+
Environment.Exit(2);
51+
}
52+
53+
// Соберём версии и выберем последнюю стабильную, если есть, иначе последнюю доступную
54+
var versions = metadata_list
55+
.Select(m => m.Identity.Version)
56+
.Where(v => v is not null)
57+
.OrderBy(v => v)
58+
.ToArray();
59+
60+
if (versions.Length == 0)
61+
{
62+
Console.Error.WriteLine("No versions found");
63+
Environment.Exit(2);
64+
}
65+
66+
var stable_version = versions
67+
.Where(v => !v.IsPrerelease)
68+
.OrderByDescending(v => v)
69+
.FirstOrDefault()
70+
?? versions.OrderByDescending(v => v).First();
71+
72+
var latest_version = stable_version.ToNormalizedString();
73+
74+
Console.WriteLine(latest_version); // вывод версии в stdout
75+
Environment.Exit(0);
76+
}
77+
catch (Exception ex)
78+
{
79+
Console.Error.WriteLine($"Error: {ex.Message}");
80+
Environment.Exit(2);
81+
}

.scripts/nuget-ver-wait.cs

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
#!/usr/local/share/dotnet/dotnet run
2+
// Файл file-based app скрипта для ожидания появления указанной версии NuGet пакета на сервере.
3+
// Использование: dotnet run .scripts/nuget-ver-wait.cs <package-name> <target-version> [-n <tries>] [-t <timeout-ms>]
4+
5+
#nullable enable
6+
7+
#:package NuGet.Protocol@7.0.1
8+
#:package NuGet.Configuration@7.0.1
9+
10+
using System;
11+
using System.Linq;
12+
using System.Threading;
13+
using System.Threading.Tasks;
14+
using NuGet.Common;
15+
using NuGet.Configuration;
16+
using NuGet.Protocol;
17+
using NuGet.Protocol.Core.Types;
18+
using NuGet.Versioning;
19+
20+
if (args.Length < 2)
21+
{
22+
Console.Error.WriteLine("Usage: dotnet run .scripts/nuget-ver-wait.cs <package-name> <target-version> [-n <tries>] [-t <timeout-ms>]");
23+
Environment.Exit(1);
24+
}
25+
26+
var package_name = args[0]; // имя пакета
27+
var target_version_str = args[1]; // требуемая версия
28+
if (string.IsNullOrWhiteSpace(package_name) || string.IsNullOrWhiteSpace(target_version_str))
29+
{
30+
Console.Error.WriteLine("Package name or target version is empty");
31+
Environment.Exit(1);
32+
}
33+
34+
// Значения по умолчанию
35+
var tries = 10; // -n по умолчанию
36+
var timeout_ms = 1000; // -t по умолчанию
37+
38+
// Разбор дополнительных аргументов
39+
for (var i = 2; i < args.Length; i++)
40+
{
41+
var a = args[i];
42+
const StringComparison cmp = StringComparison.OrdinalIgnoreCase;
43+
if (string.Equals(a, "-n", cmp) && i + 1 < args.Length)
44+
{
45+
if (int.TryParse(args[++i], out var v)) tries = v;
46+
}
47+
else if (string.Equals(a, "-t", cmp) && i + 1 < args.Length)
48+
{
49+
if (int.TryParse(args[++i], out var v)) timeout_ms = v;
50+
}
51+
}
52+
53+
if (tries <= 0) tries = 1;
54+
if (timeout_ms < 0) timeout_ms = 0;
55+
56+
if (!NuGetVersion.TryParse(target_version_str, out var target_version))
57+
{
58+
Console.Error.WriteLine($"Невозможно распарсить целевую версию: {target_version_str}");
59+
Environment.Exit(1);
60+
}
61+
62+
Console.WriteLine($"Ожидание версии {target_version} пакета {package_name} на nuget.org ({tries} попыток, таймаут {timeout_ms}ms)");
63+
64+
try
65+
{
66+
var source_repo = Repository.Factory.GetCoreV3("https://api.nuget.org/v3/index.json");
67+
using var cache = new SourceCacheContext();
68+
var logger = NullLogger.Instance;
69+
var resource = await source_repo.GetResourceAsync<PackageMetadataResource>();
70+
71+
for (var attempt = 1; attempt <= tries; attempt++)
72+
{
73+
// Получим метаданные пакета
74+
var metadata = await resource.GetMetadataAsync(package_name, includePrerelease: true, includeUnlisted: false, cache, logger, CancellationToken.None);
75+
var metadata_list = metadata?.ToList() ?? [];
76+
77+
if (metadata_list.Count == 0)
78+
Console.WriteLine($"[{attempt}/{tries}] Пакет не найден на сервере");
79+
else
80+
{
81+
var versions = metadata_list
82+
.Select(m => m.Identity.Version)
83+
.Where(v => v is not null)
84+
.OrderByDescending(v => v)
85+
.ToArray();
86+
87+
if (versions.Length == 0)
88+
Console.WriteLine($"[{attempt}/{tries}] На сервере нет версий пакета");
89+
else
90+
{
91+
var latest = versions[0];
92+
Console.WriteLine($"[{attempt}/{tries}] Серверная последняя версия: {latest}");
93+
94+
// Сравним последнюю серверную версию с целевой
95+
if (latest < target_version)
96+
Console.WriteLine($"Серверная версия {latest} младше требуемой {target_version}, ожидаем...");
97+
else
98+
{
99+
Console.WriteLine($"Требуемая версия {target_version} доступна на сервере (серверная версия {latest})");
100+
Environment.Exit(0);
101+
}
102+
}
103+
}
104+
105+
if (attempt < tries)
106+
await Task.Delay(timeout_ms);
107+
}
108+
109+
Console.Error.WriteLine($"Не удалось дождаться версии {target_version} для пакета {package_name} после {tries} попыток");
110+
Environment.Exit(2);
111+
}
112+
catch (Exception ex)
113+
{
114+
Console.Error.WriteLine($"Ошибка: {ex.Message}");
115+
Environment.Exit(2);
116+
}

.scripts/xml-xpath.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#!/usr/local/share/dotnet/dotnet run
2+
// Файл file-based app скрипта для выполнения XPath запросов к XML файлам.
3+
// запуск через команду: dotnet run .scripts/xml-xpath.cs <xml-file> <xpath-query>
4+
5+
using System;
6+
using System.Xml;
7+
8+
if (args.Length != 2)
9+
{
10+
Console.WriteLine("Usage: dotnet run .scripts/xml-xpath.cs <xml-file> <xpath-query>");
11+
return;
12+
}
13+
14+
var xml_file = args[0];
15+
var xpath_query = args[1];
16+
17+
XmlDocument xml_doc = new XmlDocument();
18+
xml_doc.Load(xml_file);
19+
20+
var nodes = xml_doc.SelectNodes(xpath_query);
21+
if (nodes is null || nodes.Count == 0)
22+
Console.WriteLine("No nodes found."); // нет найденных узлов
23+
else
24+
// используем явный тип XmlNode чтобы не получать object и иметь доступ к OuterXml
25+
foreach (XmlNode node in nodes)
26+
Console.WriteLine(node.OuterXml);

MathCore.slnx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
<Folder Name="/.Service/">
77
<File Path=".editorconfig" />
88
<File Path=".github/copilot-instructions.md" />
9-
<File Path=".github/workflows/publish.yml" />
10-
<File Path=".github/workflows/testing.yml" />
119
<File Path="BuildAndPublish.bat" />
1210
<File Path="BuildAndTest.bat" />
1311
<File Path="BuildRelease.bat" />
@@ -20,6 +18,12 @@
2018
<File Path=".github/workflows/publish.yml" />
2119
<File Path=".github/workflows/testing.yml" />
2220
</Folder>
21+
<Folder Name="/.Service/Scripts/">
22+
<File Path=".scripts/nuget-ver-remote.cs" />
23+
<File Path=".scripts/nuget-ver-wait.cs" />
24+
<File Path=".scripts/xml-xpath.cs" />
25+
<File Path="publish-nuget.bat" />
26+
</Folder>
2327
<Folder Name="/Tests/">
2428
<Project Path="Tests/Benchmarks/Benchmarks.csproj">
2529
<BuildType Solution="Debug|Any CPU" Project="Release" />

MathCore/MathCore.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
</PropertyGroup>
1313

1414
<PropertyGroup>
15-
<Version>0.0.94.1</Version>
15+
<Version>0.0.94.2</Version>
1616
<PackageReleaseNotes>
1717
Миграция на .NET 10.0
1818
</PackageReleaseNotes>

publish-nuget.bat

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
@echo off
2+
:: Запуск процесса публикации пакета NuGet
3+
4+
:: Изменим кодировку терминала на UTF-8 для корректного отображения символов
5+
chcp 65001 > nul
6+
7+
set "script_dir=%~dp0"
8+
if "%script_dir:~-1%"=="\" set "script_dir=%script_dir:~0,-1%"
9+
for %%i in ("%script_dir%") do set "PackageName=%%~nxi"
10+
echo Публикация пакета %PackageName%
11+
12+
:: Получим версию проекта, подставляя %PackageName% в путь к csproj
13+
set "local_version="
14+
set "temp_ver=%TEMP%\%PackageName%_ver.txt"
15+
:: Запускаем dotnet и перенаправляем вывод во временный файл чтобы избежать проблем с синтаксисом командной строки
16+
dotnet run .scripts\xml-xpath.cs "%~dp0\%PackageName%\%PackageName%.csproj" "/Project/PropertyGroup/Version/text()" > "%temp_ver%" 2>nul
17+
if exist "%temp_ver%" (
18+
set /p local_version=<"%temp_ver%"
19+
del "%temp_ver%" 2>nul
20+
)
21+
if defined local_version (
22+
echo Локальная версия: %local_version%
23+
) else (
24+
echo Не удалось получить версию проекта
25+
exit /b 1
26+
)
27+
28+
:: Получим версию пакета на сервере через скрипт .scripts\nuget-ver-remote.cs
29+
set "remote_version="
30+
set "temp_remote=%TEMP%\%PackageName%_remote_ver.txt"
31+
:: Вызов скрипта, вывод версии в файл
32+
dotnet run .scripts\nuget-ver-remote.cs "%PackageName%" > "%temp_remote%" 2>nul
33+
if exist "%temp_remote%" (
34+
set /p remote_version=<"%temp_remote%"
35+
del "%temp_remote%" 2>nul
36+
)
37+
if defined remote_version (
38+
echo Серверная версия: %remote_version%
39+
if "%local_version%"=="%remote_version%" (
40+
echo Версия на сервере совпадает с локальной, публикация не требуется.
41+
exit /b 0
42+
) else (
43+
echo Локальная версия отличается от серверной, продолжаем публикацию.
44+
)
45+
) else (
46+
echo Не удалось получить версию с сервера, продолжаем публикацию.
47+
)
48+
49+
:: Проверим что в локальном репозитории нет незакоммиченных изменений
50+
rem git status --porcelain > nul
51+
rem if not errorlevel 1 (
52+
rem echo Есть незакоммиченные изменения. Пожалуйста, закоммитьте их перед публикацией.
53+
rem pause
54+
rem exit /b 1
55+
rem )
56+
57+
git pull
58+
59+
:: Выполнение мержа из ветки dev в ветку master
60+
::git checkout master
61+
::git merge dev
62+
::git push origin master
63+
::git checkout dev
64+
65+
:: Сборка и публикация проекта произойдёт автоматически на сервере GitHub Actions
66+
67+
:: Ожидание обновления новой версии на сервер NuGet.org 15 итераций по 20 секунд
68+
dotnet run .scripts\nuget-ver-wait.cs "%PackageName%" "%local_version%" -n 15 -t 20000
69+
:: если errorlevel не 0, дождаться не удалось. Требуется внимание пользователя
70+
if errorlevel 1 (
71+
echo Не удалось подтвердить публикацию пакета на сервере NuGet.org.
72+
echo Пожалуйста, проверьте вручную.
73+
pause
74+
exit /b 1
75+
)
76+
77+
:: Теперь пройдём по всем зависимостям от данного пакета и вызовем их публикацию
78+
:: для этого перечислим все строки в файле .\.scripts\dependencies.txt
79+
80+
echo.
81+
if not exist ".\.scripts\dependencies.txt" (
82+
echo Файл зависимостей не найден: .\.scripts\dependencies.txt
83+
echo Публикация завершена.
84+
exit /b 0
85+
)
86+
87+
rem тут будет выполнение скрипта ожидания завершения проверки пакета на сервере NuGet.org
88+
89+
90+
for /f "usebackq delims=" %%i in (".\.scripts\dependencies.txt") do (
91+
rem Проверим что каталог существует
92+
if not exist "%%i" (
93+
echo Каталог не найден: %%i
94+
rem пропустить эту итерацию
95+
) else (
96+
rem Проверим, что в каталоге есть файл publish-nuget.bat
97+
if not exist "%%i\publish-nuget.bat" (
98+
echo Файл publish-nuget.bat не найден в каталоге: %%i
99+
rem пропустить эту итерацию
100+
) else (
101+
echo.
102+
echo Публикация зависимого пакета: %%i
103+
pushd "%%i"
104+
rem Вызов публикации зависимого пакета (раскомментировать при необходимости)
105+
call publish-nuget.bat
106+
if errorlevel 1 (
107+
echo Ошибка при публикации зависимого пакета: %%i
108+
popd
109+
exit /b 1
110+
)
111+
popd
112+
)
113+
)
114+
)
115+
116+
pause
117+
exit /b 0

0 commit comments

Comments
 (0)