增加编译节点关系表,支持配置应用所对应的编译节点服务器

This commit is contained in:
智能大石头 2025-06-17 02:06:53 +08:00
parent f11f29ef84
commit 059101ede5
14 changed files with 1028 additions and 14 deletions

View File

@ -24,7 +24,7 @@ public class DeployWorker(StarFactory factory) : IHostedService
Name = "Deploy",
Code = set.Code,
Secret = set.Secret,
ProductCode = factory.AppId,
ProductCode = "StarDeploy",
Setting = set,
Tracer = factory.Tracer,

View File

@ -1,5 +1,4 @@
using System.Reflection;
using System.Xml;
using DeployAgent;
using DeployAgent.Commands;
using NewLife;

View File

@ -56,8 +56,9 @@
<Column Name="Urls" DataType="String" Description="服务地址。对外提供服务的域名端口地址自动生成nginx配置如https://sso.newlifex.com" />
<Column Name="Repository" DataType="String" ItemType="url" Length="200" Description="代码库。下载代码的位置" Category="编译参数" />
<Column Name="Branch" DataType="String" DefaultValue="master" Description="分支。默认master" Category="编译参数" />
<Column Name="ProjectPath" DataType="String" Description="项目路径。需要编译的项目路径" Category="编译参数" />
<Column Name="ProjectPath" DataType="String" Description="项目路径。需要编译的项目路径,相对于代码库根目录" Category="编译参数" />
<Column Name="ProjectKind" DataType="Int32" DefaultValue="1" Description="项目类型。默认dotnet" Type="Stardust.Models.ProjectKinds" Category="编译参数" />
<Column Name="BuildArgs" DataType="String" Length="200" Description="编译参数。编译项目时所需参数" Category="编译参数" />
<Column Name="PackageFilters" DataType="String" Description="打包过滤器。需要打包哪些文件,支持通配符,多项分号隔开" Category="编译参数" />
<Column Name="FileName" DataType="String" Description="文件。应用启动文件可直接使用zip包" Category="发布参数" />
<Column Name="Arguments" DataType="String" Length="500" Description="参数。启动应用的参数" Category="发布参数" />
@ -168,6 +169,31 @@
<Index Columns="NodeId,Id" />
</Indexes>
</Table>
<Table Name="AppBuildNode" Description="编译节点。应用部署集和编译节点的关系一个应用可有多个部署集如arm和x64在目标节点上发布该部署集对应的应用zip包">
<Columns>
<Column Name="Id" DataType="Int32" Identity="True" PrimaryKey="True" Description="编号" />
<Column Name="DeployId" ColumnName="AppId" DataType="Int32" Map="AppDeploy@Id@$" Description="应用部署集。对应AppDeploy" />
<Column Name="NodeId" DataType="Int32" Description="节点。节点服务器" />
<Column Name="Enable" DataType="Boolean" Description="启用" />
<Column Name="SourcePath" DataType="String" Description="源代码目录" />
<Column Name="PullCode" DataType="Boolean" Description="拉取源代码" />
<Column Name="BuildProject" DataType="Boolean" Description="编译项目" />
<Column Name="PackageOutput" DataType="Boolean" Description="打包输出" />
<Column Name="UploadPackage" DataType="Boolean" Description="上传应用包" />
<Column Name="TraceId" DataType="String" Description="追踪。最新一次查看采样可用于关联多个片段建立依赖关系随线程上下文、Http、Rpc传递" Category="扩展" />
<Column Name="CreateUserId" DataType="Int32" Description="创建人" Category="扩展" />
<Column Name="CreateTime" DataType="DateTime" Description="创建时间" Category="扩展" />
<Column Name="CreateIP" DataType="String" Description="创建地址" Category="扩展" />
<Column Name="UpdateUserId" DataType="Int32" Description="更新者" Category="扩展" />
<Column Name="UpdateTime" DataType="DateTime" Description="更新时间" Category="扩展" />
<Column Name="UpdateIP" DataType="String" Description="更新地址" Category="扩展" />
<Column Name="Remark" DataType="String" Length="500" Description="备注" Category="扩展" />
</Columns>
<Indexes>
<Index Columns="DeployId" />
<Index Columns="NodeId" />
</Indexes>
</Table>
<Table Name="Attachment" Description="附件。用于记录各系统模块使用的文件可以是Local/NAS/OSS等对应魔方附件表" ConnName="Cube">
<Columns>
<Column Name="Id" DataType="Int64" PrimaryKey="True" DataScale="time" Description="编号" />

View File

