0.4.3-ci
ln.build - build0.waldrennach.l--n.de build job pending
Details
ln.build - build0.waldrennach.l--n.de build job pending
Details
parent
18e7a3a229
commit
1b9ed4e7ad
43
build.ln
43
build.ln
|
@ -1,52 +1,17 @@
|
|||
{
|
||||
"templates": [
|
||||
"dotnet"
|
||||
],
|
||||
"env": {
|
||||
"NUGET_SOURCE": "https://nexus.niclas-thobaben.de/repository/l--n.de/",
|
||||
"CONFIGURATION": "Release"
|
||||
},
|
||||
"stages": [
|
||||
{
|
||||
"name": "setup",
|
||||
"env": {
|
||||
"SOME_ENV_VAR": "Some text",
|
||||
},
|
||||
"commands": [
|
||||
"SH echo Setting up build environment",
|
||||
"SH set",
|
||||
"SH rm -Rf .build"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "prepare",
|
||||
"commands": [
|
||||
"SH dotnet restore",
|
||||
"SH dotnet clean"
|
||||
"dotnet prepare */*.csproj"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "build",
|
||||
"commands": [
|
||||
"SH dotnet build -c $CONFIGURATION"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "pack_and_publish",
|
||||
"commands": [
|
||||
"SH dotnet pack ln.build -o .build -c $CONFIGURATION",
|
||||
"SH dotnet pack ln.build.server -o .build -c $CONFIGURATION",
|
||||
"SH dotnet publish ln.build.server -p:PublishTrimmed=true -p:PublishSingleFile=true -p:PublishReadyToRun=true --self-contained -r linux-x64 -c $CONFIGURATION -o .build/linux-x64",
|
||||
"SH dotnet publish ln.build.server -p:PublishTrimmed=true -p:PublishSingleFile=true -p:PublishReadyToRun=false --self-contained -r win-x64 -c $CONFIGURATION -o .build/windows-x64"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "push",
|
||||
"commands": [
|
||||
"SH for NUPKG in .build/ln.build.*.nupkg; do dotnet nuget push $NUPKG -s $NUGET_SOURCE -k $NUGET_APIKEY; done",
|
||||
"RELEASE .build/linux-x64/ln.build.server=ln.build.server-linux-amd64",
|
||||
"RELEASE .build/windows-x64/ln.build.server.exe=ln.build.server-windows-x64.exe"
|
||||
],
|
||||
"secrets": {
|
||||
"NUGET_APIKEY": "https://nexus.niclas-thobaben.de"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -12,18 +12,41 @@ using Microsoft.VisualBasic;
|
|||
using ln.application;
|
||||
using System.IO;
|
||||
using ln.build.repositories.gitea;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using ln.build.semver;
|
||||
using ln.build.pipeline;
|
||||
|
||||
namespace ln.build.server
|
||||
{
|
||||
public enum RunMode {
|
||||
serv,
|
||||
versioning,
|
||||
build
|
||||
}
|
||||
|
||||
class Program
|
||||
{
|
||||
static CIService CIService;
|
||||
|
||||
[StaticArgument( Option = 'm')]
|
||||
static RunMode RunMode { get; set; } = RunMode.serv;
|
||||
|
||||
[StaticArgument( LongOption = "build")]
|
||||
public static string BuildPath { get; set; }
|
||||
static string BuildPath { get; set; }
|
||||
|
||||
[StaticArgument( LongOption = "build-secret")]
|
||||
public static string BuildSecret { get; set; }
|
||||
static string BuildSecret { get; set; }
|
||||
|
||||
[StaticArgument( LongOption = "versioning-provider")]
|
||||
static string VersioningProviderName { get; set; }
|
||||
|
||||
[StaticArgument( LongOption = "versioning-level")]
|
||||
static SemVerLevels VersioningLevel { get; set;} = SemVerLevels.PATCH;
|
||||
|
||||
[StaticArgument( LongOption = "versioning-source")]
|
||||
static string VersioningSource { get; set;}
|
||||
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
|
@ -35,19 +58,39 @@ namespace ln.build.server
|
|||
|
||||
CIService.Initialize();
|
||||
|
||||
if (BuildPath != null)
|
||||
switch (RunMode)
|
||||
{
|
||||
CIJob job = new CIJob(CIService,null, (BuildSecret != null) ? CIService.GetSecretStorage(BuildSecret) : null);
|
||||
job.WorkingDirectory = BuildPath;
|
||||
job.RunJob();
|
||||
} else {
|
||||
CIService.Initialize();
|
||||
CIService.AddWebHookHandler("gitea", GiteaRepository.WebHookHandler);
|
||||
CIService.Start();
|
||||
case RunMode.serv:
|
||||
CIService.Initialize();
|
||||
CIService.AddWebHookHandler("gitea", GiteaRepository.WebHookHandler);
|
||||
CIService.Start();
|
||||
break;
|
||||
case RunMode.build:
|
||||
CIJob job = new CIJob(CIService,null, (BuildSecret != null) ? CIService.GetSecretStorage(BuildSecret) : null);
|
||||
job.WorkingDirectory = BuildPath;
|
||||
job.RunJob();
|
||||
break;
|
||||
case RunMode.versioning:
|
||||
Versioning versioning = new Versioning(VersioningProviderName);
|
||||
versioning.Sources = new string[]{ VersioningSource };
|
||||
|
||||
SemVersion version = versioning.GetCurrentVersion(null);
|
||||
Logging.Log("INFO: found version {0}", version);
|
||||
version.Increment(VersioningLevel);
|
||||
Logging.Log("INFO: write back version {0}", version);
|
||||
versioning.SetVersion(null, version);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||
Host.CreateDefaultBuilder(args)
|
||||
.UseSystemd()
|
||||
.ConfigureServices((hostContext, services) =>
|
||||
{
|
||||
services.AddHostedService<ServiceWorker>();
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace ln.build
|
||||
{
|
||||
public class ServiceWorker : BackgroundService
|
||||
{
|
||||
protected override Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<Version>0.4.2</Version>
|
||||
<Version>0.4.3-ci</Version>
|
||||
<Authors>Harald Wolff-Thobaben</Authors>
|
||||
<Company>l--n.de</Company>
|
||||
<Description>A simple build server scheduling builds triggered via web-hooks</Description>
|
||||
|
@ -15,11 +15,12 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ln.application" Version="0.1.1" />
|
||||
<PackageReference Include="ln.http" Version="0.1.2" />
|
||||
<PackageReference Include="ln.json" Version="1.0.0" />
|
||||
<PackageReference Include="ln.logging" Version="1.0.1" />
|
||||
<PackageReference Include="ln.threading" Version="0.1.0" />
|
||||
<PackageReference Include="ln.application" Version="0.1.*" />
|
||||
<PackageReference Include="ln.http" Version="0.1.*" />
|
||||
<PackageReference Include="ln.json" Version="1.0.*" />
|
||||
<PackageReference Include="ln.logging" Version="1.0.*" />
|
||||
<PackageReference Include="ln.threading" Version="0.1.*" />
|
||||
<PackageReference Include="ln.type" Version="0.1.*" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -1,20 +1,22 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using ln.build.commands;
|
||||
using ln.build.pipeline;
|
||||
using ln.build.repositories;
|
||||
using ln.build.secrets;
|
||||
using ln.build.semver;
|
||||
using ln.json;
|
||||
using ln.logging;
|
||||
using ln.threading;
|
||||
|
||||
namespace ln.build
|
||||
{
|
||||
public delegate void CIJobCompleted(CIJob cIJob);
|
||||
public class CIJob : PoolJob
|
||||
{
|
||||
public event CIJobCompleted OnJobCompleted;
|
||||
|
||||
public string JobID { get; } = Guid.NewGuid().ToString("N");
|
||||
public CIService CIService { get; }
|
||||
public Repository Repository { get; set; }
|
||||
|
@ -115,6 +117,8 @@ namespace ln.build
|
|||
Logger.Log(LogLevel.ERROR, "CIJob failed at CloneRepository()");
|
||||
}
|
||||
|
||||
OnJobCompleted?.Invoke(this);
|
||||
|
||||
Notify();
|
||||
Cleanup();
|
||||
}
|
||||
|
@ -158,5 +162,30 @@ namespace ln.build
|
|||
Directory.Delete(WorkingDirectory, true);
|
||||
}
|
||||
|
||||
|
||||
public void PublishRelease(SemVerLevels releaseLevel)
|
||||
{
|
||||
if (BuildState == BuildState.SUCCESS)
|
||||
{
|
||||
if (PipeLine.Versioning != null)
|
||||
{
|
||||
Versioning versioning = PipeLine.Versioning;
|
||||
SemVersion version = versioning.GetCurrentVersion(this);
|
||||
|
||||
if (version.IsPreRelease)
|
||||
{
|
||||
SemVersion releaseVersion = new SemVersion(version);
|
||||
releaseVersion.PreRelease = null;
|
||||
|
||||
versioning.SetVersion(this, releaseVersion);
|
||||
} else if (version.IsRelease)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,11 @@ using System.IO;
|
|||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using ln.application;
|
||||
using ln.build.commands;
|
||||
using ln.build.pipeline;
|
||||
using ln.build.repositories;
|
||||
using ln.build.secrets;
|
||||
using ln.build.semver;
|
||||
using ln.http;
|
||||
using ln.http.router;
|
||||
using ln.json;
|
||||
|
@ -43,9 +46,7 @@ namespace ln.build
|
|||
TemplateRouter templateRouter;
|
||||
HTTPServer httpServer;
|
||||
|
||||
HashSet<PipeLine> pipelines = new HashSet<PipeLine>();
|
||||
public IEnumerable<PipeLine> PipeLines => pipelines;
|
||||
|
||||
public StageCommandContainer StageCommands { get; } = new StageCommandContainer(null,null);
|
||||
|
||||
public CIService()
|
||||
{
|
||||
|
@ -72,6 +73,8 @@ namespace ln.build
|
|||
Directory.CreateDirectory(ReportsDirectory);
|
||||
Directory.CreateDirectory(Path.Combine(BaseDirectory, "secrets"));
|
||||
|
||||
InitializeStageCommands();
|
||||
|
||||
InitializeHttpServer();
|
||||
}
|
||||
|
||||
|
@ -114,6 +117,21 @@ namespace ln.build
|
|||
}
|
||||
}
|
||||
|
||||
public void InitializeStageCommands()
|
||||
{
|
||||
StageCommands.AddCommand(CoreCommands.ShellCommand, "sh");
|
||||
|
||||
StageCommands.AddCommand(DotNetCommand.Prepare, "dotnet", "prepare" );
|
||||
StageCommands.AddCommand(DotNetCommand.Build, "dotnet", "build" );
|
||||
StageCommands.AddCommand(DotNetCommand.Test, "dotnet", "test" );
|
||||
StageCommands.AddCommand(DotNetCommand.Pack, "dotnet", "pack" );
|
||||
StageCommands.AddCommand(DotNetCommand.Push, "dotnet", "push" );
|
||||
StageCommands.AddCommand(DotNetCommand.Publish, "dotnet", "publish" );
|
||||
|
||||
StageCommands.AddCommand(DeployCommand.Deploy, "deploy" );
|
||||
StageCommands.AddCommand(DeployCommand.Release, "release" );
|
||||
}
|
||||
|
||||
public string GetJobURL(CIJob job) => string.Format("{0}/builds/{1}", BaseURL, job.JobID);
|
||||
|
||||
public void Start()
|
||||
|
@ -122,11 +140,6 @@ namespace ln.build
|
|||
httpServer.Start();
|
||||
}
|
||||
|
||||
public void AddPipeline(PipeLine pipeLine)
|
||||
{
|
||||
pipelines.Add(pipeLine);
|
||||
}
|
||||
|
||||
public void AddWebHookHandler(string name, Func<CIService,HttpRequest,HttpResponse> webHookHandler)
|
||||
{
|
||||
hookRouter.AddSimpleRoute(String.Format("/{0}", name), (HttpRoutingContext context,HttpRequest request) => webHookHandler(this, request));
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using ln.http.exceptions;
|
||||
|
||||
namespace ln.build
|
||||
{
|
||||
public static class PathHelper
|
||||
{
|
||||
|
||||
public static IEnumerable<string> ResolvePattern(string pattern) => ResolvePattern(pattern, Environment.CurrentDirectory);
|
||||
public static IEnumerable<string> ResolvePattern(string pattern, string start)
|
||||
{
|
||||
string[] patternTokens = pattern.Split('/', StringSplitOptions.RemoveEmptyEntries);
|
||||
List<string> matches = new List<string>();
|
||||
collect(patternTokens, 0, start, matches);
|
||||
return matches;
|
||||
}
|
||||
|
||||
static void collect(string[] tokens,int depth,string currentPath, List<string> matches)
|
||||
{
|
||||
if (depth < tokens.Length-1)
|
||||
{
|
||||
foreach (string dirname in Directory.GetDirectories(currentPath, tokens[depth]))
|
||||
{
|
||||
collect(tokens, depth + 1, dirname, matches);
|
||||
}
|
||||
} else if (depth == (tokens.Length - 1))
|
||||
{
|
||||
foreach (string filename in Directory.GetFiles(currentPath, tokens[depth]))
|
||||
{
|
||||
matches.Add(filename);
|
||||
}
|
||||
} else
|
||||
throw new Exception("serious bug");
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Jint.Parser.Ast;
|
||||
using ln.logging;
|
||||
|
||||
namespace ln.build.commands
|
||||
|
@ -33,9 +34,9 @@ namespace ln.build.commands
|
|||
TestExitCode = testExitCode;
|
||||
}
|
||||
|
||||
public void AddArgument(Argument argument) => arguments.Add(argument);
|
||||
public void AddArguments(params Argument[] args) => arguments.AddRange(args);
|
||||
|
||||
public CommandRunner AddArgument(Argument argument){ arguments.Add(argument); return this; }
|
||||
public CommandRunner AddArguments(params Argument[] args) { arguments.AddRange(args); return this; }
|
||||
public CommandRunner AddArguments(params string[] args) { arguments.AddRange(args.Select((string arg)=>(Argument)arg)); return this; }
|
||||
public string FindFileInPath(CommandEnvironment environment, string filename)
|
||||
{
|
||||
Logger.Log(LogLevel.DEBUG, "Looking up {0} in paths {1}", filename, environment.Get("PATH",""));
|
||||
|
@ -116,7 +117,7 @@ namespace ln.build.commands
|
|||
|
||||
public class Argument
|
||||
{
|
||||
string value;
|
||||
protected string value;
|
||||
public bool MaskValue { get; set; }
|
||||
|
||||
protected Argument(){ }
|
||||
|
@ -142,8 +143,10 @@ namespace ln.build.commands
|
|||
public Option(string optionArgument, string optionValue) : this(optionArgument, optionValue, false){ }
|
||||
public Option(string optionArgument, string optionValue, bool maskValue)
|
||||
{
|
||||
value = optionValue;
|
||||
|
||||
OptionArgument = optionArgument;
|
||||
GetValue = (e) => optionValue;
|
||||
GetValue = (e) => value;
|
||||
MaskValue = maskValue;
|
||||
}
|
||||
public Option(string optionArgument, Func<CommandEnvironment,string> getOptionValue) : this(optionArgument, getOptionValue, false) { }
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<Version>0.4.2</Version>
|
||||
<Version>0.4.3-ci</Version>
|
||||
<Authors>Harald Wolff-Thobaben</Authors>
|
||||
<Company>l--n.de</Company>
|
||||
<Description>A simple build server scheduling builds triggered via web-hooks</Description>
|
||||
|
@ -15,16 +15,18 @@
|
|||
|
||||
<ItemGroup>
|
||||
<None Update="html/**" CopyToOutputDirectory="PreserveNewest" />
|
||||
<None Update="scripts/**" CopyToOutputDirectory="PreserveNewest" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ln.logging" Version="1.0.1" />
|
||||
<PackageReference Include="ln.threading" Version="0.1.0" />
|
||||
<PackageReference Include="ln.json" Version="1.0.0" />
|
||||
<PackageReference Include="ln.http" Version="0.1.2" />
|
||||
<PackageReference Include="ln.templates" Version="0.1.1" />
|
||||
<PackageReference Include="ln.templates.http" Version="0.0.1-test" />
|
||||
<PackageReference Include="ln.logging" Version="1.0.*" />
|
||||
<PackageReference Include="ln.threading" Version="0.1.*" />
|
||||
<PackageReference Include="ln.json" Version="1.0.*" />
|
||||
<PackageReference Include="ln.http" Version="0.1.*" />
|
||||
<PackageReference Include="ln.templates" Version="0.1.*" />
|
||||
<PackageReference Include="ln.templates.http" Version="0.0.*" />
|
||||
<PackageReference Include="ln.type" Version="0.1.*" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using ln.build.commands;
|
||||
using ln.logging;
|
||||
|
||||
namespace ln.build.pipeline
|
||||
{
|
||||
public static class CoreCommands
|
||||
{
|
||||
|
||||
public static void ShellCommand(Stage stage,params string[] arguments)
|
||||
{
|
||||
CommandRunner commandRunner = new CommandRunner("/bin/bash", "-c", string.Format("\"{0}\"", string.Join(' ', arguments))) { Throw = CRThrow.NEVER, };
|
||||
MemoryStream logStream = new MemoryStream();
|
||||
|
||||
int result = commandRunner.Run(stage.CommandEnvironment, logStream);
|
||||
|
||||
stage.CommandEnvironment.Logger.Log(LogLevel.INFO, "command output:\n{0}", Encoding.UTF8.GetString(logStream.ToArray()));
|
||||
stage.CommandEnvironment.Logger.Log(LogLevel.INFO, "command exit code: {0}", result);
|
||||
|
||||
if (result != 0)
|
||||
throw new Exception(String.Format("command exited with code {0} [0x{0:x}]", result));
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,5 +1,9 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using ln.build.commands;
|
||||
using ln.build.semver;
|
||||
using ln.json;
|
||||
using ln.logging;
|
||||
|
||||
|
@ -14,6 +18,11 @@ namespace ln.build.pipeline
|
|||
List<Stage> stages = new List<Stage>();
|
||||
public IEnumerable<Stage> Stages => stages;
|
||||
|
||||
public Versioning Versioning { get; set; }
|
||||
|
||||
List<string> loadedTemplates = new List<string>();
|
||||
public IEnumerable<string> LoadedTemplates => loadedTemplates;
|
||||
|
||||
public DefaultPipeLine(CIService ciService)
|
||||
{
|
||||
CIService = ciService;
|
||||
|
@ -27,6 +36,29 @@ namespace ln.build.pipeline
|
|||
|
||||
public void LoadJson(JSONObject jsonPipeLine)
|
||||
{
|
||||
if (jsonPipeLine.ContainsKey("templates"))
|
||||
{
|
||||
foreach (JSONString jsonTemplateName in jsonPipeLine["templates"].Children)
|
||||
{
|
||||
if (!loadedTemplates.Contains(jsonTemplateName.Value))
|
||||
{
|
||||
loadedTemplates.Add(jsonTemplateName.Value);
|
||||
|
||||
string repoTemplate = Path.Combine(CommandEnvironment.WorkingDirectory, String.Format("{0}.ln", jsonTemplateName.Value));
|
||||
string systemTemplate = Path.Combine(CIService.ContextDirectory, "scripts", "pipeline", String.Format("{0}.ln", jsonTemplateName.Value));
|
||||
|
||||
if (File.Exists(repoTemplate))
|
||||
{
|
||||
LoadJson(JSONParser.ParseFile(repoTemplate) as JSONObject);
|
||||
} else if (File.Exists(systemTemplate))
|
||||
{
|
||||
LoadJson(JSONParser.ParseFile(systemTemplate) as JSONObject);
|
||||
} else
|
||||
throw new FileNotFoundException(String.Format("{0}.ln", jsonTemplateName.Value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (jsonPipeLine.ContainsKey("env"))
|
||||
CommandEnvironment.Apply(jsonPipeLine["env"] as JSONObject);
|
||||
|
||||
|
@ -35,12 +67,13 @@ namespace ln.build.pipeline
|
|||
JSONArray jsonStages = jsonPipeLine["stages"] as JSONArray;
|
||||
foreach (JSONObject jsonStage in jsonStages.Children)
|
||||
{
|
||||
Stage stage = new Stage(this);
|
||||
Stage stage = GetStage(jsonStage["name"].ToNative().ToString());
|
||||
stage.LoadJson(jsonStage);
|
||||
|
||||
stages.Add(stage);
|
||||
}
|
||||
}
|
||||
|
||||
if (jsonPipeLine.ContainsKey("versioning"))
|
||||
Versioning = new Versioning(jsonPipeLine["versioning"] as JSONObject);
|
||||
}
|
||||
|
||||
public void Run()
|
||||
|
@ -54,6 +87,19 @@ namespace ln.build.pipeline
|
|||
}
|
||||
}
|
||||
|
||||
public Stage GetStage(string stageName)
|
||||
{
|
||||
foreach (Stage stage in stages)
|
||||
{
|
||||
if (stageName.Equals(stage.Name))
|
||||
return stage;
|
||||
}
|
||||
|
||||
Stage _stage = new Stage(this);
|
||||
_stage.Name = stageName;
|
||||
stages.Add(_stage);
|
||||
return _stage;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -61,11 +107,11 @@ namespace ln.build.pipeline
|
|||
{
|
||||
public DefaultPipeLine PipeLine { get; }
|
||||
public string Name { get; set; }
|
||||
public int Priority { get; set; }
|
||||
|
||||
public CommandEnvironment CommandEnvironment { get; }
|
||||
|
||||
List<StageCommand> commands = new List<StageCommand>();
|
||||
public IEnumerable<StageCommand> Commands => commands;
|
||||
public List<string> commands = new List<string>();
|
||||
|
||||
public Stage(DefaultPipeLine pipeLine)
|
||||
{
|
||||
|
@ -76,6 +122,8 @@ namespace ln.build.pipeline
|
|||
public void LoadJson(JSONObject jsonStage)
|
||||
{
|
||||
Name = jsonStage["name"].ToNative().ToString();
|
||||
if (jsonStage.ContainsKey("priority"))
|
||||
Priority = (int)(long)jsonStage["priority"].ToNative();
|
||||
|
||||
if (jsonStage.ContainsKey("env"))
|
||||
{
|
||||
|
@ -86,7 +134,8 @@ namespace ln.build.pipeline
|
|||
JSONArray jsonCommands = jsonStage["commands"] as JSONArray;
|
||||
foreach (JSONValue jsonValue in jsonCommands.Children)
|
||||
{
|
||||
commands.Add(StageCommand.Create(jsonValue.ToNative().ToString()));
|
||||
Logging.Log(LogLevel.DEBUG, "stage {0} command: {1}", Name, jsonValue.ToNative().ToString());
|
||||
commands.Add(jsonValue.ToNative().ToString());
|
||||
}
|
||||
}
|
||||
if (jsonStage.ContainsKey("secrets"))
|
||||
|
@ -96,15 +145,14 @@ namespace ln.build.pipeline
|
|||
{
|
||||
CommandEnvironment.Set(key, CommandEnvironment.SecretStorage?.GetSecret(jsonSecrets[key]?.ToNative()?.ToString()));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void Run()
|
||||
{
|
||||
foreach (StageCommand command in commands)
|
||||
command.Run(this);
|
||||
foreach (string command in commands)
|
||||
PipeLine.CIService.StageCommands.Run(this, command.Split());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,22 +1,26 @@
|
|||
|
||||
using System;
|
||||
using System.IO;
|
||||
using Jint.Native.Function;
|
||||
using ln.build.repositories;
|
||||
using ln.logging;
|
||||
|
||||
namespace ln.build.pipeline
|
||||
{
|
||||
public class ReleaseCommand : StageCommand
|
||||
public static class DeployCommand
|
||||
{
|
||||
public string[] Arguments { get; }
|
||||
public ReleaseCommand(string args) :base("RELEASE")
|
||||
|
||||
public static void Deploy(Stage stage,params string[] arguments)
|
||||
{
|
||||
Arguments = args.Split();
|
||||
stage.CommandEnvironment.Logger.Log(LogLevel.WARNING, "stage command: deploy not yet implemented");
|
||||
}
|
||||
|
||||
public override void Run(Stage stage)
|
||||
public static void Release(Stage stage,params string[] arguments)
|
||||
{
|
||||
stage.CommandEnvironment.Logger.Log(LogLevel.WARNING, "stage command: release not yet implemented");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
if (stage.CommandEnvironment.Get("REPO_EVENT","").Equals("release"))
|
||||
{
|
||||
Repository repository = stage.CommandEnvironment.CIJob?.Repository;
|
||||
|
@ -55,6 +59,6 @@ namespace ln.build.pipeline
|
|||
} else {
|
||||
stage.CommandEnvironment.Logger.Log(LogLevel.INFO, "RELEASE: build is no release build. Ignoring.");
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
|
||||
using ln.build.pipeline;
|
||||
|
||||
namespace ln.build.commands
|
||||
{
|
||||
|
||||
public class DotNetCommand : StageCommand
|
||||
{
|
||||
|
||||
|
||||
public DotNetCommand(string arguments) :base("DOTNET"){
|
||||
|
||||
}
|
||||
|
||||
public void Analyze(Stage stage)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public override void Run(Stage stage)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,211 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using ln.application;
|
||||
using ln.build.pipeline;
|
||||
using ln.build.semver;
|
||||
using ln.build.support.dotnet;
|
||||
using ln.logging;
|
||||
using ln.type;
|
||||
|
||||
namespace ln.build.commands
|
||||
{
|
||||
|
||||
public static class DotNetCommand
|
||||
{
|
||||
public static void Prepare(Stage stage,params string[] arguments)
|
||||
{
|
||||
if (Directory.Exists(".build"))
|
||||
Directory.Delete(".build", true);
|
||||
|
||||
List<string> projectFiles = new List<string>();
|
||||
List<string> slnFiles = new List<string>();
|
||||
|
||||
foreach (string argument in arguments)
|
||||
{
|
||||
foreach (string filename in PathHelper.ResolvePattern(argument, stage.CommandEnvironment.WorkingDirectory))
|
||||
{
|
||||
stage.CommandEnvironment.Logger.Log(LogLevel.INFO, "dotnet prepare: found {0}", filename);
|
||||
if (filename.EndsWith(".csproj",StringComparison.InvariantCultureIgnoreCase))
|
||||
projectFiles.Add(filename);
|
||||
else
|
||||
slnFiles.Add(filename);
|
||||
}
|
||||
}
|
||||
|
||||
// ToDo: Parse .sln files for referenced projects
|
||||
|
||||
|
||||
foreach (string projectFileName in projectFiles)
|
||||
{
|
||||
stage.PipeLine.CommandEnvironment.Extend("DOTNET_PROJECTS", projectFileName);
|
||||
CSProjHelper csp = new CSProjHelper(projectFileName);
|
||||
|
||||
string projectName = csp.GetName();
|
||||
SemVersion projectVersion= csp.GetVersion();
|
||||
string ot = csp.GetOutputType();
|
||||
|
||||
stage.CommandEnvironment.Logger.Log(LogLevel.INFO, "dotnet prepare: project {0} version={1} type={2}", projectName, projectVersion, ot);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void Build(Stage stage,params string[] arguments)
|
||||
{
|
||||
foreach (string projectFileName in stage.CommandEnvironment.Get("DOTNET_PROJECTS","").Split(':'))
|
||||
{
|
||||
new CommandRunner("dotnet","build", projectFileName, new CommandRunner.Option("-c", stage.CommandEnvironment.Get("DOTNET_CONFIGURATION")))
|
||||
.Run(stage.CommandEnvironment);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Pack(Stage stage,params string[] arguments)
|
||||
{
|
||||
foreach (string projectFileName in stage.CommandEnvironment.Get("DOTNET_PROJECTS","").Split(':'))
|
||||
{
|
||||
CSProjHelper csProject = new CSProjHelper(projectFileName);
|
||||
|
||||
if (!csProject.GetOutputType().Equals("Library"))
|
||||
{
|
||||
stage.CommandEnvironment.Logger.Log(LogLevel.WARNING, "dotnet pack: not packing {0} [{1}]",projectFileName, csProject.GetOutputType());
|
||||
continue;
|
||||
}
|
||||
stage.CommandEnvironment.Logger.Log(LogLevel.WARNING, "dotnet pack: packing now {0} [{1}]",projectFileName, csProject.GetOutputType());
|
||||
|
||||
new CommandRunner("dotnet","pack", projectFileName)
|
||||
.AddArgument(new CommandRunner.Option("-c", stage.CommandEnvironment.Get("DOTNET_CONFIGURATION")))
|
||||
.AddArguments("-o", ".build/")
|
||||
.Run(stage.CommandEnvironment);
|
||||
|
||||
string artefact = String.Format(".build/{0}.{1}.nupkg",csProject.GetName(), csProject.GetVersion());
|
||||
if (!File.Exists(artefact))
|
||||
throw new FileNotFoundException(artefact);
|
||||
|
||||
stage.PipeLine.CommandEnvironment.Extend("DOTNET_ARTEFACTS", artefact);
|
||||
|
||||
}
|
||||
}
|
||||
public static void Publish(Stage stage,params string[] arguments)
|
||||
{
|
||||
List<string> projectFileNames = new List<string>();
|
||||
List<string> artefacts = new List<string>();
|
||||
|
||||
if (arguments.Length == 0)
|
||||
projectFileNames.AddRange(stage.CommandEnvironment.Get("DOTNET_PROJECTS","").Split(':'));
|
||||
else
|
||||
projectFileNames.AddRange(arguments);
|
||||
|
||||
foreach (string projectFileName in projectFileNames)
|
||||
{
|
||||
CSProjHelper csProject = new CSProjHelper(projectFileName);
|
||||
|
||||
if (!csProject.GetOutputType().Equals("Exe"))
|
||||
{
|
||||
stage.CommandEnvironment.Logger.Log(LogLevel.WARNING, "dotnet publish: not publishing {0} [{1}]",projectFileName, csProject.GetOutputType());
|
||||
continue;
|
||||
}
|
||||
stage.CommandEnvironment.Logger.Log(LogLevel.WARNING, "dotnet publish: publishing now {0} [{1}]",projectFileName, csProject.GetOutputType());
|
||||
|
||||
CommandRunner cr = new CommandRunner("dotnet","publish", projectFileName)
|
||||
.AddArgument(new CommandRunner.Option("-c", stage.CommandEnvironment.Get("DOTNET_CONFIGURATION")))
|
||||
.AddArguments("-p:PublishTrimmed=true","-p:PublishSingleFile=true","-p:PublishReadyToRun=false");
|
||||
|
||||
CommandRunner.Option outputOption = new CommandRunner.Option("-o", ".build/");
|
||||
cr.AddArgument(outputOption);
|
||||
|
||||
string[] rids = stage.CommandEnvironment.Get("DOTNET_RIDS","").Split(':');
|
||||
stage.CommandEnvironment.Logger.Log(LogLevel.INFO,"dotnet publish: using rids: {0}", string.Join(' ', rids));
|
||||
|
||||
if (rids.Length == 0)
|
||||
{
|
||||
cr.Run(stage.CommandEnvironment);
|
||||
} else
|
||||
{
|
||||
CommandRunner.Option ridOption = new CommandRunner.Option("-r", "");
|
||||
cr.AddArgument(ridOption);
|
||||
cr.AddArgument("--self-contained");
|
||||
foreach (string rid in rids)
|
||||
{
|
||||
ridOption.SetValue(rid);
|
||||
outputOption.SetValue(String.Format(".build/{0}/", rid));
|
||||
|
||||
cr.Run(stage.CommandEnvironment);
|
||||
|
||||
string artefact = Directory.GetFiles(String.Format(".build/{0}/", rid)).Where((fn)=>!fn.EndsWith(".pdb")).FirstOrDefault();
|
||||
if (artefact != null)
|
||||
{
|
||||
string ext = Path.GetExtension(artefact);
|
||||
if (!ext.Equals(".exe"))
|
||||
ext = "";
|
||||
|
||||
string finalName = string.Format(".build/{0}-{1}{2}",csProject.GetName(), rid, ext);
|
||||
File.Move(artefact, finalName);
|
||||
artefacts.Add(finalName);
|
||||
|
||||
stage.PipeLine.CommandEnvironment.Extend("DOTNET_ARTEFACTS", finalName);
|
||||
|
||||
Directory.Delete(String.Format(".build/{0}/", rid), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage.CommandEnvironment.Logger.Log(LogLevel.INFO,"dotnet publish: created the following artefacts: {0}", string.Join(' ', artefacts));
|
||||
}
|
||||
|
||||
public static void Test(Stage stage,params string[] arguments)
|
||||
{
|
||||
foreach (string projectFileName in stage.CommandEnvironment.Get("DOTNET_PROJECTS","").Split(':'))
|
||||
{
|
||||
new CommandRunner("dotnet","test", projectFileName, new CommandRunner.Option("-c", stage.CommandEnvironment.Get("DOTNET_CONFIGURATION")))
|
||||
.Run(stage.CommandEnvironment);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Push(Stage stage,params string[] arguments)
|
||||
{
|
||||
if (stage.CommandEnvironment.SecretStorage == null)
|
||||
{
|
||||
stage.CommandEnvironment.Logger.Log(LogLevel.WARNING,"dotnet push: no SecretStorage available, push operations are going to fail without authorization!");
|
||||
} else {
|
||||
stage.CommandEnvironment.Logger.Log(LogLevel.INFO,"dotnet push: using secrets from {0}", stage.CommandEnvironment.SecretStorage.FileName);
|
||||
}
|
||||
|
||||
string[] nupkgList = stage.CommandEnvironment.Get("DOTNET_ARTEFACTS","").Split(':').Where((fn)=>fn.EndsWith(".nupkg")).ToArray();
|
||||
string[] binaryList = stage.CommandEnvironment.Get("DOTNET_ARTEFACTS","").Split(':').Where((fn)=>!fn.EndsWith(".nupkg")).ToArray();
|
||||
|
||||
if (nupkgList.Length > 0)
|
||||
{
|
||||
string nugetSource = stage.CommandEnvironment.Get("NUGET_SOURCE");
|
||||
string nugetApiKey = null;
|
||||
|
||||
if (!(stage.CommandEnvironment.SecretStorage?.TryGetSecret(nugetSource, out nugetApiKey) ?? false))
|
||||
{
|
||||
URI uriNuget = new URI(nugetSource);
|
||||
stage.CommandEnvironment.SecretStorage?.TryGetSecret(new URI(uriNuget.Scheme, uriNuget.Authority, "").ToString(), out nugetApiKey);
|
||||
}
|
||||
|
||||
CommandRunner cr = new CommandRunner("dotnet", "nuget", "push");
|
||||
|
||||
CommandRunner.Argument argNupkg = new CommandRunner.Argument("");
|
||||
cr.AddArgument(argNupkg);
|
||||
|
||||
CommandRunner.Option optSource = new CommandRunner.Option("-s",nugetSource);
|
||||
cr.AddArgument(optSource);
|
||||
|
||||
CommandRunner.Option optApiKey = new CommandRunner.Option("-k", nugetApiKey);
|
||||
cr.AddArgument(optApiKey);
|
||||
|
||||
foreach (string nupkg in nupkgList)
|
||||
{
|
||||
argNupkg.SetValue(nupkg);
|
||||
cr.Run(stage.CommandEnvironment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using ln.build.commands;
|
||||
using ln.logging;
|
||||
|
||||
namespace ln.build.pipeline
|
||||
{
|
||||
public class ShellCommand : StageCommand
|
||||
{
|
||||
public event CommandExitedDelegate OnCommandExited;
|
||||
|
||||
public CommandRunner CommandRunner { get; }
|
||||
|
||||
public ShellCommand(string filename,params CommandRunner.Argument[] arguments)
|
||||
:base("SH")
|
||||
{
|
||||
CommandRunner = new CommandRunner("/bin/bash", "-c"){ Throw = CRThrow.NEVER, };
|
||||
CommandRunner.AddArguments(arguments);
|
||||
}
|
||||
public ShellCommand(string cmdline)
|
||||
:base("SH")
|
||||
{
|
||||
CommandRunner = new CommandRunner("/bin/bash", "-c", string.Format("\"{0}\"",cmdline)){ Throw = CRThrow.NEVER, };
|
||||
}
|
||||
|
||||
public override void Run(Stage stage)
|
||||
{
|
||||
MemoryStream logStream = new MemoryStream();
|
||||
int result = CommandRunner.Run(stage.CommandEnvironment, logStream);
|
||||
stage.CommandEnvironment.Logger.Log(LogLevel.INFO, "command output:\n{0}", Encoding.UTF8.GetString(logStream.ToArray()));
|
||||
stage.CommandEnvironment.Logger.Log(LogLevel.INFO, "command exit code: {0}", result);
|
||||
if (result != 0)
|
||||
throw new Exception(String.Format("command exited with code {0} [0x{0:x}]", result));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ln.build.commands;
|
||||
|
||||
namespace ln.build.pipeline
|
||||
{
|
||||
public abstract class StageCommand
|
||||
{
|
||||
public string Name { get; }
|
||||
|
||||
public StageCommand(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public abstract void Run(Stage stage);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static Dictionary<string,Func<string,StageCommand>> commandFactories = new Dictionary<string, Func<string, StageCommand>>();
|
||||
|
||||
public static StageCommand Create(string cmdline)
|
||||
{
|
||||
string[] tokens = cmdline.Split(new char[]{' ','\t'}, 2);
|
||||
|
||||
if (commandFactories.TryGetValue(tokens[0],out Func<string,StageCommand> factory))
|
||||
{
|
||||
return factory(tokens[1]);
|
||||
}
|
||||
throw new Exception(string.Format("can't find factory for command keyword '{0}'", tokens[0]));
|
||||
}
|
||||
|
||||
static StageCommand()
|
||||
{
|
||||
commandFactories.Add("SH", (args) => new ShellCommand(args));
|
||||
commandFactories.Add("DOTNET", (args) => new DotNetCommand(args));
|
||||
commandFactories.Add("GITEA", (args) => new DotNetCommand(args));
|
||||
commandFactories.Add("RELEASE", (args) => new ReleaseCommand(args));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using ln.build.commands;
|
||||
using ln.type;
|
||||
|
||||
namespace ln.build.pipeline
|
||||
{
|
||||
|
||||
public class StageCommandContainer
|
||||
{
|
||||
public StageCommandContainer Parent { get; }
|
||||
public string Name { get; }
|
||||
|
||||
public string FullName => Parent?.FullName != null ? string.Format("{0} {1}", Parent.FullName, Name) : Name;
|
||||
|
||||
Dictionary<string,Action<Stage,string[]>> commands = new Dictionary<string, Action<Stage,string[]>>();
|
||||
Dictionary<string,StageCommandContainer> children = new Dictionary<string, StageCommandContainer>();
|
||||
|
||||
public StageCommandContainer(StageCommandContainer parent, string name)
|
||||
{
|
||||
Parent = parent;
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public void AddCommand(Action<Stage,string[]> commandAction, string commandPath) => AddCommand(commandAction, commandPath.Split());
|
||||
public void AddCommand(Action<Stage,string[]> commandAction, params string[] commandPath)
|
||||
{
|
||||
if (commandPath.Length == 0)
|
||||
throw new ArgumentException(nameof(commandPath));
|
||||
if (commandPath.Length > 1)
|
||||
{
|
||||
if (!children.TryGetValue(commandPath[0], out StageCommandContainer childContainer))
|
||||
{
|
||||
childContainer = new StageCommandContainer(this, commandPath[0]);
|
||||
children.Add(commandPath[0], childContainer);
|
||||
}
|
||||
childContainer.AddCommand(commandAction, commandPath.Slice(1));
|
||||
} else {
|
||||
commands.Add(commandPath[0], commandAction);
|
||||
}
|
||||
}
|
||||
|
||||
public void Run(Stage stage, params string[] arguments)
|
||||
{
|
||||
if (commands.TryGetValue(arguments[0], out Action<Stage,string[]> commandAction))
|
||||
commandAction(stage, arguments.Slice(1));
|
||||
else if (children.TryGetValue(arguments[0], out StageCommandContainer childContainer))
|
||||
childContainer.Run(stage, arguments.Slice(1));
|
||||
else
|
||||
throw new ArgumentException(String.Format("command not found: {0}", arguments[0]));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using ln.build.semver;
|
||||
using ln.build.semver.provider;
|
||||
using ln.json;
|
||||
|
||||
namespace ln.build.pipeline
|
||||
{
|
||||
public class Versioning
|
||||
{
|
||||
public string ProviderName { get; set; }
|
||||
public string[] Sources { get; set; }
|
||||
|
||||
public Provider Provider { get; }
|
||||
|
||||
public Versioning()
|
||||
{}
|
||||
public Versioning(JSONObject jsonVersioning)
|
||||
{
|
||||
ProviderName = jsonVersioning["provider"].ToNative().ToString();
|
||||
if (jsonVersioning.ContainsKey("sources"))
|
||||
Sources = jsonVersioning["sources"].Children.Select((s) => s.ToNative().ToString()).ToArray();
|
||||
|
||||
Provider = Provider.CreateProvider(ProviderName);
|
||||
}
|
||||
|
||||
public Versioning(string providerName)
|
||||
{
|
||||
ProviderName = providerName;
|
||||
Provider = Provider.CreateProvider(ProviderName);
|
||||
}
|
||||
|
||||
public SemVersion GetCurrentVersion(CIJob job) => GetVersion(job, Sources[0]);
|
||||
public SemVersion GetVersion(CIJob job, string source)
|
||||
{
|
||||
string sourceFileName = Path.Combine(job?.WorkingDirectory ?? "", source);
|
||||
return Provider.GetVersion(sourceFileName);
|
||||
}
|
||||
|
||||
public void SetVersion(CIJob job, SemVersion version)
|
||||
{
|
||||
foreach (string source in Sources)
|
||||
SetVersion(job, source, version);
|
||||
}
|
||||
public void SetVersion(CIJob job, string source, SemVersion version)
|
||||
{
|
||||
string sourceFileName = Path.Combine(job?.WorkingDirectory ?? "", source);
|
||||
Provider.SetVersion(sourceFileName, version);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -13,6 +13,10 @@ namespace ln.build.repositories
|
|||
public abstract Release[] GetReleases();
|
||||
public abstract Release GetRelease(string tagName);
|
||||
public abstract Release GetRelease(int id);
|
||||
|
||||
|
||||
public abstract void CommitAndPush(string message, string[] addedPaths, string[] modifiedPaths, string[] removedPaths);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using ln.build.commands;
|
||||
using ln.build.pipeline;
|
||||
using ln.build.secrets;
|
||||
using ln.build.semver;
|
||||
using ln.http;
|
||||
using ln.json;
|
||||
using ln.logging;
|
||||
using ln.threading;
|
||||
using ln.type;
|
||||
|
||||
namespace ln.build.repositories.gitea
|
||||
{
|
||||
|
@ -20,6 +26,8 @@ namespace ln.build.repositories.gitea
|
|||
|
||||
public JsonApiClient Client { get; }
|
||||
|
||||
string AccessToken { get; set; }
|
||||
|
||||
public GiteaRepository(string baseURL, string owner, string name)
|
||||
:base(string.Format("{0}/{1}/{2}.git",baseURL, owner, name))
|
||||
{
|
||||
|
@ -34,6 +42,7 @@ namespace ln.build.repositories.gitea
|
|||
public GiteaRepository(string baseURL, string owner, string name, string accessToken)
|
||||
:this(baseURL, owner, name)
|
||||
{
|
||||
AccessToken = accessToken;
|
||||
if (accessToken != null)
|
||||
Client.HttpClient.DefaultRequestHeaders.Add("Authorization",String.Format("token {0}", accessToken));
|
||||
}
|
||||
|
@ -93,6 +102,27 @@ namespace ln.build.repositories.gitea
|
|||
|
||||
public bool ContainsFile(string filename,string _ref) => (Client.GetJson(out JSONValue response, "repos", Owner, Name, "contents", string.Format("{0}?ref={1}",filename, _ref)) == HttpStatusCode.OK);
|
||||
|
||||
public override void CommitAndPush(string message, string[] addedPaths, string[] modifiedPaths, string[] removedPaths)
|
||||
{
|
||||
CommandRunner cr = new CommandRunner("git","add");
|
||||
cr.AddArguments(addedPaths);
|
||||
cr.AddArguments(modifiedPaths);
|
||||
cr.Run();
|
||||
|
||||
cr = new CommandRunner("git","rm");
|
||||
cr.AddArguments(removedPaths);
|
||||
cr.Run();
|
||||
|
||||
cr = new CommandRunner("git","commit", "-m", message);
|
||||
cr.Run();
|
||||
|
||||
URI baseUri = new URI(BaseURL);
|
||||
if (!AccessToken?.Equals(String.Empty) ?? false)
|
||||
baseUri = baseUri.WithUserInfo(AccessToken);
|
||||
|
||||
cr = new CommandRunner("git","push", baseUri.ToString(true));
|
||||
cr.Run();
|
||||
}
|
||||
|
||||
|
||||
public static HttpResponse WebHookHandler(CIService ciService, HttpRequest request)
|
||||
|
@ -135,6 +165,7 @@ namespace ln.build.repositories.gitea
|
|||
|
||||
string eventType = request.GetRequestHeader("X-GITEA-EVENT");
|
||||
List<string> buildRefs = new List<string>();
|
||||
JSONObject jsonCommit = null;
|
||||
|
||||
switch (eventType)
|
||||
{
|
||||
|
@ -145,8 +176,16 @@ namespace ln.build.repositories.gitea
|
|||
buildRefs.Add(message["release"]["tag_name"].ToNative().ToString());
|
||||
break;
|
||||
case "push":
|
||||
foreach (JSONObject jsonCommit in (message["commits"] as JSONArray).Children)
|
||||
buildRefs.Add(jsonCommit["id"].ToNative().ToString());
|
||||
string currentCommitId = message["after"].ToNative().ToString();
|
||||
foreach (JSONObject _jsonCommit in (message["commits"] as JSONArray).Children)
|
||||
{
|
||||
if (currentCommitId.Equals(_jsonCommit["id"].ToNative().ToString()))
|
||||
{
|
||||
buildRefs.Add(_jsonCommit["id"].ToNative().ToString());
|
||||
jsonCommit = _jsonCommit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Logging.Log(LogLevel.WARNING, "received webhook with unsupported event type [{0}]", eventType);
|
||||
|
@ -162,6 +201,7 @@ namespace ln.build.repositories.gitea
|
|||
.SetVariable("REPO_OWNER", owner)
|
||||
.SetVariable("REPO_NAME", repoName)
|
||||
.SetVariable("REPO_REF", _ref)
|
||||
.SetVariable("REPO_BASE", giteaRepository.BaseURL)
|
||||
// .SetVariable("NOTIFY", message["pusher"]["email"].ToNative().ToString())
|
||||
;
|
||||
ciJob.Environment.SecretStorage = secretStorage;
|
||||
|
@ -173,6 +213,16 @@ namespace ln.build.repositories.gitea
|
|||
ciJob.SetVariable("RELEASE_ID", message["release"]["id"].ToNative().ToString());
|
||||
break;
|
||||
case "push":
|
||||
if (jsonCommit != null)
|
||||
{
|
||||
string commitMessage = jsonCommit["message"].ToNative().ToString();
|
||||
if (commitMessage.Contains("#ReleaseMajor"))
|
||||
ciJob.OnJobCompleted += (job) => job.PublishRelease(SemVerLevels.MAJOR);
|
||||
else if (commitMessage.Contains("#ReleaseMinor"))
|
||||
ciJob.OnJobCompleted += (job) => job.PublishRelease(SemVerLevels.MINOR);
|
||||
else if (commitMessage.Contains("#ReleasePatch"))
|
||||
ciJob.OnJobCompleted += (job) => job.PublishRelease(SemVerLevels.PATCH);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
{
|
||||
"env": {
|
||||
"CONFIGURATION": "Release",
|
||||
"DOTNET_RIDS": "linux-x64:win-x64:osx-x64"
|
||||
},
|
||||
"stages": [
|
||||
{
|
||||
"name": "prepare",
|
||||
"priority": 100,
|
||||
"commands": [
|
||||
"dotnet prepare *.sln *.csproj"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "build",
|
||||
"priority": 300,
|
||||
"commands": [
|
||||
"dotnet build"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "test",
|
||||
"priority": 500,
|
||||
"commands": [
|
||||
"dotnet test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "pack",
|
||||
"priority": 700,
|
||||
"commands": [
|
||||
"dotnet pack",
|
||||
"dotnet publish"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "push",
|
||||
"priority": 1000,
|
||||
"commands": [
|
||||
"dotnet push",
|
||||
"deploy"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -28,6 +28,7 @@ namespace ln.build.secrets
|
|||
JSONObject secretsObject = JSONParser.ParseFile(FileName) as JSONObject;
|
||||
foreach (string key in secretsObject.Keys)
|
||||
{
|
||||
//Logging.Log(LogLevel.INFO, "loading secret {0}", key);
|
||||
secrets.Add(key, secretsObject[key].ToNative().ToString());
|
||||
}
|
||||
}
|
||||
|
@ -36,9 +37,15 @@ namespace ln.build.secrets
|
|||
|
||||
public string GetSecret(string key)
|
||||
{
|
||||
//Logging.Log(LogLevel.INFO, "trying to fetch secret for: [{0}]", key);
|
||||
TryGetSecret(key, out string secret);
|
||||
return secret;
|
||||
}
|
||||
public bool TryGetSecret(string key, out string secret) => secrets.TryGetValue(key, out secret);
|
||||
public bool TryGetSecret(string key, out string secret){
|
||||
//Logging.Log(LogLevel.INFO, "trying to fetch secret for: [{0}]", key);
|
||||
bool success = secrets.TryGetValue(key, out secret);
|
||||
//Logging.Log(LogLevel.INFO, "{1} to fetch secret for: [{0}]", key, success ? "succeded" : "failed");
|
||||
return success;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
|
||||
namespace ln.build.semver
|
||||
{
|
||||
public enum SemVerLevels {
|
||||
MAJOR,
|
||||
MINOR,
|
||||
PATCH,
|
||||
TAG
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using ln.build.semver;
|
||||
using Microsoft.VisualBasic;
|
||||
|
||||
namespace ln.build.semver
|
||||
{
|
||||
|
||||
public class SemVersion
|
||||
{
|
||||
public int Major { get; set; }
|
||||
public int Minor { get; set; }
|
||||
public int Patch { get; set; }
|
||||
public string PreRelease { get; set; } = String.Empty;
|
||||
|
||||
public bool IsPreRelease => !PreRelease?.Equals(string.Empty) ?? false;
|
||||
public bool IsRelease => PreRelease?.Equals(string.Empty) ?? true;
|
||||
|
||||
public SemVersion(int major,int minor,int patch,string prerelease)
|
||||
{
|
||||
Major = major;
|
||||
Minor = minor;
|
||||
Patch = patch;
|
||||
PreRelease = prerelease;
|
||||
}
|
||||
private SemVersion(){}
|
||||
public SemVersion(SemVersion source)
|
||||
:this(source.Major, source.Minor, source.Patch, source.PreRelease)
|
||||
{ }
|
||||
|
||||
|
||||
public void Increment(SemVerLevels level){
|
||||
switch (level)
|
||||
{
|
||||
case SemVerLevels.MAJOR:
|
||||
Major++;
|
||||
Minor = 0;
|
||||
Patch = 0;
|
||||
break;
|
||||
case SemVerLevels.MINOR:
|
||||
Minor++;
|
||||
Patch = 0;
|
||||
break;
|
||||
case SemVerLevels.PATCH:
|
||||
Patch++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
stringBuilder.AppendFormat("{0}.{1}.{2}", Major, Minor, Patch);
|
||||
if (!PreRelease?.Equals(string.Empty) ?? false)
|
||||
stringBuilder.AppendFormat("-{0}", PreRelease);
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
|
||||
public static Regex rexVersion = new Regex("^(?<major>\\d+).(?<minor>\\d+).(?<patch>\\d+)(-(?<prerelease>.+))?$");
|
||||
public static SemVersion Parse(string versionString)
|
||||
{
|
||||
Match match = rexVersion.Match(versionString);
|
||||
if (!match.Success)
|
||||
throw new FormatException(String.Format("{0} is no valid SemVer", versionString));
|
||||
|
||||
SemVersion version = new SemVersion();
|
||||
version.Major = int.Parse(match.Groups["major"].Value);
|
||||
version.Minor = int.Parse(match.Groups["minor"].Value);
|
||||
version.Patch = int.Parse(match.Groups["patch"].Value);
|
||||
if (match.Groups["prerelease"].Success)
|
||||
version.PreRelease = match.Groups["prerelease"].Value;
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
using System;
|
||||
using System.Xml;
|
||||
using ln.build.semver;
|
||||
|
||||
namespace ln.build.semver.provider
|
||||
{
|
||||
|
||||
public class DotNetProvider : Provider
|
||||
{
|
||||
public DotNetProvider(): base("dotnet")
|
||||
{}
|
||||
|
||||
public override SemVersion GetVersion(string source)
|
||||
{
|
||||
XmlDocument projectFile = new XmlDocument();
|
||||
projectFile.Load(source);
|
||||
|
||||
XmlNode nodeVersion = projectFile.SelectSingleNode("Project/PropertyGroup/Version");
|
||||
return SemVersion.Parse(nodeVersion.InnerText);
|
||||
}
|
||||
|
||||
public override void SetVersion(string source, SemVersion version)
|
||||
{
|
||||
XmlDocument projectFile = new XmlDocument();
|
||||
projectFile.Load(source);
|
||||
|
||||
XmlNode nodeVersion = projectFile.SelectSingleNode("Project/PropertyGroup/Version");
|
||||
nodeVersion.InnerText = version.ToString();
|
||||
|
||||
projectFile.Save(source);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.IO;
|
||||
|
||||
namespace ln.build.semver.provider
|
||||
{
|
||||
|
||||
public abstract class Provider
|
||||
{
|
||||
|
||||
public String Name { get; }
|
||||
|
||||
public Provider(string providerName)
|
||||
{
|
||||
Name = providerName;
|
||||
}
|
||||
|
||||
public abstract SemVersion GetVersion(string source);
|
||||
public abstract void SetVersion(string source, SemVersion version);
|
||||
|
||||
|
||||
|
||||
public static Provider CreateProvider(string providerName)
|
||||
{
|
||||
switch (providerName)
|
||||
{
|
||||
case "dotnet":
|
||||
return new DotNetProvider();
|
||||
default:
|
||||
throw new FileNotFoundException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
|
||||
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using ln.build.semver;
|
||||
|
||||
namespace ln.build.support.dotnet
|
||||
{
|
||||
|
||||
public class CSProjHelper
|
||||
{
|
||||
public string FileName { get; set; }
|
||||
|
||||
public CSProjHelper(string filename)
|
||||
{
|
||||
FileName = filename;
|
||||
}
|
||||
|
||||
public string GetName()
|
||||
{
|
||||
XmlDocument projectFile = new XmlDocument();
|
||||
projectFile.Load(FileName);
|
||||
|
||||
XmlNode nodeVersion = projectFile.SelectSingleNode("Project/PropertyGroup/AssemblyName");
|
||||
return nodeVersion?.InnerText ?? Path.GetFileNameWithoutExtension(FileName);
|
||||
}
|
||||
|
||||
public SemVersion GetVersion()
|
||||
{
|
||||
XmlDocument projectFile = new XmlDocument();
|
||||
projectFile.Load(FileName);
|
||||
XmlNode nodeVersion = projectFile.SelectSingleNode("Project/PropertyGroup/Version");
|
||||
return SemVersion.Parse(nodeVersion.InnerText);
|
||||
}
|
||||
|
||||
public void SetVersion(SemVersion version)
|
||||
{
|
||||
XmlDocument projectFile = new XmlDocument();
|
||||
projectFile.Load(FileName);
|
||||
|
||||
XmlNode nodeVersion = projectFile.SelectSingleNode("Project/PropertyGroup/Version");
|
||||
nodeVersion.InnerText = version.ToString();
|
||||
|
||||
projectFile.Save(FileName);
|
||||
}
|
||||
|
||||
public bool IsPackable()
|
||||
{
|
||||
XmlDocument projectFile = new XmlDocument();
|
||||
projectFile.Load(FileName);
|
||||
XmlNode nodePackable = projectFile.SelectSingleNode("Project/PropertyGroup/IsPackable");
|
||||
return bool.Parse(nodePackable?.InnerText ?? "true");
|
||||
}
|
||||
|
||||
public string GetOutputType()
|
||||
{
|
||||
XmlDocument projectFile = new XmlDocument();
|
||||
projectFile.Load(FileName);
|
||||
|
||||
XmlNode nodeVersion = projectFile.SelectSingleNode("Project/PropertyGroup/OutputType");
|
||||
return nodeVersion?.InnerText ?? "Library";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue