tgstation-server 6.16.0
The /tg/station 13 server suite
Loading...
Searching...
No Matches
BaseRemoteDeploymentManager.cs
Go to the documentation of this file.
1using System;
2using System.Collections.Concurrent;
3using System.Collections.Generic;
4using System.Linq;
5using System.Threading;
6using System.Threading.Tasks;
7
8using Microsoft.Extensions.Logging;
9
13
15{
20 {
24 public const string DeploymentMsgHeaderStart = "<!-- tgs_test_merge_comment -->";
25
29 protected Api.Models.Instance Metadata { get; }
30
34 protected ILogger<BaseRemoteDeploymentManager> Logger { get; }
35
39 readonly ConcurrentDictionary<long, Action<bool>> activationCallbacks;
40
48 ILogger<BaseRemoteDeploymentManager> logger,
49 Api.Models.Instance metadata,
50 ConcurrentDictionary<long, Action<bool>> activationCallbacks)
51 {
52 Logger = logger ?? throw new ArgumentNullException(nameof(logger));
53 Metadata = metadata ?? throw new ArgumentNullException(nameof(metadata));
54 this.activationCallbacks = activationCallbacks ?? throw new ArgumentNullException(nameof(activationCallbacks));
55 }
56
58 public async ValueTask PostDeploymentComments(
59 CompileJob compileJob,
60 RevisionInformation? previousRevisionInformation,
61 RepositorySettings repositorySettings,
62 string? repoOwner,
63 string? repoName,
64 CancellationToken cancellationToken)
65 {
66 ArgumentNullException.ThrowIfNull(compileJob);
67 ArgumentNullException.ThrowIfNull(repositorySettings);
68 ArgumentNullException.ThrowIfNull(repoOwner);
69 ArgumentNullException.ThrowIfNull(repoName);
70
71 if (repositorySettings.AccessToken == null)
72 return;
73
74 var revisionInformation = compileJob.RevisionInformation;
75 if ((previousRevisionInformation != null && previousRevisionInformation.CommitSha == revisionInformation.CommitSha)
76 || !repositorySettings.PostTestMergeComment!.Value)
77 return;
78
79 var previousTestMerges = (IEnumerable<RevInfoTestMerge>?)previousRevisionInformation?.ActiveTestMerges ?? Enumerable.Empty<RevInfoTestMerge>();
80 var currentTestMerges = (IEnumerable<RevInfoTestMerge>?)revisionInformation.ActiveTestMerges ?? Enumerable.Empty<RevInfoTestMerge>();
81
82 // determine what TMs were changed and how
83 var addedTestMerges = currentTestMerges
84 .Select(x => x.TestMerge)
85 .Where(x => !previousTestMerges
86 .Any(y => y.TestMerge.Number == x.Number))
87 .ToList();
88 var removedTestMerges = previousTestMerges
89 .Select(x => x.TestMerge)
90 .Where(x => !currentTestMerges
91 .Any(y => y.TestMerge.Number == x.Number))
92 .ToList();
93 var updatedTestMerges = currentTestMerges
94 .Select(x => x.TestMerge)
95 .Where(x => previousTestMerges
96 .Any(y => y.TestMerge.Number == x.Number))
97 .ToList();
98
99 if (addedTestMerges.Count == 0 && removedTestMerges.Count == 0 && updatedTestMerges.Count == 0)
100 return;
101
102 Logger.LogTrace(
103 "Commenting on {addedCount} added, {removedCount} removed, and {updatedCount} updated test merge sources...",
104 addedTestMerges.Count,
105 removedTestMerges.Count,
106 updatedTestMerges.Count);
107
108 var tasks = new List<ValueTask>(addedTestMerges.Count + updatedTestMerges.Count + removedTestMerges.Count);
109 foreach (var addedTestMerge in addedTestMerges)
110 {
111 var addCommentTask = CommentOnTestMergeSource(
112 repositorySettings,
113 repoOwner,
114 repoName,
116 repositorySettings,
117 compileJob,
118 addedTestMerge,
119 repoOwner,
120 repoName,
121 false),
122 addedTestMerge.Number,
123 cancellationToken);
124 tasks.Add(addCommentTask);
125 }
126
127 foreach (var removedTestMerge in removedTestMerges)
128 {
129 var removeCommentTask = CommentOnTestMergeSource(
130 repositorySettings,
131 repoOwner,
132 repoName,
134 repositorySettings,
135 compileJob,
136 removedTestMerge,
137 repoOwner,
138 repoName),
139 removedTestMerge.Number,
140 cancellationToken);
141 tasks.Add(removeCommentTask);
142 }
143
144 foreach (var updatedTestMerge in updatedTestMerges)
145 {
146 var updateCommentTask = CommentOnTestMergeSource(
147 repositorySettings,
148 repoOwner,
149 repoName,
151 repositorySettings,
152 compileJob,
153 updatedTestMerge,
154 repoOwner,
155 repoName,
156 true),
157 updatedTestMerge.Number,
158 cancellationToken);
159 tasks.Add(updateCommentTask);
160 }
161
162 if (tasks.Count > 0)
163 await ValueTaskExtensions.WhenAll(tasks);
164 }
165
167 public ValueTask ApplyDeployment(CompileJob compileJob, CancellationToken cancellationToken)
168 {
169 ArgumentNullException.ThrowIfNull(compileJob);
170
171 if (activationCallbacks.TryGetValue(compileJob.Require(x => x.Id), out var activationCallback))
172 activationCallback(true);
173
174 return ApplyDeploymentImpl(compileJob, cancellationToken);
175 }
176
178 public abstract ValueTask FailDeployment(CompileJob compileJob, string errorMessage, CancellationToken cancellationToken);
179
181 public ValueTask MarkInactive(CompileJob compileJob, CancellationToken cancellationToken)
182 {
183 ArgumentNullException.ThrowIfNull(compileJob);
184
185 if (activationCallbacks.TryRemove(compileJob.Require(x => x.Id), out var activationCallback))
186 activationCallback(false);
187
188 return MarkInactiveImpl(compileJob, cancellationToken);
189 }
190
192 public abstract ValueTask<IReadOnlyCollection<TestMerge>> RemoveMergedTestMerges(
193 IRepository repository,
194 RepositorySettings repositorySettings,
195 RevisionInformation revisionInformation,
196 CancellationToken cancellationToken);
197
199 public ValueTask StageDeployment(CompileJob compileJob, Action<bool>? activationCallback, CancellationToken cancellationToken)
200 {
201 ArgumentNullException.ThrowIfNull(compileJob);
202
203 var compileJobId = compileJob.Require(x => x.Id);
204 if (activationCallback != null && !activationCallbacks.TryAdd(compileJobId, activationCallback))
205 Logger.LogError("activationCallbacks conflicted on CompileJob #{id}!", compileJobId);
206
207 return StageDeploymentImpl(compileJob, cancellationToken);
208 }
209
211 public abstract ValueTask StartDeployment(
212 Api.Models.Internal.IGitRemoteInformation remoteInformation,
213 CompileJob compileJob,
214 CancellationToken cancellationToken);
215
222 protected abstract ValueTask StageDeploymentImpl(CompileJob compileJob, CancellationToken cancellationToken);
223
230 protected abstract ValueTask ApplyDeploymentImpl(CompileJob compileJob, CancellationToken cancellationToken);
231
238 protected abstract ValueTask MarkInactiveImpl(CompileJob compileJob, CancellationToken cancellationToken);
239
250 protected abstract string FormatTestMerge(
251 RepositorySettings repositorySettings,
252 CompileJob compileJob,
253 TestMerge testMerge,
254 string remoteRepositoryOwner,
255 string remoteRepositoryName,
256 bool updated);
257
267 protected abstract string FormatTestMergeRemoval(
268 RepositorySettings repositorySettings,
269 CompileJob compileJob,
270 TestMerge testMerge,
271 string remoteRepositoryOwner,
272 string remoteRepositoryName);
273
284 protected abstract ValueTask CommentOnTestMergeSource(
285 RepositorySettings repositorySettings,
286 string remoteRepositoryOwner,
287 string remoteRepositoryName,
288 string comment,
289 int testMergeNumber,
290 CancellationToken cancellationToken);
291 }
292}
Metadata about a server instance.
Definition Instance.cs:9
bool? PostTestMergeComment
If test merging should create a comment. Requires AccessToken to be set to function.
string? AccessToken
The token/password to access the git repository with. Can also be a TGS encoded app private key....
Extension methods for the ValueTask and ValueTask<TResult> classes.
static async ValueTask WhenAll(IEnumerable< ValueTask > tasks)
Fully await a given list of tasks .
ValueTask StartDeployment(Api.Models.Internal.IGitRemoteInformation remoteInformation, CompileJob compileJob, CancellationToken cancellationToken)
Start a deployment for a given compileJob .A ValueTask representing the running operation.
ValueTask ApplyDeploymentImpl(CompileJob compileJob, CancellationToken cancellationToken)
Implementation of ApplyDeployment(CompileJob, CancellationToken).
Api.Models.Instance Metadata
The Api.Models.Instance for the BaseRemoteDeploymentManager.
ValueTask FailDeployment(CompileJob compileJob, string errorMessage, CancellationToken cancellationToken)
Fail a deployment for a given compileJob .A ValueTask representing the running operation.
const string DeploymentMsgHeaderStart
The header comment that begins every deployment message comment/note.
ValueTask StageDeployment(CompileJob compileJob, Action< bool >? activationCallback, CancellationToken cancellationToken)
Stage a given compileJob 's deployment.A ValueTask representing the running operation.
ValueTask MarkInactiveImpl(CompileJob compileJob, CancellationToken cancellationToken)
Implementation of MarkInactive(CompileJob, CancellationToken).
ValueTask MarkInactive(CompileJob compileJob, CancellationToken cancellationToken)
Mark the deplotment for a given compileJob as inactive.A Task representing the running operation.
ValueTask CommentOnTestMergeSource(RepositorySettings repositorySettings, string remoteRepositoryOwner, string remoteRepositoryName, string comment, int testMergeNumber, CancellationToken cancellationToken)
Create a comment of a given testMergeNumber 's source.
string FormatTestMerge(RepositorySettings repositorySettings, CompileJob compileJob, TestMerge testMerge, string remoteRepositoryOwner, string remoteRepositoryName, bool updated)
Formats a comment for a given testMerge .
ValueTask StageDeploymentImpl(CompileJob compileJob, CancellationToken cancellationToken)
Implementation of StageDeployment(CompileJob, Action<bool>, CancellationToken).
readonly ConcurrentDictionary< long, Action< bool > > activationCallbacks
A map of CompileJob Api.Models.EntityId.Ids to activation callback Action<T1>s.
BaseRemoteDeploymentManager(ILogger< BaseRemoteDeploymentManager > logger, Api.Models.Instance metadata, ConcurrentDictionary< long, Action< bool > > activationCallbacks)
Initializes a new instance of the BaseRemoteDeploymentManager class.
async ValueTask PostDeploymentComments(CompileJob compileJob, RevisionInformation? previousRevisionInformation, RepositorySettings repositorySettings, string? repoOwner, string? repoName, CancellationToken cancellationToken)
Post deployment comments to the test merge ticket.A ValueTask representing the running operation.
ValueTask ApplyDeployment(CompileJob compileJob, CancellationToken cancellationToken)
Stage a given compileJob 's deployment.A ValueTask representing the running operation.
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...
string FormatTestMergeRemoval(RepositorySettings repositorySettings, CompileJob compileJob, TestMerge testMerge, string remoteRepositoryOwner, string remoteRepositoryName)
Formats a comment for a given testMerge removal.
ILogger< BaseRemoteDeploymentManager > Logger
The ILogger for the BaseRemoteDeploymentManager.
RevisionInformation RevisionInformation
See CompileJobResponse.RevisionInformation.
Definition CompileJob.cs:27
Many to many relationship for Models.RevisionInformation and Models.TestMerge.
Represents an on-disk git repository.