Example #1
0
        public async Task <IActionResult> AddBuildToChannel(int channelId, int buildId)
        {
            Data.Models.Channel channel = await _context.Channels.FindAsync(channelId);

            if (channel == null)
            {
                return(NotFound(new ApiError($"The channel with id '{channelId}' was not found.")));
            }

            Data.Models.Build build = await _context.Builds.FindAsync(buildId);

            if (build == null)
            {
                return(NotFound(new ApiError($"The build with id '{buildId}' was not found.")));
            }

            var buildChannel = new Data.Models.BuildChannel {
                Channel = channel, Build = build
            };
            await _context.BuildChannels.AddAsync(buildChannel);

            await _context.SaveChangesAsync();

            return(StatusCode((int)HttpStatusCode.Created));
        }
Example #2
0
        public Build([NotNull] Data.Models.Build other)
        {
            if (other == null)
            {
                throw new ArgumentNullException(nameof(other));
            }

            Id                           = other.Id;
            Commit                       = other.Commit;
            GitHubRepository             = other.GitHubRepository;
            GitHubBranch                 = other.GitHubBranch;
            PublishUsingPipelines        = other.PublishUsingPipelines;
            AzureDevOpsBuildId           = other.AzureDevOpsBuildId;
            AzureDevOpsBuildDefinitionId = other.AzureDevOpsBuildDefinitionId;
            AzureDevOpsAccount           = other.AzureDevOpsAccount;
            AzureDevOpsProject           = other.AzureDevOpsProject;
            AzureDevOpsBuildNumber       = other.AzureDevOpsBuildNumber;
            AzureDevOpsRepository        = other.AzureDevOpsRepository;
            AzureDevOpsBranch            = other.AzureDevOpsBranch;
            DateProduced                 = other.DateProduced;
            Channels                     = other.BuildChannels?.Select(bc => bc.Channel)
                                           .Where(c => c != null)
                                           .Select(c => new v2018_07_16.Models.Channel(c))
                                           .ToList();
            Assets       = other.Assets?.Select(a => new v2018_07_16.Models.Asset(a)).ToList();
            Dependencies = other.DependentBuildIds?.Select(d => new BuildRef(d.DependentBuildId, d.IsProduct, d.TimeToInclusionInMinutes)).ToList();
            Staleness    = other.Staleness;
            Released     = other.Released;
        }
Example #3
0
        protected async Task <IActionResult> TriggerSubscriptionCore(Guid id, int buildId)
        {
            Data.Models.Subscription subscription = await _context.Subscriptions.Include(sub => sub.LastAppliedBuild)
                                                    .Include(sub => sub.Channel)
                                                    .FirstOrDefaultAsync(sub => sub.Id == id);

            if (buildId != 0)
            {
                Data.Models.Build build = await _context.Builds.Where(b => b.Id == buildId).FirstOrDefaultAsync();

                // Non-existent build
                if (build == null)
                {
                    return(BadRequest($"Build {buildId} was not found"));
                }
                // Build doesn't match source repo
                if (!(build.GitHubRepository?.Equals(subscription.SourceRepository, StringComparison.InvariantCultureIgnoreCase) == true ||
                      build.AzureDevOpsRepository?.Equals(subscription.SourceRepository, StringComparison.InvariantCultureIgnoreCase) == true))
                {
                    return(BadRequest($"Build {buildId} does not match source repo"));
                }
            }

            if (subscription == null)
            {
                return(NotFound());
            }

            var values = new { SubId = id, BuildId = buildId };

            _queue.Post <StartSubscriptionUpdateWorkItem>(JToken.FromObject(values));
            return(Accepted(new Subscription(subscription)));
        }
