/// <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));
        }
Ejemplo n.º 2
0
        /// <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)))));
        }
Ejemplo n.º 3
0
        /// <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;
                        }