/// <inheritdoc /> public async Task <string> Invoke(string arguments, User user, CancellationToken cancellationToken) { string result; if (arguments.Split(' ').Any(x => x.ToUpperInvariant() == "--REPO")) { using (var repo = await repositoryManager.LoadRepository(cancellationToken).ConfigureAwait(false)) { if (repo == null) { return("Repository unavailable!"); } result = repo.Head; } } else { if (!watchdog.Running) { return("Server offline!"); } result = watchdog.ActiveCompileJob?.RevisionInformation.CommitSha; } return(String.Format(CultureInfo.InvariantCulture, "^{0}", result)); }
/// <inheritdoc /> // TODO: Decomplexify #pragma warning disable CA1506 public async Task <string> Invoke(string arguments, ChatUser user, CancellationToken cancellationToken) { IEnumerable <Models.TestMerge> results = null; if (arguments.Split(' ').Any(x => x.ToUpperInvariant() == "--REPO")) { string head; using (var repo = await repositoryManager.LoadRepository(cancellationToken).ConfigureAwait(false)) { if (repo == null) { return("Repository unavailable!"); } head = repo.Head; } await databaseContextFactory.UseContext( async db => results = await db .RevisionInformations .AsQueryable() .Where(x => x.Instance.Id == instance.Id && x.CommitSha == head) .SelectMany(x => x.ActiveTestMerges) .Select(x => x.TestMerge) .Select(x => new Models.TestMerge { Number = x.Number, PullRequestRevision = x.PullRequestRevision }) .ToListAsync(cancellationToken) .ConfigureAwait(false)) .ConfigureAwait(false); } else { if (!watchdog.Running) { return("Server offline!"); } results = watchdog.ActiveCompileJob?.RevisionInformation.ActiveTestMerges.Select(x => x.TestMerge).ToList() ?? new List <Models.TestMerge>(); } return(!results.Any() ? "None!" : String.Join(", ", results.Select(x => String.Format(CultureInfo.InvariantCulture, "#{0} at {1}", x.Number, x.PullRequestRevision.Substring(0, 7))))); }
/// <inheritdoc /> #pragma warning disable CA1506 public async Task DeploymentProcess( Models.Job job, IDatabaseContextFactory databaseContextFactory, Action <int> progressReporter, CancellationToken cancellationToken) { if (job == null) { throw new ArgumentNullException(nameof(job)); } if (databaseContextFactory == null) { throw new ArgumentNullException(nameof(databaseContextFactory)); } if (progressReporter == null) { throw new ArgumentNullException(nameof(progressReporter)); } lock (deploymentLock) { if (deploying) { throw new JobException(ErrorCode.DreamMakerCompileJobInProgress); } deploying = true; } currentChatCallback = null; currentDreamMakerOutput = null; Models.CompileJob compileJob = null; try { string repoOwner = null; string repoName = null; TimeSpan?averageSpan = null; Models.RepositorySettings repositorySettings = null; Models.DreamDaemonSettings ddSettings = null; Models.DreamMakerSettings dreamMakerSettings = null; IRepository repo = null; IRemoteDeploymentManager remoteDeploymentManager = null; Models.RevisionInformation revInfo = null; await databaseContextFactory.UseContext( async databaseContext => { averageSpan = await CalculateExpectedDeploymentTime(databaseContext, cancellationToken).ConfigureAwait(false); ddSettings = await databaseContext .DreamDaemonSettings .AsQueryable() .Where(x => x.InstanceId == metadata.Id) .Select(x => new Models.DreamDaemonSettings { StartupTimeout = x.StartupTimeout, }) .FirstOrDefaultAsync(cancellationToken) .ConfigureAwait(false); if (ddSettings == default) { throw new JobException(ErrorCode.InstanceMissingDreamDaemonSettings); } dreamMakerSettings = await databaseContext .DreamMakerSettings .AsQueryable() .Where(x => x.InstanceId == metadata.Id) .FirstAsync(cancellationToken) .ConfigureAwait(false); if (dreamMakerSettings == default) { throw new JobException(ErrorCode.InstanceMissingDreamMakerSettings); } repositorySettings = await databaseContext .RepositorySettings .AsQueryable() .Where(x => x.InstanceId == metadata.Id) .Select(x => new Models.RepositorySettings { AccessToken = x.AccessToken, ShowTestMergeCommitters = x.ShowTestMergeCommitters, PushTestMergeCommits = x.PushTestMergeCommits, PostTestMergeComment = x.PostTestMergeComment, }) .FirstOrDefaultAsync(cancellationToken) .ConfigureAwait(false); if (repositorySettings == default) { throw new JobException(ErrorCode.InstanceMissingRepositorySettings); } repo = await repositoryManager.LoadRepository(cancellationToken).ConfigureAwait(false); try { if (repo == null) { throw new JobException(ErrorCode.RepoMissing); } remoteDeploymentManager = remoteDeploymentManagerFactory .CreateRemoteDeploymentManager(metadata, repo.RemoteGitProvider.Value); var repoSha = repo.Head; repoOwner = repo.RemoteRepositoryOwner; repoName = repo.RemoteRepositoryName; revInfo = await databaseContext .RevisionInformations .AsQueryable() .Where(x => x.CommitSha == repoSha && x.Instance.Id == metadata.Id) .Include(x => x.ActiveTestMerges) .ThenInclude(x => x.TestMerge) .ThenInclude(x => x.MergedBy) .FirstOrDefaultAsync(cancellationToken) .ConfigureAwait(false); if (revInfo == default) { revInfo = new Models.RevisionInformation { CommitSha = repoSha, Timestamp = await repo.TimestampCommit(repoSha, cancellationToken).ConfigureAwait(false), OriginCommitSha = repoSha, Instance = new Models.Instance { Id = metadata.Id, }, ActiveTestMerges = new List <RevInfoTestMerge>(), }; logger.LogInformation(Repository.Repository.OriginTrackingErrorTemplate, repoSha); databaseContext.Instances.Attach(revInfo.Instance); await databaseContext.Save(cancellationToken).ConfigureAwait(false); } } catch { repo?.Dispose(); throw; } }) .ConfigureAwait(false); var likelyPushedTestMergeCommit = repositorySettings.PushTestMergeCommits.Value && repositorySettings.AccessToken != null && repositorySettings.AccessUser != null; using (repo) compileJob = await Compile( revInfo, dreamMakerSettings, ddSettings.StartupTimeout.Value, repo, remoteDeploymentManager, progressReporter, averageSpan, likelyPushedTestMergeCommit, cancellationToken) .ConfigureAwait(false); var activeCompileJob = compileJobConsumer.LatestCompileJob(); try { await databaseContextFactory.UseContext( async databaseContext => { var fullJob = compileJob.Job; compileJob.Job = new Models.Job { Id = job.Id, }; var fullRevInfo = compileJob.RevisionInformation; compileJob.RevisionInformation = new Models.RevisionInformation { Id = revInfo.Id, }; databaseContext.Jobs.Attach(compileJob.Job); databaseContext.RevisionInformations.Attach(compileJob.RevisionInformation); databaseContext.CompileJobs.Add(compileJob); // The difficulty with compile jobs is they have a two part commit await databaseContext.Save(cancellationToken).ConfigureAwait(false); logger.LogTrace("Created CompileJob {0}", compileJob.Id); try { await compileJobConsumer.LoadCompileJob(compileJob, cancellationToken).ConfigureAwait(false); } catch { // So we need to un-commit the compile job if the above throws databaseContext.CompileJobs.Remove(compileJob); // DCT: Cancellation token is for job, operation must run regardless await databaseContext.Save(default).ConfigureAwait(false); throw; }