Example #4
0
        private Build ToClientModelBuild(Data.Models.Build other)
        {
            var channels = other.BuildChannels?
                           .Select(bc => ToClientModelChannel(bc.Channel))
                           .ToImmutableList();

            var assets = other.Assets?
                         .Select(a => new Asset(a.Id, a.BuildId, a.NonShipping, a.Name, a.Version, null))
                         .ToImmutableList();

            var dependencies = other.DependentBuildIds?
                               .Select(ToClientModelBuildDependency)
                               .ToImmutableList();

            var incoherences = other.Incoherencies?
                               .Select(ToClientModelBuildIncoherence)
                               .ToImmutableList();

            return(new Build(
                       other.Id,
                       other.DateProduced,
                       other.Staleness,
                       other.Released,
                       other.Stable,
                       other.Commit,
                       channels,
                       assets,
                       dependencies,
                       incoherences));
        }
        public virtual async Task <IActionResult> Update(int buildId, [FromBody, Required] BuildUpdate buildUpdate)
        {
            Data.Models.Build build = await _context.Builds.Where(b => b.Id == buildId).FirstOrDefaultAsync();

            if (build == null)
            {
                return(NotFound());
            }

            bool doUpdate = false;

            if (buildUpdate.Released.HasValue && build.Released != buildUpdate.Released.Value)
            {
                build.Released = buildUpdate.Released.Value;
                doUpdate       = true;
            }

            if (doUpdate)
            {
                _context.Builds.Update(build);
                await _context.SaveChangesAsync();
            }

            return(Ok(new Models.Build(build)));
        }
Example #6
0
        public async Task <IActionResult> Create([FromBody, Required] BuildData build)
        {
            Data.Models.Build buildModel = build.ToDb();
            buildModel.DateProduced = DateTimeOffset.UtcNow;
            if (build.Dependencies != null)
            {
                await _context.BuildDependencies.AddRangeAsync(
                    build.Dependencies.Select(
                        b => new Data.Models.BuildDependency
                {
                    Build = buildModel, DependentBuildId = b.BuildId, IsProduct = b.IsProduct,
                }));
            }

            await _context.Builds.AddAsync(buildModel);

            await _context.SaveChangesAsync();

            return(CreatedAtRoute(
                       new
            {
                action = "GetBuild",
                id = buildModel.Id
            },
                       new Models.Build(buildModel)));
        }
        public override async Task <IActionResult> GetLatest(
            string repository,
            string commit,
            string buildNumber,
            int?channelId,
            DateTimeOffset?notBefore,
            DateTimeOffset?notAfter,
            bool?loadCollections)
        {
            IQueryable <Data.Models.Build> query = Query(
                repository,
                commit,
                buildNumber,
                null,
                null,
                null,
                channelId,
                notBefore,
                notAfter,
                loadCollections);

            Data.Models.Build build = await query.OrderByDescending(o => o.DateProduced).FirstOrDefaultAsync();

            if (build == null)
            {
                return(NotFound());
            }

            return(Ok(new Models.Build(build)));
        }
Example #8
0
        public async Task <IActionResult> Create([FromBody] BuildData build)
        {
            var buildModel = new Data.Models.Build(build)
            {
                DateProduced = DateTimeOffset.UtcNow,
                Dependencies = await _context.Builds.Where(b => build.Dependencies.Contains(b.Id)).ToListAsync()
            };
            await _context.Builds.AddAsync(buildModel);

            var defaultChannels = await _context.DefaultChannels
                                  .Where(dc => dc.Repository == buildModel.Repository && dc.Branch == buildModel.Branch)
                                  .Select(dc => dc.ChannelId)
                                  .ToListAsync();

            foreach (var channelId in defaultChannels)
            {
                await _context.BuildChannels.AddAsync(new Data.Models.BuildChannel
                {
                    ChannelId = channelId,
                    Build     = buildModel,
                });
            }
            await _context.SaveChangesAsync();

            return(CreatedAtRoute(new { action = "GetBuild", id = buildModel.Id }, new Build(buildModel)));
        }
