![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICN4ETMfdHLkVGepZ2XtxSZ6l2clJ3LcBnYldHL0FWby9mZvwVPrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdsAjMfd3bkFGazxCMx8VesATMfhHLlN3XnxCMz8FdsYkRGZkRG9lcvx2bjxSa2EWNhJTW1AlUxEFeVRUUfRHelRHL0EzXlpXazxyayFWbyVGdhd3LcV2Zh1Wa9M3clN2byBXLzN3btg3PwJWZ35CNykTOyE2MhJjMkVTN5cjZxYzXxAzM1UTMxMzLcFDMyIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjLyM3Lc9CX6MHc0RHaiojIsJye.webp)
前兩篇博文中提到Development,QA,Staging,Production四個環境,也說明了源代碼的分支和四個環境的對應關系,本篇博文聊一下,怎麼把源碼自動化釋出到對應的環境中。
市面上主流的DevOpt工具都支援這些功能,github,gitlab,都有CICD功能,當然,如果源碼伺服器是自己搭建的,也可以利用像Jenkins這類軟體來實作CICD,關于這些大衆工具,網上有很多教程式,這裡就不主要來分享了,本例是用.net core實作一個極簡的自動釋出工具——《MyCICD》。
說一下實作思路吧!
- clone 或 pull分支代碼
- publish
- run
是不是很簡單,上代碼吧
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
namespace MyCICD
{
class Program
{
static void Main(string[] args)
{
var processIDs = new int[0];
while (true)
{
if (Clone())
{
if (Publish(processIDs))
{
processIDs = Run();
}
}
Thread.Sleep(30000);
}
}
/// <summary>
/// git 克隆
/// </summary>
/// <returns></returns>
static bool Clone()
{
var gitLib = ConfigurationManager.AppSettings["GitLib"];
var sourcePath = ConfigurationManager.AppSettings["SourcePath"];
var sourceDir = $"{sourcePath.TrimEnd('/', '\\') }/{ Path.GetFileNameWithoutExtension(gitLib)} ";
//存在就拉取代碼,不存在就克隆
if (Directory.Exists(sourceDir))
{
return Pull(sourceDir);
}
else
{
return Clone(gitLib, sourceDir);
}
}
/// <summary>
/// 克隆項目代碼
/// </summary>
/// <param name="gitLib">git庫</param>
/// <param name="sourceDir">本地儲存路徑</param>
/// <returns></returns>
static bool Clone(string gitLib, string sourceDir)
{
Console.WriteLine("開始Clone");
var processStartInfo = new ProcessStartInfo("git", $"clone {gitLib} {sourceDir}") { RedirectStandardOutput = true };
var process = Process.Start(processStartInfo);
if (process == null)
{
Console.WriteLine("請确認是否安裝git");
return false;
}
else
{
using (var output = process.StandardOutput)
{
while (!output.EndOfStream)
{
Console.WriteLine(output.ReadLine());
}
if (!process.HasExited)
{
process.Kill();
}
}
Console.WriteLine($"執行時間 :{(process.ExitTime - process.StartTime).TotalMilliseconds} ms");
Console.WriteLine("結束Clone");
return process.ExitCode == 0;
}
}
/// <summary>
/// 拉取項目代碼
/// </summary>
/// <param name="sourceDir">源碼路徑</param>
/// <returns></returns>
static bool Pull(string sourceDir)
{
Console.WriteLine("開始Fetch");
var processStartInfo = new ProcessStartInfo("git", $"pull origin")
{
RedirectStandardOutput = true,
WorkingDirectory = sourceDir,
};
var process = Process.Start(processStartInfo);
using (var output = process.StandardOutput)
{
var resultBuilder = new StringBuilder();
while (!output.EndOfStream)
{
resultBuilder.AppendLine(output.ReadLine());
}
Console.WriteLine(resultBuilder);
if (!process.HasExited)
{
process.Kill();
}
if (resultBuilder.ToString() != "Already up to date.\r\n")
{
Console.WriteLine("結束Fetch");
return true;
}
else
{
Console.WriteLine("結束Fetch,遠端倉庫沒有更新");
return false;
}
}
}
#region 釋出項目
/// <summary>
/// 釋出項目
/// </summary>
/// <returns></returns>
static bool Publish(int[] processIDs)
{
Console.WriteLine("開始Publish");
var sourcePath = ConfigurationManager.AppSettings["SourcePath"];
var publishProject = ConfigurationManager.AppSettings["PublishProject"];
//找出要釋出的項目
var projectPathLists = publishProject.Split(",");
var projects = GetProjectsPath(sourcePath, projectPathLists);
var publishDir = $"{sourcePath}/publish";
var result = true;//如果有一個項目失敗,釋出就會失敗
//為了釋出,關閉之前運作中的程序
foreach (var processid in processIDs)
{
Process.GetProcessById(processid).Kill();
}
//釋出項目
foreach (var project in projects)
{
var processStartInfo = new ProcessStartInfo("dotnet", $"publish {project} -o {publishDir}/{Path.GetFileNameWithoutExtension(project)}") { RedirectStandardOutput = true };
var process = Process.Start(processStartInfo);
if (process == null)
{
Console.WriteLine("請确認是否安裝dotnet sdk");
return false;
}
else
{
using (var output = process.StandardOutput)
{
while (!output.EndOfStream)
{
Console.WriteLine(output.ReadLine());
}
if (!process.HasExited)
{
process.Kill();
}
}
Console.WriteLine($"執行時間 :{(process.ExitTime - process.StartTime).TotalMilliseconds} ms");
if (process.ExitCode != 0)
{
Console.WriteLine($"{Path.GetFileNameWithoutExtension(project)}釋出失敗");
}
result = result || process.ExitCode == 0;
}
}
Console.WriteLine("結束Publish");
return result;
}
/// <summary>
/// 查找項目
/// </summary>
/// <param name="sourcePath">源碼路徑</param>
/// <param name="projects">項目集</param>
/// <returns></returns>
static string[] GetProjectsPath(string sourcePath, string[] projects)
{
var paths = new List<string>();
foreach (var file in Directory.GetFiles(sourcePath))
{
if (projects.Contains(Path.GetFileName(file)))
{
paths.Add(file);
}
}
foreach (var dir in Directory.GetDirectories(sourcePath))
{
paths.AddRange(GetProjectsPath(dir, projects));
}
return paths.ToArray();
}
#endregion
#region 運作項目
/// <summary>
/// 運作項目
/// </summary>
/// <returns></returns>
static int[] Run()
{
Console.WriteLine("開始運作");
var sourcePath = ConfigurationManager.AppSettings["SourcePath"];
var publishDir = $"{sourcePath}/publish";
var proceddIDs = new List<int>();
foreach (var projectPath in Directory.GetDirectories(publishDir))
{
var processStartInfo = new ProcessStartInfo("dotnet", $"{Path.GetFileNameWithoutExtension(projectPath)}.dll")
{
RedirectStandardOutput = true,
WorkingDirectory = projectPath,
};
var process = Process.Start(processStartInfo);
proceddIDs.Add(process.Id);
}
Console.WriteLine("結束運作");
return proceddIDs.ToArray();
}
#endregion
}
}
App.config配置檔案
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<!--git庫相關:git庫路徑,clone後本地何存路徑-->
<add key="GitLib" value="https://github.com/axzxs2001/Asp.NetCoreExperiment.git"/>
<add key="SourcePath" value="e:/test/"/>
<!--dotnet釋出相關:要釋出的項目-->
<add key="PublishProject" value="AspNetCoreEnvironment.csproj,WebError.csproj"/>
</appSettings>
</configuration>
這個例子很簡單,隻支援在windows下運作,同時run起來的應用和MyCICD是在一個程序中,一但程序關閉,run的服務也就掉了,還有很多需要改進,如果有興趣,可以完善,比如可以跑大多個平台上(linux,docker,mac)下,也可以把MyCICD和運作的服務分離,程序間互不影響。
想要更快更友善的了解相關知識,可以關注微信公衆号