Compare commits
3
Commits
a3338e1cf3
...
006814823b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
006814823b | ||
|
|
7ff0d0f4e6 | ||
|
|
a9f78f99df |
No files matched your search
@@ -7,12 +7,19 @@ clone:
|
||||
image: plugin-git
|
||||
settings:
|
||||
lfs: false
|
||||
# 要拿到 tag 才算得出开发版本号(ci/version.sh:自最近 tag 的提交数)
|
||||
tags: true
|
||||
|
||||
when:
|
||||
- event: push
|
||||
branch: main
|
||||
evaluate: 'CI_COMMIT_MESSAGE contains "[CI]"'
|
||||
|
||||
# 先等后端测试和前端构建都通过再出镜像(提交信息写 [SKIP TESTS] 只跳过后端测试)
|
||||
depends_on:
|
||||
- verify
|
||||
- web-build
|
||||
|
||||
concurrency: 1
|
||||
|
||||
steps:
|
||||
@@ -28,7 +35,7 @@ steps:
|
||||
RELEASE_SIGNING_KEY:
|
||||
from_secret: release_signing_key
|
||||
commands:
|
||||
- bash ci/build-main-amd64.sh backend
|
||||
- bash ci/build-dev-image.sh backend
|
||||
depends_on: []
|
||||
|
||||
- name: build-linux-amd64-agent
|
||||
@@ -43,7 +50,7 @@ steps:
|
||||
RELEASE_SIGNING_KEY:
|
||||
from_secret: release_signing_key
|
||||
commands:
|
||||
- bash ci/build-main-amd64.sh agent
|
||||
- bash ci/build-dev-image.sh agent
|
||||
depends_on: []
|
||||
|
||||
- name: build-linux-amd64-probe
|
||||
@@ -58,5 +65,5 @@ steps:
|
||||
RELEASE_SIGNING_KEY:
|
||||
from_secret: release_signing_key
|
||||
commands:
|
||||
- bash ci/build-main-amd64.sh probe
|
||||
- bash ci/build-dev-image.sh probe
|
||||
depends_on: []
|
||||
@@ -22,6 +22,8 @@ steps:
|
||||
environment:
|
||||
NPM_CONFIG_CACHE: /home/justme/.npm
|
||||
commands:
|
||||
# 版本取自 tag:先写进工作区(仓库里的版本号只是占位),前端才会带上对的版本
|
||||
- bash ci/version.sh apply
|
||||
- npm ci --prefix web --prefer-offline
|
||||
- timeout 600 npm run build --prefix web
|
||||
depends_on: []
|
||||
|
||||
@@ -11,7 +11,7 @@ clone:
|
||||
when:
|
||||
- event: pull_request
|
||||
- event: push
|
||||
branch: dev
|
||||
branch: main
|
||||
|
||||
# On Gitea PR events, CI_COMMIT_MESSAGE is the PR title.
|
||||
steps:
|
||||
|
||||
@@ -11,7 +11,7 @@ clone:
|
||||
when:
|
||||
- event: pull_request
|
||||
- event: push
|
||||
branch: dev
|
||||
branch: main
|
||||
|
||||
depends_on:
|
||||
- verify
|
||||
|
||||
@@ -6,8 +6,9 @@ MoShiro is a self-hosted network path quality monitor. Backend coordinates Agent
|
||||
|
||||
## Branch and workspace safety
|
||||
|
||||
- Treat `main` as the stable release branch and `dev` as the integration branch. Keep ordinary implementation work on `dev` or a feature branch; integrate into `main` through a pull request.
|
||||
- A push to `main` builds images only if its commit message contains `[CI]` (for a merged PR, put it in the PR or merge commit title). Without `[CI]` nothing is built; use `[CI SKIP]` to skip the pipeline entirely. When squashing or pushing to `main`, add `[CI]` unless a build is explicitly not wanted.
|
||||
- `main` is the only working branch (the old `dev` branch is retired and no pipeline uses it). Commit and push to `main` directly; use a pull request when a review is wanted.
|
||||
- A push to `main` publishes development images only if its commit message contains `[CI]` (for a merged PR, put it in the PR or merge commit title). Without `[CI]` nothing is built; use `[CI SKIP]` to skip the pipeline entirely. Backend tests and the web build run on every `main` push and must pass first; `[SKIP TESTS]` skips only the Backend tests.
|
||||
- Versions are filled in by CI (`ci/version.sh`): a `vX.Y.Z` tag builds exactly `X.Y.Z`; a `[CI]` build on `main` is `vX.Y.(Z+1)-dev.<N>-<sha7>` (`N` = commits since the latest tag). The `<Version>` in `backend/Directory.Build.props` and the `version` in the `web` `package.json` files are placeholders (`0.0.0-dev`); never bump them by hand.
|
||||
- Before editing, inspect `git status`. Preserve pre-existing user changes: do not reset, clean, stash, or include unrelated files in a commit.
|
||||
- Do not commit credentials, API keys, registry passwords, or generated runtime data. CI credentials belong in Woodpecker secrets (`zot_secret`, `gitea_token`, `release_signing_key` for signing release manifests). CI registers the signed manifests at `/api/release/offer`, which needs no token because the panel verifies the signature. The release signing private key never goes into the repository or the panel; only the public key in `packaging/update/` does.
|
||||
- Keep development OCI images in the `moshiro-dev/` repository path and release images in `moshiro/`. Do not let a development build overwrite release tags such as `latest`.
|
||||
@@ -40,4 +41,4 @@ Follow the user's requested validation scope. Do not start a full tag/release bu
|
||||
|
||||
CI triggers and image tags can change; inspect `.woodpecker/*.yml` and `docs/ops/deployment.md` before changing or describing them. In particular, check the distinction between `[CI]` main builds, `[SKIP TESTS]`, and version-tag releases in the current branch.
|
||||
|
||||
A version tag `vMAJOR.MINOR.PATCH` runs the full cross-platform release pipeline. Development image builds and releases must remain isolated in their respective Zot repository paths.
|
||||
A version tag `vMAJOR.MINOR.PATCH` runs the full cross-platform release pipeline; it needs no version-bump commit, because CI takes the version from the tag. Development image builds and releases must remain isolated in their respective Zot repository paths.
|
||||
@@ -13,7 +13,7 @@
|
||||
<UseArtifactsOutput>true</UseArtifactsOutput>
|
||||
<ArtifactsPath>$(MSBuildThisFileDirectory)artifacts</ArtifactsPath>
|
||||
<Deterministic>true</Deterministic>
|
||||
<Version>0.4.0</Version>
|
||||
<Version>0.0.0-dev</Version>
|
||||
<NuGetAudit>false</NuGetAudit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -143,6 +143,7 @@ public sealed class AgentApp : IDisposable
|
||||
|
||||
public async Task RunAsync(CancellationToken ct)
|
||||
{
|
||||
_log.Info("moshiro agent starting", MoShiro.Protocol.BuildInfo.Fields);
|
||||
using CancellationTokenSource linked = CancellationTokenSource.CreateLinkedTokenSource(ct);
|
||||
// 数据面和控制端口先开始监听,再连接 Backend:hello 里上报的是实际端口
|
||||
_udp.Bind();
|
||||
|
||||
@@ -103,6 +103,7 @@ public sealed class ProbeApp : IDisposable
|
||||
|
||||
public async Task RunAsync(CancellationToken ct)
|
||||
{
|
||||
_log.Info("moshiro probe starting", MoShiro.Protocol.BuildInfo.Fields);
|
||||
if (_env.Directory.Agents.Count == 0)
|
||||
{
|
||||
_log.Info("no agents known yet, waiting for the panel to send the list");
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
namespace MoShiro.Protocol;
|
||||
|
||||
/// <summary>构建信息的人能读的形式(启动时打进日志);常量部分由 MoShiro.Protocol.csproj 的 WriteBuildInfo 在构建时生成。</summary>
|
||||
public static partial class BuildInfo
|
||||
{
|
||||
/// <summary>版本、tag、提交、构建时间的字段,没有的(本地构建不设环境变量)写 unknown。</summary>
|
||||
public static (string Key, object? Value)[] Fields { get; } =
|
||||
[
|
||||
("version", Or(Version)),
|
||||
("tag", Or(Tag)),
|
||||
("commit", Or(Commit)),
|
||||
("built_at", Or(BuiltAt)),
|
||||
];
|
||||
|
||||
/// <summary>一行摘要,例如:0.4.1-dev.2-a3338e1 (tag v0.4.1-dev.2-a3338e1, commit a3338e1b2c, built 2026-10-09T03:00:00Z)。</summary>
|
||||
public static string Summary => $"{Or(Version)} (tag {Or(Tag)}, commit {Or(Commit)}, built {Or(BuiltAt)})";
|
||||
|
||||
private static string Or(string value) => string.IsNullOrWhiteSpace(value) ? "unknown" : value;
|
||||
}
|
||||
@@ -18,7 +18,7 @@
|
||||
<ItemGroup>
|
||||
<BuildInfoLine Include="namespace MoShiro.Protocol%3B" />
|
||||
<BuildInfoLine Include="/// <summary>这个程序是什么时候、从哪个版本构建出来的(构建时生成)。</summary>" />
|
||||
<BuildInfoLine Include="public static class BuildInfo" />
|
||||
<BuildInfoLine Include="public static partial class BuildInfo" />
|
||||
<BuildInfoLine Include="{" />
|
||||
<BuildInfoLine Include=" public const string Version = "$(Version)"%3B" />
|
||||
<BuildInfoLine Include=" public const string Tag = "$(MOSHIRO_TAG)"%3B" />
|
||||
|
||||
@@ -55,9 +55,14 @@ public sealed class BackendUpdates : IHostedService
|
||||
return "release";
|
||||
}
|
||||
|
||||
return BuildInfo.Tag is { } tag && (tag.StartsWith("dev-", StringComparison.Ordinal) || tag.StartsWith("main-", StringComparison.Ordinal)) ? "dev" : "release";
|
||||
return IsDevTag(BuildInfo.Tag) ? "dev" : "release";
|
||||
}
|
||||
|
||||
/// <summary>开发构建的 tag:新格式 v0.4.1-dev.12-abc1234(含 -dev.),以及旧的 dev-<sha>、main-<sha>。</summary>
|
||||
public static bool IsDevTag(string? tag) =>
|
||||
tag is not null
|
||||
&& (tag.Contains("-dev.", StringComparison.Ordinal) || tag.StartsWith("dev-", StringComparison.Ordinal) || tag.StartsWith("main-", StringComparison.Ordinal));
|
||||
|
||||
public async ValueTask<BackendUpdateView> GetAsync(CancellationToken ct)
|
||||
{
|
||||
string channel = ChannelOf(_options);
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
using MoShiro.Backend;
|
||||
|
||||
await BackendHost.Build(args).RunAsync();
|
||||
WebApplication app = BackendHost.Build(args);
|
||||
// 启动时打一行构建信息:版本、tag、提交、构建时间(和 Agent、Probe 启动时打的是同一组)
|
||||
if (app.Logger.IsEnabled(LogLevel.Information))
|
||||
{
|
||||
app.Logger.LogInformation("moshiro backend starting: version {BuildInfo}", MoShiro.Protocol.BuildInfo.Summary);
|
||||
}
|
||||
|
||||
await app.RunAsync();
|
||||
@@ -30,6 +30,18 @@ public sealed class BackendUpdateTests : IAsyncLifetime
|
||||
Assert.Equal(expected, BackendUpdates.ChannelOf(new BackendOptions { UpdateChannel = "auto", ImageNamespace = imageNamespace }));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("v0.4.1-dev.12-044ce0c", true)]
|
||||
[InlineData("dev-725fe17a7de8", true)]
|
||||
[InlineData("main-725fe17a7d", true)]
|
||||
[InlineData("v0.4.0", false)]
|
||||
[InlineData("v0.4.1-rc.1", false)]
|
||||
[InlineData(null, false)]
|
||||
public void IsDevTag_RecognisesDevelopmentBuilds(string? tag, bool expected)
|
||||
{
|
||||
Assert.Equal(expected, BackendUpdates.IsDevTag(tag));
|
||||
}
|
||||
|
||||
private async Task<HttpResponseMessage> PublishAsync(long seq, string channel = "dev")
|
||||
{
|
||||
string manifest = $$"""{"component":"backend","channel":"{{channel}}","image":"registry.example/moshiro-{{channel}}/moshiro-backend","digest":"{{Digest}}","tag":"{{channel}}-{{seq}}","version":"0.1.1","seq":{{seq}}}""";
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build and push one opt-in main Linux amd64 image to the dev repository in Zot.
|
||||
# Build and push one opt-in Linux amd64 development image (main push with [CI]) to the moshiro-dev repository in Zot.
|
||||
set -euo pipefail
|
||||
|
||||
[[ "${CI_PIPELINE_EVENT:-}" == push && "${CI_COMMIT_BRANCH:-}" == main && "${CI_COMMIT_MESSAGE:-}" == *"[CI]"* ]] || {
|
||||
echo "main amd64 builds require a main push with [CI] in the commit message" >&2
|
||||
echo "development image builds require a main push with [CI] in the commit message" >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
component="${1:?usage: build-main-amd64.sh <backend|agent|probe>}"
|
||||
component="${1:?usage: build-dev-image.sh <backend|agent|probe>}"
|
||||
case "$component" in
|
||||
backend|agent|probe) ;;
|
||||
*) echo "unsupported component: $component" >&2; exit 2 ;;
|
||||
@@ -22,20 +22,22 @@ esac
|
||||
}
|
||||
|
||||
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
# 版本:v<下一个补丁版本>-dev.<自最近 tag 的提交数>-<提交前 7 位>(见 ci/version.sh);写进工作区的 Directory.Build.props,镜像标签、构建信息、签名清单都用它
|
||||
source "$root/ci/version.sh"
|
||||
moshiro_apply_version
|
||||
registry="${ZOT_REGISTRY:-registry.oeo.one}"
|
||||
repository="$registry/moshiro-dev/moshiro-$component"
|
||||
work="$root/.release/main-amd64-build"
|
||||
base_home="/home/justme/woodpecker/buildah-home/main-amd64-build-$component"
|
||||
short_sha="${CI_COMMIT_SHA:0:12}"
|
||||
dev_tag="dev-$short_sha"
|
||||
work="$root/.release/dev-image-build"
|
||||
base_home="/home/justme/woodpecker/buildah-home/dev-image-build-$component"
|
||||
# 镜像标签不带 v(和正式版一致):latest 和 <版本>;构建信息和清单里的 tag 带 v
|
||||
image_version="$MOSHIRO_VERSION"
|
||||
mkdir -p "$work" "$base_home"
|
||||
|
||||
if [[ "$component" == backend ]]; then
|
||||
export MOSHIRO_TAG="$dev_tag"
|
||||
BUILDAH_HOME="$base_home" \
|
||||
ZOT_REGISTRY="$registry" \
|
||||
ZOT_IMAGE_REPOSITORY="$repository" \
|
||||
IMAGE_TAGS="latest,$dev_tag" \
|
||||
IMAGE_TAGS="latest,$image_version" \
|
||||
IMAGE_PUBLISH=true \
|
||||
bash "$root/ci/release-linux.sh" amd64 backend
|
||||
exit 0
|
||||
@@ -45,12 +47,12 @@ export HOME="$base_home"
|
||||
export BUILDAH_HOME="$base_home"
|
||||
export REGISTRY_AUTH_FILE="$work/$component-auth.json"
|
||||
context="$work/$component"
|
||||
local_image="localhost/moshiro-$component:main-amd64-check"
|
||||
local_image="localhost/moshiro-$component:dev-amd64-check"
|
||||
|
||||
python3 "$root/ci/stage-node-image.py" "$component" "$context"
|
||||
buildah bud --layers --network host --tls-verify=true --arch amd64 \
|
||||
--build-arg APP_VERSION=main \
|
||||
--build-arg "MOSHIRO_TAG=$dev_tag" --build-arg "MOSHIRO_COMMIT=${CI_COMMIT_SHA:0:10}" --build-arg "MOSHIRO_BUILT_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
||||
--build-arg "APP_VERSION=$image_version" \
|
||||
--build-arg "MOSHIRO_TAG=$MOSHIRO_TAG" --build-arg "MOSHIRO_COMMIT=${CI_COMMIT_SHA:0:10}" --build-arg "MOSHIRO_BUILT_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
||||
-f "$context/Containerfile" \
|
||||
-t "$local_image" "$context"
|
||||
|
||||
@@ -67,7 +69,7 @@ for attempt in 1 2 3 4; do
|
||||
done
|
||||
[[ "$logged_in" == true ]] || { echo "could not authenticate to Zot after 4 attempts" >&2; exit 1; }
|
||||
|
||||
for tag in latest "$dev_tag"; do
|
||||
for tag in latest "$image_version"; do
|
||||
pushed=false
|
||||
for attempt in 1 2 3; do
|
||||
if buildah push --tls-verify=true --digestfile "$work/$component.digest" "$local_image" "docker://$repository:$tag"; then
|
||||
@@ -86,5 +88,5 @@ done
|
||||
# 发布清单:给镜像的 digest 签名(私钥只在 CI 密钥里),放进镜像仓库(<仓库>-manifest:dev),面板在线时再登记一份加速。
|
||||
# 没有配置签名密钥(例如 fork)就只构建镜像、不发清单。
|
||||
if [[ -n "${RELEASE_SIGNING_KEY:-}" ]]; then
|
||||
bash "$root/ci/publish-release-offer.sh" "$component" "$repository" "$(cat "$work/$component.digest")" "$dev_tag" dev "$work/$component-release"
|
||||
bash "$root/ci/publish-release-offer.sh" "$component" "$repository" "$(cat "$work/$component.digest")" "$MOSHIRO_TAG" dev "$work/$component-release"
|
||||
fi
|
||||
@@ -10,10 +10,10 @@ if (-not $env:GITEA_TOKEN) {
|
||||
$version = $Matches[1]
|
||||
$root = Split-Path -Parent $PSScriptRoot
|
||||
$backend = Join-Path $root 'backend'
|
||||
$projectVersion = [regex]::Match((Get-Content (Join-Path $backend 'Directory.Build.props') -Raw), '<Version>([^<]+)</Version>').Groups[1].Value
|
||||
if ($version -ne $projectVersion) {
|
||||
throw "Tag version $version does not match project version $projectVersion."
|
||||
}
|
||||
# 版本取自 tag:写进工作区的 Directory.Build.props(仓库里的 <Version> 只是占位,发版不用再提交 bump)
|
||||
$propsPath = Join-Path $backend 'Directory.Build.props'
|
||||
$props = Get-Content $propsPath -Raw
|
||||
Set-Content -LiteralPath $propsPath -Value ([regex]::Replace($props, '<Version>[^<]*</Version>', "<Version>$version</Version>")) -NoNewline
|
||||
|
||||
$tarProject = Join-Path $PSScriptRoot 'MoShiro.Tar\MoShiro.Tar.csproj'
|
||||
$tarTool = Join-Path $PSScriptRoot 'MoShiro.Tar\bin\Release\net10.0\MoShiro.Tar.dll'
|
||||
|
||||
@@ -20,10 +20,10 @@ if (-not $env:CI_COMMIT_TAG -or $env:CI_COMMIT_TAG -notmatch '^v(\d+\.\d+\.\d+(?
|
||||
$version = $Matches[1]
|
||||
$root = Split-Path -Parent $PSScriptRoot
|
||||
$backend = Join-Path $root 'backend'
|
||||
$projectVersion = [regex]::Match((Get-Content (Join-Path $backend 'Directory.Build.props') -Raw), '<Version>([^<]+)</Version>').Groups[1].Value
|
||||
if ($version -ne $projectVersion) {
|
||||
throw "Tag version $version does not match project version $projectVersion."
|
||||
}
|
||||
# 版本取自 tag:写进工作区的 Directory.Build.props(仓库里的 <Version> 只是占位,发版不用再提交 bump)
|
||||
$propsPath = Join-Path $backend 'Directory.Build.props'
|
||||
$props = Get-Content $propsPath -Raw
|
||||
Set-Content -LiteralPath $propsPath -Value ([regex]::Replace($props, '<Version>[^<]*</Version>', "<Version>$version</Version>")) -NoNewline
|
||||
|
||||
if ($RuntimeIdentifier -in @('win-x64', 'win-arm64')) {
|
||||
$vcArchitecture = if ($RuntimeIdentifier -eq 'win-x64') { 'x64' } else { 'arm64' }
|
||||
@@ -52,7 +52,7 @@ $buildRoot = Join-Path $root ".release\build\$RuntimeIdentifier-$Component"
|
||||
$null = New-Item -ItemType Directory -Force -Path $output
|
||||
|
||||
# 构建信息:程序里显示的 tag、提交、构建时间
|
||||
$env:MOSHIRO_TAG = if ($env:CI_COMMIT_TAG) { $env:CI_COMMIT_TAG } else { "main-$($env:CI_COMMIT_SHA.Substring(0, 10))" }
|
||||
$env:MOSHIRO_TAG = $env:CI_COMMIT_TAG
|
||||
$env:MOSHIRO_COMMIT = $env:CI_COMMIT_SHA.Substring(0, 10)
|
||||
$env:MOSHIRO_BUILT_AT = (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ')
|
||||
|
||||
|
||||
+6
-16
@@ -6,19 +6,16 @@ set -euo pipefail
|
||||
arch="${1:?usage: release-linux.sh <amd64|arm64>}"
|
||||
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
tag="${CI_COMMIT_TAG:-}"
|
||||
if [[ -n "$tag" ]]; then
|
||||
[[ "$tag" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]] || {
|
||||
echo "release must run from a vMAJOR.MINOR.PATCH tag" >&2
|
||||
exit 2
|
||||
}
|
||||
version="${tag#v}"
|
||||
else
|
||||
if [[ -z "$tag" ]]; then
|
||||
[[ "${CI_PIPELINE_EVENT:-}" == push && "${CI_COMMIT_BRANCH:-}" == main && "${CI_COMMIT_MESSAGE:-}" == *"[CI]"* ]] || {
|
||||
echo "untagged backend builds require a main push with [CI] in the commit message" >&2
|
||||
exit 2
|
||||
}
|
||||
version=main
|
||||
fi
|
||||
# 版本:tag 发版就是 tag 的版本,开发构建是 v<下一个补丁版本>-dev.<N>-<提交>(ci/version.sh);写进工作区的 Directory.Build.props
|
||||
source "$root/ci/version.sh"
|
||||
moshiro_apply_version
|
||||
version="$MOSHIRO_VERSION"
|
||||
image_publish="${IMAGE_PUBLISH:-true}"
|
||||
[[ "$image_publish" == true || "$image_publish" == false ]] || {
|
||||
echo "IMAGE_PUBLISH must be true or false" >&2; exit 2;
|
||||
@@ -34,12 +31,6 @@ case "$arch" in
|
||||
*) echo "unsupported architecture: $arch" >&2; exit 2 ;;
|
||||
esac
|
||||
|
||||
project_version="$(sed -n 's#.*<Version>\(.*\)</Version>.*#\1#p' "$root/backend/Directory.Build.props" | head -1)"
|
||||
if [[ -n "$tag" && "$version" != "$project_version" ]]; then
|
||||
echo "tag version $version does not match project version $project_version" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
registry="${ZOT_REGISTRY:-registry.oeo.one}"
|
||||
image="${ZOT_IMAGE_REPOSITORY:-$registry/moshiro/moshiro-backend}"
|
||||
output="$root/.release/linux-$arch/backend"
|
||||
@@ -47,8 +38,7 @@ build_root="$root/.release/build/linux-$arch-backend"
|
||||
container_context="$root/.release/container/linux-$arch"
|
||||
mkdir -p "$output" "$build_root" "$container_context/app" "$container_context/data"
|
||||
|
||||
# 构建信息:tag 发布用 tag,main 构建用 main-<提交>
|
||||
export MOSHIRO_TAG="${MOSHIRO_TAG:-${tag:-main-${CI_COMMIT_SHA:0:10}}}"
|
||||
# 构建信息:tag 发布用 tag,开发构建用 v<版本>-dev.<N>-<提交>(MOSHIRO_TAG 已由 ci/version.sh 设好)
|
||||
export MOSHIRO_COMMIT="${MOSHIRO_COMMIT:-${CI_COMMIT_SHA:0:10}}"
|
||||
export MOSHIRO_BUILT_AT="${MOSHIRO_BUILT_AT:-$(date -u +%Y-%m-%dT%H:%M:%SZ)}"
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@ repository="${2:?}"; digest="${3:?}"; tag="${4:?}"; channel="${5:?}"; outdir="${
|
||||
[[ -n "${RELEASE_SIGNING_KEY:-}" ]] || { echo "RELEASE_SIGNING_KEY is required" >&2; exit 2; }
|
||||
|
||||
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
version="$(sed -n 's#.*<Version>\(.*\)</Version>.*#\1#p' "$root/backend/Directory.Build.props" | head -1)"
|
||||
source "$root/ci/version.sh"
|
||||
version="$MOSHIRO_VERSION"
|
||||
commit="$(git -C "$root" rev-parse --short=10 HEAD 2>/dev/null || true)"
|
||||
built_at="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
seq="$(date +%s)"
|
||||
|
||||
@@ -15,11 +15,9 @@ tag="${CI_COMMIT_TAG:-}"
|
||||
|
||||
version="${tag#v}"
|
||||
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
project_version="$(sed -n 's#.*<Version>\(.*\)</Version>.*#\1#p' "$root/backend/Directory.Build.props" | head -1)"
|
||||
if [[ "$version" != "$project_version" ]]; then
|
||||
echo "tag version $version does not match project version $project_version" >&2
|
||||
exit 1
|
||||
fi
|
||||
# 版本取自 tag:写进工作区的 Directory.Build.props(仓库里的 <Version> 只是占位,发版不用再提交 bump)
|
||||
source "$root/ci/version.sh"
|
||||
moshiro_apply_version
|
||||
|
||||
gitea_base="${GITEA_BASE:-http://127.0.0.1:3100}"
|
||||
gitea_base="${gitea_base%/}"
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env bash
|
||||
# 算出这次构建的版本号。用法:
|
||||
# source ci/version.sh # 得到 MOSHIRO_VERSION(不带 v)和 MOSHIRO_TAG(带 v)
|
||||
# bash ci/version.sh apply # 同上,并把 MOSHIRO_VERSION 写进工作区里的 backend/Directory.Build.props 和三个 web/*/package.json(只改工作区,不提交)
|
||||
#
|
||||
# 规则:
|
||||
# - 打 tag 发版(CI_COMMIT_TAG 是 vMAJOR.MINOR.PATCH):版本就是 tag 的版本。仓库里的 <Version> 只是占位,发版不用再提交一次 bump;
|
||||
# - 其余(main 上带 [CI] 的开发构建):vMAJOR.MINOR.(PATCH+1)-dev.<N>-<提交前 7 位>,
|
||||
# 基准是最近一个 v* tag,N 是这个 tag 之后的提交数。开发版本按语义化版本排在下一个正式版之前,同一个提交算出来永远一样。
|
||||
# 最近的 tag 要拿得到:CI 的克隆要带 tags(见 .woodpecker/dev-image.yml 的 clone 设置);没有任何 tag 时基准是 0.0.0。
|
||||
_moshiro_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
|
||||
_moshiro_compute_version() {
|
||||
local tag="${CI_COMMIT_TAG:-}"
|
||||
if [[ -n "$tag" ]]; then
|
||||
[[ "$tag" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]] || {
|
||||
echo "release must run from a vMAJOR.MINOR.PATCH tag" >&2
|
||||
return 2
|
||||
}
|
||||
MOSHIRO_VERSION="${tag#v}"
|
||||
else
|
||||
local sha="${CI_COMMIT_SHA:-$(git -C "$_moshiro_root" rev-parse HEAD)}"
|
||||
local last base count major minor patch
|
||||
last="$(git -C "$_moshiro_root" describe --tags --abbrev=0 --match 'v[0-9]*.[0-9]*.[0-9]*' "$sha" 2>/dev/null || true)"
|
||||
if [[ -n "$last" ]]; then
|
||||
base="${last#v}"
|
||||
base="${base%%-*}"
|
||||
count="$(git -C "$_moshiro_root" rev-list --count "$last..$sha")"
|
||||
else
|
||||
base="0.0.0"
|
||||
count="$(git -C "$_moshiro_root" rev-list --count "$sha")"
|
||||
fi
|
||||
IFS=. read -r major minor patch <<< "$base"
|
||||
MOSHIRO_VERSION="$major.$minor.$((patch + 1))-dev.$count-${sha:0:7}"
|
||||
fi
|
||||
MOSHIRO_TAG="v$MOSHIRO_VERSION"
|
||||
export MOSHIRO_VERSION MOSHIRO_TAG
|
||||
}
|
||||
|
||||
# 把算出来的版本写进工作区的 backend/Directory.Build.props(所有 .NET 项目、清单、镜像标签都从那里读版本)和三个 package.json
|
||||
moshiro_apply_version() {
|
||||
[[ -n "${MOSHIRO_VERSION:-}" ]] || _moshiro_compute_version
|
||||
sed -i "s#<Version>[^<]*</Version>#<Version>$MOSHIRO_VERSION</Version>#" "$_moshiro_root/backend/Directory.Build.props"
|
||||
# 前端在构建时从 web/package.json 读版本(web/build-info.mjs),其余两个工作区包的版本也一起对上
|
||||
local manifest
|
||||
for manifest in web/package.json web/display/package.json web/admin/package.json; do
|
||||
sed -i -E '0,/"version": "[^"]*"/s//"version": "'"$MOSHIRO_VERSION"'"/' "$_moshiro_root/$manifest"
|
||||
done
|
||||
}
|
||||
|
||||
_moshiro_compute_version
|
||||
|
||||
if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
|
||||
if [[ "${1:-}" == apply ]]; then moshiro_apply_version; fi
|
||||
echo "$MOSHIRO_VERSION"
|
||||
fi
|
||||
+22
-11
@@ -23,7 +23,7 @@ scripts/publish.sh <agent|probe|backend|fleet-enroll> <rid> → backend/art
|
||||
scripts/package.sh <agent|probe> <rid> → backend/artifacts/packages/moshiro-<role>-<version>-<rid>.tar.gz(附 .sha256)
|
||||
```
|
||||
|
||||
构建信息(程序里显示的 tag、提交、构建时间):`publish.sh` 会用 `git describe --tags --always --dirty`、`git rev-parse` 和当前时间自动设置环境变量 `MOSHIRO_TAG`、`MOSHIRO_COMMIT`、`MOSHIRO_BUILT_AT`,直接用 `dotnet publish` 或 CI 构建时自己设置它们(容器镜像的 `*.NativeBuild.Containerfile` 用同名的 `--build-arg`,CI 脚本会传);不设置就是空,本地构建照常可重复。版本号取自 `backend/Directory.Build.props` 的 `Version`。前端的信息由 `web/build-info.mjs` 在构建时写入(版本取自 `web/package.json`)。
|
||||
构建信息(程序里显示的 tag、提交、构建时间):`publish.sh` 会用 `git describe --tags --always --dirty`、`git rev-parse` 和当前时间自动设置环境变量 `MOSHIRO_TAG`、`MOSHIRO_COMMIT`、`MOSHIRO_BUILT_AT`,直接用 `dotnet publish` 或 CI 构建时自己设置它们(容器镜像的 `*.NativeBuild.Containerfile` 用同名的 `--build-arg`,CI 脚本会传);不设置就是空,本地构建照常可重复。版本号取自 `backend/Directory.Build.props` 的 `Version`;仓库里它只是占位(`0.0.0-dev`),CI 构建时由 `ci/version.sh` 写进工作区(见下文「版本号」)。前端的信息由 `web/build-info.mjs` 在构建时写入(版本取自 `web/package.json`,同样由 CI 填写)。Agent、Probe、Backend 启动时都会在日志里打印一行构建信息:版本、tag、提交、构建时间(没设置环境变量的本地构建显示 `unknown`)。
|
||||
|
||||
| rid | 目标 | 构建方式 |
|
||||
| --- | --- | --- |
|
||||
@@ -74,25 +74,36 @@ Woodpecker 在 `vMAJOR.MINOR.PATCH` tag 上,由 Windows runner 使用 AotAnywh
|
||||
|
||||
## CI 工作流
|
||||
|
||||
### Pull request 与 dev 验证
|
||||
### Pull request 与 main 验证
|
||||
|
||||
Pull request 和 `dev` push 会运行 Backend tests;通过后,独立的 `web-build` workflow 才会构建前端并检查 CSS。提交信息后缀 `[SKIP TESTS]` 只跳过 Backend tests,前端构建仍会运行。Gitea PR 事件的 `CI_COMMIT_MESSAGE` 是 PR 标题,因此在 PR 中跳过测试时,把后缀写入 PR 标题;普通分支 push 则写在 commit message 中。
|
||||
Pull request 和 `main` 的 push 会运行 Backend tests;通过后,独立的 `web-build` workflow 才会构建前端并检查 CSS。提交信息后缀 `[SKIP TESTS]` 只跳过 Backend tests,前端构建仍会运行。Gitea PR 事件的 `CI_COMMIT_MESSAGE` 是 PR 标题,因此在 PR 中跳过测试时,把后缀写入 PR 标题;普通分支 push 则写在 commit message 中。项目只用 `main` 一个工作分支,旧的 `dev` 分支不再被任何流水线使用。
|
||||
|
||||
### 版本号
|
||||
|
||||
版本都由 CI 填写,仓库里写死的只是占位(`backend/Directory.Build.props` 的 `<Version>` 和三个 `web/**/package.json` 的 `version` 都是 `0.0.0-dev`),发版不需要提交 bump。规则在 `ci/version.sh`:
|
||||
|
||||
| 构建 | 版本 | 构建信息里的 tag |
|
||||
| --- | --- | --- |
|
||||
| 推 `vX.Y.Z` tag(正式版) | `X.Y.Z` | `vX.Y.Z` |
|
||||
| `main` 上带 `[CI]` 的 push(开发镜像) | `X.Y.(Z+1)-dev.<N>-<提交前 7 位>` | `v` + 同一个版本 |
|
||||
|
||||
开发版本的基准是最近一个 `v*` tag(`X.Y.Z`),`N` 是这个 tag 之后的提交数(`git rev-list --count`),所以同一个提交算出来永远一样,也按语义化版本排在下一个正式版之前,例如 `0.4.1-dev.12-044ce0c`。算版本要拿得到 tag,所以开发镜像的 workflow 克隆时带 `tags: true`。镜像标签不带 `v`(和正式版一致),构建信息和签名清单里的 `tag` 带 `v`。
|
||||
|
||||
### main 开发镜像
|
||||
|
||||
`main` 上只有提交信息包含 `[CI]` 的 push 才构建镜像。合并 PR 时,请把 `[CI]` 放入 PR 标题或合并提交标题。Backend、Agent、Probe 的 Linux/amd64 镜像会并行构建,并推送到同一个 Zot Registry 下独立的 `moshiro-dev/` 仓库:
|
||||
`main` 上只有提交信息包含 `[CI]` 的 push 才构建镜像,并且要等上面的 Backend tests 和 `web-build` 都通过(提交信息写 `[SKIP TESTS]` 可以跳过测试)。合并 PR 时,请把 `[CI]` 放入 PR 标题或合并提交标题。Backend、Agent、Probe 的 Linux/amd64 镜像会并行构建,并推送到同一个 Zot Registry 下独立的 `moshiro-dev/` 仓库:
|
||||
|
||||
| 镜像 | 滚动标签 | 固定提交标签 |
|
||||
| 镜像 | 滚动标签 | 固定版本标签 |
|
||||
| --- | --- | --- |
|
||||
| Backend | `registry.oeo.one/moshiro-dev/moshiro-backend:latest` | `registry.oeo.one/moshiro-dev/moshiro-backend:dev-<12位SHA>` |
|
||||
| Agent | `registry.oeo.one/moshiro-dev/moshiro-agent:latest` | `registry.oeo.one/moshiro-dev/moshiro-agent:dev-<12位SHA>` |
|
||||
| Probe | `registry.oeo.one/moshiro-dev/moshiro-probe:latest` | `registry.oeo.one/moshiro-dev/moshiro-probe:dev-<12位SHA>` |
|
||||
| Backend | `registry.oeo.one/moshiro-dev/moshiro-backend:latest` | `registry.oeo.one/moshiro-dev/moshiro-backend:<版本>`(如 `0.4.1-dev.12-044ce0c`) |
|
||||
| Agent | `registry.oeo.one/moshiro-dev/moshiro-agent:latest` | `registry.oeo.one/moshiro-dev/moshiro-agent:<版本>` |
|
||||
| Probe | `registry.oeo.one/moshiro-dev/moshiro-probe:latest` | `registry.oeo.one/moshiro-dev/moshiro-probe:<版本>` |
|
||||
|
||||
Dev 镜像目前仅支持 amd64;Agent/Probe 在 `sdk:10.0-alpine-aot` 中构建 `linux-musl-x64` 产物,运行基底为 `runtime-deps:10.0-alpine`。它们不创建 Gitea Release,也不修改正式版 `moshiro/` 仓库中的标签。普通 main push 不会构建镜像。
|
||||
Dev 镜像目前仅支持 amd64;Agent/Probe 在 `sdk:10.0-alpine-aot` 中构建 `linux-musl-x64` 产物,运行基底为 `runtime-deps:10.0-alpine`。它们不创建 Gitea Release,也不修改正式版 `moshiro/` 仓库中的标签。普通 main push 不会构建镜像。节点和 Backend 判断自己是不是开发构建,看构建信息里的 tag 含 `-dev.`(旧的 `dev-<sha>`、`main-<sha>` 也认)。
|
||||
|
||||
### 正式版发布
|
||||
|
||||
推送匹配项目版本的 `vMAJOR.MINOR.PATCH` tag 会触发完整跨平台构建、正式 OCI 镜像推送和 Gitea Release。正式镜像使用 `registry.oeo.one/moshiro/` 路径;Agent、Probe 提供 amd64 与 arm64 多架构标签,稳定版本更新正式仓库自己的 `latest`。这与 `moshiro-dev/` 的 dev `latest` 相互独立。
|
||||
在 `main` 上推送 `vMAJOR.MINOR.PATCH` tag 会触发完整跨平台构建、正式 OCI 镜像推送和 Gitea Release,版本取自 tag,不需要先提交版本号。正式镜像使用 `registry.oeo.one/moshiro/` 路径;Agent、Probe 提供 amd64 与 arm64 多架构标签,稳定版本更新正式仓库自己的 `latest`。这与 `moshiro-dev/` 的 dev `latest` 相互独立。
|
||||
|
||||
Agent 和 Probe 镜像分别发布为 `registry.oeo.one/moshiro/moshiro-agent:<version>` 与 `registry.oeo.one/moshiro/moshiro-probe:<version>`,包含 amd64、arm64 多架构索引;也可指定 `:<version>-amd64` 或 `:<version>-arm64`。稳定版本同时更新 `latest`。镜像以非 root 用户(UID/GID 1654)运行,默认读取 `/etc/moshiro/agent.json` 或 `/etc/moshiro/probe.json`。使用 `packaging/compose/agent`、`probe` 下的标准 Compose 模板,配置和身份放在命名 volume 中;首次注册/导入、宿主指标挂载与更新器见下文。
|
||||
|
||||
@@ -261,7 +272,7 @@ chmod 600 .env && curl -fsSL 'https://panel.example.com/install/compose/probe.ya
|
||||
- 只读根文件系统、丢掉全部能力、`no-new-privileges`、命名卷;Linux 上用宿主网络(Agent 对外暴露端口,也靠它识别本机公网地址,并只读挂载 `/proc`、`/sys`、`/` 读主机指标)。**Agent 的 compose 只适用于 Linux**;Probe 在 macOS 和 Windows(Docker Desktop)上没有宿主网络,面板给的命令会在 `.env` 里写 `MOSHIRO_NETWORK_MODE=bridge`。
|
||||
- 身份和配置在命名卷 `moshiro-<role>-config` 里:镜像入口脚本(`packaging/container/entrypoint.sh`)第一次启动用 `MOSHIRO_SERVER`、`MOSHIRO_JOIN`(和信任根指纹、属主)注册并写配置,之后重启、换新镜像重建容器都不需要再给参数,所以注册成功之后可以把 `.env` 里的 `MOSHIRO_JOIN` 删掉。缺了信任根指纹或属主就不注册(只有还没有信任根的老面板才用 `MOSHIRO_ALLOW_NO_OWNER=1`)。
|
||||
- Podman 的开机自启要靠 `podman-restart.service`(`systemctl enable --now podman-restart`;rootless 用 `--user`,并 `loginctl enable-linger`);Docker 用 compose 里的 `restart: unless-stopped`。
|
||||
- **更新**:`podman compose pull && podman compose up -d`(Docker 用 `docker compose`),只重建镜像变了的容器,身份和配置不动,节点几十秒内重连。想固定版本,在 `.env` 里写 `MOSHIRO_VERSION=0.3.3`;想要更严,写成 `MOSHIRO_VERSION=0.3.3@sha256:<digest>`,digest 取自面板信任页或签名清单(那里有发布签名)。回滚就是改回旧版本再 `up -d`。
|
||||
- **更新**:`podman compose pull && podman compose up -d`(Docker 用 `docker compose`),只重建镜像变了的容器,身份和配置不动,节点几十秒内重连。想固定版本,在 `.env` 里写 `MOSHIRO_VERSION=<版本号>`;想要更严,写成 `MOSHIRO_VERSION=<版本号>@sha256:<digest>`,digest 取自面板信任页或签名清单(那里有发布签名)。回滚就是改回旧版本再 `up -d`。
|
||||
- **信任**:compose 来自面板或 CI 渠道,面板被攻破也改不了镜像地址;但客户端不再验发布签名,拉取靠 TLS 加「注册表可信」这个假设(文档里本来就把 CI、Gitea、注册表放在可信范围内)。compose 不会自动更新(见下节),也没有管理端的「更新」列和确认更新按钮。
|
||||
|
||||
**一行安装脚本(备用,Docker 或 Podman,Agent 和 Probe 共用)**:管理端的弹窗里折叠着一条旧的一行命令,先核对脚本哈希再执行,脚本向面板取签名清单、用内置发布公钥验签、按 digest 拉镜像:
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# 把面板给的 .env 内容存成 .env,再下载本文件为 compose.yaml
|
||||
# podman compose up -d # Docker 用 docker compose
|
||||
# 更新:podman compose pull && podman compose up -d (身份和配置在命名卷里,不会动)
|
||||
# 固定版本:在 .env 里写 MOSHIRO_VERSION=0.3.3;想要更严,写成 MOSHIRO_VERSION=0.3.3@sha256:<digest>。
|
||||
# 固定版本:在 .env 里写 MOSHIRO_VERSION=<版本号>;想要更严,写成 MOSHIRO_VERSION=<版本号>@sha256:<digest>。
|
||||
# .env 里的 MOSHIRO_SERVER、MOSHIRO_JOIN(只在第一次启动用来注册,之后可以删掉)、MOSHIRO_GENESIS、MOSHIRO_CONTROLLERS、MOSHIRO_NAME 原样传进容器。
|
||||
# 说明见 docs/ops/deployment.md。
|
||||
services:
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# 把面板给的 .env 内容存成 .env,再下载本文件为 compose.yaml
|
||||
# podman compose up -d # Docker 用 docker compose
|
||||
# 更新:podman compose pull && podman compose up -d (身份和配置在命名卷里,不会动)
|
||||
# 固定版本:在 .env 里写 MOSHIRO_VERSION=0.3.3;想要更严,写成 MOSHIRO_VERSION=0.3.3@sha256:<digest>。
|
||||
# 固定版本:在 .env 里写 MOSHIRO_VERSION=<版本号>;想要更严,写成 MOSHIRO_VERSION=<版本号>@sha256:<digest>。
|
||||
# macOS、Windows 的 Docker Desktop 没有宿主网络:面板给的 .env 里已经写了 MOSHIRO_NETWORK_MODE=bridge。
|
||||
# .env 里的 MOSHIRO_SERVER、MOSHIRO_JOIN(只在第一次启动用来注册,之后可以删掉)、MOSHIRO_GENESIS、MOSHIRO_CONTROLLERS、MOSHIRO_NAME 原样传进容器。
|
||||
# 说明见 docs/ops/deployment.md。
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
# loginctl enable-linger $USER # 退出登录后继续运行(需要管理员执行一次)
|
||||
# rootful:本文件放进 /etc/containers/systemd/,.env 内容存成 /etc/moshiro/agent.env,把下面的 EnvironmentFile 改成这个路径、
|
||||
# WantedBy 改成 multi-user.target,用 systemctl(不加 --user)。
|
||||
# 开发通道:把 Image 的 moshiro 换成 moshiro-dev。固定版本:把 :latest 换成 :0.3.3(固定之后更新不会换版本)。
|
||||
# 开发通道:把 Image 的 moshiro 换成 moshiro-dev。固定版本:把 :latest 换成 :<版本号>(固定之后更新不会换版本)。
|
||||
# 想要完全自动、不用在管理端点:另外启用 podman-auto-update.timer,并在 [Container] 里加 AutoUpdate=registry(Pull=always 也保留)。
|
||||
# 说明见 docs/ops/deployment.md。
|
||||
[Unit]
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
# loginctl enable-linger $USER # 退出登录后继续运行(需要管理员执行一次)
|
||||
# rootful:本文件放进 /etc/containers/systemd/,.env 内容存成 /etc/moshiro/probe.env,把下面的 EnvironmentFile 改成这个路径、
|
||||
# WantedBy 改成 multi-user.target,用 systemctl(不加 --user)。
|
||||
# 开发通道:把 Image 的 moshiro 换成 moshiro-dev。固定版本:把 :latest 换成 :0.3.3(固定之后更新不会换版本)。
|
||||
# 开发通道:把 Image 的 moshiro 换成 moshiro-dev。固定版本:把 :latest 换成 :<版本号>(固定之后更新不会换版本)。
|
||||
# 想要完全自动、不用在管理端点:另外启用 podman-auto-update.timer,并在 [Container] 里加 AutoUpdate=registry(Pull=always 也保留)。
|
||||
# 说明见 docs/ops/deployment.md。
|
||||
[Unit]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "moshiro-admin",
|
||||
"private": true,
|
||||
"version": "0.1.0",
|
||||
"version": "0.0.0-dev",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "moshiro-display",
|
||||
"private": true,
|
||||
"version": "0.1.0",
|
||||
"version": "0.0.0-dev",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
Generated
+4
-4
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "moshiro-web",
|
||||
"version": "0.4.0",
|
||||
"version": "0.0.0-dev",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "moshiro-web",
|
||||
"version": "0.4.0",
|
||||
"version": "0.0.0-dev",
|
||||
"workspaces": [
|
||||
"display",
|
||||
"admin"
|
||||
@@ -18,7 +18,7 @@
|
||||
},
|
||||
"admin": {
|
||||
"name": "moshiro-admin",
|
||||
"version": "0.1.0",
|
||||
"version": "0.0.0-dev",
|
||||
"dependencies": {
|
||||
"lucide-react": "^0.468.0",
|
||||
"react": "^19.2.8",
|
||||
@@ -38,7 +38,7 @@
|
||||
},
|
||||
"display": {
|
||||
"name": "moshiro-display",
|
||||
"version": "0.1.0",
|
||||
"version": "0.0.0-dev",
|
||||
"dependencies": {
|
||||
"lucide-react": "^0.468.0",
|
||||
"react": "^19.2.8",
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "moshiro-web",
|
||||
"private": true,
|
||||
"version": "0.4.0",
|
||||
"version": "0.0.0-dev",
|
||||
"workspaces": [
|
||||
"display",
|
||||
"admin"
|
||||
|
||||
Reference in new issue
Block a user