255 lines
11 KiB
C#
255 lines
11 KiB
C#
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
|
|
{
|
|
|
|
public class GiteaRepository : GitRepository
|
|
{
|
|
public string BaseURL { get; }
|
|
public string Owner { get; }
|
|
public string Name { get; }
|
|
|
|
public SecretStorage SecretStorage { get; set; }
|
|
|
|
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))
|
|
{
|
|
Logging.Log(LogLevel.DEBUG, "new GiteaRepository({0},{1},{2})", baseURL, owner, name);
|
|
|
|
BaseURL = baseURL;
|
|
Owner = owner;
|
|
Name = name;
|
|
|
|
Client = new JsonApiClient(string.Format("{0}/api/v1",baseURL));
|
|
}
|
|
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));
|
|
}
|
|
|
|
public override void UpdateBuildState(CIJob job)
|
|
{
|
|
JSONObject stateObject = new JSONObject();
|
|
stateObject.Add("context", string.Format("ln.build - {0}", job.CIService.HostName));
|
|
stateObject.Add("description", "build job pending");
|
|
stateObject.Add("state", job.BuildState.ToString().ToLower());
|
|
stateObject.Add("target_url", job.CIService.GetJobURL(job));
|
|
|
|
if (HttpStatusCode.Created != Client.PostJson(
|
|
stateObject,
|
|
out JSONValue response,
|
|
"repos", job.GetVariable("REPO_OWNER"), job.GetVariable("REPO_NAME"), "statuses", job.GetVariable("REPO_REF")
|
|
))
|
|
{
|
|
job.Logger.Log(LogLevel.ERROR, "{0}: UpdateBuildState(): could not post state", GetType().Name);
|
|
}
|
|
}
|
|
|
|
public override Release[] GetReleases()
|
|
{
|
|
if (HttpStatusCode.OK == Client.GetJson(
|
|
out JSONValue jsonReleases,
|
|
"repos", Owner, Name, "releases"
|
|
))
|
|
{
|
|
List<Release> releases = new List<Release>();
|
|
|
|
foreach (JSONObject jsonRelease in jsonReleases.Children)
|
|
{
|
|
GiteaRelease giteaRelease = new GiteaRelease(this, jsonRelease);
|
|
releases.Add(giteaRelease);
|
|
}
|
|
|
|
|
|
return releases.ToArray();
|
|
}
|
|
return new Release[0];
|
|
}
|
|
|
|
public override Release GetRelease(string tagName)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
public override Release GetRelease(int releaseId)
|
|
{
|
|
if (HttpStatusCode.OK == Client.GetJson(out JSONValue jsonRelease, "repos", Owner, Name, "releases", releaseId.ToString()))
|
|
{
|
|
return new GiteaRelease(this, jsonRelease as JSONObject);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
|
|
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)
|
|
{
|
|
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 hookSecret = message["secret"].ToNative().ToString();
|
|
string owner = message["repository"]["owner"]["username"].ToNative().ToString();
|
|
string repoName = message["repository"]["name"].ToNative().ToString();
|
|
|
|
string htmlUrl = message["repository"]["html_url"].ToNative().ToString();
|
|
string repoPath = String.Format("/{0}/{1}", owner, repoName);
|
|
if (!htmlUrl.EndsWith(repoPath))
|
|
{
|
|
Logging.Log(LogLevel.WARNING, "unable to detect gitea base url from [{0}] for ({1}/{2})", htmlUrl, owner, repoName);
|
|
response.StatusCode = 500;
|
|
return response;
|
|
}
|
|
|
|
string giteaBaseUrl = htmlUrl.Remove(htmlUrl.Length - repoPath.Length);
|
|
|
|
|
|
SecretStorage secretStorage = ciService.GetSecretStorage(hookSecret);
|
|
GiteaRepository giteaRepository = new GiteaRepository(giteaBaseUrl, owner, repoName, secretStorage.GetSecret(giteaBaseUrl)){
|
|
SecretStorage = secretStorage,
|
|
};
|
|
|
|
string eventType = request.GetRequestHeader("X-GITEA-EVENT");
|
|
List<string> buildRefs = new List<string>();
|
|
JSONObject jsonCommit = null;
|
|
|
|
switch (eventType)
|
|
{
|
|
case "release":
|
|
if (!message["action"].ToNative().ToString().Equals("published"))
|
|
return response;
|
|
|
|
buildRefs.Add(message["release"]["tag_name"].ToNative().ToString());
|
|
break;
|
|
case "push":
|
|
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);
|
|
return response;
|
|
}
|
|
|
|
foreach (string _ref in buildRefs)
|
|
{
|
|
if (giteaRepository.ContainsFile("build.ln", _ref))
|
|
{
|
|
CIJob ciJob = new CIJob(ciService, giteaRepository)
|
|
.SetVariable("REPO_EVENT", eventType)
|
|
.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;
|
|
|
|
switch (eventType)
|
|
{
|
|
case "release":
|
|
ciJob.SetVariable("RELEASE_TAGNAME", message["release"]["tag_name"].ToNative().ToString());
|
|
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;
|
|
}
|
|
|
|
|
|
ciJob.UpdateBuildState(BuildState.PENDING);
|
|
ciService.Enqueue(ciJob);
|
|
}
|
|
}
|
|
} 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} |