Initial Commit
ln.build build job pending
ln.build build job pending
commit
182d0be12a
|
@ -0,0 +1,41 @@
|
||||||
|
# Autosave files
|
||||||
|
*~
|
||||||
|
|
||||||
|
# build
|
||||||
|
[Oo]bj/
|
||||||
|
[Bb]in/
|
||||||
|
packages/
|
||||||
|
TestResults/
|
||||||
|
|
||||||
|
# globs
|
||||||
|
Makefile.in
|
||||||
|
*.DS_Store
|
||||||
|
*.sln.cache
|
||||||
|
*.suo
|
||||||
|
*.cache
|
||||||
|
*.pidb
|
||||||
|
*.userprefs
|
||||||
|
*.usertasks
|
||||||
|
config.log
|
||||||
|
config.make
|
||||||
|
config.status
|
||||||
|
aclocal.m4
|
||||||
|
install-sh
|
||||||
|
autom4te.cache/
|
||||||
|
*.user
|
||||||
|
*.tar.gz
|
||||||
|
tarballs/
|
||||||
|
test-results/
|
||||||
|
Thumbs.db
|
||||||
|
.vs/
|
||||||
|
|
||||||
|
# Mac bundle stuff
|
||||||
|
*.dmg
|
||||||
|
*.app
|
||||||
|
|
||||||
|
# resharper
|
||||||
|
*_Resharper.*
|
||||||
|
*.Resharper
|
||||||
|
|
||||||
|
# dotCover
|
||||||
|
*.dotCover
|
|
@ -0,0 +1,93 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using ln.http;
|
||||||
|
using ln.http.router;
|
||||||
|
using ln.json;
|
||||||
|
using ln.logging;
|
||||||
|
using ln.type;
|
||||||
|
using ln.threading;
|
||||||
|
using ln.build;
|
||||||
|
|
||||||
|
namespace ln.build.server
|
||||||
|
{
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
|
||||||
|
static Pool pool = new Pool(2);
|
||||||
|
|
||||||
|
static HttpResponse WebHookRequest(HttpRoutingContext context, HttpRequest request)
|
||||||
|
{
|
||||||
|
HttpResponse response = new HttpResponse(request);
|
||||||
|
|
||||||
|
if (!request.Method.Equals("POST"))
|
||||||
|
{
|
||||||
|
response.StatusCode = 405;
|
||||||
|
} else if (!request.GetRequestHeader("content-type").Equals("application/json"))
|
||||||
|
{
|
||||||
|
response.StatusCode = 415;
|
||||||
|
response.ContentWriter.WriteLine("Unsupported Media Type, should be application/json");
|
||||||
|
} else {
|
||||||
|
JSONValue jsonRequest = JSONParser.Parse(request.ContentReader.ReadToEnd());
|
||||||
|
if (jsonRequest is JSONObject message)
|
||||||
|
{
|
||||||
|
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 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);
|
||||||
|
|
||||||
|
job.UpdateBuildState(BuildState.PENDING);
|
||||||
|
|
||||||
|
pool.Enqueue(job);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} catch (Exception e)
|
||||||
|
{
|
||||||
|
response.StatusCode = 500;
|
||||||
|
response.StatusMessage = "An exception occured";
|
||||||
|
response.ContentWriter.WriteLine("{0}", e.ToString());
|
||||||
|
Logging.Log(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
response.StatusCode = 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
CommandRunner.DefaultThrow = CRThrow.NEGATIVE;
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<Version>0.1.0</Version>
|
||||||
|
<Authors>Harald Wolff-Thobaben</Authors>
|
||||||
|
<Company>l--n.de</Company>
|
||||||
|
<Description>A simple build server scheduling builds triggered via web-hooks</Description>
|
||||||
|
<Copyright>(c) 2020 Harald Wolff-Thobaben</Copyright>
|
||||||
|
<PackageTags>build build-server</PackageTags>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="ln.application" Version="0.1.1" />
|
||||||
|
<PackageReference Include="ln.http" Version="0.1.1" />
|
||||||
|
<PackageReference Include="ln.json" Version="1.0.0" />
|
||||||
|
<PackageReference Include="ln.logging" Version="1.0.1" />
|
||||||
|
<PackageReference Include="ln.threading" Version="0.1.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="../ln.build/ln.build.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
|
@ -0,0 +1,48 @@
|
||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio 15
|
||||||
|
VisualStudioVersion = 15.0.26124.0
|
||||||
|
MinimumVisualStudioVersion = 15.0.26124.0
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ln.build", "ln.build\ln.build.csproj", "{682A1FD5-3722-4C16-BED9-FFD90ED40FE8}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ln.build.server", "ln.build.server\ln.build.server.csproj", "{3437B6AB-7937-42DD-A526-5716E0114C61}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
|
Debug|x86 = Debug|x86
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
Release|x64 = Release|x64
|
||||||
|
Release|x86 = Release|x86
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{682A1FD5-3722-4C16-BED9-FFD90ED40FE8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{682A1FD5-3722-4C16-BED9-FFD90ED40FE8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{682A1FD5-3722-4C16-BED9-FFD90ED40FE8}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{682A1FD5-3722-4C16-BED9-FFD90ED40FE8}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{682A1FD5-3722-4C16-BED9-FFD90ED40FE8}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{682A1FD5-3722-4C16-BED9-FFD90ED40FE8}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{682A1FD5-3722-4C16-BED9-FFD90ED40FE8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{682A1FD5-3722-4C16-BED9-FFD90ED40FE8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{682A1FD5-3722-4C16-BED9-FFD90ED40FE8}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{682A1FD5-3722-4C16-BED9-FFD90ED40FE8}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{682A1FD5-3722-4C16-BED9-FFD90ED40FE8}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{682A1FD5-3722-4C16-BED9-FFD90ED40FE8}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{3437B6AB-7937-42DD-A526-5716E0114C61}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{3437B6AB-7937-42DD-A526-5716E0114C61}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{3437B6AB-7937-42DD-A526-5716E0114C61}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{3437B6AB-7937-42DD-A526-5716E0114C61}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{3437B6AB-7937-42DD-A526-5716E0114C61}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{3437B6AB-7937-42DD-A526-5716E0114C61}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{3437B6AB-7937-42DD-A526-5716E0114C61}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{3437B6AB-7937-42DD-A526-5716E0114C61}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{3437B6AB-7937-42DD-A526-5716E0114C61}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{3437B6AB-7937-42DD-A526-5716E0114C61}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{3437B6AB-7937-42DD-A526-5716E0114C61}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{3437B6AB-7937-42DD-A526-5716E0114C61}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
|
@ -0,0 +1,6 @@
|
||||||
|
namespace ln.build
|
||||||
|
{
|
||||||
|
|
||||||
|
public enum BuildState { PENDING, SUCCESS, ERROR, FAILURE, WARNING }
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,175 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
using System.Text;
|
||||||
|
using ln.json;
|
||||||
|
using ln.logging;
|
||||||
|
using ln.threading;
|
||||||
|
|
||||||
|
namespace ln.build
|
||||||
|
{
|
||||||
|
public class CIJob : PoolJob
|
||||||
|
{
|
||||||
|
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 Logger Logger { get; private set; }
|
||||||
|
|
||||||
|
List<PipeLine> pipeLines = new List<PipeLine>();
|
||||||
|
Dictionary<string,string> variables = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
if (!logStreams.TryGetValue(name,out MemoryStream logStream))
|
||||||
|
{
|
||||||
|
logStream = new MemoryStream();
|
||||||
|
logStreams.Add(name, logStream);
|
||||||
|
}
|
||||||
|
return logStream;
|
||||||
|
}
|
||||||
|
public Logger GetLogger(string name)
|
||||||
|
{
|
||||||
|
if (!logStreamLoggers.TryGetValue(name, out Logger logStreamLogger))
|
||||||
|
{
|
||||||
|
logStreamLogger = new Logger(GetLogStream(name));
|
||||||
|
logStreamLogger.Backends.Add(Logger.ConsoleLogger);
|
||||||
|
logStreamLoggers.Add(name, logStreamLogger);
|
||||||
|
}
|
||||||
|
return logStreamLogger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetVariable(string varName) => GetVariable(varName, null);
|
||||||
|
public string GetVariable(string varName,string defValue)
|
||||||
|
{
|
||||||
|
if (!variables.TryGetValue(varName,out string value))
|
||||||
|
value = defValue;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
public void SetVariable(string varName,string value)
|
||||||
|
{
|
||||||
|
if (value != null)
|
||||||
|
variables[varName] = value;
|
||||||
|
else
|
||||||
|
variables.Remove(varName);
|
||||||
|
}
|
||||||
|
public void ExtendVariable(string varName,string value) => ExtendVariable(varName, value, ':');
|
||||||
|
public void ExtendVariable(string varName, string value, char seperator)
|
||||||
|
{
|
||||||
|
String currentValue = GetVariable(varName, "");
|
||||||
|
if (String.Empty.Equals(currentValue))
|
||||||
|
{
|
||||||
|
currentValue = value;
|
||||||
|
} else {
|
||||||
|
currentValue = string.Format("{0}{1}{2}",currentValue, seperator, value);
|
||||||
|
}
|
||||||
|
SetVariable(varName, currentValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async void UpdateBuildState(BuildState buildState)
|
||||||
|
{
|
||||||
|
string buildStateURL = String.Format("https://git.l--n.de/api/v1/repos/{0}/{1}/statuses/{2}",
|
||||||
|
GetVariable("REPO_OWNER"),
|
||||||
|
GetVariable("REPO_NAME"),
|
||||||
|
GetVariable("COMMIT_ID")
|
||||||
|
);
|
||||||
|
|
||||||
|
if (buildStateURL != null)
|
||||||
|
{
|
||||||
|
JSONObject stateObject = new JSONObject();
|
||||||
|
stateObject.Add("context", "ln.build");
|
||||||
|
stateObject.Add("description", "build job pending");
|
||||||
|
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"));
|
||||||
|
Logger.Log(LogLevel.DEBUG, "UpdateBuildState({0}): {1}", buildState, buildStateURL);
|
||||||
|
Logger.Log(LogLevel.DEBUG, "Response: {0}", response );
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public override void RunJob()
|
||||||
|
{
|
||||||
|
CloneRepository();
|
||||||
|
DetectPipelines();
|
||||||
|
|
||||||
|
try{
|
||||||
|
foreach (PipeLine pipeLine in pipeLines)
|
||||||
|
{
|
||||||
|
pipeLine.Run(this);
|
||||||
|
}
|
||||||
|
UpdateBuildState(BuildState.SUCCESS);
|
||||||
|
} catch (Exception e)
|
||||||
|
{
|
||||||
|
UpdateBuildState(BuildState.FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
Notify();
|
||||||
|
Cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetectPipelines()
|
||||||
|
{
|
||||||
|
string[] sln = Directory.GetFileSystemEntries(WorkingDirectory,"*.sln");
|
||||||
|
if (sln.Length > 0)
|
||||||
|
{
|
||||||
|
pipeLines.Add(new DotNetPipeLine());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void CloneRepository()
|
||||||
|
{
|
||||||
|
Logging.Log("cloning repository to {0}", WorkingDirectory);
|
||||||
|
new CommandRunner(Logger, "git", "clone",RepositoryURL,WorkingDirectory).Run();
|
||||||
|
new CommandRunner(Logger, "git", "checkout", Commit).Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Notify()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Cleanup()
|
||||||
|
{
|
||||||
|
Directory.Delete(WorkingDirectory, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static CIJob()
|
||||||
|
{
|
||||||
|
httpClient.DefaultRequestHeaders.Add("Authorization","token 1d03e9577c404b5b4f46b340147b1d500ff95b2e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,127 @@
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using ln.logging;
|
||||||
|
|
||||||
|
namespace ln.build
|
||||||
|
{
|
||||||
|
public enum CRThrow { NEVER, NEGATIVE, NONZERO }
|
||||||
|
|
||||||
|
public class CommandRunner
|
||||||
|
{
|
||||||
|
public static CRThrow DefaultThrow { get; set; } = CRThrow.NONZERO;
|
||||||
|
|
||||||
|
public CRThrow Throw { get; set; } = DefaultThrow;
|
||||||
|
public string Executable { get; }
|
||||||
|
public string[] Arguments { get; set; }
|
||||||
|
public string WorkingDirectory { get; set; } = ".";
|
||||||
|
|
||||||
|
public Logger Logger { get; }
|
||||||
|
|
||||||
|
public CommandRunner(string executable,params string[] arguments) : this(Logger.Default, executable, arguments){}
|
||||||
|
public CommandRunner(Logger logger, string executable,params string[] arguments)
|
||||||
|
{
|
||||||
|
Logger = logger;
|
||||||
|
Executable = executable;
|
||||||
|
Arguments = arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string FindFileInPath(string filename)
|
||||||
|
{
|
||||||
|
Logger.Log(LogLevel.DEBUG, "Looking up {0} in paths {1}", filename, Environment.GetEnvironmentVariable("PATH"));
|
||||||
|
|
||||||
|
foreach (string path in Environment.GetEnvironmentVariable("PATH").Split(Path.PathSeparator))
|
||||||
|
{
|
||||||
|
string fullpath = Path.Combine(path,filename);
|
||||||
|
if (File.Exists(fullpath))
|
||||||
|
return fullpath;
|
||||||
|
}
|
||||||
|
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Run() => Run(Logger, null, null);
|
||||||
|
public int Run(Stream stdout, Stream stderr) => Run(Logger, stdout, stderr);
|
||||||
|
public int Run(Logger logger, Stream stdout) => Run(logger, stdout, stdout);
|
||||||
|
public int Run(Logger logger, Stream stdout, Stream stderr)
|
||||||
|
{
|
||||||
|
ProcessStartInfo psi = new ProcessStartInfo(FindFileInPath(Executable), string.Join(' ', Arguments))
|
||||||
|
{
|
||||||
|
CreateNoWindow = true,
|
||||||
|
RedirectStandardError = true,
|
||||||
|
RedirectStandardOutput = true,
|
||||||
|
RedirectStandardInput = true,
|
||||||
|
WorkingDirectory = this.WorkingDirectory
|
||||||
|
};
|
||||||
|
psi.EnvironmentVariables.Remove("LANG");
|
||||||
|
|
||||||
|
logger.Log(LogLevel.INFO, "Executing: {0} {1}", psi.FileName, psi.Arguments);
|
||||||
|
|
||||||
|
Process process = Process.Start(psi);
|
||||||
|
process.WaitForExit();
|
||||||
|
|
||||||
|
if (stdout != null)
|
||||||
|
process.StandardOutput.BaseStream.CopyTo(stdout);
|
||||||
|
if (stderr != null)
|
||||||
|
process.StandardError.BaseStream.CopyTo(stderr);
|
||||||
|
|
||||||
|
logger.Log(LogLevel.INFO, "Result: {0}", process.ExitCode);
|
||||||
|
|
||||||
|
if (
|
||||||
|
((Throw == CRThrow.NEGATIVE) && (process.ExitCode < 0)) ||
|
||||||
|
((Throw == CRThrow.NONZERO) && (process.ExitCode != 0))
|
||||||
|
)
|
||||||
|
throw new Exception(String.Format("{0} execution gave result {1}", psi.FileName, process.ExitCode));
|
||||||
|
|
||||||
|
return process.ExitCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Run(out string stdout,out string stderr) => Run(Logger, out stdout, out stderr);
|
||||||
|
public int Run(Logger logger, out string stdout,out string stderr)
|
||||||
|
{
|
||||||
|
MemoryStream outstream,errstream;
|
||||||
|
|
||||||
|
outstream = new MemoryStream();
|
||||||
|
errstream = new MemoryStream();
|
||||||
|
|
||||||
|
int status = Run(logger, outstream, errstream);
|
||||||
|
|
||||||
|
using (StreamReader sr = new StreamReader(outstream))
|
||||||
|
stdout = sr.ReadToEnd();
|
||||||
|
|
||||||
|
using (StreamReader sr = new StreamReader(errstream))
|
||||||
|
stderr = sr.ReadToEnd();
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
public static int Run(string executable,out Stream stdout,out Stream stderr,params string[] arguments)
|
||||||
|
{
|
||||||
|
CommandRunner runner = new CommandRunner(executable,arguments);
|
||||||
|
return runner.Run(out stdout,out stderr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int Run(string executable,out string stdout,out string stderr,params string[] arguments) => Run(Logger.Default, executable, out stdout, out stderr, arguments);
|
||||||
|
public static int Run(Logger logger, string executable, out string stdout, out string stderr, params string[] arguments)
|
||||||
|
{
|
||||||
|
CommandRunner runner = new CommandRunner(logger, executable, arguments);
|
||||||
|
int result = runner.Run(out stdout, out stderr);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int Run(string executable,params string[] arguments) => Run(executable,out Stream stdout,out Stream stderr,arguments);
|
||||||
|
public static int Run(Logger logger, string executable, params string[] arguments){
|
||||||
|
|
||||||
|
return Run(executable,out Stream stdout,out Stream stderr,arguments);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection.Metadata.Ecma335;
|
||||||
|
using System.Runtime.Serialization.Formatters;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using LibGit2Sharp.Handlers;
|
||||||
|
using ln.logging;
|
||||||
|
using ln.type;
|
||||||
|
|
||||||
|
namespace ln.build
|
||||||
|
{
|
||||||
|
|
||||||
|
public class DotNetPipeLine : PipeLine
|
||||||
|
{
|
||||||
|
static Regex regexPackages = new Regex(".*(Successfully created package '(.*)').*");
|
||||||
|
|
||||||
|
public DotNetPipeLine()
|
||||||
|
{
|
||||||
|
AddStep(new RestoreStep());
|
||||||
|
AddStep(new CleanStep());
|
||||||
|
|
||||||
|
BuildStep buildStep = new BuildStep();
|
||||||
|
buildStep.OnCommandExited += FilterPackageFilenames;
|
||||||
|
AddStep(buildStep);
|
||||||
|
|
||||||
|
AddStep(new TestStep());
|
||||||
|
|
||||||
|
PackStep packStep = new PackStep();
|
||||||
|
packStep.OnCommandExited += FilterPackageFilenames;
|
||||||
|
AddStep(packStep);
|
||||||
|
|
||||||
|
AddStep(new PublishStep());
|
||||||
|
}
|
||||||
|
|
||||||
|
void FilterPackageFilenames(CommandStep commandStep, CIJob job, int exitCode)
|
||||||
|
{
|
||||||
|
Stream outStream = job.GetLogStream(commandStep.DefaultLogFileName);
|
||||||
|
outStream.Position = 0;
|
||||||
|
|
||||||
|
job.Logger.Log(LogLevel.INFO,"filterPackageFilenames(): started");
|
||||||
|
|
||||||
|
String consoleOutput = Encoding.UTF8.GetString(outStream.ReadToEnd());
|
||||||
|
|
||||||
|
MatchCollection matches = regexPackages.Matches(consoleOutput);
|
||||||
|
foreach (Match match in matches)
|
||||||
|
{
|
||||||
|
Logging.Log(LogLevel.INFO,"filterPackageFilenames(): {0}", match.Groups[2].Value);
|
||||||
|
job.ExtendVariable("DOTNET_PACKAGES", match.Groups[2].Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class CleanStep : CommandStep
|
||||||
|
{
|
||||||
|
public CleanStep():base("clean", "dotnet","clean"){ }
|
||||||
|
}
|
||||||
|
class RestoreStep : CommandStep
|
||||||
|
{
|
||||||
|
public RestoreStep():base("restore", "dotnet","restore"){ }
|
||||||
|
}
|
||||||
|
class TestStep : CommandStep
|
||||||
|
{
|
||||||
|
public TestStep():base("test", "dotnet","test"){ }
|
||||||
|
}
|
||||||
|
class BuildStep : CommandStep
|
||||||
|
{
|
||||||
|
public BuildStep():base("build", "dotnet","build"){ }
|
||||||
|
}
|
||||||
|
class PackStep : CommandStep
|
||||||
|
{
|
||||||
|
public PackStep():base("pack", "dotnet","pack"){ }
|
||||||
|
}
|
||||||
|
class PublishStep : CommandStep
|
||||||
|
{
|
||||||
|
public PublishStep():base("push", "dotnet","nuget", "push", "<filename>", "-s", "<source>", "-k", "<apikey>"){ }
|
||||||
|
|
||||||
|
public override int Run(CIJob job)
|
||||||
|
{
|
||||||
|
bool success = true;
|
||||||
|
|
||||||
|
CommandRunner.Arguments[4] = "http://nuget.l--n.de/nuget/l--n/v3/index.json";
|
||||||
|
CommandRunner.Arguments[6] = "3yAJPMxcaEhb_HP62dxK";
|
||||||
|
|
||||||
|
foreach (string package in job.GetVariable("DOTNET_PACKAGES","").Split(':',StringSplitOptions.RemoveEmptyEntries))
|
||||||
|
{
|
||||||
|
CommandRunner.Arguments[2] = package;
|
||||||
|
if (base.Run(job) != 0)
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
return success ? 0 : -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using ln.logging;
|
||||||
|
|
||||||
|
namespace ln.build
|
||||||
|
{
|
||||||
|
|
||||||
|
public class PipeLine
|
||||||
|
{
|
||||||
|
|
||||||
|
List<Step> steps = new List<Step>();
|
||||||
|
|
||||||
|
public PipeLine()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddStep(Step step) => steps.Add(step);
|
||||||
|
|
||||||
|
public virtual void Run(CIJob job)
|
||||||
|
{
|
||||||
|
job.Logger.Log(LogLevel.INFO,"PipeLine [{0}] start",GetType().Name);
|
||||||
|
|
||||||
|
foreach (Step step in steps)
|
||||||
|
{
|
||||||
|
if (step.Run(job) != 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
job.Logger.Log(LogLevel.INFO,"PipeLine [{0}] ended", GetType().Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class Step
|
||||||
|
{
|
||||||
|
public string Name { get; }
|
||||||
|
public Step(string stepName)
|
||||||
|
{
|
||||||
|
Name = stepName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract int Run(CIJob job);
|
||||||
|
|
||||||
|
public string DefaultLogFileName => String.Format("step.{0}.log", Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public delegate void CommandExitedDelegate(CommandStep commandStep, CIJob job, int exitCode);
|
||||||
|
public class CommandStep : PipeLine.Step
|
||||||
|
{
|
||||||
|
public event CommandExitedDelegate OnCommandExited;
|
||||||
|
|
||||||
|
public CommandRunner CommandRunner { get; }
|
||||||
|
|
||||||
|
public CommandStep(string stepName, string filename,params string[] arguments)
|
||||||
|
:base(stepName)
|
||||||
|
{
|
||||||
|
CommandRunner = new CommandRunner(filename, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Run(CIJob job)
|
||||||
|
{
|
||||||
|
CommandRunner.WorkingDirectory = job.WorkingDirectory;
|
||||||
|
|
||||||
|
int result = CommandRunner.Run(job.Logger, job.GetLogStream(DefaultLogFileName));
|
||||||
|
OnCommandExited?.Invoke(this, job, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<Version>0.1.0</Version>
|
||||||
|
<Authors>Harald Wolff-Thobaben</Authors>
|
||||||
|
<Company>l--n.de</Company>
|
||||||
|
<Description>A simple build server scheduling builds triggered via web-hooks</Description>
|
||||||
|
<Copyright>(c) 2020 Harald Wolff-Thobaben</Copyright>
|
||||||
|
<PackageTags>build build-server</PackageTags>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="LibGit2Sharp" Version="0.26.2" />
|
||||||
|
<PackageReference Include="ln.logging" Version="1.0.1" />
|
||||||
|
<PackageReference Include="ln.threading" Version="0.1.0" />
|
||||||
|
<PackageReference Include="ln.json" Version="1.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
Loading…
Reference in New Issue