@ -222,7 +222,7 @@
<td></td>
<td></td>
<td></td>
<td>需要编译的项目路径</td>
<td>需要编译的项目路径,相对于代码库根目录</td>
</tr>
<tr>
@ -236,6 +236,17 @@
<td>默认dotnet</td>
</tr>
<tr>
<td>BuildArgs</td>
<td>编译参数</td>
<td>String</td>
<td>200</td>
<td></td>
<td></td>
<td></td>
<td>编译项目时所需参数</td>
</tr>
<tr>
<td>PackageFilters</td>
<td>打包过滤器</td>
@ -1169,6 +1180,210 @@
</tbody>
</table>
<br></br>
<h3>编译节点AppBuildNode</h3>
<table>
<thead>
<tr>
<th>名称</th>
<th>显示名</th>
<th>类型</th>
<th>长度</th>
<th>精度</th>
<th>主键</th>
<th>允许空</th>
<th>备注</th>
</tr>
</thead>
<tbody>
<tr>
<td>Id</td>
<td>编号</td>
<td>Int32</td>
<td></td>
<td></td>
<td title="自增">AI</td>
<td>N</td>
<td></td>
</tr>
<tr>
<td>AppId</td>
<td>应用部署集</td>
<td>Int32</td>
<td></td>
<td></td>
<td></td>
<td>N</td>
<td>对应AppDeploy</td>
</tr>
<tr>
<td>NodeId</td>
<td>节点</td>
<td>Int32</td>
<td></td>
<td></td>
<td></td>
<td>N</td>
<td>节点服务器</td>
</tr>
<tr>
<td>Enable</td>
<td>启用</td>
<td>Boolean</td>
<td></td>
<td></td>
<td></td>
<td>N</td>
<td></td>
</tr>
<tr>
<td>SourcePath</td>
<td>源代码目录</td>
<td>String</td>
<td>50</td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>PullCode</td>
<td>拉取源代码</td>
<td>Boolean</td>
<td></td>
<td></td>
<td></td>
<td>N</td>
<td></td>
</tr>
<tr>
<td>BuildProject</td>
<td>编译项目</td>
<td>Boolean</td>
<td></td>
<td></td>
<td></td>
<td>N</td>
<td></td>
</tr>
<tr>
<td>PackageOutput</td>
<td>打包输出</td>
<td>Boolean</td>
<td></td>
<td></td>
<td></td>
<td>N</td>
<td></td>
</tr>
<tr>
<td>UploadPackage</td>
<td>上传应用包</td>
<td>Boolean</td>
<td></td>
<td></td>
<td></td>
<td>N</td>
<td></td>
</tr>
<tr>
<td>TraceId</td>
<td>追踪</td>
<td>String</td>
<td>50</td>
<td></td>
<td></td>
<td></td>
<td>最新一次查看采样可用于关联多个片段建立依赖关系随线程上下文、Http、Rpc传递</td>
</tr>
<tr>
<td>CreateUserId</td>
<td>创建人</td>
<td>Int32</td>
<td></td>
<td></td>
<td></td>
<td>N</td>
<td></td>
</tr>
<tr>
<td>CreateTime</td>
<td>创建时间</td>
<td>DateTime</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>CreateIP</td>
<td>创建地址</td>
<td>String</td>
<td>50</td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>UpdateUserId</td>
<td>更新者</td>
<td>Int32</td>
<td></td>
<td></td>
<td></td>
<td>N</td>
<td></td>
</tr>
<tr>
<td>UpdateTime</td>
<td>更新时间</td>
<td>DateTime</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>UpdateIP</td>
<td>更新地址</td>
<td>String</td>
<td>50</td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Remark</td>
<td>备注</td>
<td>String</td>
<td>500</td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<br></br>
<h3>附件Attachment</h3>
<table>
<thead>

View File

@ -146,12 +146,12 @@ public partial class AppDeploy
public String Branch { get => _Branch; set { if (OnPropertyChanging("Branch", value)) { _Branch = value; OnPropertyChanged("Branch"); } } }
private String _ProjectPath;
/// <summary>项目路径。需要编译的项目路径</summary>
/// <summary>项目路径。需要编译的项目路径,相对于代码库根目录</summary>
[Category("编译参数")]
[DisplayName("项目路径")]
[Description("项目路径。需要编译的项目路径")]
[Description("项目路径。需要编译的项目路径,相对于代码库根目录")]
[DataObjectField(false, false, true, 50)]
[BindColumn("ProjectPath", "项目路径。需要编译的项目路径", "")]
[BindColumn("ProjectPath", "项目路径。需要编译的项目路径,相对于代码库根目录", "")]
public String ProjectPath { get => _ProjectPath; set { if (OnPropertyChanging("ProjectPath", value)) { _ProjectPath = value; OnPropertyChanged("ProjectPath"); } } }
private Stardust.Models.ProjectKinds _ProjectKind;
@ -163,6 +163,15 @@ public partial class AppDeploy
[BindColumn("ProjectKind", "项目类型。默认dotnet", "", DefaultValue = "1")]
public Stardust.Models.ProjectKinds ProjectKind { get => _ProjectKind; set { if (OnPropertyChanging("ProjectKind", value)) { _ProjectKind = value; OnPropertyChanged("ProjectKind"); } } }
private String _BuildArgs;
/// <summary>编译参数。编译项目时所需参数</summary>
[Category("编译参数")]
[DisplayName("编译参数")]
[Description("编译参数。编译项目时所需参数")]
[DataObjectField(false, false, true, 200)]
[BindColumn("BuildArgs", "编译参数。编译项目时所需参数", "")]
public String BuildArgs { get => _BuildArgs; set { if (OnPropertyChanging("BuildArgs", value)) { _BuildArgs = value; OnPropertyChanged("BuildArgs"); } } }
private String _PackageFilters;
/// <summary>打包过滤器。需要打包哪些文件,支持通配符,多项分号隔开</summary>
[Category("编译参数")]
@ -342,6 +351,7 @@ public partial class AppDeploy
"Branch" => _Branch,
"ProjectPath" => _ProjectPath,
"ProjectKind" => _ProjectKind,
"BuildArgs" => _BuildArgs,
"PackageFilters" => _PackageFilters,
"FileName" => _FileName,
"Arguments" => _Arguments,
@ -382,6 +392,7 @@ public partial class AppDeploy
case "Branch": _Branch = Convert.ToString(value); break;
case "ProjectPath": _ProjectPath = Convert.ToString(value); break;
case "ProjectKind": _ProjectKind = (Stardust.Models.ProjectKinds)value.ToInt(); break;
case "BuildArgs": _BuildArgs = Convert.ToString(value); break;
case "PackageFilters": _PackageFilters = Convert.ToString(value); break;
case "FileName": _FileName = Convert.ToString(value); break;
case "Arguments": _Arguments = Convert.ToString(value); break;
@ -468,12 +479,15 @@ public partial class AppDeploy
/// <summary>分支。默认master</summary>
public static readonly Field Branch = FindByName("Branch");
/// <summary>项目路径。需要编译的项目路径</summary>
/// <summary>项目路径。需要编译的项目路径,相对于代码库根目录</summary>
public static readonly Field ProjectPath = FindByName("ProjectPath");
/// <summary>项目类型。默认dotnet</summary>
public static readonly Field ProjectKind = FindByName("ProjectKind");
/// <summary>编译参数。编译项目时所需参数</summary>
public static readonly Field BuildArgs = FindByName("BuildArgs");
/// <summary>打包过滤器。需要打包哪些文件,支持通配符,多项分号隔开</summary>
public static readonly Field PackageFilters = FindByName("PackageFilters");
@ -576,12 +590,15 @@ public partial class AppDeploy
/// <summary>分支。默认master</summary>
public const String Branch = "Branch";
/// <summary>项目路径。需要编译的项目路径</summary>
/// <summary>项目路径。需要编译的项目路径,相对于代码库根目录</summary>
public const String ProjectPath = "ProjectPath";
/// <summary>项目类型。默认dotnet</summary>
public const String ProjectKind = "ProjectKind";
/// <summary>编译参数。编译项目时所需参数</summary>
public const String BuildArgs = "BuildArgs";
/// <summary>打包过滤器。需要打包哪些文件,支持通配符,多项分号隔开</summary>
public const String PackageFilters = "PackageFilters";

