// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using EpicGames.Core; using EpicGames.Horde.Agents.Pools; using EpicGames.Horde.Issues; using EpicGames.Horde.Jobs; using EpicGames.Horde.Jobs.Schedules; using EpicGames.Horde.Jobs.Templates; using EpicGames.Horde.Projects; using EpicGames.Horde.Users; #pragma warning disable CA2227 // Change x to be read-only by removing the property setter namespace EpicGames.Horde.Streams { /// /// Response describing a stream /// public class GetStreamResponse { /// /// Unique id of the stream /// public StreamId Id { get; set; } /// /// Unique id of the project containing this stream /// public ProjectId ProjectId { get; set; } /// /// Name of the stream /// public string Name { get; set; } /// /// The config file path on the server /// public string ConfigPath { get; set; } = String.Empty; /// /// Revision of the config file /// public string ConfigRevision { get; set; } = String.Empty; /// /// Order to display in the list /// public int Order { get; set; } /// /// Notification channel for all jobs in this stream /// public string? NotificationChannel { get; set; } /// /// Notification channel filter for this template. Can be a combination of "Success", "Failure" and "Warnings" separated by pipe characters. /// public string? NotificationChannelFilter { get; set; } /// /// Channel to post issue triage notifications /// public string? TriageChannel { get; set; } /// /// Default template for running preflights /// public string? DefaultPreflightTemplate { get; set; } /// /// Default template to use for preflights /// public DefaultPreflightMessage? DefaultPreflight { get; set; } /// /// List of tabs to display for this stream /// public List Tabs { get; set; } /// /// Map of agent name to type /// public Dictionary AgentTypes { get; set; } /// /// Map of workspace name to type /// public Dictionary? WorkspaceTypes { get; set; } /// /// Templates for jobs in this stream /// public List Templates { get; set; } /// /// Stream paused for new builds until this date /// public DateTime? PausedUntil { get; set; } /// /// Reason for stream being paused /// public string? PauseComment { get; set; } /// /// Workflows for this stream /// public List Workflows { get; set; } /// /// Constructor /// /// The stream to construct from /// Templates for this stream public GetStreamResponse(IStream stream, List templates) { Id = stream.Id; ProjectId = stream.ProjectId; Name = stream.Name; ConfigPath = stream.ConfigPath ?? String.Empty; ConfigRevision = stream.ConfigRevision; Order = stream.Order; NotificationChannel = stream.NotificationChannel; NotificationChannelFilter = stream.NotificationChannelFilter; TriageChannel = stream.TriageChannel; DefaultPreflightTemplate = stream.DefaultPreflight?.TemplateId?.ToString(); DefaultPreflight = (stream.DefaultPreflight == null) ? null : new DefaultPreflightMessage(stream.DefaultPreflight); Tabs = stream.Tabs.ConvertAll(x => new GetStreamTabResponse(x)); AgentTypes = stream.AgentTypes.ToDictionary(x => x.Key, x => new GetAgentTypeResponse(x.Value)); WorkspaceTypes = stream.WorkspaceTypes.ToDictionary(x => x.Key, x => new GetWorkspaceTypeResponse(x.Value)); Templates = templates; Workflows = stream.Workflows.ConvertAll(x => new GetWorkflowResponse(x)); PausedUntil = stream.PausedUntil; PauseComment = stream.PauseComment; } } /// /// Information about the default preflight to run /// public class DefaultPreflightMessage : IDefaultPreflight { /// public TemplateId? TemplateId { get; set; } /// public ChangeQueryMessage? Change { get; set; } IChangeQuery? IDefaultPreflight.Change => Change; /// /// Constructor /// public DefaultPreflightMessage() { } /// /// Constructor /// public DefaultPreflightMessage(IDefaultPreflight other) { TemplateId = other.TemplateId; Change = (other.Change == null) ? null : new ChangeQueryMessage(other.Change); } } /// /// Information about a page to display in the dashboard for a stream /// public class GetStreamTabResponse : IStreamTab { /// public string Title { get; set; } /// public string Type { get; set; } /// public TabStyle Style { get; set; } /// public bool ShowNames { get; set; } /// public bool? ShowPreflights { get; set; } /// public List? JobNames { get; set; } IReadOnlyList? IStreamTab.JobNames => JobNames; /// public List? Templates { get; set; } IReadOnlyList? IStreamTab.Templates => Templates; /// public List? Columns { get; set; } IReadOnlyList? IStreamTab.Columns => Columns; /// /// Constructor /// public GetStreamTabResponse() { Title = String.Empty; Type = String.Empty; } /// /// Constructor /// public GetStreamTabResponse(IStreamTab other) { Title = other.Title; Type = other.Type; Style = other.Style; ShowNames = other.ShowNames; ShowPreflights = other.ShowPreflights; JobNames = other.JobNames?.ToList(); Templates = other.Templates?.ToList(); Columns = other.Columns?.ConvertAll(x => new GetStreamTabColumnResponse(x)); } } /// /// Describes a column to display on the jobs page /// public class GetStreamTabColumnResponse : IStreamTabColumn { /// public TabColumnType Type { get; set; } /// public string Heading { get; set; } /// public string? Category { get; set; } /// public string? Parameter { get; set; } /// public int? RelativeWidth { get; set; } /// /// Default constructor /// public GetStreamTabColumnResponse() { Heading = String.Empty; } /// /// Constructor /// public GetStreamTabColumnResponse(IStreamTabColumn other) { Type = other.Type; Heading = other.Heading; Category = other.Category; Parameter = other.Parameter; RelativeWidth = other.RelativeWidth; } } /// /// Mapping from a BuildGraph agent type to a set of machines on the farm /// public class GetAgentTypeResponse { /// /// Pool of agents to use for this agent type /// public PoolId Pool { get; set; } /// /// Name of the workspace to sync /// public string? Workspace { get; set; } /// /// Path to the temporary storage dir /// public string? TempStorageDir { get; set; } /// /// Environment variables to be set when executing the job /// public Dictionary? Environment { get; set; } /// /// Constructor /// public GetAgentTypeResponse() { } /// /// Constructor /// public GetAgentTypeResponse(IAgentType other) { Pool = other.Pool; Workspace = other.Workspace; TempStorageDir = other.TempStorageDir; Environment = other.Environment?.ToDictionary(); } } /// /// Information about a workspace type /// public class GetWorkspaceTypeResponse : IWorkspaceType { /// public string? Cluster { get; set; } /// public string? ServerAndPort { get; set; } /// public string? UserName { get; set; } /// string? IWorkspaceType.Password => throw new NotSupportedException(); /// public string? Identifier { get; set; } /// public string? Stream { get; set; } /// public List? View { get; set; } IReadOnlyList? IWorkspaceType.View => View; /// public bool? Incremental { get; set; } /// public bool? UseAutoSdk { get; set; } /// public List? AutoSdkView { get; set; } IReadOnlyList? IWorkspaceType.AutoSdkView => AutoSdkView; /// public string? Method { get; set; } = null; /// public long? MinScratchSpace { get; set; } = null; /// public long? ConformDiskFreeSpace { get; set; } = null; /// /// Default constructor /// public GetWorkspaceTypeResponse() { } /// /// Constructor /// public GetWorkspaceTypeResponse(IWorkspaceType other) { Cluster = other.Cluster; ServerAndPort = other.ServerAndPort; UserName = other.UserName; Identifier = other.Identifier; Stream = other.Stream; View = other.View?.ToList(); Incremental = other.Incremental; UseAutoSdk = other.UseAutoSdk; AutoSdkView = other.AutoSdkView?.ToList(); Method = other.Method; MinScratchSpace = other.MinScratchSpace; ConformDiskFreeSpace = other.ConformDiskFreeSpace; } } /// /// State information for a step in the stream /// public class GetTemplateStepStateResponse { /// /// Name of the step /// public string Name { get; set; } = String.Empty; /// /// User who paused the step /// public GetThinUserInfoResponse? PausedByUserInfo { get; set; } /// /// The UTC time when the step was paused /// public DateTime? PauseTimeUtc { get; set; } /// /// Default constructor for serialization /// private GetTemplateStepStateResponse() { } /// /// Constructor /// public GetTemplateStepStateResponse(ITemplateStep state, GetThinUserInfoResponse? pausedByUserInfo) { Name = state.Name; PauseTimeUtc = state.PauseTimeUtc; PausedByUserInfo = pausedByUserInfo; } } /// /// Information about a template in this stream /// public class GetTemplateRefResponse : GetTemplateResponseBase { /// /// Id of the template ref /// public string Id { get; set; } /// /// Hash of the template definition /// public string Hash { get; set; } /// /// Whether to show badges in UGS for these jobs /// public bool ShowUgsBadges { get; set; } /// /// Whether to show alerts in UGS for these jobs /// public bool ShowUgsAlerts { get; set; } /// /// Notification channel for this template. Overrides the stream channel if set. /// public string? NotificationChannel { get; set; } /// /// Notification channel filter for this template. Can be a combination of "Success", "Failure" and "Warnings" separated by pipe characters. /// public string? NotificationChannelFilter { get; set; } /// /// Triage channel for this template. Overrides the stream channel if set. /// public string? TriageChannel { get; set; } /// /// The schedule for this ref /// public GetScheduleResponse? Schedule { get; set; } /// /// List of templates to trigger /// public List? ChainedJobs { get; set; } /// /// List of step states /// public List? StepStates { get; set; } /// /// List of queries for the default changelist /// public List? DefaultChange { get; set; } /// /// Whether the user is allowed to create jobs from this template /// public bool CanRun { get; set; } /// /// Constructor /// /// The template ref id /// The template ref /// The actual template /// The template step states /// The scheduler time zone /// Whether the user can run this template public GetTemplateRefResponse(TemplateId id, ITemplateRef templateRef, ITemplate template, List? stepStates, TimeZoneInfo schedulerTimeZone, bool canRun) : base(template) { Id = id.ToString(); Hash = template.Hash.ToString(); ShowUgsBadges = templateRef.ShowUgsBadges; ShowUgsAlerts = templateRef.ShowUgsAlerts; NotificationChannel = templateRef.NotificationChannel; NotificationChannelFilter = templateRef.NotificationChannelFilter; Schedule = (templateRef.Schedule != null) ? new GetScheduleResponse(templateRef.Schedule, schedulerTimeZone) : null; ChainedJobs = (templateRef.ChainedJobs != null && templateRef.ChainedJobs.Count > 0) ? templateRef.ChainedJobs.ConvertAll(x => new GetChainedJobTemplateResponse(x)) : null; StepStates = stepStates; DefaultChange = templateRef.DefaultChange?.ConvertAll(x => new ChangeQueryMessage(x)); CanRun = canRun; } } /// /// Trigger for another template /// public class GetChainedJobTemplateResponse : IChainedJobTemplate { /// public string Trigger { get; set; } /// public TemplateId TemplateId { get; set; } /// public bool UseDefaultChangeForTemplate { get; set; } /// /// Constructor /// public GetChainedJobTemplateResponse() { Trigger = String.Empty; } /// /// Constructor /// public GetChainedJobTemplateResponse(IChainedJobTemplate other) { Trigger = other.Trigger; TemplateId = other.TemplateId; UseDefaultChangeForTemplate = other.UseDefaultChangeForTemplate; } } /// /// Step state update request /// public class UpdateStepStateRequest { /// /// Name of the step /// [Required] public string Name { get; set; } = String.Empty; /// /// User who paused the step /// public string? PausedByUserId { get; set; } } /// /// Updates an existing stream template ref /// public class UpdateTemplateRefRequest { /// /// Step states to update /// public List? StepStates { get; set; } } }