mirror of
https://github.com/RPCS3/discord-bot.git
synced 2024-11-23 02:09:38 +00:00
cirrus-ci client
This commit is contained in:
parent
c68678c740
commit
057a4763bb
18
.config/dotnet-tools.json
Normal file
18
.config/dotnet-tools.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"strawberryshake.tools": {
|
||||
"version": "11.1.0",
|
||||
"commands": [
|
||||
"dotnet-graphql"
|
||||
]
|
||||
},
|
||||
"dotnet-ef": {
|
||||
"version": "5.0.5",
|
||||
"commands": [
|
||||
"dotnet-ef"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -265,4 +265,5 @@ launchSettings.json
|
||||
*.db-journal
|
||||
logs/
|
||||
*.ird
|
||||
credentials.json
|
||||
credentials.json
|
||||
Generated/
|
12
Clients/CirrusCiClient/.graphqlrc.json
Normal file
12
Clients/CirrusCiClient/.graphqlrc.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"schema": "schema.graphql",
|
||||
"documents": "**/*.graphql",
|
||||
"extensions": {
|
||||
"strawberryShake": {
|
||||
"name": "Client",
|
||||
"namespace": "CirrusCiClient",
|
||||
"url": "https://api.cirrus-ci.com/graphql",
|
||||
"dependencyInjection": true
|
||||
}
|
||||
}
|
||||
}
|
130
Clients/CirrusCiClient/CirrusCi.cs
Normal file
130
Clients/CirrusCiClient/CirrusCi.cs
Normal file
@ -0,0 +1,130 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CirrusCiClient.POCOs;
|
||||
using CompatApiClient;
|
||||
using CompatApiClient.Utils;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using StrawberryShake;
|
||||
|
||||
namespace CirrusCiClient
|
||||
{
|
||||
public static class CirrusCi
|
||||
{
|
||||
private static readonly MemoryCache BuildInfoCache = new(new MemoryCacheOptions { ExpirationScanFrequency = TimeSpan.FromHours(1) });
|
||||
private static readonly IServiceProvider ServiceProvider;
|
||||
private static IClient Client => ServiceProvider.GetRequiredService<IClient>();
|
||||
|
||||
static CirrusCi()
|
||||
{
|
||||
var collection = new ServiceCollection();
|
||||
collection.AddClient(ExecutionStrategy.CacheAndNetwork)
|
||||
.ConfigureHttpClient(c => c.BaseAddress = new("https://api.cirrus-ci.com/graphql"));
|
||||
ServiceProvider = collection.BuildServiceProvider();
|
||||
}
|
||||
|
||||
public static async Task<BuildInfo?> GetPrBuildInfoAsync(string? commit, DateTime? oldestTimestamp, int pr, CancellationToken cancellationToken)
|
||||
{
|
||||
if (string.IsNullOrEmpty(commit))
|
||||
return null;
|
||||
|
||||
commit = commit.ToLower();
|
||||
var queryResult = await Client.GetPrBuilds.ExecuteAsync("pull/" + pr, oldestTimestamp.ToTimestamp(), cancellationToken);
|
||||
queryResult.EnsureNoErrors();
|
||||
if (queryResult.Data?.GithubRepository?.Builds?.Edges is {Count: > 0} edgeList)
|
||||
{
|
||||
var node = edgeList.LastOrDefault(e => e?.Node?.ChangeIdInRepo == commit)?.Node;
|
||||
if (node is null)
|
||||
return null;
|
||||
|
||||
var winTask = node.Tasks?.FirstOrDefault(t => t?.Name.Contains("Windows") ?? false);
|
||||
var winArtifact = winTask?.Artifacts?
|
||||
.Where(a => a?.Files is {Count: >0})
|
||||
.SelectMany(a => a!.Files!)
|
||||
.FirstOrDefault(f => f?.Path.EndsWith(".7z") ?? false);
|
||||
var linTask = node.Tasks?.FirstOrDefault(t => t is {} lt && lt.Name.Contains("Linux") && lt.Name.Contains("GCC"));
|
||||
var linArtifact = linTask?.Artifacts?
|
||||
.Where(a => a?.Files is {Count: >0})
|
||||
.SelectMany(a => a!.Files!)
|
||||
.FirstOrDefault(a => a?.Path.EndsWith(".AppImage") ?? false);
|
||||
|
||||
var startTime = FromTimestamp(node.BuildCreatedTimestamp);
|
||||
var finishTime = GetFinishTime(node);
|
||||
return new()
|
||||
{
|
||||
Commit = node.ChangeIdInRepo,
|
||||
WindowsFilename = winArtifact?.Path is string wp ? Path.GetFileName(wp) : null,
|
||||
LinuxFilename = linArtifact?.Path is string lp ? Path.GetFileName(lp) : null,
|
||||
WindowsBuildDownloadLink = winTask?.Id is string wtid && winArtifact?.Path is string wtap ? $"https://api.cirrus-ci.com/v1/artifact/task/{wtid}/Artifact/{wtap}" : null,
|
||||
LinuxBuildDownloadLink = linTask?.Id is string ltid && linArtifact?.Path is string ltap ? $"https://api.cirrus-ci.com/v1/artifact/task/{ltid}/Artifact/{ltap}" : null,
|
||||
StartTime = startTime,
|
||||
FinishTime = finishTime,
|
||||
Status = node.Status,
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static async Task<ProjectBuildStats> GetPipelineDurationAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
const string cacheKey = "project-build-stats";
|
||||
if (BuildInfoCache.TryGetValue(cacheKey, out ProjectBuildStats result))
|
||||
return result;
|
||||
|
||||
try
|
||||
{
|
||||
var queryResult = await Client.GetLastFewBuilds.ExecuteAsync(200, cancellationToken).ConfigureAwait(false);
|
||||
queryResult.EnsureNoErrors();
|
||||
|
||||
var times = (
|
||||
from edge in queryResult.Data?.GithubRepository?.Builds?.Edges
|
||||
let node = edge?.Node
|
||||
where node?.Status == BuildStatus.Completed
|
||||
let p = new {start = FromTimestamp(node.BuildCreatedTimestamp), finish = GetFinishTime(node)}
|
||||
where p.finish.HasValue
|
||||
let ts = p.finish!.Value - p.start
|
||||
orderby ts descending
|
||||
select ts
|
||||
).ToList();
|
||||
if (times.Count <= 10)
|
||||
return ProjectBuildStats.Defaults;
|
||||
|
||||
result = new()
|
||||
{
|
||||
Percentile95 = times[(int)(times.Count * 0.05)],
|
||||
Percentile90 = times[(int)(times.Count * 0.10)],
|
||||
Percentile85 = times[(int)(times.Count * 0.16)],
|
||||
Percentile80 = times[(int)(times.Count * 0.20)],
|
||||
Mean = TimeSpan.FromTicks(times.Select(t => t.Ticks).Mean()),
|
||||
StdDev = TimeSpan.FromTicks((long)times.Select(t => t.Ticks).StdDev()),
|
||||
BuildCount = times.Count,
|
||||
};
|
||||
BuildInfoCache.Set(cacheKey, result, TimeSpan.FromDays(1));
|
||||
return result;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ApiConfig.Log.Error(e, "Failed to get Cirrus build stats");
|
||||
}
|
||||
return ProjectBuildStats.Defaults;
|
||||
}
|
||||
|
||||
private static DateTime? GetFinishTime(IBaseNodeInfo node)
|
||||
=> node.LatestGroupTasks?
|
||||
.Select(t => t?.FinalStatusTimestamp)
|
||||
.Where(ts => ts > 0)
|
||||
.ToList() is {Count: >0} finalTimes
|
||||
? FromTimestamp(finalTimes.Max()!.Value)
|
||||
: node.ClockDurationInSeconds > 0
|
||||
? FromTimestamp(node.BuildCreatedTimestamp).AddSeconds(node.ClockDurationInSeconds.Value)
|
||||
: (DateTime?)null;
|
||||
|
||||
[return: NotNullIfNotNull(nameof(DateTime))]
|
||||
private static string? ToTimestamp(this DateTime? dateTime) => dateTime.HasValue ? (dateTime.Value.ToUniversalTime() - DateTime.UnixEpoch).TotalMilliseconds.ToString("0") : null;
|
||||
private static DateTime FromTimestamp(long timestamp) => DateTime.UnixEpoch.AddMilliseconds(timestamp);
|
||||
}
|
||||
}
|
20
Clients/CirrusCiClient/CirrusCiClient.csproj
Normal file
20
Clients/CirrusCiClient/CirrusCiClient.csproj
Normal file
@ -0,0 +1,20 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\CompatApiClient\CompatApiClient.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" />
|
||||
<PackageReference Include="StrawberryShake.CodeGeneration.CSharp.Analyzers" Version="11.1.0" />
|
||||
<PackageReference Include="StrawberryShake.Transport.Http" Version="11.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
16
Clients/CirrusCiClient/POCOs/BuildInfo.cs
Normal file
16
Clients/CirrusCiClient/POCOs/BuildInfo.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System;
|
||||
|
||||
namespace CirrusCiClient.POCOs
|
||||
{
|
||||
public record BuildInfo
|
||||
{
|
||||
public string? Commit { get; init; }
|
||||
public string? WindowsFilename { get; init; }
|
||||
public string? LinuxFilename { get; init; }
|
||||
public string? WindowsBuildDownloadLink { get; init; }
|
||||
public string? LinuxBuildDownloadLink { get; init; }
|
||||
public DateTime StartTime { get; init; }
|
||||
public DateTime? FinishTime { get; init; }
|
||||
public BuildStatus? Status { get; init; }
|
||||
}
|
||||
}
|
25
Clients/CirrusCiClient/POCOs/ProjectBuildStats.cs
Normal file
25
Clients/CirrusCiClient/POCOs/ProjectBuildStats.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using System;
|
||||
|
||||
namespace CirrusCiClient.POCOs
|
||||
{
|
||||
public record ProjectBuildStats
|
||||
{
|
||||
public TimeSpan Percentile95 { get; init; }
|
||||
public TimeSpan Percentile90 { get; init; }
|
||||
public TimeSpan Percentile85 { get; init; }
|
||||
public TimeSpan Percentile80 { get; init; }
|
||||
public TimeSpan Mean { get; init; }
|
||||
public TimeSpan StdDev { get; init; }
|
||||
public int BuildCount { get; init; }
|
||||
|
||||
public static readonly ProjectBuildStats Defaults = new()
|
||||
{
|
||||
Percentile95 = TimeSpan.FromSeconds(1120),
|
||||
Percentile90 = TimeSpan.FromSeconds(900),
|
||||
Percentile85 = TimeSpan.FromSeconds(870),
|
||||
Percentile80 = TimeSpan.FromSeconds(865),
|
||||
Mean = TimeSpan.FromSeconds(860),
|
||||
StdDev = TimeSpan.FromSeconds(420),
|
||||
};
|
||||
}
|
||||
}
|
65
Clients/CirrusCiClient/Queries/GetBuilds.graphql
Normal file
65
Clients/CirrusCiClient/Queries/GetBuilds.graphql
Normal file
@ -0,0 +1,65 @@
|
||||
query GetPrBuilds($branch: String, $after: String) {
|
||||
githubRepository(owner: "RPCS3", name: "rpcs3") {
|
||||
builds(branch: $branch, after: $after, last: 20) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
changeIdInRepo
|
||||
pullRequest
|
||||
...BaseNodeInfo
|
||||
tasks {
|
||||
id
|
||||
name
|
||||
status
|
||||
artifacts {
|
||||
files {
|
||||
path
|
||||
size
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
query GetBuildWithArtifacts($buildId: ID!) {
|
||||
build(id: $buildId) {
|
||||
pullRequest
|
||||
buildCreatedTimestamp
|
||||
clockDurationInSeconds
|
||||
tasks {
|
||||
name
|
||||
status
|
||||
artifacts {
|
||||
name
|
||||
files {
|
||||
path
|
||||
size
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
query GetLastFewBuilds($count: Int!) {
|
||||
githubRepository(owner: "RPCS3", name: "rpcs3") {
|
||||
builds(last: $count) {
|
||||
edges {
|
||||
node {
|
||||
...BaseNodeInfo
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fragment BaseNodeInfo on Build {
|
||||
status
|
||||
buildCreatedTimestamp
|
||||
clockDurationInSeconds
|
||||
latestGroupTasks {
|
||||
finalStatusTimestamp
|
||||
}
|
||||
}
|
1
Clients/CirrusCiClient/schema.extensions.graphql
Normal file
1
Clients/CirrusCiClient/schema.extensions.graphql
Normal file
@ -0,0 +1 @@
|
||||
extend schema @key(fields: "id")
|
913
Clients/CirrusCiClient/schema.graphql
Normal file
913
Clients/CirrusCiClient/schema.graphql
Normal file
@ -0,0 +1,913 @@
|
||||
schema {
|
||||
query: Root
|
||||
mutation: Mutation
|
||||
subscription: Subscription
|
||||
}
|
||||
|
||||
type AccountTransaction {
|
||||
accountId: Long!
|
||||
taskId: Long!
|
||||
repositoryId: Long!
|
||||
timestamp: Long!
|
||||
microCreditsAmount: Long!
|
||||
creditsAmount: String!
|
||||
initialCreditsAmount: String
|
||||
task: Task
|
||||
repository: Repository
|
||||
}
|
||||
|
||||
"An edge in a connection"
|
||||
type AccountTransactionEdge {
|
||||
"The item at the end of the edge"
|
||||
node: AccountTransaction
|
||||
"cursor marks a unique position or index into the connection"
|
||||
cursor: String!
|
||||
}
|
||||
|
||||
"A connection to a list of items."
|
||||
type AccountTransactionsConnection {
|
||||
"a list of edges"
|
||||
edges: [AccountTransactionEdge]
|
||||
"details about this specific page"
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type ApiAccessToken {
|
||||
maskedToken: String
|
||||
creationTimestamp: Long
|
||||
}
|
||||
|
||||
type ArtifactFileInfo {
|
||||
path: String!
|
||||
size: Long!
|
||||
}
|
||||
|
||||
type Artifacts {
|
||||
name: String!
|
||||
type: String
|
||||
format: String
|
||||
files: [ArtifactFileInfo]
|
||||
}
|
||||
|
||||
type BillingSettings {
|
||||
accountId: Long!
|
||||
enabled: Boolean!
|
||||
billingCreditsLimit: Long!
|
||||
billingEmailAddress: String!
|
||||
invoiceTemplate: String
|
||||
}
|
||||
|
||||
input BillingSettingsInput {
|
||||
accountId: ID!
|
||||
enabled: Boolean!
|
||||
billingEmailAddress: String!
|
||||
invoiceTemplate: String
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type BillingSettingsPayload {
|
||||
settings: BillingSettings
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type Build {
|
||||
id: ID!
|
||||
repositoryId: ID!
|
||||
branch: String!
|
||||
changeIdInRepo: String!
|
||||
changeMessageTitle: String
|
||||
changeMessage: String
|
||||
durationInSeconds: Long
|
||||
clockDurationInSeconds: Long
|
||||
pullRequest: Long
|
||||
checkSuiteId: Long
|
||||
isSenderUserCollaborator: Boolean
|
||||
senderUserPermissions: String
|
||||
changeTimestamp: Long!
|
||||
buildCreatedTimestamp: Long!
|
||||
status: BuildStatus
|
||||
notifications: [Notification]
|
||||
parsingResult: ParsingResult
|
||||
tasks: [Task]
|
||||
taskGroupsAmount: Long
|
||||
latestGroupTasks: [Task]
|
||||
repository: Repository!
|
||||
viewerPermission: PermissionType!
|
||||
source: String
|
||||
hooks: [Hook]
|
||||
}
|
||||
|
||||
input BuildApproveInput {
|
||||
buildId: ID!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type BuildApprovePayload {
|
||||
build: Build!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
input BuildReTriggerInput {
|
||||
buildId: ID!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type BuildReTriggerPayload {
|
||||
build: Build!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
"Build status."
|
||||
enum BuildStatus {
|
||||
CREATED
|
||||
NEEDS_APPROVAL
|
||||
TRIGGERED
|
||||
EXECUTING
|
||||
FAILED
|
||||
COMPLETED
|
||||
ABORTED
|
||||
ERRORED
|
||||
}
|
||||
|
||||
input BuyComputeCreditsInput {
|
||||
accountId: ID!
|
||||
amountOfCredits: String!
|
||||
paymentTokenId: String!
|
||||
receiptEmail: String
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type BuyComputeCreditsPayload {
|
||||
error: String
|
||||
info: GitHubOrganizationInfo
|
||||
user: User
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
"Repository Setting to choose where to look for the configuration file."
|
||||
enum ConfigResolutionStrategy {
|
||||
SAME_SHA
|
||||
MERGE_FOR_PRS
|
||||
DEFAULT_BRANCH
|
||||
}
|
||||
|
||||
input CreatePersistentWorkerPoolInput {
|
||||
ownerId: Long!
|
||||
name: String!
|
||||
enabledForPublic: Boolean!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type CreatePersistentWorkerPoolPayload {
|
||||
pool: PersistentWorkerPool!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type DayDate {
|
||||
year: Int
|
||||
month: Int
|
||||
day: Int
|
||||
}
|
||||
|
||||
"Repository Setting to choose how to decrypt variables."
|
||||
enum DecryptEnvironmentVariablesFor {
|
||||
USERS_WITH_WRITE_PERMISSIONS
|
||||
EVERYONE
|
||||
}
|
||||
|
||||
input DeletePersistentWorkerInput {
|
||||
poolId: String!
|
||||
name: String!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type DeletePersistentWorkerPayload {
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
input DeletePersistentWorkerPoolInput {
|
||||
poolId: String!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type DeletePersistentWorkerPoolPayload {
|
||||
deletedPoolId: String!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
input DeleteWebPushConfigurationInput {
|
||||
endpoint: String!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type DeleteWebPushConfigurationPayload {
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type ExecutionChart {
|
||||
startTimestamp: Long!
|
||||
maxValue: Float!
|
||||
minValue: Float!
|
||||
points: [ExecutionChartPoint]!
|
||||
}
|
||||
|
||||
type ExecutionChartPoint {
|
||||
value: Float!
|
||||
secondsFromStart: Long!
|
||||
}
|
||||
|
||||
type ExecutionEvent {
|
||||
timestamp: Long!
|
||||
message: String!
|
||||
}
|
||||
|
||||
type ExecutionInfo {
|
||||
labels: [String]
|
||||
events: [ExecutionEvent]
|
||||
cpuChart: ExecutionChart
|
||||
memoryChart: ExecutionChart
|
||||
}
|
||||
|
||||
input GenerateNewAccessTokenInput {
|
||||
accountId: ID
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type GenerateNewAccessTokenPayload {
|
||||
token: String!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
input GetPersistentWorkerPoolRegistrationTokenInput {
|
||||
poolId: ID
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type GetPersistentWorkerPoolRegistrationTokenPayload {
|
||||
token: String!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type GitHubMarketplacePurchase {
|
||||
accountId: Long!
|
||||
login: String!
|
||||
planId: Long!
|
||||
planName: String!
|
||||
unitCount: Long!
|
||||
onFreeTrial: Boolean!
|
||||
freeTrialDaysLeft: Int!
|
||||
}
|
||||
|
||||
type GitHubOrganizationInfo {
|
||||
id: ID!
|
||||
name: String!
|
||||
role: String!
|
||||
purchase: GitHubMarketplacePurchase
|
||||
activeUsersAmount: Int!
|
||||
activeUserNames: [String]
|
||||
balanceInCredits: String!
|
||||
transactions("fetching only nodes before this node (exclusive)" before: String "fetching only nodes after this node (exclusive)" after: String "fetching only the first certain number of nodes" first: Int "fetching only the last certain number of nodes" last: Int): AccountTransactionsConnection
|
||||
billingSettings: BillingSettings
|
||||
webhookSettings: WebHookSettings
|
||||
webhookDeliveries("fetching only nodes before this node (exclusive)" before: String "fetching only nodes after this node (exclusive)" after: String "fetching only the first certain number of nodes" first: Int "fetching only the last certain number of nodes" last: Int): WebhookDeliveriesConnection
|
||||
apiToken: ApiAccessToken
|
||||
persistentWorkerPools: [PersistentWorkerPool]
|
||||
}
|
||||
|
||||
type Hook {
|
||||
id: ID!
|
||||
repositoryId: ID!
|
||||
repository: Repository!
|
||||
buildId: ID
|
||||
build: Build
|
||||
taskId: ID
|
||||
task: Task
|
||||
timestamp: Long!
|
||||
name: String!
|
||||
info: HookExecutionInfo!
|
||||
}
|
||||
|
||||
type HookExecutionInfo {
|
||||
error: String!
|
||||
arguments: String
|
||||
result: String
|
||||
outputLogs: [String]
|
||||
durationNanos: Long!
|
||||
}
|
||||
|
||||
type InstanceResources {
|
||||
cpu: Float!
|
||||
memory: Long!
|
||||
}
|
||||
|
||||
"Long type"
|
||||
scalar Long
|
||||
|
||||
type MetricsChart {
|
||||
title: String
|
||||
points: [TimePoint]
|
||||
dataUnits: String
|
||||
}
|
||||
|
||||
input MetricsQueryParameters {
|
||||
status: TaskStatus
|
||||
platform: PlatformType
|
||||
type: String
|
||||
isCommunity: Boolean
|
||||
isPR: Boolean
|
||||
usedComputeCredits: Boolean
|
||||
branch: String
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
securedVariable(input: RepositorySecuredVariableInput!): RepositorySecuredVariablePayload
|
||||
securedOrganizationVariable(input: OrganizationSecuredVariableInput!): OrganizationSecuredVariablePayload
|
||||
updateSecuredOrganizationVariable(input: UpdateOrganizationSecuredVariableInput!): UpdateOrganizationSecuredVariablePayload
|
||||
createBuild(input: RepositoryCreateBuildInput!): RepositoryCreateBuildPayload
|
||||
deleteRepository(input: RepositoryDeleteInput!): RepositoryDeletePayload
|
||||
rerun(input: TaskReRunInput!): TaskReRunPayload
|
||||
batchReRun(input: TasksReRunInput!): TasksReRunPayload
|
||||
abortTask(input: TaskAbortInput!): TaskAbortPayload
|
||||
batchAbort(input: TaskBatchAbortInput!): TaskBatchAbortPayload
|
||||
retrigger(input: BuildReTriggerInput!): BuildReTriggerPayload
|
||||
saveSettings(input: RepositorySettingsInput!): RepositorySettingsPayload
|
||||
saveCronSettings(input: RepositorySaveCronSettingsInput!): RepositorySaveCronSettingsPayload
|
||||
removeCronSettings(input: RepositoryRemoveCronSettingsInput!): RepositoryRemoveCronSettingsPayload
|
||||
approve(input: BuildApproveInput!): BuildApprovePayload
|
||||
trigger(input: TaskTriggerInput!): TaskTriggerPayload
|
||||
buyComputeCredits(input: BuyComputeCreditsInput!): BuyComputeCreditsPayload
|
||||
saveWebHookSettings(input: SaveWebHookSettingsInput!): SaveWebHookSettingsPayload
|
||||
saveBillingSettings(input: BillingSettingsInput!): BillingSettingsPayload
|
||||
generateNewAccessToken(input: GenerateNewAccessTokenInput!): GenerateNewAccessTokenPayload
|
||||
deletePersistentWorker(input: DeletePersistentWorkerInput!): DeletePersistentWorkerPayload
|
||||
updatePersistentWorker(input: UpdatePersistentWorkerInput!): UpdatePersistentWorkerPayload
|
||||
persistentWorkerPoolRegistrationToken(input: GetPersistentWorkerPoolRegistrationTokenInput!): GetPersistentWorkerPoolRegistrationTokenPayload
|
||||
createPersistentWorkerPool(input: CreatePersistentWorkerPoolInput!): CreatePersistentWorkerPoolPayload
|
||||
updatePersistentWorkerPool(input: UpdatePersistentWorkerPoolInput!): UpdatePersistentWorkerPoolPayload
|
||||
deletePersistentWorkerPool(input: DeletePersistentWorkerPoolInput!): DeletePersistentWorkerPoolPayload
|
||||
saveWebPushConfiguration(input: SaveWebPushConfigurationInput!): SaveWebPushConfigurationPayload
|
||||
deleteWebPushConfiguration(input: DeleteWebPushConfigurationInput!): DeleteWebPushConfigurationPayload
|
||||
}
|
||||
|
||||
type Notification {
|
||||
level: NotificationLevel
|
||||
message: String!
|
||||
link: String
|
||||
}
|
||||
|
||||
"Notification level."
|
||||
enum NotificationLevel {
|
||||
INFO
|
||||
WARNING
|
||||
ERROR
|
||||
}
|
||||
|
||||
input OrganizationSecuredVariableInput {
|
||||
organizationId: ID!
|
||||
valueToSecure: String!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type OrganizationSecuredVariablePayload {
|
||||
variableName: String!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
"Information about pagination in a connection."
|
||||
type PageInfo {
|
||||
"When paginating forwards, are there more items?"
|
||||
hasNextPage: Boolean!
|
||||
"When paginating backwards, are there more items?"
|
||||
hasPreviousPage: Boolean!
|
||||
"When paginating backwards, the cursor to continue."
|
||||
startCursor: String
|
||||
"When paginating forwards, the cursor to continue."
|
||||
endCursor: String
|
||||
}
|
||||
|
||||
type ParsingResult {
|
||||
rawYamlConfig: String!
|
||||
rawStarlarkConfig: String!
|
||||
processedYamlConfig: String!
|
||||
issues: [ParsingResultIssue]
|
||||
outputLogs: [String]
|
||||
}
|
||||
|
||||
type ParsingResultIssue {
|
||||
level: ParsingResultIssueLevel!
|
||||
message: String!
|
||||
line: Long!
|
||||
column: Long!
|
||||
}
|
||||
|
||||
enum ParsingResultIssueLevel {
|
||||
INFO
|
||||
WARNING
|
||||
ERROR
|
||||
}
|
||||
|
||||
"User access level."
|
||||
enum PermissionType {
|
||||
NONE
|
||||
READ
|
||||
WRITE
|
||||
ADMIN
|
||||
}
|
||||
|
||||
type PersistentWorker {
|
||||
name: String!
|
||||
disabled: Boolean!
|
||||
arch: String!
|
||||
hostname: String!
|
||||
os: String!
|
||||
version: String!
|
||||
labels: [String]
|
||||
info: PersistentWorkerInfo
|
||||
assignedTasks("fetching only nodes before this node (exclusive)" before: String "fetching only nodes after this node (exclusive)" after: String "fetching only the first certain number of nodes" first: Int "fetching only the last certain number of nodes" last: Int): PersistentWorkerAssignedTasksConnection
|
||||
}
|
||||
|
||||
"An edge in a connection"
|
||||
type PersistentWorkerAssignedTaskEdge {
|
||||
"The item at the end of the edge"
|
||||
node: Task
|
||||
"cursor marks a unique position or index into the connection"
|
||||
cursor: String!
|
||||
}
|
||||
|
||||
"A connection to a list of items."
|
||||
type PersistentWorkerAssignedTasksConnection {
|
||||
"a list of edges"
|
||||
edges: [PersistentWorkerAssignedTaskEdge]
|
||||
"details about this specific page"
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type PersistentWorkerInfo {
|
||||
heartbeatTimestamp: Long!
|
||||
runningTasks: [Task]
|
||||
}
|
||||
|
||||
type PersistentWorkerPool {
|
||||
id: ID!
|
||||
name: String!
|
||||
enabledForPublic: Boolean!
|
||||
workers: [PersistentWorker]
|
||||
viewerPermission: PermissionType
|
||||
}
|
||||
|
||||
"Task platform."
|
||||
enum PlatformType {
|
||||
LINUX
|
||||
DARWIN
|
||||
WINDOWS
|
||||
FREEBSD
|
||||
}
|
||||
|
||||
type Repository {
|
||||
id: ID!
|
||||
owner: String!
|
||||
name: String!
|
||||
cloneUrl: String!
|
||||
masterBranch: String!
|
||||
isPrivate: Boolean!
|
||||
builds("fetching only nodes before this node (exclusive)" before: String "fetching only nodes after this node (exclusive)" after: String "fetching only the first certain number of nodes" first: Int "fetching only the last certain number of nodes" last: Int "branch to fetch builds for" branch: String): RepositoryBuildsConnection
|
||||
settings: RepositorySettings
|
||||
cronSettings: [RepositoryCronSettings]
|
||||
viewerPermission: PermissionType
|
||||
lastDefaultBranchBuild: Build
|
||||
metrics(parameters: MetricsQueryParameters): [MetricsChart]
|
||||
}
|
||||
|
||||
"An edge in a connection"
|
||||
type RepositoryBuildEdge {
|
||||
"The item at the end of the edge"
|
||||
node: Build
|
||||
"cursor marks a unique position or index into the connection"
|
||||
cursor: String!
|
||||
}
|
||||
|
||||
"A connection to a list of items."
|
||||
type RepositoryBuildsConnection {
|
||||
"a list of edges"
|
||||
edges: [RepositoryBuildEdge]
|
||||
"details about this specific page"
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
input RepositoryCreateBuildInput {
|
||||
repositoryId: ID!
|
||||
branch: String!
|
||||
sha: String
|
||||
configOverride: String
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type RepositoryCreateBuildPayload {
|
||||
build: Build!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type RepositoryCronSettings {
|
||||
name: String!
|
||||
expression: String!
|
||||
branch: String!
|
||||
nextInvocationTimestamp: Long!
|
||||
lastInvocationBuild: Build
|
||||
}
|
||||
|
||||
input RepositoryDeleteInput {
|
||||
repositoryId: ID!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type RepositoryDeletePayload {
|
||||
deleted: Boolean!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
input RepositoryRemoveCronSettingsInput {
|
||||
repositoryId: ID!
|
||||
name: String!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type RepositoryRemoveCronSettingsPayload {
|
||||
settings: [RepositoryCronSettings]
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
input RepositorySaveCronSettingsInput {
|
||||
repositoryId: ID!
|
||||
name: String!
|
||||
expression: String!
|
||||
branch: String!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type RepositorySaveCronSettingsPayload {
|
||||
settings: [RepositoryCronSettings]
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
input RepositorySecuredVariableInput {
|
||||
repositoryId: ID!
|
||||
valueToSecure: String!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type RepositorySecuredVariablePayload {
|
||||
variableName: String!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type RepositorySettings {
|
||||
needsApproval: Boolean
|
||||
decryptEnvironmentVariables: DecryptEnvironmentVariablesFor
|
||||
configResolutionStrategy: ConfigResolutionStrategy
|
||||
additionalEnvironment: [String]
|
||||
}
|
||||
|
||||
input RepositorySettingsInput {
|
||||
repositoryId: ID!
|
||||
needsApproval: Boolean
|
||||
decryptEnvironmentVariables: DecryptEnvironmentVariablesFor
|
||||
configResolutionStrategy: ConfigResolutionStrategy
|
||||
additionalEnvironment: [String]
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type RepositorySettingsPayload {
|
||||
settings: RepositorySettings!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type Root {
|
||||
viewer: User
|
||||
repository(id: ID!): Repository
|
||||
githubRepository(owner: String! name: String!): Repository
|
||||
githubRepositories(owner: String!): [Repository]
|
||||
githubOrganizationInfo(organization: String!): GitHubOrganizationInfo
|
||||
build(id: ID!): Build
|
||||
searchBuilds(repositoryOwner: String! repositoryName: String! SHA: String): [Build]
|
||||
task(id: ID!): Task
|
||||
hook(id: ID!): Hook
|
||||
webhookDelivery(id: String!): WebHookDelivery
|
||||
persistentWorkerPool(poolId: ID): PersistentWorkerPool
|
||||
persistentWorker(poolId: ID name: String): PersistentWorker
|
||||
}
|
||||
|
||||
input SaveWebHookSettingsInput {
|
||||
accountId: ID!
|
||||
webhookURL: String!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type SaveWebHookSettingsPayload {
|
||||
error: String
|
||||
info: GitHubOrganizationInfo
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
input SaveWebPushConfigurationInput {
|
||||
endpoint: String!
|
||||
p256dhKey: String!
|
||||
authKey: String!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type SaveWebPushConfigurationPayload {
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type Subscription {
|
||||
task(id: ID!): Task
|
||||
build(id: ID!): Build
|
||||
repository(id: ID!): Repository
|
||||
}
|
||||
|
||||
type Task {
|
||||
id: ID!
|
||||
buildId: ID!
|
||||
repositoryId: ID!
|
||||
name: String!
|
||||
localGroupId: Long!
|
||||
requiredGroups: [Long]
|
||||
status: TaskStatus
|
||||
notifications: [Notification]
|
||||
commands: [TaskCommand]
|
||||
firstFailedCommand: TaskCommand
|
||||
artifacts: [Artifacts]
|
||||
commandLogsTail(name: String!): [String]
|
||||
statusTimestamp: Long!
|
||||
creationTimestamp: Long!
|
||||
scheduledTimestamp: Long!
|
||||
executingTimestamp: Long!
|
||||
finalStatusTimestamp: Long!
|
||||
durationInSeconds: Long!
|
||||
labels: [String]
|
||||
uniqueLabels: [String]
|
||||
requiredPRLabels: [String]
|
||||
timeoutInSeconds: Long!
|
||||
optional: Boolean
|
||||
statusDurations: [TaskStatusDuration]
|
||||
repository: Repository!
|
||||
build: Build!
|
||||
previousRuns: [Task]
|
||||
allOtherRuns: [Task]
|
||||
dependencies: [Task]
|
||||
automaticReRun: Boolean!
|
||||
automaticallyReRunnable: Boolean!
|
||||
experimental: Boolean!
|
||||
stateful: Boolean!
|
||||
useComputeCredits: Boolean!
|
||||
usedComputeCredits: Boolean!
|
||||
transaction: AccountTransaction
|
||||
triggerType: TaskTriggerType!
|
||||
instanceResources: InstanceResources
|
||||
executionInfo: ExecutionInfo
|
||||
baseEnvironment: [String]
|
||||
hooks: [Hook]
|
||||
}
|
||||
|
||||
input TaskAbortInput {
|
||||
taskId: ID!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type TaskAbortPayload {
|
||||
abortedTask: Task!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
input TaskBatchAbortInput {
|
||||
taskIds: [ID]
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type TaskBatchAbortPayload {
|
||||
tasks: [Task]
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type TaskCommand {
|
||||
name: String
|
||||
type: TaskCommandType
|
||||
status: TaskCommandStatus
|
||||
durationInSeconds: Int
|
||||
logsTail: [String]
|
||||
}
|
||||
|
||||
"Task Command status."
|
||||
enum TaskCommandStatus {
|
||||
UNDEFINED
|
||||
SUCCESS
|
||||
FAILURE
|
||||
EXECUTING
|
||||
SKIPPED
|
||||
ABORTED
|
||||
}
|
||||
|
||||
"Task Command type."
|
||||
enum TaskCommandType {
|
||||
WAIT
|
||||
EXIT
|
||||
EXECUTE_SCRIPT
|
||||
CACHE
|
||||
UPLOAD_CACHE
|
||||
CLONE
|
||||
EXECUTE_BACKGROUND_SCRIPT
|
||||
ARTIFACTS
|
||||
}
|
||||
|
||||
input TaskReRunInput {
|
||||
taskId: ID!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type TaskReRunPayload {
|
||||
newTask: Task!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
"Task status."
|
||||
enum TaskStatus {
|
||||
CREATED
|
||||
TRIGGERED
|
||||
SCHEDULED
|
||||
EXECUTING
|
||||
ABORTED
|
||||
FAILED
|
||||
COMPLETED
|
||||
SKIPPED
|
||||
PAUSED
|
||||
}
|
||||
|
||||
type TaskStatusDuration {
|
||||
status: TaskStatus!
|
||||
durationInSeconds: Long!
|
||||
}
|
||||
|
||||
input TaskTriggerInput {
|
||||
taskId: ID!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type TaskTriggerPayload {
|
||||
task: Task!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
"Task trigger type."
|
||||
enum TaskTriggerType {
|
||||
AUTOMATIC
|
||||
MANUAL
|
||||
}
|
||||
|
||||
input TasksReRunInput {
|
||||
taskIds: [ID]
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type TasksReRunPayload {
|
||||
newTasks: [Task]
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type TimePoint {
|
||||
date: DayDate
|
||||
value: Float
|
||||
}
|
||||
|
||||
input UpdateOrganizationSecuredVariableInput {
|
||||
organizationId: ID!
|
||||
name: String!
|
||||
updatedValueToSecure: String!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type UpdateOrganizationSecuredVariablePayload {
|
||||
variableName: String!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
input UpdatePersistentWorkerInput {
|
||||
poolId: String!
|
||||
name: String!
|
||||
disabled: Boolean!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type UpdatePersistentWorkerPayload {
|
||||
worker: PersistentWorker!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
input UpdatePersistentWorkerPoolInput {
|
||||
poolId: String!
|
||||
name: String!
|
||||
enabledForPublic: Boolean!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type UpdatePersistentWorkerPoolPayload {
|
||||
pool: PersistentWorkerPool!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type User {
|
||||
id: ID!
|
||||
githubUserId: Long
|
||||
githubUserName: String!
|
||||
category: UserCategoryType!
|
||||
avatarURL: String
|
||||
builds("fetching only nodes before this node (exclusive)" before: String "fetching only nodes after this node (exclusive)" after: String "fetching only the first certain number of nodes" first: Int "fetching only the last certain number of nodes" last: Int): UserBuildsConnection
|
||||
githubMarketplacePurchase: GitHubMarketplacePurchase
|
||||
topActiveRepositories: [Repository]
|
||||
organizations: [GitHubOrganizationInfo]
|
||||
balanceInCredits: String!
|
||||
transactions("fetching only nodes before this node (exclusive)" before: String "fetching only nodes after this node (exclusive)" after: String "fetching only the first certain number of nodes" first: Int "fetching only the last certain number of nodes" last: Int): UserTransactionsConnection
|
||||
apiToken: ApiAccessToken
|
||||
webPushServerKey: String!
|
||||
persistentWorkerPools: [PersistentWorkerPool]
|
||||
}
|
||||
|
||||
"An edge in a connection"
|
||||
type UserBuildEdge {
|
||||
"The item at the end of the edge"
|
||||
node: Build
|
||||
"cursor marks a unique position or index into the connection"
|
||||
cursor: String!
|
||||
}
|
||||
|
||||
"A connection to a list of items."
|
||||
type UserBuildsConnection {
|
||||
"a list of edges"
|
||||
edges: [UserBuildEdge]
|
||||
"details about this specific page"
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
"User type."
|
||||
enum UserCategoryType {
|
||||
DEFAULT
|
||||
BLOCKED
|
||||
TRUSTED
|
||||
ADMIN
|
||||
}
|
||||
|
||||
"An edge in a connection"
|
||||
type UserTransactionEdge {
|
||||
"The item at the end of the edge"
|
||||
node: AccountTransaction
|
||||
"cursor marks a unique position or index into the connection"
|
||||
cursor: String!
|
||||
}
|
||||
|
||||
"A connection to a list of items."
|
||||
type UserTransactionsConnection {
|
||||
"a list of edges"
|
||||
edges: [UserTransactionEdge]
|
||||
"details about this specific page"
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type WebHookDelivery {
|
||||
id: String!
|
||||
accountId: Long!
|
||||
repositoryId: Long!
|
||||
timestamp: Long!
|
||||
payload: WebHookDeliveryPayload!
|
||||
response: WebHookDeliveryResponse!
|
||||
}
|
||||
|
||||
"An edge in a connection"
|
||||
type WebHookDeliveryEdge {
|
||||
"The item at the end of the edge"
|
||||
node: WebHookDelivery
|
||||
"cursor marks a unique position or index into the connection"
|
||||
cursor: String!
|
||||
}
|
||||
|
||||
type WebHookDeliveryPayload {
|
||||
event: String!
|
||||
action: String!
|
||||
data: String!
|
||||
}
|
||||
|
||||
type WebHookDeliveryResponse {
|
||||
status: Int!
|
||||
duration: Long!
|
||||
data: String!
|
||||
}
|
||||
|
||||
type WebHookSettings {
|
||||
webhookURL: String
|
||||
}
|
||||
|
||||
"A connection to a list of items."
|
||||
type WebhookDeliveriesConnection {
|
||||
"a list of edges"
|
||||
edges: [WebHookDeliveryEdge]
|
||||
"details about this specific page"
|
||||
pageInfo: PageInfo!
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace CompatBot.Utils
|
||||
namespace CompatApiClient.Utils
|
||||
{
|
||||
public static class Statistics
|
||||
{
|
@ -33,7 +33,7 @@ namespace GithubClient
|
||||
public Client()
|
||||
{
|
||||
client = HttpClientFactory.Create(new CompressionMessageHandler());
|
||||
jsonOptions = new JsonSerializerOptions
|
||||
jsonOptions = new()
|
||||
{
|
||||
PropertyNamingPolicy = SpecialJsonNamingPolicy.SnakeCase,
|
||||
IgnoreNullValues = true,
|
||||
@ -72,7 +72,7 @@ namespace GithubClient
|
||||
if (result == null)
|
||||
{
|
||||
ApiConfig.Log.Debug($"Failed to get {nameof(PrInfo)}, returning empty result");
|
||||
return new PrInfo { Number = pr };
|
||||
return new() { Number = pr };
|
||||
}
|
||||
|
||||
StatusesCache.Set(pr, result, PrStatusCacheTime);
|
||||
@ -111,7 +111,7 @@ namespace GithubClient
|
||||
if (result == null)
|
||||
{
|
||||
ApiConfig.Log.Debug($"Failed to get {nameof(IssueInfo)}, returning empty result");
|
||||
return new IssueInfo { Number = issue };
|
||||
return new() { Number = issue };
|
||||
}
|
||||
|
||||
IssuesCache.Set(issue, result, IssueStatusCacheTime);
|
||||
|
@ -2,6 +2,7 @@
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using CirrusCiClient;
|
||||
using CompatApiClient.Utils;
|
||||
using CompatBot.Commands.Attributes;
|
||||
using CompatBot.Utils;
|
||||
@ -12,6 +13,7 @@ using DSharpPlus.CommandsNext;
|
||||
using DSharpPlus.CommandsNext.Attributes;
|
||||
using DSharpPlus.Entities;
|
||||
using Microsoft.TeamFoundation.Build.WebApi;
|
||||
using BuildStatus = Microsoft.TeamFoundation.Build.WebApi.BuildStatus;
|
||||
|
||||
namespace CompatBot.Commands
|
||||
{
|
||||
@ -127,12 +129,12 @@ namespace CompatBot.Commands
|
||||
string? linuxDownloadText = null;
|
||||
string? buildTime = null;
|
||||
|
||||
if (azureClient != null && prInfo.Head?.Sha is string commit)
|
||||
if (prInfo.Head?.Sha is string commit)
|
||||
try
|
||||
{
|
||||
windowsDownloadText = "⏳ Pending...";
|
||||
linuxDownloadText = "⏳ Pending...";
|
||||
var latestBuild = await azureClient.GetPrBuildInfoAsync(commit, prInfo.MergedAt, pr, Config.Cts.Token).ConfigureAwait(false);
|
||||
var latestBuild = await CirrusCi.GetPrBuildInfoAsync(commit, prInfo.MergedAt, pr, Config.Cts.Token).ConfigureAwait(false);
|
||||
if (latestBuild == null)
|
||||
{
|
||||
if (state == "Open")
|
||||
@ -143,18 +145,16 @@ namespace CompatBot.Commands
|
||||
else
|
||||
{
|
||||
bool shouldHaveArtifacts = false;
|
||||
if (latestBuild.Status == BuildStatus.Completed
|
||||
&& (latestBuild.Result == BuildResult.Succeeded || latestBuild.Result == BuildResult.PartiallySucceeded)
|
||||
&& latestBuild.FinishTime.HasValue)
|
||||
if (latestBuild is {Status: CirrusCiClient.BuildStatus.Completed, FinishTime: not null})
|
||||
{
|
||||
buildTime = $"Built on {latestBuild.FinishTime:u} ({(DateTime.UtcNow - latestBuild.FinishTime.Value).AsTimeDeltaDescription()} ago)";
|
||||
shouldHaveArtifacts = true;
|
||||
}
|
||||
else if (latestBuild.Result == BuildResult.Failed || latestBuild.Result == BuildResult.Canceled)
|
||||
windowsDownloadText = $"❌ {latestBuild.Result}";
|
||||
else if (latestBuild.Status == BuildStatus.InProgress && latestBuild.StartTime != null)
|
||||
else if (latestBuild.Status is CirrusCiClient.BuildStatus.Failed or CirrusCiClient.BuildStatus.Errored or CirrusCiClient.BuildStatus.Aborted)
|
||||
windowsDownloadText = $"❌ {latestBuild.Status}";
|
||||
else if (latestBuild is {Status: CirrusCiClient.BuildStatus.Executing})
|
||||
{
|
||||
var estimatedCompletionTime = latestBuild.StartTime.Value + (await azureClient.GetPipelineDurationAsync(Config.Cts.Token).ConfigureAwait(false)).Mean;
|
||||
var estimatedCompletionTime = latestBuild.StartTime + (await CirrusCi.GetPipelineDurationAsync(Config.Cts.Token).ConfigureAwait(false)).Mean;
|
||||
var estimatedTime = TimeSpan.FromMinutes(1);
|
||||
if (estimatedCompletionTime > DateTime.UtcNow)
|
||||
estimatedTime = estimatedCompletionTime - DateTime.UtcNow;
|
||||
@ -202,7 +202,7 @@ namespace CompatBot.Commands
|
||||
if (!string.IsNullOrEmpty(buildTime))
|
||||
embed.WithFooter(buildTime);
|
||||
}
|
||||
else if (state == "Merged")
|
||||
else if (state == "Merged" && azureClient is not null)
|
||||
{
|
||||
var mergeTime = prInfo.MergedAt.GetValueOrDefault();
|
||||
var now = DateTime.UtcNow;
|
||||
|
@ -86,6 +86,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Clients\CirrusCiClient\CirrusCiClient.csproj" />
|
||||
<ProjectReference Include="..\SourceGenerators\SourceGenerators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
||||
<ProjectReference Include="..\Clients\CompatApiClient\CompatApiClient.csproj" />
|
||||
<ProjectReference Include="..\Clients\GithubClient\GithubClient.csproj" />
|
||||
|
@ -6,6 +6,7 @@ using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CirrusCiClient;
|
||||
using CompatBot.Commands;
|
||||
using CompatBot.Commands.Converters;
|
||||
using CompatBot.Database;
|
||||
@ -113,7 +114,8 @@ namespace CompatBot
|
||||
#endif
|
||||
StatsStorage.BackgroundSaveAsync(),
|
||||
CompatList.ImportCompatListAsync(),
|
||||
Config.GetAzureDevOpsClient().GetPipelineDurationAsync(Config.Cts.Token)
|
||||
Config.GetAzureDevOpsClient().GetPipelineDurationAsync(Config.Cts.Token),
|
||||
CirrusCi.GetPipelineDurationAsync(Config.Cts.Token)
|
||||
);
|
||||
|
||||
try
|
||||
|
@ -5,6 +5,7 @@ using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CompatApiClient.Utils;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.TeamFoundation.Build.WebApi;
|
||||
using SharpCompress.Readers;
|
||||
|
@ -40,6 +40,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YandexDiskClient", "Clients
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SourceGenerators", "SourceGenerators\SourceGenerators.csproj", "{1A75FAF1-1DD1-43FF-A789-1AB216F4B94E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CirrusCiClient", "Clients\CirrusCiClient\CirrusCiClient.csproj", "{897476B0-B80A-4134-A576-8CAEAEA14A28}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -89,6 +91,10 @@ Global
|
||||
{1A75FAF1-1DD1-43FF-A789-1AB216F4B94E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1A75FAF1-1DD1-43FF-A789-1AB216F4B94E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1A75FAF1-1DD1-43FF-A789-1AB216F4B94E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{897476B0-B80A-4134-A576-8CAEAEA14A28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{897476B0-B80A-4134-A576-8CAEAEA14A28}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{897476B0-B80A-4134-A576-8CAEAEA14A28}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{897476B0-B80A-4134-A576-8CAEAEA14A28}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@ -101,6 +107,7 @@ Global
|
||||
{5C4BCF33-2EC6-455F-B026-8A0001B7B7AD} = {E7FE0ADD-CBA6-4321-8A1C-0A3B5C3F54C2}
|
||||
{1F743D3D-4A87-47EF-B88D-A0DCEE1C5FB7} = {E7FE0ADD-CBA6-4321-8A1C-0A3B5C3F54C2}
|
||||
{CABC3E5E-2153-443B-A5A8-DA3E389359EC} = {E7FE0ADD-CBA6-4321-8A1C-0A3B5C3F54C2}
|
||||
{897476B0-B80A-4134-A576-8CAEAEA14A28} = {E7FE0ADD-CBA6-4321-8A1C-0A3B5C3F54C2}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {D7696F56-AEAC-4D83-9BD8-BE0C122A5DCE}
|
||||
|
Loading…
Reference in New Issue
Block a user