View File

@ -0,0 +1,171 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Script.Serialization;
using System.Xml.Serialization;
using NewLife;
using NewLife.Data;
using NewLife.Log;
using NewLife.Model;
using NewLife.Reflection;
using NewLife.Threading;
using NewLife.Web;
using Stardust.Data.Nodes;
using XCode;
using XCode.Cache;
using XCode.Configuration;
using XCode.DataAccessLayer;
using XCode.Membership;
using XCode.Shards;
namespace Stardust.Data.Deployment;
public partial class AppBuildNode : Entity<AppBuildNode>
{
#region
static AppBuildNode()
{
// 累加字段,生成 Update xx Set Count=Count+1234 Where xxx
//var df = Meta.Factory.AdditionalFields;
//df.Add(nameof(DeployId));
// 过滤器 UserModule、TimeModule、IPModule
Meta.Modules.Add(new UserModule { AllowEmpty = false });
Meta.Modules.Add<TimeModule>();
Meta.Modules.Add(new IPModule { AllowEmpty = false });
Meta.Modules.Add<TraceModule>();
// 实体缓存
// var ec = Meta.Cache;
// ec.Expire = 60;
}
/// <summary>验证并修补数据,返回验证结果,或者通过抛出异常的方式提示验证失败。</summary>
/// <param name="method">添删改方法</param>
public override Boolean Valid(DataMethod method)
{
//if (method == DataMethod.Delete) return true;
// 如果没有脏数据,则不需要进行任何处理
if (!HasDirty) return true;
// 建议先调用基类方法,基类方法会做一些统一处理
if (!base.Valid(method)) return false;
// 在新插入数据或者修改了指定字段时进行修正
// 处理当前已登录用户信息可以由UserModule过滤器代劳
/*var user = ManageProvider.User;
if (user != null)
{
if (method == DataMethod.Insert && !Dirtys[nameof(CreateUserId)]) CreateUserId = user.ID;
if (!Dirtys[nameof(UpdateUserId)]) UpdateUserId = user.ID;
}*/
//if (method == DataMethod.Insert && !Dirtys[nameof(CreateTime)]) CreateTime = DateTime.Now;
//if (!Dirtys[nameof(UpdateTime)]) UpdateTime = DateTime.Now;
//if (method == DataMethod.Insert && !Dirtys[nameof(CreateIP)]) CreateIP = ManageProvider.UserHost;
//if (!Dirtys[nameof(UpdateIP)]) UpdateIP = ManageProvider.UserHost;
return true;
}
///// <summary>首次连接数据库时初始化数据,仅用于实体类重载,用户不应该调用该方法</summary>
//[EditorBrowsable(EditorBrowsableState.Never)]
//protected override void InitData()
//{
// // InitData一般用于当数据表没有数据时添加一些默认数据该实体类的任何第一次数据库操作都会触发该方法默认异步调用
// if (Meta.Session.Count > 0) return;
// if (XTrace.Debug) XTrace.WriteLine("开始初始化AppBuildNode[编译节点]数据……");
// var entity = new AppBuildNode();
// entity.DeployName = "abc";
// entity.DeployId = 0;
// entity.NodeId = 0;
// entity.Enable = true;
// entity.SourcePath = "abc";
// entity.PullCode = true;
// entity.BuildProject = true;
// entity.PackageOutput = true;
// entity.UploadPackage = true;
// entity.Insert();
// if (XTrace.Debug) XTrace.WriteLine("完成初始化AppBuildNode[编译节点]数据!");
//}
///// <summary>已重载。基类先调用Valid(true)验证数据然后在事务保护内调用OnInsert</summary>
///// <returns></returns>
//public override Int32 Insert()
//{
// return base.Insert();
//}
///// <summary>已重载。在事务保护范围内处理业务位于Valid之后</summary>
///// <returns></returns>
//protected override Int32 OnDelete()
//{
// return base.OnDelete();
//}
#endregion
#region
/// <summary>节点</summary>
[XmlIgnore, ScriptIgnore, IgnoreDataMember]
public Node Node => Extends.Get(nameof(Node), k => Node.FindByID(NodeId));
/// <summary>节点</summary>
[Map(__.NodeId)]
public String NodeName => Node?.Name;
#endregion
#region
/// <summary>高级查询</summary>
/// <param name="deployId">应用部署集。对应AppDeploy</param>
/// <param name="nodeId">节点。节点服务器</param>
/// <param name="pullCode">拉取源代码</param>
/// <param name="buildProject">编译项目</param>
/// <param name="packageOutput">打包输出</param>
/// <param name="uploadPackage">上传应用包</param>
/// <param name="enable">启用</param>
/// <param name="start">更新时间开始</param>
/// <param name="end">更新时间结束</param>
/// <param name="key">关键字</param>
/// <param name="page">分页参数信息。可携带统计和数据权限扩展查询等信息</param>
/// <returns>实体列表</returns>
public static IList<AppBuildNode> Search(Int32 deployId, Int32 nodeId, Boolean? pullCode, Boolean? buildProject, Boolean? packageOutput, Boolean? uploadPackage, Boolean? enable, DateTime start, DateTime end, String key, PageParameter page)
{
var exp = new WhereExpression();
if (deployId >= 0) exp &= _.DeployId == deployId;
if (nodeId >= 0) exp &= _.NodeId == nodeId;
if (pullCode != null) exp &= _.PullCode == pullCode;
if (buildProject != null) exp &= _.BuildProject == buildProject;
if (packageOutput != null) exp &= _.PackageOutput == packageOutput;
if (uploadPackage != null) exp &= _.UploadPackage == uploadPackage;
if (enable != null) exp &= _.Enable == enable;
exp &= _.UpdateTime.Between(start, end);
if (!key.IsNullOrEmpty()) exp &= SearchWhereByKeys(key);
return FindAll(exp, page);
}
// Select Count(Id) as Id,Category From AppBuildNode Where CreateTime>'2020-01-24 00:00:00' Group By Category Order By Id Desc limit 20
//static readonly FieldCache<AppBuildNode> _CategoryCache = new(nameof(Category))
//{
//Where = _.CreateTime > DateTime.Today.AddDays(-30) & Expression.Empty
//};
///// <summary>获取类别列表字段缓存10分钟分组统计数据最多的前20种用于魔方前台下拉选择</summary>
///// <returns></returns>
//public static IDictionary<String, String> GetCategoryList() => _CategoryCache.FindAllName();
#endregion
#region
#endregion
}

