2using System.Collections.Concurrent;
3using System.Collections.Generic;
4using System.Globalization;
7using System.Threading.Tasks;
9using Microsoft.Extensions.Logging;
31 ILogger<GitLabRemoteDeploymentManager> logger,
32 Api.Models.Instance metadata,
43 CancellationToken cancellationToken)
45 ArgumentNullException.ThrowIfNull(repository);
46 ArgumentNullException.ThrowIfNull(repositorySettings);
47 ArgumentNullException.ThrowIfNull(revisionInformation);
51 Logger.LogTrace(
"No test merges to remove.");
55 var newList = revisionInformation.
ActiveTestMerges.Select(x => x.TestMerge).ToList();
58 IOperationResult<IGetMergeRequestsResult> operationResult;
61 operationResult = await client.GraphQL.GetMergeRequests.ExecuteAsync(
62 $
"{repository.RemoteRepositoryOwner}/{repository.RemoteRepositoryName}",
63 revisionInformation.
ActiveTestMerges.Select(revInfoTestMerge => revInfoTestMerge.TestMerge.Number.ToString(CultureInfo.InvariantCulture)).ToList(),
66 operationResult.EnsureNoErrors();
68 catch (
Exception ex) when (ex is not OperationCanceledException)
70 Logger.LogWarning(ex,
"Merge requests update check failed!");
74 var data = operationResult.Data?.Project?.MergeRequests?.Nodes;
77 Logger.LogWarning(
"GitLab MergeRequests check returned null!");
81 async ValueTask CheckRemoveMR(IGetMergeRequests_Project_MergeRequests_Nodes? mergeRequest)
83 if (mergeRequest ==
null)
85 Logger.LogWarning(
"GitLab MergeRequest node was null!");
89 if (mergeRequest.State != MergeRequestState.Merged)
92 var mergeCommitSha = mergeRequest.MergeCommitSha;
93 if (mergeCommitSha ==
null)
95 Logger.LogWarning(
"MergeRequest #{id} had no MergeCommitSha!", mergeRequest.Iid);
99 var closedAtStr = mergeRequest.ClosedAt;
100 if (closedAtStr ==
null)
102 Logger.LogWarning(
"MergeRequest #{id} had no ClosedAt!", mergeRequest.Iid);
106 if (!DateTimeOffset.TryParseExact(closedAtStr,
"O", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out DateTimeOffset closedAt))
108 Logger.LogWarning(
"MergeRequest #{id} had invalid ClosedAt: {closedAt}", mergeRequest.Iid, closedAtStr);
112 if (!Int64.TryParse(mergeRequest.Iid, out
long number))
114 Logger.LogWarning(
"MergeRequest #{id} is non-numeric!", mergeRequest.Iid);
122 potential => potential.Number == number));
125 foreach (var mergeRequest
in data)
126 await CheckRemoveMR(mergeRequest);
135 CancellationToken cancellationToken) => ValueTask.CompletedTask;
139 Api.Models.Internal.IGitRemoteInformation remoteInformation,
141 CancellationToken cancellationToken) => ValueTask.CompletedTask;
146 CancellationToken cancellationToken) => ValueTask.CompletedTask;
157 string remoteRepositoryOwner,
158 string remoteRepositoryName,
161 CancellationToken cancellationToken)
166 string header = String.Format(CultureInfo.InvariantCulture,
"{1}{0}## Test merge deployment history:{0}{0}", Environment.NewLine,
DeploymentMsgHeaderStart);
169 var notesQueryResult = await client.GraphQL.GetMergeRequestNotes.ExecuteAsync(
170 $
"{remoteRepositoryOwner}/{remoteRepositoryName}",
171 testMergeNumber.ToString(CultureInfo.InvariantCulture),
174 notesQueryResult.EnsureNoErrors();
176 var mergeRequest = notesQueryResult.Data?.Project?.MergeRequest;
177 if (mergeRequest ==
null)
179 Logger.LogWarning(
"GitLab GetMergeRequestNotes mergeRequest returned null!");
183 var comments = mergeRequest.Notes?.Nodes;
184 IGetMergeRequestNotes_Project_MergeRequest_Notes_Nodes? existingComment =
null;
185 if (comments !=
null)
187 for (
int i = comments.Count - 1; i > -1; i--)
189 var currentComment = comments[i];
192 if (currentComment.Body.Length > 987856)
197 existingComment = currentComment;
204 if (existingComment !=
null)
206 var noteModificationResult = await client.GraphQL.ModifyNote.ExecuteAsync(
208 existingComment.Body + comment,
211 notesQueryResult.EnsureNoErrors();
215 var noteCreationResult = await client.GraphQL.CreateNote.ExecuteAsync(
220 noteCreationResult.EnsureNoErrors();
223 catch (
Exception ex) when (ex is not OperationCanceledException)
225 Logger.LogWarning(ex,
"Error posting GitLab comment!");
234 string remoteRepositoryOwner,
235 string remoteRepositoryName,
236 bool updated) => String.Format(
237 CultureInfo.InvariantCulture,
238 "<details><summary>Test Merge {4} @ {8}</summary>{0}{0}##### Server Instance{0}{5}{1}{0}{0}##### Revision{0}Origin: {6}{0}Merge Request: {2}{0}Server: {7}{3}</details>{0}",
240 repositorySettings.ShowTestMergeCommitters!.Value
242 CultureInfo.InvariantCulture,
243 "{0}{0}##### Merged By{0}{1}",
245 testMerge.MergedBy!.Name)
247 testMerge.TargetCommitSha,
248 String.IsNullOrEmpty(testMerge.Comment)
251 CultureInfo.InvariantCulture,
252 "{0}{0}##### Comment{0}{1}",
255 updated ?
"Updated" :
"Deployed",
259 compileJob.
Job.StartedAt);
266 string remoteRepositoryOwner,
267 string remoteRepositoryName) => String.Format(
268 CultureInfo.InvariantCulture,
269 "<details><summary>Test Merge Removed @ {2}:</summary>{0}{0}##### Server Instance{0}{1}{0}</details>{0}",
272 compileJob.Job.StartedAt);
string? AccessToken
The token/password to access the git repository with. Can also be a TGS encoded app private key....
string? AccessUser
The username to access the git repository with. If using a TGS encoded app private key for AccessToke...
Base class for implementing IRemoteDeploymentManagers.
Api.Models.Instance Metadata
The Api.Models.Instance for the BaseRemoteDeploymentManager.
const string DeploymentMsgHeaderStart
The header comment that begins every deployment message comment/note.
readonly ConcurrentDictionary< long, Action< bool > > activationCallbacks
A map of CompileJob Api.Models.EntityId.Ids to activation callback Action<T1>s.
ILogger< BaseRemoteDeploymentManager > Logger
The ILogger for the BaseRemoteDeploymentManager.
IRemoteDeploymentManager for GitLab.com.
override async ValueTask< IReadOnlyCollection< TestMerge > > RemoveMergedTestMerges(IRepository repository, RepositorySettings repositorySettings, RevisionInformation revisionInformation, CancellationToken cancellationToken)
Get the updated list of TestMerges for an origin merge.A ValueTask<TResult> resulting in the IReadOnl...
override ValueTask ApplyDeploymentImpl(CompileJob compileJob, CancellationToken cancellationToken)
override string FormatTestMerge(RepositorySettings repositorySettings, CompileJob compileJob, TestMerge testMerge, string remoteRepositoryOwner, string remoteRepositoryName, bool updated)
override async ValueTask CommentOnTestMergeSource(RepositorySettings repositorySettings, string remoteRepositoryOwner, string remoteRepositoryName, string comment, int testMergeNumber, CancellationToken cancellationToken)
override ValueTask StageDeploymentImpl(CompileJob compileJob, CancellationToken cancellationToken)
override ValueTask StartDeployment(Api.Models.Internal.IGitRemoteInformation remoteInformation, CompileJob compileJob, CancellationToken cancellationToken)
Start a deployment for a given compileJob .A ValueTask representing the running operation.
GitLabRemoteDeploymentManager(ILogger< GitLabRemoteDeploymentManager > logger, Api.Models.Instance metadata, ConcurrentDictionary< long, Action< bool > > activationCallbacks)
Initializes a new instance of the GitLabRemoteDeploymentManager class.
override string FormatTestMergeRemoval(RepositorySettings repositorySettings, CompileJob compileJob, TestMerge testMerge, string remoteRepositoryOwner, string remoteRepositoryName)
override ValueTask MarkInactiveImpl(CompileJob compileJob, CancellationToken cancellationToken)
override ValueTask FailDeployment(CompileJob compileJob, string errorMessage, CancellationToken cancellationToken)
Fail a deployment for a given compileJob .A ValueTask representing the running operation.
Factory for creating IGraphQLGitLabClients.
static async ValueTask< IGraphQLGitLabClient > CreateClient(string? bearerToken=null)
Sets up a IGraphQLGitLabClient.
Represents an on-disk git repository.
Task< bool > CommittishIsParent(string committish, CancellationToken cancellationToken)
Check if a given committish is a parent of the current Head.