<commit_before>﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Octokit;

using Tgstation.Server.Host.Components.Repository;
using Tgstation.Server.Host.Core;
using Tgstation.Server.Host.Database;
using Tgstation.Server.Host.Extensions;
using Tgstation.Server.Host.Models;

namespace Tgstation.Server.Host.Components.Deployment.Remote
{
	/// <summary>
	/// <see cref="IRemoteDeploymentManager"/> for GitHub.com.
	/// </summary>
	sealed class GitHubRemoteDeploymentManager : BaseRemoteDeploymentManager
	{
		/// <summary>
		/// The <see cref="IDatabaseContextFactory"/> for the <see cref="GitHubRemoteDeploymentManager"/>.
		/// </summary>
		readonly IDatabaseContextFactory databaseContextFactory;

		/// <summary>
		/// The <see cref="IGitHubClientFactory"/> for the <see cref="GitHubRemoteDeploymentManager"/>.
		/// </summary>
		readonly IGitHubClientFactory gitHubClientFactory;

		/// <summary>
		/// Initializes a new instance of the <see cref="GitHubRemoteDeploymentManager"/> class.
		/// </summary>
		/// <param name="databaseContextFactory">The value of <see cref="databaseContextFactory"/>.</param>
		/// <param name="gitHubClientFactory">The value of <see cref="gitHubClientFactory"/>.</param>
		/// <param name="logger">The <see cref="ILogger"/> for the <see cref="BaseRemoteDeploymentManager"/>.</param>
		/// <param name="metadata">The <see cref="Api.Models.Instance"/> for the <see cref="BaseRemoteDeploymentManager"/>.</param>
		public GitHubRemoteDeploymentManager(
			IDatabaseContextFactory databaseContextFactory,
			IGitHubClientFactory gitHubClientFactory,
			ILogger<GitHubRemoteDeploymentManager> logger,
			Api.Models.Instance metadata)
			: base(logger, metadata)
		{
			this.databaseContextFactory = databaseContextFactory ?? throw new ArgumentNullException(nameof(databaseContextFactory));
			this.gitHubClientFactory = gitHubClientFactory ?? throw new ArgumentNullException(nameof(gitHubClientFactory));
		}