View File

@ -0,0 +1,393 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.Serialization;
using System.Web.Script.Serialization;
using System.Xml.Serialization;
using NewLife;
using NewLife.Data;
using XCode;
using XCode.Cache;
using XCode.Configuration;
using XCode.DataAccessLayer;
namespace Stardust.Data.Deployment;
/// <summary>编译节点。应用部署集和编译节点的关系一个应用可有多个部署集如arm和x64在目标节点上发布该部署集对应的应用zip包</summary>
[Serializable]
[DataObject]
[Description("编译节点。应用部署集和编译节点的关系一个应用可有多个部署集如arm和x64在目标节点上发布该部署集对应的应用zip包")]
[BindIndex("IX_AppBuildNode_DeployId", false, "DeployId")]
[BindIndex("IX_AppBuildNode_NodeId", false, "NodeId")]
[BindTable("AppBuildNode", Description = "编译节点。应用部署集和编译节点的关系一个应用可有多个部署集如arm和x64在目标节点上发布该部署集对应的应用zip包", ConnName = "Stardust", DbType = DatabaseType.None)]
public partial class AppBuildNode
{
#region
private Int32 _Id;
/// <summary>编号</summary>
[DisplayName("编号")]
[Description("编号")]
[DataObjectField(true, true, false, 0)]
[BindColumn("Id", "编号", "")]
public Int32 Id { get => _Id; set { if (OnPropertyChanging("Id", value)) { _Id = value; OnPropertyChanged("Id"); } } }
private Int32 _DeployId;
/// <summary>应用部署集。对应AppDeploy</summary>
[DisplayName("应用部署集")]
[Description("应用部署集。对应AppDeploy")]
[DataObjectField(false, false, false, 0)]
[BindColumn("AppId", "应用部署集。对应AppDeploy", "")]
public Int32 DeployId { get => _DeployId; set { if (OnPropertyChanging("DeployId", value)) { _DeployId = value; OnPropertyChanged("DeployId"); } } }
private Int32 _NodeId;
/// <summary>节点。节点服务器</summary>
[DisplayName("节点")]
[Description("节点。节点服务器")]
[DataObjectField(false, false, false, 0)]
[BindColumn("NodeId", "节点。节点服务器", "")]
public Int32 NodeId { get => _NodeId; set { if (OnPropertyChanging("NodeId", value)) { _NodeId = value; OnPropertyChanged("NodeId"); } } }
private Boolean _Enable;
/// <summary>启用</summary>
[DisplayName("启用")]
[Description("启用")]
[DataObjectField(false, false, false, 0)]
[BindColumn("Enable", "启用", "")]
public Boolean Enable { get => _Enable; set { if (OnPropertyChanging("Enable", value)) { _Enable = value; OnPropertyChanged("Enable"); } } }
private String _SourcePath;
/// <summary>源代码目录</summary>
[DisplayName("源代码目录")]
[Description("源代码目录")]
[DataObjectField(false, false, true, 50)]
[BindColumn("SourcePath", "源代码目录", "")]
public String SourcePath { get => _SourcePath; set { if (OnPropertyChanging("SourcePath", value)) { _SourcePath = value; OnPropertyChanged("SourcePath"); } } }
private Boolean _PullCode;
/// <summary>拉取源代码</summary>
[DisplayName("拉取源代码")]
[Description("拉取源代码")]
[DataObjectField(false, false, false, 0)]
[BindColumn("PullCode", "拉取源代码", "")]
public Boolean PullCode { get => _PullCode; set { if (OnPropertyChanging("PullCode", value)) { _PullCode = value; OnPropertyChanged("PullCode"); } } }
private Boolean _BuildProject;
/// <summary>编译项目</summary>
[DisplayName("编译项目")]
[Description("编译项目")]
[DataObjectField(false, false, false, 0)]
[BindColumn("BuildProject", "编译项目", "")]
public Boolean BuildProject { get => _BuildProject; set { if (OnPropertyChanging("BuildProject", value)) { _BuildProject = value; OnPropertyChanged("BuildProject"); } } }
private Boolean _PackageOutput;
/// <summary>打包输出</summary>
[DisplayName("打包输出")]
[Description("打包输出")]
[DataObjectField(false, false, false, 0)]
[BindColumn("PackageOutput", "打包输出", "")]
public Boolean PackageOutput { get => _PackageOutput; set { if (OnPropertyChanging("PackageOutput", value)) { _PackageOutput = value; OnPropertyChanged("PackageOutput"); } } }
private Boolean _UploadPackage;
/// <summary>上传应用包</summary>
[DisplayName("上传应用包")]
[Description("上传应用包")]
[DataObjectField(false, false, false, 0)]
[BindColumn("UploadPackage", "上传应用包", "")]
public Boolean UploadPackage { get => _UploadPackage; set { if (OnPropertyChanging("UploadPackage", value)) { _UploadPackage = value; OnPropertyChanged("UploadPackage"); } } }
private String _TraceId;
/// <summary>追踪。最新一次查看采样可用于关联多个片段建立依赖关系随线程上下文、Http、Rpc传递</summary>
[Category("扩展")]
[DisplayName("追踪")]
[Description("追踪。最新一次查看采样可用于关联多个片段建立依赖关系随线程上下文、Http、Rpc传递")]
[DataObjectField(false, false, true, 50)]
[BindColumn("TraceId", "追踪。最新一次查看采样可用于关联多个片段建立依赖关系随线程上下文、Http、Rpc传递", "")]
public String TraceId { get => _TraceId; set { if (OnPropertyChanging("TraceId", value)) { _TraceId = value; OnPropertyChanged("TraceId"); } } }
private Int32 _CreateUserId;
/// <summary>创建人</summary>
[Category("扩展")]
[DisplayName("创建人")]
[Description("创建人")]
[DataObjectField(false, false, false, 0)]
[BindColumn("CreateUserId", "创建人", "")]
public Int32 CreateUserId { get => _CreateUserId; set { if (OnPropertyChanging("CreateUserId", value)) { _CreateUserId = value; OnPropertyChanged("CreateUserId"); } } }
private DateTime _CreateTime;
/// <summary>创建时间</summary>
[Category("扩展")]
[DisplayName("创建时间")]
[Description("创建时间")]
[DataObjectField(false, false, true, 0)]
[BindColumn("CreateTime", "创建时间", "")]
public DateTime CreateTime { get => _CreateTime; set { if (OnPropertyChanging("CreateTime", value)) { _CreateTime = value; OnPropertyChanged("CreateTime"); } } }
private String _CreateIP;
/// <summary>创建地址</summary>
[Category("扩展")]
[DisplayName("创建地址")]
[Description("创建地址")]
[DataObjectField(false, false, true, 50)]
[BindColumn("CreateIP", "创建地址", "")]
public String CreateIP { get => _CreateIP; set { if (OnPropertyChanging("CreateIP", value)) { _CreateIP = value; OnPropertyChanged("CreateIP"); } } }
private Int32 _UpdateUserId;
/// <summary>更新者</summary>
[Category("扩展")]
[DisplayName("更新者")]
[Description("更新者")]
[DataObjectField(false, false, false, 0)]
[BindColumn("UpdateUserId", "更新者", "")]
public Int32 UpdateUserId { get => _UpdateUserId; set { if (OnPropertyChanging("UpdateUserId", value)) { _UpdateUserId = value; OnPropertyChanged("UpdateUserId"); } } }
private DateTime _UpdateTime;
/// <summary>更新时间</summary>
[Category("扩展")]
[DisplayName("更新时间")]
[Description("更新时间")]
[DataObjectField(false, false, true, 0)]
[BindColumn("UpdateTime", "更新时间", "")]
public DateTime UpdateTime { get => _UpdateTime; set { if (OnPropertyChanging("UpdateTime", value)) { _UpdateTime = value; OnPropertyChanged("UpdateTime"); } } }
private String _UpdateIP;
/// <summary>更新地址</summary>
[Category("扩展")]
[DisplayName("更新地址")]
[Description("更新地址")]
[DataObjectField(false, false, true, 50)]
[BindColumn("UpdateIP", "更新地址", "")]
public String UpdateIP { get => _UpdateIP; set { if (OnPropertyChanging("UpdateIP", value)) { _UpdateIP = value; OnPropertyChanged("UpdateIP"); } } }
private String _Remark;
/// <summary>备注</summary>
[Category("扩展")]
[DisplayName("备注")]
[Description("备注")]
[DataObjectField(false, false, true, 500)]
[BindColumn("Remark", "备注", "")]
public String Remark { get => _Remark; set { if (OnPropertyChanging("Remark", value)) { _Remark = value; OnPropertyChanged("Remark"); } } }
#endregion
#region /
/// <summary>获取/设置 字段值</summary>
/// <param name="name">字段名</param>
/// <returns></returns>
public override Object this[String name]
{
get => name switch
{
"Id" => _Id,
"DeployId" => _DeployId,
"NodeId" => _NodeId,
"Enable" => _Enable,
"SourcePath" => _SourcePath,
"PullCode" => _PullCode,
"BuildProject" => _BuildProject,
"PackageOutput" => _PackageOutput,
"UploadPackage" => _UploadPackage,
"TraceId" => _TraceId,
"CreateUserId" => _CreateUserId,
"CreateTime" => _CreateTime,
"CreateIP" => _CreateIP,
"UpdateUserId" => _UpdateUserId,
"UpdateTime" => _UpdateTime,
"UpdateIP" => _UpdateIP,
"Remark" => _Remark,
_ => base[name]
};
set
{
switch (name)
{
case "Id": _Id = value.ToInt(); break;
case "DeployId": _DeployId = value.ToInt(); break;
case "NodeId": _NodeId = value.ToInt(); break;
case "Enable": _Enable = value.ToBoolean(); break;
case "SourcePath": _SourcePath = Convert.ToString(value); break;
case "PullCode": _PullCode = value.ToBoolean(); break;
case "BuildProject": _BuildProject = value.ToBoolean(); break;
case "PackageOutput": _PackageOutput = value.ToBoolean(); break;
case "UploadPackage": _UploadPackage = value.ToBoolean(); break;
case "TraceId": _TraceId = Convert.ToString(value); break;
case "CreateUserId": _CreateUserId = value.ToInt(); break;
case "CreateTime": _CreateTime = value.ToDateTime(); break;
case "CreateIP": _CreateIP = Convert.ToString(value); break;
case "UpdateUserId": _UpdateUserId = value.ToInt(); break;
case "UpdateTime": _UpdateTime = value.ToDateTime(); break;
case "UpdateIP": _UpdateIP = Convert.ToString(value); break;
case "Remark": _Remark = Convert.ToString(value); break;
default: base[name] = value; break;
}
}
}
#endregion
#region
/// <summary>应用部署集</summary>
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
public AppDeploy Deploy => Extends.Get(nameof(Deploy), k => AppDeploy.FindById(DeployId));
/// <summary>应用部署集</summary>
[Map(nameof(DeployId), typeof(AppDeploy), "Id")]
public String DeployName => Deploy?.ToString();
#endregion
#region
/// <summary>根据编号查找</summary>
/// <param name="id">编号</param>
/// <returns>实体对象</returns>
public static AppBuildNode FindById(Int32 id)
{
if (id < 0) return null;
// 实体缓存
if (Meta.Session.Count < 1000) return Meta.Cache.Find(e => e.Id == id);
// 单对象缓存
return Meta.SingleCache[id];
//return Find(_.Id == id);
}
/// <summary>根据应用部署集查找</summary>
/// <param name="deployId">应用部署集</param>
/// <returns>实体列表</returns>
public static IList<AppBuildNode> FindAllByDeployId(Int32 deployId)
{
if (deployId < 0) return [];
// 实体缓存
if (Meta.Session.Count < 1000) return Meta.Cache.FindAll(e => e.DeployId == deployId);
return FindAll(_.DeployId == deployId);
}
/// <summary>根据节点查找</summary>
/// <param name="nodeId">节点</param>
/// <returns>实体列表</returns>
public static IList<AppBuildNode> FindAllByNodeId(Int32 nodeId)
{
if (nodeId < 0) return [];
// 实体缓存
if (Meta.Session.Count < 1000) return Meta.Cache.FindAll(e => e.NodeId == nodeId);
return FindAll(_.NodeId == nodeId);
}
#endregion
#region
/// <summary>取得编译节点字段信息的快捷方式</summary>
public partial class _
{
/// <summary>编号</summary>
public static readonly Field Id = FindByName("Id");
/// <summary>应用部署集。对应AppDeploy</summary>
public static readonly Field DeployId = FindByName("DeployId");
/// <summary>节点。节点服务器</summary>
public static readonly Field NodeId = FindByName("NodeId");
/// <summary>启用</summary>
public static readonly Field Enable = FindByName("Enable");
/// <summary>源代码目录</summary>
public static readonly Field SourcePath = FindByName("SourcePath");
/// <summary>拉取源代码</summary>
public static readonly Field PullCode = FindByName("PullCode");
/// <summary>编译项目</summary>
public static readonly Field BuildProject = FindByName("BuildProject");
/// <summary>打包输出</summary>
public static readonly Field PackageOutput = FindByName("PackageOutput");
/// <summary>上传应用包</summary>
public static readonly Field UploadPackage = FindByName("UploadPackage");
/// <summary>追踪。最新一次查看采样可用于关联多个片段建立依赖关系随线程上下文、Http、Rpc传递</summary>
public static readonly Field TraceId = FindByName("TraceId");
/// <summary>创建人</summary>
public static readonly Field CreateUserId = FindByName("CreateUserId");
/// <summary>创建时间</summary>
public static readonly Field CreateTime = FindByName("CreateTime");
/// <summary>创建地址</summary>
public static readonly Field CreateIP = FindByName("CreateIP");
/// <summary>更新者</summary>
public static readonly Field UpdateUserId = FindByName("UpdateUserId");
/// <summary>更新时间</summary>
public static readonly Field UpdateTime = FindByName("UpdateTime");
/// <summary>更新地址</summary>
public static readonly Field UpdateIP = FindByName("UpdateIP");
/// <summary>备注</summary>
public static readonly Field Remark = FindByName("Remark");
static Field FindByName(String name) => Meta.Table.FindByName(name);
}
/// <summary>取得编译节点字段名称的快捷方式</summary>
public partial class __
{
/// <summary>编号</summary>
public const String Id = "Id";
/// <summary>应用部署集。对应AppDeploy</summary>
public const String DeployId = "DeployId";
/// <summary>节点。节点服务器</summary>
public const String NodeId = "NodeId";
/// <summary>启用</summary>
public const String Enable = "Enable";
/// <summary>源代码目录</summary>
public const String SourcePath = "SourcePath";
/// <summary>拉取源代码</summary>
public const String PullCode = "PullCode";
/// <summary>编译项目</summary>
public const String BuildProject = "BuildProject";
/// <summary>打包输出</summary>
public const String PackageOutput = "PackageOutput";
/// <summary>上传应用包</summary>
public const String UploadPackage = "UploadPackage";
/// <summary>追踪。最新一次查看采样可用于关联多个片段建立依赖关系随线程上下文、Http、Rpc传递</summary>
public const String TraceId = "TraceId";
/// <summary>创建人</summary>
public const String CreateUserId = "CreateUserId";
/// <summary>创建时间</summary>
public const String CreateTime = "CreateTime";
/// <summary>创建地址</summary>
public const String CreateIP = "CreateIP";
/// <summary>更新者</summary>
public const String UpdateUserId = "UpdateUserId";
/// <summary>更新时间</summary>
public const String UpdateTime = "UpdateTime";
/// <summary>更新地址</summary>
public const String UpdateIP = "UpdateIP";
/// <summary>备注</summary>
public const String Remark = "Remark";
}
#endregion
}

