// Copyright Epic Games, Inc. All Rights Reserved.
using System;
using System.Collections.Generic;
using EpicGames.Horde.Issues;
namespace EpicGames.Horde.Jobs.Graphs
{
///
/// Interface which wraps a generic key/value dictionary to provide specific node annotations
///
#pragma warning disable CA1710 // Identifiers should have correct suffix
public interface IReadOnlyNodeAnnotations : IReadOnlyDictionary
#pragma warning restore CA1710 // Identifiers should have correct suffix
{
///
/// Workflow to use for triaging issues from this node
///
WorkflowId? WorkflowId { get; }
///
/// Whether to create issues for this node
///
bool? CreateIssues { get; }
///
/// Whether to automatically assign issues that could only be caused by one user, or have a well defined correlation with a modified file.
///
bool? AutoAssign { get; }
///
/// Automatically assign any issues to the given user
///
string? AutoAssignToUser { get; }
///
/// Whether to notify all submitters between a build suceeding and failing, allowing them to step forward and take ownership of an issue.
///
bool? NotifySubmitters { get; }
///
/// Key to use for grouping issues together, preventing them being merged with other groups
///
string? IssueGroup { get; }
///
/// Whether failures in this node should be flagged as build blockers
///
bool? BuildBlocker { get; }
}
///
/// Set of annotations for a node
///
public class NodeAnnotations : Dictionary, IReadOnlyNodeAnnotations
{
///
/// Empty annotation dictionary
///
public static IReadOnlyNodeAnnotations Empty { get; } = new NodeAnnotations();
///
public const string WorkflowKeyName = "Workflow";
///
public const string CreateIssuesKeyName = "CreateIssues";
///
public const string AutoAssignKeyName = "AutoAssign";
///
public const string AutoAssignToUserKeyName = "AutoAssignToUser";
///
public const string NotifySubmittersKeyName = "NotifySubmitters";
///
public const string IssueGroupKeyName = "IssueGroup";
///
public const string BuildBlockerKeyName = "BuildBlocker";
///
/// Constructor
///
public NodeAnnotations()
: base(StringComparer.OrdinalIgnoreCase)
{
}
///
/// Constructor
///
///
public NodeAnnotations(IReadOnlyDictionary annotations)
: this()
{
Merge(annotations);
}
///
public WorkflowId? WorkflowId
{
get
{
string? workflowName;
if (!TryGetValue(WorkflowKeyName, out workflowName))
{
return null;
}
try
{
return new WorkflowId(workflowName);
}
catch
{
return null;
}
}
set => SetStringValue(WorkflowKeyName, value?.ToString());
}
///
public bool? CreateIssues
{
get => GetBoolValue(CreateIssuesKeyName);
set => SetBoolValue(CreateIssuesKeyName, value);
}
///
public bool? AutoAssign
{
get => GetBoolValue(AutoAssignKeyName);
set => SetBoolValue(AutoAssignKeyName, value);
}
///
public string? AutoAssignToUser
{
get => GetStringValue(AutoAssignToUserKeyName);
set => SetStringValue(AutoAssignToUserKeyName, value);
}
///
public bool? NotifySubmitters
{
get => GetBoolValue(NotifySubmittersKeyName);
set => SetBoolValue(NotifySubmittersKeyName, value);
}
///
public string? IssueGroup
{
get => GetStringValue(IssueGroupKeyName);
set => SetStringValue(IssueGroupKeyName, value);
}
///
public bool? BuildBlocker
{
get => GetBoolValue(BuildBlockerKeyName);
set => SetBoolValue(BuildBlockerKeyName, value);
}
private bool? GetBoolValue(string key)
{
string? value = GetStringValue(key);
if (value != null)
{
if (value.Equals("0", StringComparison.Ordinal) || value.Equals("false", StringComparison.OrdinalIgnoreCase))
{
return false;
}
if (value.Equals("1", StringComparison.Ordinal) || value.Equals("true", StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
return null;
}
private void SetBoolValue(string key, bool? value)
{
if (value == null)
{
Remove(key);
}
else
{
SetStringValue(key, value.Value ? "1" : "0");
}
}
private string? GetStringValue(string key)
{
TryGetValue(key, out string? value);
return value;
}
private void SetStringValue(string key, string? value)
{
if (value == null)
{
Remove(key);
}
else
{
this[key] = value;
}
}
///
/// Merge in entries from another set of annotation
///
///
public void Merge(IReadOnlyDictionary other)
{
foreach ((string key, string value) in other)
{
this[key] = value;
}
}
}
}