Several Fixes and improvements.
ln.build build job pending

master
Harald Wolff 2020-11-28 01:08:49 +01:00
parent 9885e21d60
commit 8455a2dad4
8 changed files with 131 additions and 57 deletions

View File

@ -13,8 +13,7 @@ namespace ln.build.server
class Program
{
static Pool pool = new Pool(2);
static CIService CIService;
static HttpResponse WebHookRequest(HttpRoutingContext context, HttpRequest request)
{
HttpResponse response = new HttpResponse(request);
@ -32,28 +31,24 @@ namespace ln.build.server
{
try
{
string repoName = message["repository"]["name"].ToNative().ToString();
string cloneUrl = message["repository"]["clone_url"].ToNative().ToString();
string notifyEmail = message["pusher"]["email"].ToNative().ToString();
foreach (JSONValue commit in (message["commits"] as JSONArray).Children)
{
string commitID = commit["id"].ToNative().ToString();
Logging.Log("Received CI request of repository {0} for commit {1}", cloneUrl, commitID);
Logging.Log("Received CI request for repository {2} [{0}] for the commit {1}", cloneUrl, commitID, repoName);
CIJob job = new CIJob(repoName, cloneUrl, commitID, notifyEmail);
job.SetVariable("REPO_OWNER", message["repository"]["owner"]["username"].ToNative().ToString());
job.SetVariable("REPO_NAME", message["repository"]["name"].ToNative().ToString());
job.SetVariable("COMMIT_ID", commitID);
CIJob job = new CIJob(cloneUrl)
.SetVariable("REPO_OWNER", message["repository"]["owner"]["username"].ToNative().ToString())
.SetVariable("REPO_NAME", message["repository"]["name"].ToNative().ToString())
.SetVariable("COMMIT_ID", commitID)
.SetVariable("NOTIFY", message["pusher"]["email"].ToNative().ToString());
job.UpdateBuildState(BuildState.PENDING);
pool.Enqueue(job);
CIService.Enqueue(job);
}
} catch (Exception e)
{
response.StatusCode = 500;
@ -74,15 +69,17 @@ namespace ln.build.server
static void Main(string[] args)
{
CommandRunner.DefaultThrow = CRThrow.NEGATIVE;
CIService = new CIService();
CIService.Start();
CIService.AddPipeline(new DotNetPipeLine());
SimpleRouter genericRouter = new SimpleRouter();
genericRouter.AddSimpleRoute("/", WebHookRequest);
HTTPServer httpServer = new HTTPServer(new Endpoint(IPv6.ANY, 1888), new LoggingRouter(genericRouter));
pool.Start();
Logging.Log("Starting http listener...");
httpServer.Start();
}

View File

@ -6,7 +6,7 @@
</PropertyGroup>
<PropertyGroup>
<Version>0.1.0-test</Version>
<Version>0.1.0-test1</Version>
<Authors>Harald Wolff-Thobaben</Authors>
<Company>l--n.de</Company>
<Description>A simple build server scheduling builds triggered via web-hooks</Description>

View File

@ -4,6 +4,7 @@ using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Reflection.Metadata.Ecma335;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using ln.json;
@ -16,15 +17,12 @@ namespace ln.build
{
static HttpClient httpClient = new HttpClient();
public string JobID { get; } = Guid.NewGuid().ToString("N");
public string RepositoryURL { get; }
public string RepositoryName { get; }
public string Commit { get; }
public string NotifyEMail { get; set; }
public string WorkingDirectory { get; set; }
public CIService CurrentCIService { get; set; }
public Logger Logger { get; private set; }
@ -34,16 +32,13 @@ namespace ln.build
Dictionary<string,MemoryStream> logStreams = new Dictionary<string, MemoryStream>();
Dictionary<string,Logger> logStreamLoggers = new Dictionary<string, Logger>();
public CIJob(string repositoryName, string repositoryURL, string commit, string notifyEMail)
public CIJob(string repositoryURL)
{
WorkingDirectory = Path.Combine(Path.GetTempPath(), JobID);
Logger = new Logger(new FileLogger(Path.Combine(Path.GetTempPath(), String.Format("{0}.log", JobID))));
Logger.Backends.Add(Logger.ConsoleLogger);
RepositoryName = repositoryName;
RepositoryURL = repositoryURL;
Commit = commit;
NotifyEMail = notifyEMail;
}
public Stream GetLogStream(string name)
@ -73,12 +68,14 @@ namespace ln.build
value = defValue;
return value;
}
public void SetVariable(string varName,string value)
public CIJob SetVariable(string varName,string value)
{
if (value != null)
variables[varName] = value;
else
variables.Remove(varName);
return this;
}
public void ExtendVariable(string varName,string value) => ExtendVariable(varName, value, ':');
public void ExtendVariable(string varName, string value, char seperator)
@ -93,6 +90,16 @@ namespace ln.build
SetVariable(varName, currentValue);
}
public bool ContainsVariable(string varName) => variables.ContainsKey(varName);
public bool ContainsVariable(params string[] varNames)
{
foreach (string varName in varNames)
{
if (!variables.ContainsKey(varName))
return false;
}
return true;
}
public async void UpdateBuildState(BuildState buildState)
{
@ -110,7 +117,7 @@ namespace ln.build
stateObject.Add("state", buildState.ToString().ToLower());
stateObject.Add("target_url", JSONNull.Instance);
HttpResponseMessage response = await httpClient.PostAsync(buildStateURL, new StringContent(stateObject.ToString(),Encoding.UTF8,"application/json"));
HttpResponseMessage response = httpClient.PostAsync(buildStateURL, new StringContent(stateObject.ToString(),Encoding.UTF8,"application/json")).Result;
Logger.Log(LogLevel.DEBUG, "UpdateBuildState({0}): {1}", buildState, buildStateURL);
Logger.Log(LogLevel.DEBUG, "Response: {0}", response );
@ -122,39 +129,50 @@ namespace ln.build
public override void RunJob()
{
CloneRepository();
DetectPipelines();
try{
foreach (PipeLine pipeLine in pipeLines)
{
pipeLine.Run(this);
}
UpdateBuildState(BuildState.SUCCESS);
} catch (Exception e)
if (CloneRepository())
{
UpdateBuildState(BuildState.FAILURE);
if (DetectPipelines())
{
UpdateBuildState(BuildState.PENDING);
try{
foreach (PipeLine pipeLine in pipeLines)
{
pipeLine.Run(this);
}
UpdateBuildState(BuildState.SUCCESS);
} catch (Exception e)
{
UpdateBuildState(BuildState.FAILURE);
}
}
} else {
Logger.Log(LogLevel.ERROR, "CIJob failed at CloneRepository()");
}
Notify();
Cleanup();
}
void DetectPipelines()
{
string[] sln = Directory.GetFileSystemEntries(WorkingDirectory,"*.sln");
if (sln.Length > 0)
{
pipeLines.Add(new DotNetPipeLine());
}
}
public void CloneRepository()
public bool CloneRepository()
{
Logging.Log("cloning repository to {0}", WorkingDirectory);
new CommandRunner(Logger, "git", "clone",RepositoryURL,WorkingDirectory).Run();
new CommandRunner(Logger, "git", "checkout", Commit).Run();
return
(new CommandRunner(Logger, "git", "clone", RepositoryURL, WorkingDirectory).Run() == 0) &&
(!ContainsVariable("COMMIT_ID") || new CommandRunner(Logger, "git", "checkout", GetVariable("COMMIT_ID")){ WorkingDirectory = this.WorkingDirectory, }.Run() == 0);
}
public bool DetectPipelines()
{
if (CurrentCIService != null)
{
foreach (PipeLine pipeLine in CurrentCIService.PipeLines)
{
if (pipeLine.DetectValidity(this))
pipeLines.Add(pipeLine);
}
}
return pipeLines.Count > 0;
}
public void Notify()

View File

@ -0,0 +1,38 @@
using System.Collections.Generic;
using ln.threading;
namespace ln.build
{
public class CIService
{
public Pool buildPool;
HashSet<PipeLine> pipelines = new HashSet<PipeLine>();
public IEnumerable<PipeLine> PipeLines => pipelines;
public CIService()
{
buildPool = new Pool(2);
}
public void Start()
{
buildPool.Start();
}
public void AddPipeline(PipeLine pipeLine)
{
pipelines.Add(pipeLine);
}
public void Enqueue(CIJob job)
{
job.CurrentCIService = this;
buildPool.Enqueue(job);
}
}
}

View File

@ -6,7 +6,6 @@ using ln.logging;
namespace ln.build
{
public enum CRThrow { NEVER, NEGATIVE, NONZERO }
public class CommandRunner
{
public static CRThrow DefaultThrow { get; set; } = CRThrow.NONZERO;
@ -18,12 +17,17 @@ namespace ln.build
public Logger Logger { get; }
Func<int,bool> TestExitCode = null;
public CommandRunner(string executable,params string[] arguments) : this(Logger.Default, executable, arguments){}
public CommandRunner(Logger logger, string executable,params string[] arguments)
public CommandRunner(Logger logger, string executable,params string[] arguments) : this(logger, null, executable, arguments){}
public CommandRunner(Logger logger, Func<int,bool> testExitCode, string executable,params string[] arguments)
{
Logger = logger;
Executable = executable;
Arguments = arguments;
TestExitCode = testExitCode;
}
public string FindFileInPath(string filename)
@ -68,6 +72,7 @@ namespace ln.build
logger.Log(LogLevel.INFO, "Result: {0}", process.ExitCode);
if (
((TestExitCode != null) && !TestExitCode(process.ExitCode)) ||
((Throw == CRThrow.NEGATIVE) && (process.ExitCode < 0)) ||
((Throw == CRThrow.NONZERO) && (process.ExitCode != 0))
)

View File

@ -2,6 +2,7 @@
using System;
using System.IO;
using System.Reflection.Metadata.Ecma335;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Runtime.Serialization.Formatters;
using System.Text;
using System.Text.RegularExpressions;
@ -33,7 +34,19 @@ namespace ln.build
AddStep(new PublishStep());
}
public override bool DetectValidity(CIJob job)
{
string[] sln = Directory.GetFileSystemEntries(job.WorkingDirectory,"*.sln");
if (sln.Length > 0)
return true;
sln = Directory.GetFileSystemEntries(job.WorkingDirectory,"*.csproj");
if (sln.Length > 0)
return true;
return false;
}
void FilterPackageFilenames(CommandStep commandStep, CIJob job, int exitCode)
{
Stream outStream = job.GetLogStream(commandStep.DefaultLogFileName);

View File

@ -8,7 +8,7 @@ using ln.logging;
namespace ln.build
{
public class PipeLine
public abstract class PipeLine
{
List<Step> steps = new List<Step>();
@ -17,6 +17,9 @@ namespace ln.build
{
}
public abstract bool DetectValidity(CIJob job);
public void AddStep(Step step) => steps.Add(step);
public virtual void Run(CIJob job)

View File

@ -5,7 +5,7 @@
</PropertyGroup>
<PropertyGroup>
<Version>0.1.0</Version>
<Version>0.1.0-test1</Version>
<Authors>Harald Wolff-Thobaben</Authors>
<Company>l--n.de</Company>
<Description>A simple build server scheduling builds triggered via web-hooks</Description>