		/// <inheritdoc />
		public override async Task StartDeployment(
			Api.Models.Internal.IGitRemoteInformation remoteInformation,
			CompileJob compileJob,
			CancellationToken cancellationToken)
		{
			if (remoteInformation == null)
				throw new ArgumentNullException(nameof(remoteInformation));
			if (compileJob == null)
				throw new ArgumentNullException(nameof(compileJob));

			Logger.LogTrace("Starting deployment...");

			RepositorySettings repositorySettings = null;
			await databaseContextFactory.UseContext(
				async databaseContext =>
					repositorySettings = await databaseContext
						.RepositorySettings
						.AsQueryable()
						.Where(x => x.InstanceId == Metadata.Id)
						.FirstAsync(cancellationToken));

			var instanceAuthenticated = repositorySettings.AccessToken != null;
			var gitHubClient = !instanceAuthenticated
				? gitHubClientFactory.CreateClient()
				: gitHubClientFactory.CreateClient(repositorySettings.AccessToken);

			var repositoryTask = gitHubClient
				.Repository
				.Get(
					remoteInformation.RemoteRepositoryOwner,
					remoteInformation.RemoteRepositoryName);

			if (!repositorySettings.CreateGitHubDeployments.Value)
				Logger.LogTrace("Not creating deployment");
			else if (!instanceAuthenticated)
				Logger.LogWarning("Can't create GitHub deployment as no access token is set for repository!");
			else
			{
				Logger.LogTrace("Creating deployment...");
				var deployment = await gitHubClient
					.Repository
					.Deployment
					.Create(
						remoteInformation.RemoteRepositoryOwner,
						remoteInformation.RemoteRepositoryName,
						new NewDeployment(compileJob.RevisionInformation.CommitSha)
						{
							AutoMerge = false,
							Description = "TGS Game Deployment",
							Environment = $"TGS: {Metadata.Name}",
							ProductionEnvironment = true,
							RequiredContexts = new Collection<string>(),
						})
					.WithToken(cancellationToken)
					;

				compileJob.GitHubDeploymentId = deployment.Id;
				Logger.LogDebug("Created deployment ID {deploymentId}", deployment.Id);

				await gitHubClient
					.Repository
					.Deployment
					.Status
					.Create(
						remoteInformation.RemoteRepositoryOwner,
						remoteInformation.RemoteRepositoryName,
						deployment.Id,
						new NewDeploymentStatus(DeploymentState.InProgress)
						{
							Description = "The project is being deployed",
							AutoInactive = false,
						})
					.WithToken(cancellationToken)
					;

				Logger.LogTrace("In-progress deployment status created");
			}

			try
			{
				var gitHubRepo = await repositoryTask
					.WithToken(cancellationToken)
					;

				compileJob.GitHubRepoId = gitHubRepo.Id;<commit_msg>Deployment creation errors shouldn't fail the job<commit_after>﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Octokit;

using Tgstation.Server.Host.Components.Repository;
using Tgstation.Server.Host.Core;
using Tgstation.Server.Host.Database;
using Tgstation.Server.Host.Extensions;
using Tgstation.Server.Host.Models;

namespace Tgstation.Server.Host.Components.Deployment.Remote
{
	/// <summary>
	/// <see cref="IRemoteDeploymentManager"/> for GitHub.com.
	/// </summary>
	sealed class GitHubRemoteDeploymentManager : BaseRemoteDeploymentManager
	{
		/// <summary>
		/// The <see cref="IDatabaseContextFactory"/> for the <see cref="GitHubRemoteDeploymentManager"/>.
		/// </summary>
		readonly IDatabaseContextFactory databaseContextFactory;

		/// <summary>
		/// The <see cref="IGitHubClientFactory"/> for the <see cref="GitHubRemoteDeploymentManager"/>.
		/// </summary>
		readonly IGitHubClientFactory gitHubClientFactory;

		/// <summary>
		/// Initializes a new instance of the <see cref="GitHubRemoteDeploymentManager"/> class.
		/// </summary>
		/// <param name="databaseContextFactory">The value of <see cref="databaseContextFactory"/>.</param>
		/// <param name="gitHubClientFactory">The value of <see cref="gitHubClientFactory"/>.</param>
		/// <param name="logger">The <see cref="ILogger"/> for the <see cref="BaseRemoteDeploymentManager"/>.</param>
		/// <param name="metadata">The <see cref="Api.Models.Instance"/> for the <see cref="BaseRemoteDeploymentManager"/>.</param>
		public GitHubRemoteDeploymentManager(
			IDatabaseContextFactory databaseContextFactory,
			IGitHubClientFactory gitHubClientFactory,
			ILogger<GitHubRemoteDeploymentManager> logger,
			Api.Models.Instance metadata)
			: base(logger, metadata)
		{
			this.databaseContextFactory = databaseContextFactory ?? throw new ArgumentNullException(nameof(databaseContextFactory));
			this.gitHubClientFactory = gitHubClientFactory ?? throw new ArgumentNullException(nameof(gitHubClientFactory));
		}

		/// <inheritdoc />
		public override async Task StartDeployment(
			Api.Models.Internal.IGitRemoteInformation remoteInformation,
			CompileJob compileJob,
			CancellationToken cancellationToken)
		{
			if (remoteInformation == null)
				throw new ArgumentNullException(nameof(remoteInformation));
			if (compileJob == null)
				throw new ArgumentNullException(nameof(compileJob));

			Logger.LogTrace("Starting deployment...");

			RepositorySettings repositorySettings = null;
			await databaseContextFactory.UseContext(
				async databaseContext =>
					repositorySettings = await databaseContext
						.RepositorySettings
						.AsQueryable()
						.Where(x => x.InstanceId == Metadata.Id)
						.FirstAsync(cancellationToken));

			var instanceAuthenticated = repositorySettings.AccessToken != null;
			var gitHubClient = !instanceAuthenticated
				? gitHubClientFactory.CreateClient()
				: gitHubClientFactory.CreateClient(repositorySettings.AccessToken);

			var repositoryTask = gitHubClient
				.Repository
				.Get(
					remoteInformation.RemoteRepositoryOwner,
					remoteInformation.RemoteRepositoryName);

			if (!repositorySettings.CreateGitHubDeployments.Value)
				Logger.LogTrace("Not creating deployment");
			else if (!instanceAuthenticated)
				Logger.LogWarning("Can't create GitHub deployment as no access token is set for repository!");
			else
			{
				Logger.LogTrace("Creating deployment...");
				Octokit.Deployment deployment;

				try
				{
					deployment = await gitHubClient
						.Repository
						.Deployment
						.Create(
							remoteInformation.RemoteRepositoryOwner,
							remoteInformation.RemoteRepositoryName,
							new NewDeployment(compileJob.RevisionInformation.CommitSha)
							{
								AutoMerge = false,
								Description = "TGS Game Deployment",
								Environment = $"TGS: {Metadata.Name}",
								ProductionEnvironment = true,
								RequiredContexts = new Collection<string>(),
							})
						.WithToken(cancellationToken);

					Logger.LogDebug("Created deployment ID {deploymentId}", deployment.Id);

					await gitHubClient
						.Repository
						.Deployment
						.Status
						.Create(
							remoteInformation.RemoteRepositoryOwner,
							remoteInformation.RemoteRepositoryName,
							deployment.Id,
							new NewDeploymentStatus(DeploymentState.InProgress)
							{
								Description = "The project is being deployed",
								AutoInactive = false,
							})
						.WithToken(cancellationToken);

					compileJob.GitHubDeploymentId = deployment.Id;
					Logger.LogTrace("In-progress deployment status created");
				}
				catch (ApiException ex)
				{
					Logger.LogError(ex, "Unable to create deployment!");
				}
			}

			try
			{
				var gitHubRepo = await repositoryTask
					.WithToken(cancellationToken)
					;

				compileJob.GitHubRepoId = gitHubRepo.Id;
{'fraction_non_alphanumeric': 0.10267044305077888, 'fraction_numerical': 0.0, 'mean_word_length': 4.067657611481292, 'pattern_counts': {'":': 0, '<': 65, '<?xml version=': 0, '>': 69, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5111183', 'n_tokens_mistral': 3300, 'n_tokens_neox': 2601, 'n_words': 561}