View File

@ -377,7 +377,7 @@ public partial class Node : Entity<Node>
{
var exp = new WhereExpression();
if (global != null)
if (projectId > 0 && global != null)
{
// 找到全局项目,然后再找到所有节点。如果项目不存在,则也不会有节点
var prjs = GalaxyProject.FindAllWithCache().Where(e => e.IsGlobal == global.Value).Select(e => e.Id).ToList();
@ -386,7 +386,7 @@ public partial class Node : Entity<Node>
exp &= _.ProjectId.In(prjs);
}
else if (projectId >= 0)
else if (projectId > 0)
exp &= _.ProjectId == projectId;
if (!category.IsNullOrEmpty()) exp &= _.Category == category | _.Category.IsNullOrEmpty();

View File

@ -1,5 +1,7 @@
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using NewLife;
using NewLife.Remoting;
using NewLife.Remoting.Extensions;
using NewLife.Serialization;
using Stardust.Data.Deployment;
@ -156,6 +158,49 @@ public class DeployController : BaseController
[HttpPost]
public Int32 Ping([FromBody] AppInfo inf) => _deployService.Ping(_node, inf, UserHost);
/// <summary>获取分配到本节点的应用发布任务</summary>
public BuildTask GetBuildTask(Int32 deployId, String deployName, String appName)
{
return null;
}
/// <summary>更新编译任务</summary>
/// <param name="result"></param>
[HttpPost]
public Int32 UpdateBuildTask(BuildResult result)
{
var ver = AppDeployVersion.FindById(result.Id)
?? throw new ArgumentNullException(nameof(result));
if (!result.CommitId.IsNullOrEmpty()) ver.CommitId = result.CommitId;
if (!result.CommitLog.IsNullOrEmpty()) ver.CommitLog = result.CommitLog;
if (result.CommitTime.Year > 2000) ver.CommitTime = result.CommitTime;
if (!result.Progress.IsNullOrEmpty()) ver.Progress = result.Progress;
return ver.Update();
}
/// <summary>上传编译任务结果文件</summary>
[HttpPost]
public String UploadBuildFile(Int32 taskId, [FromForm] IFormFile file)
{
var ver = AppDeployVersion.FindById(taskId);
if (ver == null) throw new ArgumentNullException(nameof(taskId));
//// 仅支持部分包和标准包
//if (info.Mode > DeployModes.Standard) throw new ApiException(400, "仅支持部分包和标准包!");
//// 仅支持覆盖文件
//if (info.Overwrite.IsNullOrEmpty()) throw new ApiException(400, "请指定覆盖文件!");
// 保存应用发布信息
var rs = 0;
//var rs = _deployService.UploadBuildTask(_node, info, UserHost);
//WriteHistory(info.AppId, nameof(UploadBuildTask), rs > 0, info.ToJson());
return rs > 0 ? "ok" : "fail";
}
#region
private void WriteHistory(Int32 appId, String action, Boolean success, String remark) => _deployService.WriteHistory(appId, _node?.ID ?? 0, action, success, remark, UserHost);
#endregion

View File

@ -0,0 +1,91 @@
using Microsoft.AspNetCore.Mvc;
using NewLife;
using NewLife.Cube;
using NewLife.Cube.Extensions;
using NewLife.Cube.ViewModels;
using NewLife.Web;
using Stardust.Data.Deployment;
using XCode.Membership;
namespace Stardust.Web.Areas.Deployment.Controllers;
/// <summary>编译节点。应用部署集和编译节点的关系一个应用可有多个部署集如arm和x64在目标节点上发布该部署集对应的应用zip包</summary>
[Menu(20, true, Icon = "fa-table")]
[DeploymentArea]
public class AppBuildNodeController : EntityController<AppBuildNode>
{
static AppBuildNodeController()
{
LogOnChange = true;
AddFormFields.RemoveCreateField();
ListFields.RemoveCreateField().RemoveRemarkField();
ListFields.TraceUrl("TraceId");
{
var df = ListFields.GetField("DeployName") as ListField;
df.Url = "/Deployment/AppDeploy?deployId={DeployId}";
}
{
var df = ListFields.AddListField("BuildUpload", null, "Enable");
df.DisplayName = "编译上传";
df.Url = "/Deployment/AppBuildNode/Operate?Id={Id}&act=Build-Upload";
df.DataAction = "action";
}
{
var df = ListFields.AddListField("PackageUpload", null, "Enable");
df.DisplayName = "打包上传";
df.Url = "/Deployment/AppBuildNode/Operate?Id={Id}&act=Package-Upload";
df.DataAction = "action";
}
{
var df = AddFormFields.GetField("NodeName") as FormField;
df.GroupView = "_Form_SelectNode";
}
{
var df = EditFormFields.GetField("NodeName") as FormField;
df.GroupView = "_Form_SelectNode";
}
{
var df = DetailFields.GetField("NodeName") as FormField;
df.GroupView = "_Form_SelectNode";
}
}
/// <summary>高级搜索。列表页查询、导出Excel、导出Json、分享页等使用</summary>
/// <param name="p">分页器。包含分页排序参数以及Http请求参数</param>
/// <returns></returns>
protected override IEnumerable<AppBuildNode> Search(Pager p)
{
var deployId = p["deployId"].ToInt(-1);
var nodeId = p["nodeId"].ToInt(-1);
var pullCode = p["pullCode"]?.ToBoolean();
var buildProject = p["buildProject"]?.ToBoolean();
var packageOutput = p["packageOutput"]?.ToBoolean();
var uploadPackage = p["uploadPackage"]?.ToBoolean();
var enable = p["enable"]?.ToBoolean();
var start = p["dtStart"].ToDateTime();
var end = p["dtEnd"].ToDateTime();
return AppBuildNode.Search(deployId, nodeId, pullCode, buildProject, packageOutput, uploadPackage, enable, start, end, p["Q"], p);
}
/// <summary>执行操作</summary>
/// <param name="act"></param>
/// <param name="id"></param>
/// <returns></returns>
[EntityAuthorize(PermissionFlags.Update)]
public async Task<ActionResult> Operate(String act, Int32 id)
{
var dn = AppDeployNode.FindById(id);
if (dn == null || dn.Node == null || dn.Deploy == null) return Json(500, $"[{id}]不存在");
var deployName = dn.DeployName;
if (deployName.IsNullOrEmpty()) deployName = dn.Deploy?.Name;
//await _deployService.Control(dn.Deploy, dn, act, UserHost, 0, 0);
return JsonRefresh($"在节点[{dn.NodeName}]上对应用[{deployName}]执行[{act}]操作", 1);
}
}

View File

@ -15,8 +15,6 @@ namespace Stardust.Web.Areas.Deployment.Controllers;
[Menu(90)]
public class AppDeployController : EntityController<AppDeploy>
{
//private readonly StarFactory _starFactory;
static AppDeployController()
{
ListFields.RemoveCreateField();
@ -45,6 +43,11 @@ public class AppDeployController : EntityController<AppDeploy>
df.DisplayName = "部署节点";
df.Url = "/Deployment/AppDeployNode?deployId={Id}";
}
{
var df = ListFields.AddListField("BuildNode", null, "Nodes") as ListField;
df.DisplayName = "编译节点";
df.Url = "/Deployment/AppBuildNode?deployId={Id}";
}
{
var df = ListFields.GetField("Version") as ListField;
df.Header = "版本";

View File

@ -0,0 +1,23 @@
@model EntityField
@using NewLife;
@using NewLife.Cube.ViewModels
@using Stardust.Data.Deployment
@using XCode;
@using XCode.Configuration;
@{
var entity = Model.Entity as AppBuildNode;
var field = Model.Field;
// var projectId = entity.Deploy?.ProjectId ?? 0;
var projectId = -1;
var set = NewLife.Cube.CubeSetting.Current;
var cls = set.FormGroupClass;
if (cls.IsNullOrEmpty()) { cls = "form-group col-xs-12 col-sm-6 col-lg-4"; }
}
<div class="@cls">
<label class="control-label col-xs-3 col-sm-3">节点</label>
<div class="input-group col-xs-9 col-sm-9">
@await Html.PartialAsync("_SelectNode", new SelectNodeModel { Id = "nodeId", NodeId = entity.NodeId, ProjectId = projectId, Product = "StarDeploy" })
</div>
</div>

View File

@ -0,0 +1,20 @@
namespace Stardust.Models;
/// <summary>构建结果</summary>
public class BuildResult
{
/// <summary>构建任务ID</summary>
public Int32 Id { get; set; }
/// <summary>提交标识</summary>
public String? CommitId { get; set; }
/// <summary>提交记录</summary>
public String? CommitLog { get; set; }
/// <summary>提交时间</summary>
public DateTime CommitTime { get; set; }
/// <summary>发布进度</summary>
public String? Progress { get; set; }
}

View File

@ -0,0 +1,11 @@
namespace Stardust.Models;
/// <summary>构建任务</summary>
public class BuildTask
{
/// <summary>构建任务ID</summary>
public Int32 Id { get; set; }
/// <summary>应用ID</summary>
public String Name { get; set; } = String.Empty;
}