Example #9
0
        public Build([NotNull] Data.Models.Build other)
        {
            if (other == null)
            {
                throw new ArgumentNullException(nameof(other));
            }

            var hasGitHubInfo = other.GitHubRepository != null;

            Id         = other.Id;
            Repository = (hasGitHubInfo)
                ? other.GitHubRepository
                : other.AzureDevOpsRepository;
            Branch = (hasGitHubInfo)
                ? other.GitHubBranch
                : other.AzureDevOpsBranch;
            Commit       = other.Commit;
            BuildNumber  = other.AzureDevOpsBuildNumber;
            DateProduced = other.DateProduced;
            Channels     = other.BuildChannels?.Select(bc => bc.Channel)
                           .Where(c => c != null)
                           .Select(c => new Channel(c))
                           .ToList();
            Assets = other.Assets?.Select(a => new Asset(a)).ToList();
        }
Example #10
0
        public async Task <IActionResult> Create([FromBody] BuildData build)
        {
            Data.Models.Build buildModel = build.ToDb();
            buildModel.DateProduced = DateTimeOffset.UtcNow;
            buildModel.Dependencies = build.Dependencies != null ? await _context.Builds.Where(b => build.Dependencies.Contains(b.Id)).ToListAsync() : null;

            await _context.Builds.AddAsync(buildModel);

            await _context.SaveChangesAsync();

            return(CreatedAtRoute(new { action = "GetBuild", id = buildModel.Id }, new Build(buildModel)));
        }
        public override async Task <IActionResult> GetBuildGraph(int id)
        {
            Data.Models.Build build = await _context.Builds.Include(b => b.Incoherencies).FirstOrDefaultAsync(b => b.Id == id);

            if (build == null)
            {
                return(NotFound());
            }

            var builds = await _context.GetBuildGraphAsync(build.Id);

            return(Ok(BuildGraph.Create(builds.Select(b => new Build(b)))));
        }
            public async Task ProcessAsync(JToken argumentToken)
            {
                // This method is called asynchronously whenever a new build is inserted in BAR.
                // It's goal is to compute the incoherent dependencies that the build have and
                // persist the list of them in BAR.

                int buildId = argumentToken.Value <int>();
                DependencyGraphBuildOptions graphBuildOptions = new DependencyGraphBuildOptions()
                {
                    IncludeToolset = false,
                    LookupBuilds   = false,
                    NodeDiff       = NodeDiff.None
                };

                try
                {
                    Data.Models.Build build = await _context.Builds.FindAsync(buildId);

                    DependencyGraph graph = await DependencyGraph.BuildRemoteDependencyGraphAsync(
                        _remoteFactory,
                        build.GitHubRepository ?? build.AzureDevOpsRepository,
                        build.Commit,
                        graphBuildOptions,
                        _logger);

                    var incoherencies = new List <Data.Models.BuildIncoherence>();

                    foreach (var incoherence in graph.IncoherentDependencies)
                    {
                        incoherencies.Add(new Data.Models.BuildIncoherence
                        {
                            Name       = incoherence.Name,
                            Version    = incoherence.Version,
                            Repository = incoherence.RepoUri,
                            Commit     = incoherence.Commit
                        });
                    }

                    _context.Entry(build).Reload();
                    build.Incoherencies = incoherencies;

                    _context.Builds.Update(build);
                    await _context.SaveChangesAsync();
                }
                catch (Exception e)
                {
                    _logger.LogWarning(e, $"Problems computing the dependency incoherencies for BAR build {buildId}");
                }
            }
        public async Task <IActionResult> GetCommit(int buildId)
        {
            Data.Models.Build build = await _context.Builds.Include(b => b.Incoherencies).FirstOrDefaultAsync(b => b.Id == buildId);

            if (build == null)
            {
                return(NotFound());
            }

            IRemote remote = await Factory.GetRemoteAsync(build.AzureDevOpsRepository ?? build.GitHubRepository, null);

            Microsoft.DotNet.DarcLib.Commit commit = await remote.GetCommitAsync(build.AzureDevOpsRepository ?? build.GitHubRepository, build.Commit);

            return(Ok(new Models.Commit(commit.Author, commit.Sha, commit.Message)));
        }
