mirror of
https://github.com/microsoft/onefuzz.git
synced 2025-06-09 16:51:35 +00:00
Validate scriban on new notifications (#2834)
* Add new command * Enforce scriban at notification creation time * fmt * missed when merging
This commit is contained in:
parent
21374b36e6
commit
e9f5a6a2e7
@ -39,11 +39,11 @@ public class JinjaToScriban {
|
||||
_log.Info($"Finding notifications to migrate");
|
||||
|
||||
var notifications = _context.NotificationOperations.SearchAll()
|
||||
.Select(notification => {
|
||||
.SelectAwait(async notification => {
|
||||
var (didModify, config) = notification.Config switch {
|
||||
TeamsTemplate => (false, notification.Config),
|
||||
AdoTemplate adoTemplate => ConvertToScriban(adoTemplate),
|
||||
GithubIssuesTemplate githubIssuesTemplate => ConvertToScriban(githubIssuesTemplate),
|
||||
AdoTemplate adoTemplate => await JinjaTemplateAdapter.ConvertToScriban(adoTemplate),
|
||||
GithubIssuesTemplate githubIssuesTemplate => await JinjaTemplateAdapter.ConvertToScriban(githubIssuesTemplate),
|
||||
_ => throw new NotImplementedException("Unexpected notification configuration type")
|
||||
};
|
||||
|
||||
@ -82,153 +82,4 @@ public class JinjaToScriban {
|
||||
|
||||
return await RequestHandling.Ok(req, new JinjaToScribanMigrationResponse(updatedNotificationsIds, failedNotificationIds));
|
||||
}
|
||||
|
||||
private static (bool didModify, AdoTemplate template) ConvertToScriban(AdoTemplate template) {
|
||||
var didModify = false;
|
||||
|
||||
if (JinjaTemplateAdapter.IsJinjaTemplate(template.Project)) {
|
||||
didModify = true;
|
||||
template = template with {
|
||||
Project = JinjaTemplateAdapter.AdaptForScriban(template.Project)
|
||||
};
|
||||
}
|
||||
|
||||
foreach (var item in template.AdoFields) {
|
||||
if (JinjaTemplateAdapter.IsJinjaTemplate(item.Value)) {
|
||||
template.AdoFields[item.Key] = JinjaTemplateAdapter.AdaptForScriban(item.Value);
|
||||
didModify = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (JinjaTemplateAdapter.IsJinjaTemplate(template.Type)) {
|
||||
didModify = true;
|
||||
template = template with {
|
||||
Type = JinjaTemplateAdapter.AdaptForScriban(template.Type)
|
||||
};
|
||||
}
|
||||
|
||||
if (template.Comment != null && JinjaTemplateAdapter.IsJinjaTemplate(template.Comment)) {
|
||||
didModify = true;
|
||||
template = template with {
|
||||
Comment = JinjaTemplateAdapter.AdaptForScriban(template.Comment)
|
||||
};
|
||||
}
|
||||
|
||||
foreach (var item in template.OnDuplicate.AdoFields) {
|
||||
if (JinjaTemplateAdapter.IsJinjaTemplate(item.Value)) {
|
||||
template.OnDuplicate.AdoFields[item.Key] = JinjaTemplateAdapter.AdaptForScriban(item.Value);
|
||||
didModify = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (template.OnDuplicate.Comment != null && JinjaTemplateAdapter.IsJinjaTemplate(template.OnDuplicate.Comment)) {
|
||||
didModify = true;
|
||||
template = template with {
|
||||
OnDuplicate = template.OnDuplicate with {
|
||||
Comment = JinjaTemplateAdapter.AdaptForScriban(template.OnDuplicate.Comment)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return (didModify, template);
|
||||
}
|
||||
|
||||
private static (bool didModify, GithubIssuesTemplate template) ConvertToScriban(GithubIssuesTemplate template) {
|
||||
var didModify = false;
|
||||
|
||||
if (JinjaTemplateAdapter.IsJinjaTemplate(template.UniqueSearch.str)) {
|
||||
didModify = true;
|
||||
template = template with {
|
||||
UniqueSearch = template.UniqueSearch with {
|
||||
str = JinjaTemplateAdapter.AdaptForScriban(template.UniqueSearch.str)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(template.UniqueSearch.Author) && JinjaTemplateAdapter.IsJinjaTemplate(template.UniqueSearch.Author)) {
|
||||
didModify = true;
|
||||
template = template with {
|
||||
UniqueSearch = template.UniqueSearch with {
|
||||
Author = JinjaTemplateAdapter.AdaptForScriban(template.UniqueSearch.Author)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (JinjaTemplateAdapter.IsJinjaTemplate(template.Title)) {
|
||||
didModify = true;
|
||||
template = template with {
|
||||
Title = JinjaTemplateAdapter.AdaptForScriban(template.Title)
|
||||
};
|
||||
}
|
||||
|
||||
if (JinjaTemplateAdapter.IsJinjaTemplate(template.Body)) {
|
||||
didModify = true;
|
||||
template = template with {
|
||||
Body = JinjaTemplateAdapter.AdaptForScriban(template.Body)
|
||||
};
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(template.OnDuplicate.Comment) && JinjaTemplateAdapter.IsJinjaTemplate(template.OnDuplicate.Comment)) {
|
||||
didModify = true;
|
||||
template = template with {
|
||||
OnDuplicate = template.OnDuplicate with {
|
||||
Comment = JinjaTemplateAdapter.AdaptForScriban(template.OnDuplicate.Comment)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (template.OnDuplicate.Labels.Any()) {
|
||||
template = template with {
|
||||
OnDuplicate = template.OnDuplicate with {
|
||||
Labels = template.OnDuplicate.Labels.Select(label => {
|
||||
if (JinjaTemplateAdapter.IsJinjaTemplate(label)) {
|
||||
didModify = true;
|
||||
return JinjaTemplateAdapter.AdaptForScriban(label);
|
||||
}
|
||||
return label;
|
||||
}).ToList()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (template.Assignees.Any()) {
|
||||
template = template with {
|
||||
Assignees = template.Assignees.Select(assignee => {
|
||||
if (JinjaTemplateAdapter.IsJinjaTemplate(assignee)) {
|
||||
didModify = true;
|
||||
return JinjaTemplateAdapter.AdaptForScriban(assignee);
|
||||
}
|
||||
return assignee;
|
||||
}).ToList()
|
||||
};
|
||||
}
|
||||
|
||||
if (template.Labels.Any()) {
|
||||
template = template with {
|
||||
Labels = template.Labels.Select(label => {
|
||||
if (JinjaTemplateAdapter.IsJinjaTemplate(label)) {
|
||||
didModify = true;
|
||||
return JinjaTemplateAdapter.AdaptForScriban(label);
|
||||
}
|
||||
return label;
|
||||
}).ToList()
|
||||
};
|
||||
}
|
||||
|
||||
if (JinjaTemplateAdapter.IsJinjaTemplate(template.Organization)) {
|
||||
didModify = true;
|
||||
template = template with {
|
||||
Organization = JinjaTemplateAdapter.AdaptForScriban(template.Organization)
|
||||
};
|
||||
}
|
||||
|
||||
if (JinjaTemplateAdapter.IsJinjaTemplate(template.Repository)) {
|
||||
didModify = true;
|
||||
template = template with {
|
||||
Repository = JinjaTemplateAdapter.AdaptForScriban(template.Repository)
|
||||
};
|
||||
}
|
||||
|
||||
return (didModify, template);
|
||||
}
|
||||
}
|
||||
|
@ -17,19 +17,9 @@ public class ValidateScriban {
|
||||
return await _context.RequestHandling.NotOk(req, request.ErrorV, "ValidateTemplate");
|
||||
}
|
||||
|
||||
var instanceUrl = _context.ServiceConfiguration.OneFuzzInstance!;
|
||||
|
||||
try {
|
||||
var (renderer, templateRenderContext) = await GenerateTemplateRenderContext(request.OkV.Context);
|
||||
return await RequestHandling.Ok(req, await JinjaTemplateAdapter.ValidateScribanTemplate(_context, _log, request.OkV.Context, request.OkV.Template));
|
||||
|
||||
var renderedTemaplate = await renderer.Render(request.OkV.Template, new Uri(instanceUrl), strictRendering: true);
|
||||
|
||||
var response = new TemplateValidationResponse(
|
||||
renderedTemaplate,
|
||||
templateRenderContext
|
||||
);
|
||||
|
||||
return await RequestHandling.Ok(req, response);
|
||||
} catch (Exception e) {
|
||||
return await new RequestHandling(_log).NotOk(
|
||||
req,
|
||||
@ -47,119 +37,4 @@ public class ValidateScriban {
|
||||
_ => throw new InvalidOperationException("Unsupported HTTP method"),
|
||||
};
|
||||
}
|
||||
|
||||
private async Async.Task<(NotificationsBase.Renderer, TemplateRenderContext)> GenerateTemplateRenderContext(TemplateRenderContext? templateRenderContext) {
|
||||
if (templateRenderContext != null) {
|
||||
_log.Info($"Using the request's TemplateRenderContext");
|
||||
} else {
|
||||
_log.Info($"Generating TemplateRenderContext");
|
||||
}
|
||||
|
||||
var targetUrl = templateRenderContext?.TargetUrl ?? new Uri("https://example.com/targetUrl");
|
||||
var inputUrl = templateRenderContext?.InputUrl ?? new Uri("https://example.com/inputUrl");
|
||||
var reportUrl = templateRenderContext?.ReportUrl ?? new Uri("https://example.com/reportUrl");
|
||||
var executable = "target.exe";
|
||||
var crashType = "some crash type";
|
||||
var crashSite = "some crash site";
|
||||
var callStack = new List<string>()
|
||||
{
|
||||
"stack frame 0",
|
||||
"stack frame 1"
|
||||
};
|
||||
var callStackSha = "call stack sha";
|
||||
var inputSha = "input sha";
|
||||
var taskId = Guid.NewGuid();
|
||||
var jobId = Guid.NewGuid();
|
||||
var taskState = TaskState.Running;
|
||||
var jobState = JobState.Enabled;
|
||||
var os = Os.Linux;
|
||||
var taskType = TaskType.LibfuzzerFuzz;
|
||||
var duration = 100;
|
||||
var project = "some project";
|
||||
var jobName = "job name";
|
||||
var buildName = "build name";
|
||||
var reportContainer = templateRenderContext?.ReportContainer ?? Container.Parse("example-container-name");
|
||||
var reportFileName = templateRenderContext?.ReportFilename ?? "example file name";
|
||||
var reproCmd = templateRenderContext?.ReproCmd ?? "onefuzz command to create a repro";
|
||||
var report = templateRenderContext?.Report ?? new Report(
|
||||
inputUrl.ToString(),
|
||||
null,
|
||||
executable,
|
||||
crashType,
|
||||
crashSite,
|
||||
callStack,
|
||||
callStackSha,
|
||||
inputSha,
|
||||
null,
|
||||
taskId,
|
||||
jobId,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
);
|
||||
|
||||
var task = new Task(
|
||||
jobId,
|
||||
taskId,
|
||||
taskState,
|
||||
os,
|
||||
templateRenderContext?.Task ?? new TaskConfig(
|
||||
jobId,
|
||||
null,
|
||||
new TaskDetails(
|
||||
taskType,
|
||||
duration
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
var job = new Job(
|
||||
jobId,
|
||||
jobState,
|
||||
templateRenderContext?.Job ?? new JobConfig(
|
||||
project,
|
||||
jobName,
|
||||
buildName,
|
||||
duration,
|
||||
null
|
||||
)
|
||||
);
|
||||
|
||||
var renderer = await NotificationsBase.Renderer.ConstructRenderer(
|
||||
_context,
|
||||
reportContainer,
|
||||
reportFileName,
|
||||
report,
|
||||
_log,
|
||||
task,
|
||||
job,
|
||||
targetUrl,
|
||||
inputUrl,
|
||||
reportUrl,
|
||||
scribanOnlyOverride: true
|
||||
);
|
||||
|
||||
templateRenderContext ??= new TemplateRenderContext(
|
||||
report,
|
||||
task.Config,
|
||||
job.Config,
|
||||
reportUrl,
|
||||
inputUrl,
|
||||
targetUrl,
|
||||
reportContainer,
|
||||
reportFileName,
|
||||
reproCmd
|
||||
);
|
||||
|
||||
return (renderer, templateRenderContext);
|
||||
}
|
||||
}
|
||||
|
@ -91,6 +91,11 @@ public class NotificationOperations : Orm<Notification>, INotificationOperations
|
||||
return OneFuzzResult<Notification>.Error(ErrorCode.INVALID_REQUEST, "invalid container");
|
||||
}
|
||||
|
||||
if (await _context.FeatureManagerSnapshot.IsEnabledAsync(FeatureFlagConstants.EnableScribanOnly) &&
|
||||
!await JinjaTemplateAdapter.IsValidScribanNotificationTemplate(_context, _logTracer, config)) {
|
||||
return OneFuzzResult<Notification>.Error(ErrorCode.INVALID_REQUEST, "The notification config is not a valid scriban template");
|
||||
}
|
||||
|
||||
if (replaceExisting) {
|
||||
var existing = this.SearchByRowKeys(new[] { container.String });
|
||||
await foreach (var existingEntry in existing) {
|
||||
|
@ -11,4 +11,351 @@ public class JinjaTemplateAdapter {
|
||||
.Replace("{%", "{{")
|
||||
.Replace("%}", "}}");
|
||||
}
|
||||
|
||||
public static async Async.Task<bool> IsValidScribanNotificationTemplate(IOnefuzzContext context, ILogTracer log, NotificationTemplate template) {
|
||||
try {
|
||||
var (didModify, _) = template switch {
|
||||
TeamsTemplate => (false, template),
|
||||
AdoTemplate adoTemplate => await ConvertToScriban(adoTemplate, attemptRender: true, context, log),
|
||||
GithubIssuesTemplate githubTemplate => await ConvertToScriban(githubTemplate, attemptRender: true, context, log),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(template), "Unexpected notification template type")
|
||||
};
|
||||
|
||||
if (!didModify) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (Exception e) {
|
||||
log.Exception(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static async Async.Task<TemplateValidationResponse> ValidateScribanTemplate(IOnefuzzContext context, ILogTracer log, TemplateRenderContext? renderContext, string template) {
|
||||
var instanceUrl = context.ServiceConfiguration.OneFuzzInstance!;
|
||||
|
||||
var (renderer, templateRenderContext) = await GenerateTemplateRenderContext(context, log, renderContext);
|
||||
|
||||
var renderedTemaplate = await renderer.Render(template, new Uri(instanceUrl), strictRendering: true);
|
||||
|
||||
return new TemplateValidationResponse(
|
||||
renderedTemaplate,
|
||||
templateRenderContext
|
||||
);
|
||||
}
|
||||
|
||||
private static async Async.Task<(NotificationsBase.Renderer, TemplateRenderContext)> GenerateTemplateRenderContext(IOnefuzzContext context, ILogTracer log, TemplateRenderContext? templateRenderContext) {
|
||||
if (templateRenderContext != null) {
|
||||
log.Info($"Using custom TemplateRenderContext");
|
||||
} else {
|
||||
log.Info($"Generating TemplateRenderContext");
|
||||
}
|
||||
|
||||
var targetUrl = templateRenderContext?.TargetUrl ?? new Uri("https://example.com/targetUrl");
|
||||
var inputUrl = templateRenderContext?.InputUrl ?? new Uri("https://example.com/inputUrl");
|
||||
var reportUrl = templateRenderContext?.ReportUrl ?? new Uri("https://example.com/reportUrl");
|
||||
var executable = "target.exe";
|
||||
var crashType = "some crash type";
|
||||
var crashSite = "some crash site";
|
||||
var callStack = new List<string>()
|
||||
{
|
||||
"stack frame 0",
|
||||
"stack frame 1"
|
||||
};
|
||||
var callStackSha = "call stack sha";
|
||||
var inputSha = "input sha";
|
||||
var taskId = Guid.NewGuid();
|
||||
var jobId = Guid.NewGuid();
|
||||
var taskState = TaskState.Running;
|
||||
var jobState = JobState.Enabled;
|
||||
var os = Os.Linux;
|
||||
var taskType = TaskType.LibfuzzerFuzz;
|
||||
var duration = 100;
|
||||
var project = "some project";
|
||||
var jobName = "job name";
|
||||
var buildName = "build name";
|
||||
var reportContainer = templateRenderContext?.ReportContainer ?? Container.Parse("example-container-name");
|
||||
var reportFileName = templateRenderContext?.ReportFilename ?? "example file name";
|
||||
var reproCmd = templateRenderContext?.ReproCmd ?? "onefuzz command to create a repro";
|
||||
var report = templateRenderContext?.Report ?? new Report(
|
||||
inputUrl.ToString(),
|
||||
null,
|
||||
executable,
|
||||
crashType,
|
||||
crashSite,
|
||||
callStack,
|
||||
callStackSha,
|
||||
inputSha,
|
||||
null,
|
||||
taskId,
|
||||
jobId,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
);
|
||||
|
||||
var task = new Task(
|
||||
jobId,
|
||||
taskId,
|
||||
taskState,
|
||||
os,
|
||||
templateRenderContext?.Task ?? new TaskConfig(
|
||||
jobId,
|
||||
null,
|
||||
new TaskDetails(
|
||||
taskType,
|
||||
duration
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
var job = new Job(
|
||||
jobId,
|
||||
jobState,
|
||||
templateRenderContext?.Job ?? new JobConfig(
|
||||
project,
|
||||
jobName,
|
||||
buildName,
|
||||
duration,
|
||||
null
|
||||
)
|
||||
);
|
||||
|
||||
var renderer = await NotificationsBase.Renderer.ConstructRenderer(
|
||||
context,
|
||||
reportContainer,
|
||||
reportFileName,
|
||||
report,
|
||||
log,
|
||||
task,
|
||||
job,
|
||||
targetUrl,
|
||||
inputUrl,
|
||||
reportUrl,
|
||||
scribanOnlyOverride: true
|
||||
);
|
||||
|
||||
templateRenderContext ??= new TemplateRenderContext(
|
||||
report,
|
||||
task.Config,
|
||||
job.Config,
|
||||
reportUrl,
|
||||
inputUrl,
|
||||
targetUrl,
|
||||
reportContainer,
|
||||
reportFileName,
|
||||
reproCmd
|
||||
);
|
||||
|
||||
return (renderer, templateRenderContext);
|
||||
}
|
||||
|
||||
public async static Async.Task<(bool didModify, AdoTemplate template)> ConvertToScriban(AdoTemplate template, bool attemptRender = false, IOnefuzzContext? context = null, ILogTracer? log = null) {
|
||||
if (attemptRender) {
|
||||
context = context.EnsureNotNull("Required to render");
|
||||
log = log.EnsureNotNull("Required to render");
|
||||
}
|
||||
|
||||
var didModify = false;
|
||||
|
||||
if (JinjaTemplateAdapter.IsJinjaTemplate(template.Project)) {
|
||||
didModify = true;
|
||||
template = template with {
|
||||
Project = JinjaTemplateAdapter.AdaptForScriban(template.Project)
|
||||
};
|
||||
} else if (attemptRender) {
|
||||
await ValidateScribanTemplate(context!, log!, null, template.Project).IgnoreResult();
|
||||
}
|
||||
|
||||
foreach (var item in template.AdoFields) {
|
||||
if (JinjaTemplateAdapter.IsJinjaTemplate(item.Value)) {
|
||||
template.AdoFields[item.Key] = JinjaTemplateAdapter.AdaptForScriban(item.Value);
|
||||
didModify = true;
|
||||
} else if (attemptRender) {
|
||||
await ValidateScribanTemplate(context!, log!, null, item.Value).IgnoreResult();
|
||||
}
|
||||
}
|
||||
|
||||
if (JinjaTemplateAdapter.IsJinjaTemplate(template.Type)) {
|
||||
didModify = true;
|
||||
template = template with {
|
||||
Type = JinjaTemplateAdapter.AdaptForScriban(template.Type)
|
||||
};
|
||||
} else if (attemptRender) {
|
||||
await ValidateScribanTemplate(context!, log!, null, template.Type).IgnoreResult();
|
||||
}
|
||||
|
||||
if (template.Comment != null) {
|
||||
if (JinjaTemplateAdapter.IsJinjaTemplate(template.Comment)) {
|
||||
didModify = true;
|
||||
template = template with {
|
||||
Comment = JinjaTemplateAdapter.AdaptForScriban(template.Comment)
|
||||
};
|
||||
} else if (attemptRender) {
|
||||
await ValidateScribanTemplate(context!, log!, null, template.Comment).IgnoreResult();
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var item in template.OnDuplicate.AdoFields) {
|
||||
if (JinjaTemplateAdapter.IsJinjaTemplate(item.Value)) {
|
||||
template.OnDuplicate.AdoFields[item.Key] = JinjaTemplateAdapter.AdaptForScriban(item.Value);
|
||||
didModify = true;
|
||||
} else if (attemptRender) {
|
||||
await ValidateScribanTemplate(context!, log!, null, item.Value).IgnoreResult();
|
||||
}
|
||||
}
|
||||
|
||||
if (template.OnDuplicate.Comment != null) {
|
||||
if (JinjaTemplateAdapter.IsJinjaTemplate(template.OnDuplicate.Comment)) {
|
||||
didModify = true;
|
||||
template = template with {
|
||||
OnDuplicate = template.OnDuplicate with {
|
||||
Comment = JinjaTemplateAdapter.AdaptForScriban(template.OnDuplicate.Comment)
|
||||
}
|
||||
};
|
||||
} else if (attemptRender) {
|
||||
await ValidateScribanTemplate(context!, log!, null, template.OnDuplicate.Comment).IgnoreResult();
|
||||
}
|
||||
}
|
||||
|
||||
return (didModify, template);
|
||||
}
|
||||
|
||||
public async static Async.Task<(bool didModify, GithubIssuesTemplate template)> ConvertToScriban(GithubIssuesTemplate template, bool attemptRender = false, IOnefuzzContext? context = null, ILogTracer? log = null) {
|
||||
if (attemptRender) {
|
||||
context = context.EnsureNotNull("Required to render");
|
||||
log = log.EnsureNotNull("Required to render");
|
||||
}
|
||||
|
||||
var didModify = false;
|
||||
|
||||
if (JinjaTemplateAdapter.IsJinjaTemplate(template.UniqueSearch.str)) {
|
||||
didModify = true;
|
||||
template = template with {
|
||||
UniqueSearch = template.UniqueSearch with {
|
||||
str = JinjaTemplateAdapter.AdaptForScriban(template.UniqueSearch.str)
|
||||
}
|
||||
};
|
||||
} else if (attemptRender) {
|
||||
await ValidateScribanTemplate(context!, log!, null, template.UniqueSearch.str).IgnoreResult();
|
||||
}
|
||||
|
||||
|
||||
if (!string.IsNullOrEmpty(template.UniqueSearch.Author)) {
|
||||
if (JinjaTemplateAdapter.IsJinjaTemplate(template.UniqueSearch.Author)) {
|
||||
didModify = true;
|
||||
template = template with {
|
||||
UniqueSearch = template.UniqueSearch with {
|
||||
Author = JinjaTemplateAdapter.AdaptForScriban(template.UniqueSearch.Author)
|
||||
}
|
||||
};
|
||||
} else if (attemptRender) {
|
||||
await ValidateScribanTemplate(context!, log!, null, template.UniqueSearch.Author).IgnoreResult();
|
||||
}
|
||||
}
|
||||
|
||||
if (JinjaTemplateAdapter.IsJinjaTemplate(template.Title)) {
|
||||
didModify = true;
|
||||
template = template with {
|
||||
Title = JinjaTemplateAdapter.AdaptForScriban(template.Title)
|
||||
};
|
||||
} else if (attemptRender) {
|
||||
await ValidateScribanTemplate(context!, log!, null, template.Title).IgnoreResult();
|
||||
}
|
||||
|
||||
if (JinjaTemplateAdapter.IsJinjaTemplate(template.Body)) {
|
||||
didModify = true;
|
||||
template = template with {
|
||||
Body = JinjaTemplateAdapter.AdaptForScriban(template.Body)
|
||||
};
|
||||
} else if (attemptRender) {
|
||||
await ValidateScribanTemplate(context!, log!, null, template.Body).IgnoreResult();
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(template.OnDuplicate.Comment)) {
|
||||
if (JinjaTemplateAdapter.IsJinjaTemplate(template.OnDuplicate.Comment)) {
|
||||
didModify = true;
|
||||
template = template with {
|
||||
OnDuplicate = template.OnDuplicate with {
|
||||
Comment = JinjaTemplateAdapter.AdaptForScriban(template.OnDuplicate.Comment)
|
||||
}
|
||||
};
|
||||
} else if (attemptRender) {
|
||||
await ValidateScribanTemplate(context!, log!, null, template.OnDuplicate.Comment).IgnoreResult();
|
||||
}
|
||||
}
|
||||
|
||||
if (template.OnDuplicate.Labels.Any()) {
|
||||
template = template with {
|
||||
OnDuplicate = template.OnDuplicate with {
|
||||
Labels = template.OnDuplicate.Labels.ToAsyncEnumerable().SelectAwait(async label => {
|
||||
if (JinjaTemplateAdapter.IsJinjaTemplate(label)) {
|
||||
didModify = true;
|
||||
return JinjaTemplateAdapter.AdaptForScriban(label);
|
||||
} else if (attemptRender) {
|
||||
await ValidateScribanTemplate(context!, log!, null, label).IgnoreResult();
|
||||
}
|
||||
return label;
|
||||
}).ToEnumerable().ToList()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (template.Assignees.Any()) {
|
||||
template = template with {
|
||||
Assignees = template.Assignees.ToAsyncEnumerable().SelectAwait(async assignee => {
|
||||
if (JinjaTemplateAdapter.IsJinjaTemplate(assignee)) {
|
||||
didModify = true;
|
||||
return JinjaTemplateAdapter.AdaptForScriban(assignee);
|
||||
} else if (attemptRender) {
|
||||
await ValidateScribanTemplate(context!, log!, null, assignee).IgnoreResult();
|
||||
}
|
||||
return assignee;
|
||||
}).ToEnumerable().ToList()
|
||||
};
|
||||
}
|
||||
|
||||
if (template.Labels.Any()) {
|
||||
template = template with {
|
||||
Labels = template.Labels.ToAsyncEnumerable().SelectAwait(async label => {
|
||||
if (JinjaTemplateAdapter.IsJinjaTemplate(label)) {
|
||||
didModify = true;
|
||||
return JinjaTemplateAdapter.AdaptForScriban(label);
|
||||
} else if (attemptRender) {
|
||||
await ValidateScribanTemplate(context!, log!, null, label).IgnoreResult();
|
||||
}
|
||||
return label;
|
||||
}).ToEnumerable().ToList()
|
||||
};
|
||||
}
|
||||
|
||||
if (JinjaTemplateAdapter.IsJinjaTemplate(template.Organization)) {
|
||||
didModify = true;
|
||||
template = template with {
|
||||
Organization = JinjaTemplateAdapter.AdaptForScriban(template.Organization)
|
||||
};
|
||||
} else if (attemptRender) {
|
||||
await ValidateScribanTemplate(context!, log!, null, template.Organization).IgnoreResult();
|
||||
}
|
||||
|
||||
if (JinjaTemplateAdapter.IsJinjaTemplate(template.Repository)) {
|
||||
didModify = true;
|
||||
template = template with {
|
||||
Repository = JinjaTemplateAdapter.AdaptForScriban(template.Repository)
|
||||
};
|
||||
} else if (attemptRender) {
|
||||
await ValidateScribanTemplate(context!, log!, null, template.Repository).IgnoreResult();
|
||||
}
|
||||
|
||||
return (didModify, template);
|
||||
}
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ public sealed class TestContext : IOnefuzzContext {
|
||||
UserCredentials = new UserCredentials(logTracer, ConfigOperations);
|
||||
NotificationOperations = new NotificationOperations(logTracer, this);
|
||||
SecretsOperations = new TestSecretsOperations(Creds, ServiceConfiguration);
|
||||
FeatureManagerSnapshot = new TestFeatureManagerSnapshot();
|
||||
}
|
||||
|
||||
public TestEvents Events { get; set; } = new();
|
||||
@ -92,6 +93,9 @@ public sealed class TestContext : IOnefuzzContext {
|
||||
|
||||
public ISecretsOperations SecretsOperations { get; }
|
||||
|
||||
public IFeatureManagerSnapshot FeatureManagerSnapshot { get; }
|
||||
|
||||
|
||||
// -- Remainder not implemented --
|
||||
|
||||
public IConfig Config => throw new System.NotImplementedException();
|
||||
@ -129,7 +133,6 @@ public sealed class TestContext : IOnefuzzContext {
|
||||
public ITeams Teams => throw new NotImplementedException();
|
||||
public IGithubIssues GithubIssues => throw new NotImplementedException();
|
||||
public IAdo Ado => throw new NotImplementedException();
|
||||
public IFeatureManagerSnapshot FeatureManagerSnapshot => throw new NotImplementedException();
|
||||
|
||||
public IConfigurationRefresher ConfigurationRefresher => throw new NotImplementedException();
|
||||
}
|
||||
|
@ -0,0 +1,30 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.FeatureManagement;
|
||||
|
||||
namespace IntegrationTests.Fakes;
|
||||
|
||||
public class TestFeatureManagerSnapshot : IFeatureManagerSnapshot {
|
||||
|
||||
private static ConcurrentDictionary<string, bool> FeatureFlags = new();
|
||||
public IAsyncEnumerable<string> GetFeatureNamesAsync() {
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<bool> IsEnabledAsync(string feature) {
|
||||
return Task.FromResult(FeatureFlags.ContainsKey(feature) && FeatureFlags.TryGetValue(feature, out var enabled) && enabled);
|
||||
}
|
||||
|
||||
public Task<bool> IsEnabledAsync<TContext>(string feature, TContext context) {
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public static void AddFeatureFlag(string featureName, bool enabled = false) {
|
||||
var _ = FeatureFlags.TryAdd(featureName, enabled);
|
||||
}
|
||||
|
||||
public static void SetFeatureFlag(string featureName, bool enabled) {
|
||||
var _ = FeatureFlags.TryUpdate(featureName, enabled, !enabled);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user