Example #14
0
        public override async Task <IActionResult> GetBuild(int id)
        {
            Data.Models.Build build = await _context.Builds.Where(b => b.Id == id)
                                      .Include(b => b.BuildChannels)
                                      .ThenInclude(bc => bc.Channel)
                                      .Include(b => b.Assets)
                                      .FirstOrDefaultAsync();

            if (build == null)
            {
                return(NotFound());
            }

            return(Ok(new Build(build)));
        }
        /// <summary>
        /// This method is called asynchronously whenever a new build is inserted in BAR.
        /// It's goal is to compute the incoherent dependencies that the build have and
        /// persist the list of them in BAR.
        /// </summary>
        /// <param name="buildId">Build id for which the incoherencies should be computed.</param>
        private async Task SetBuildIncoherencyInfoAsync(int buildId)
        {
            DependencyGraphBuildOptions graphBuildOptions = new DependencyGraphBuildOptions()
            {
                IncludeToolset = false,
                LookupBuilds   = false,
                NodeDiff       = NodeDiff.None
            };

            try
            {
                using (IServiceScope scope = ServiceScopeFactory.CreateScope())
                {
                    BuildAssetRegistryContext context = scope.ServiceProvider.GetRequiredService <BuildAssetRegistryContext>();

                    Data.Models.Build build = await context.Builds.FindAsync(buildId);

                    DependencyGraph graph = await DependencyGraph.BuildRemoteDependencyGraphAsync(
                        RemoteFactory,
                        build.GitHubRepository ?? build.AzureDevOpsRepository,
                        build.Commit,
                        graphBuildOptions,
                        Logger);

                    var incoherencies = new List <Data.Models.BuildIncoherence>();

                    foreach (var incoherence in graph.IncoherentDependencies)
                    {
                        build.Incoherencies.Add(new Data.Models.BuildIncoherence
                        {
                            Name       = incoherence.Name,
                            Version    = incoherence.Version,
                            Repository = incoherence.RepoUri,
                            Commit     = incoherence.Commit
                        });
                    }
                    context.Entry <Data.Models.Build>(build).Reload();
                    build.Incoherencies = incoherencies;

                    context.Builds.Update(build);
                    await context.SaveChangesAsync();
                }
            }
            catch (Exception e)
            {
                Logger.LogWarning(e, $"Problems computing the dependency incoherencies for BAR build {buildId}");
            }
        }
Example #16
0
        public Build([NotNull] Data.Models.Build other)
        {
            if (other == null)
            {
                throw new ArgumentNullException(nameof(other));
            }

            Id           = other.Id;
            Repository   = other.Repository;
            Commit       = other.Commit;
            BuildNumber  = other.BuildNumber;
            DateProduced = other.DateProduced;
            Channels     = other.BuildChannels?.Select(bc => bc.Channel).Where(c => c != null).Select(c => new Channel(c)).ToList();
            Assets       = other.Assets?.Select(a => new Asset(a)).ToList();
            Dependencies = other.Dependencies?.Select(b => new BuildRef {
                Id = b.Id
            }).ToList();
        }
Example #17
0
        public virtual async Task <IActionResult> Create([FromBody] BuildData build)
        {
            Data.Models.Build buildModel = build.ToDb();
            buildModel.DateProduced = DateTimeOffset.UtcNow;
            if (build.Dependencies?.Count > 0)
            {
                return(BadRequest("This api version doesn't support build dependencies."));
            }
            await _context.Builds.AddAsync(buildModel);

            await _context.SaveChangesAsync();

            return(CreatedAtRoute(
                       new
            {
                action = "GetBuild",
                id = buildModel.Id
            },
                       new Models.Build(buildModel)));
        }
        public async Task <IActionResult> Create([FromBody, Required] BuildData build)
        {
            Data.Models.Build buildModel = build.ToDb();
            buildModel.DateProduced = DateTimeOffset.UtcNow;

            if (build.Dependencies != null)
            {
                // For each Dependency, update the time to Inclusion.
                // This measure is to be used for telemetry purposes, and has several known corner cases
                // where the measurement will not be correct:
                // 1. For any dependencies that were added before this column was added, the TimeToInclusionInMinutes
                //    will be 0.
                // 2. For new release branches, until new builds of dependencies are added, this will recalculate
                //    the TimeToInclusion, so it will seem inordinately large until new builds are added. This will
                //    be particularly true for dependencies that are infrequently updated.
                foreach (var dep in build.Dependencies)
                {
                    // Heuristic to discover if this dependency has been added to the same repository and branch
                    // of the current build. If we find a match in the BuildDependencies table, it means
                    // that this is not a new dependency, and we should use the TimeToInclusionInMinutes
                    // of the previous time this dependency was added.
                    var buildDependency = _context.BuildDependencies.Where(d =>
                                                                           d.DependentBuildId == dep.BuildId &&
                                                                           d.Build.GitHubRepository == buildModel.GitHubRepository &&
                                                                           d.Build.GitHubBranch == buildModel.GitHubBranch &&
                                                                           d.Build.AzureDevOpsRepository == buildModel.AzureDevOpsRepository &&
                                                                           d.Build.AzureDevOpsBranch == buildModel.AzureDevOpsBranch
                                                                           ).FirstOrDefault();

                    if (buildDependency != null)
                    {
                        dep.TimeToInclusionInMinutes = buildDependency.TimeToInclusionInMinutes;
                    }
                    else
                    {
                        // If the dependent build is not currently in the BuildDependency table for this repo/branch (ie is a new dependency),
                        // find the dependency in the Builds table and calculate the time to inclusion

                        // We want to use the BuildChannel insert time if it exists. So we need to heuristically:
                        // 1. Find the subscription between these two repositories on the current branch
                        // 2. Find the entry in BuildChannels and get the insert time
                        // In certain corner cases, we may pick the wrong subscription or BuildChannel

                        Data.Models.Build depBuild = await _context.Builds.FindAsync(dep.BuildId);

                        // If we don't find a subscription or a BuildChannel entry, use the dependency's
                        // date produced.
                        DateTimeOffset startTime = depBuild.DateProduced;

                        Data.Models.Subscription subscription = _context.Subscriptions.Where(s =>
                                                                                             (s.SourceRepository == depBuild.GitHubRepository || s.SourceRepository == depBuild.AzureDevOpsRepository) &&
                                                                                             (s.TargetRepository == buildModel.GitHubRepository || s.TargetRepository == buildModel.AzureDevOpsRepository) &&
                                                                                             (s.TargetBranch == buildModel.GitHubBranch || s.TargetBranch == buildModel.AzureDevOpsBranch)
                                                                                             ).LastOrDefault();


                        if (subscription != null)
                        {
                            Data.Models.BuildChannel buildChannel = _context.BuildChannels.Where(bc =>
                                                                                                 bc.BuildId == depBuild.Id &&
                                                                                                 bc.ChannelId == subscription.ChannelId
                                                                                                 ).LastOrDefault();

                            if (buildChannel != null)
                            {
                                startTime = buildChannel.DateTimeAdded;
                            }
                        }

                        dep.TimeToInclusionInMinutes = (buildModel.DateProduced - startTime).TotalMinutes;
                    }
                }

                await _context.BuildDependencies.AddRangeAsync(
                    build.Dependencies.Select(
                        b => new Data.Models.BuildDependency
                {
                    Build = buildModel, DependentBuildId = b.BuildId, IsProduct = b.IsProduct, TimeToInclusionInMinutes = b.TimeToInclusionInMinutes,
                }));
            }

            await _context.Builds.AddAsync(buildModel);

            await _context.SaveChangesAsync();

            // Compute the dependency incoherencies of the build.
            // Since this might be an expensive operation we do it asynchronously.
            Queue.Post(
                async() =>
            {
                await SetBuildIncoherencyInfoAsync(buildModel.Id);
            });

            return(CreatedAtRoute(
                       new
            {
                action = "GetBuild",
                id = buildModel.Id
            },
                       new Models.Build(buildModel)));
        }