Example #1
0
        private async Task CreateProjectAsync(AzureDevOpsRepositoryTarget source, AzureDevOpsRepository repo, CancellationToken cancellationToken)
        {
            var targetProjects = await GetProjectsAsync(cancellationToken);

            var matched = targetProjects.FirstOrDefault(p => p.Name == repo.Project);

            if (matched != null)
            {
                return;
            }

            // get project from source again to also mirror its visibility & description
            var sourceProjects = await source.GetProjectsAsync(cancellationToken);

            var toClone = sourceProjects.Single(p => p.Name == repo.Project);
            // properties are stored separate

            // first get project to get id (not set in list)
            var response = await source.HttpClient.GetAsync($"https://dev.azure.com/{source.DevOpsOrganization}/_apis/projects/{toClone.Name}?api-version=5.1", cancellationToken);

            response.EnsureSuccessStatusCode();
            var sourceProject = await JsonSerializer.DeserializeAsync <Project>(await response.Content.ReadAsStreamAsync(), JsonSettings.Default, cancellationToken);

            // with project id we can query project properties
            // api is eternally in preview
            var properties = await source.GetCollectionAsync <NameValue>($"https://dev.azure.com/{source.DevOpsOrganization}/_apis/projects/{sourceProject.Id}/properties?api-version=5.1-preview.1", cancellationToken);

            // fallback to hardcoded default project template id
            var correctProcess = properties.FirstOrDefault(p => p.Name == "System.ProcessTemplateType")?.Value.GetString() ?? "b8a3a935-7e91-48b8-a94c-606d37c3e9f2";
            var json           = JsonSerializer.Serialize(new
            {
                name         = toClone.Name,
                description  = toClone.Description,
                visibility   = toClone.Visibility,
                capabilities = new
                {
                    versioncontrol = new
                    {
                        sourceControlType = "Git"
                    },
                    processTemplate = new
                    {
                        templateTypeId = correctProcess
                    }
                }
            }, JsonSettings.Default);

            response = await HttpClient.PostAsync($"https://dev.azure.com/{DevOpsOrganization}/_apis/projects?api-version=5.1", new StringContent(json, Encoding.UTF8, "application/json"), cancellationToken);

            response.EnsureSuccessStatusCode();
            // should wait for project creation as it takes some time. if we don't then git repo creation fails
            // don't bother because function runs every 5 mins -> repo will be created soon after again until it succeeds
        }
Example #2
0
        public ContainerBuilder SetAzureDevopsRepository(AzureDevOpsRepository repository)
        {
            container.Setup(p => p.GetService(typeof(AzureDevOpsRepository))).Returns(repository);

            return(this);
        }
        private async Task <IEnumerable <Item> > GetReadmeItemsFromRepository(Repository repository, AzureDevOpsRepository azureDevOpsRepo, AzureDevOpsMetadata metadata)
        {
            List <Item> readmeItems = new List <Item>();

            try
            {
                HttpClient client       = GetAzureDevopsHttpClient(metadata);
                var        responseBody = await client.GetStringAsync(
                    $"https://dev.azure.com/{repository.Name}/{azureDevOpsRepo.project.name}/_apis/git/repositories/{azureDevOpsRepo.name}/items?recursionLevel=full&includeContentMetadata=true&latestProcessedChange=true&includeLinks=true&api-version=5.1").ConfigureAwait(false);

                var itemsResponse = JsonConvert.DeserializeObject <ItemsResponse>(responseBody);
                foreach (var item in itemsResponse.Items)
                {
                    if (item.path.EndsWith("readme.md", StringComparison.CurrentCultureIgnoreCase))
                    {
                        readmeItems.Add(item);
                    }
                }
            }
            catch (Exception ex)
            {
                //TODO: handle exceptions
                Console.WriteLine(ex);
            }
            return(readmeItems);
        }
Example #4
0
        public async Task <Mirror[]> GetExistingMirrorsAsync(CancellationToken cancellationToken)
        {
            await EnsureAccessToken(cancellationToken);

            var mirrors = new List <Mirror>();
            var builds  = await GetBuildsAsync(cancellationToken);

            var mirrorBuilds = builds.Where(b => b.Name.StartsWith(_config.BuildNamePrefix)).ToArray();

            _log.LogInformation($"Looking for existing mirrors in {builds.Length} builds ({mirrorBuilds.Length} of those are mirror builds)..");
            foreach (var build in mirrorBuilds)
            {
                if (!_buildToCloneId.HasValue &&
                    _config.BuildToClone.Equals(build.Name, StringComparison.OrdinalIgnoreCase))
                {
                    _buildToCloneId = build.Id;
                }

                var repoName = build.Name.Substring(_config.BuildNamePrefix.Length);
                var repo     = new Repository
                {
                    Name = repoName
                };
                if (_repositorySource.Type == "dev.azure.com" &&
                    repoName.Contains(" - "))
                {
                    var ado = (AzureDevOpsRepositoryTarget)_repositorySource;
                    // ADO to ADO clone uses "Project - Repo" in build name when repo is in different repo than the build
                    var parts = repoName.Split(" - ");
                    repo = new AzureDevOpsRepository
                    {
                        Name   = parts[1],
                        GitUrl = $"https://dev.azure.com/{ado.DevOpsOrganization}/{parts[0]}/_git/{parts[1]}"
                    };
                }
                var expectedRepoUrls = _repositorySource.GetRepositoryUrls(repo);

                // repo property isn't loaded in overall list, so get definition
                // to ensure build is using correct source repo
                var buildDefinition = await GetBuildDefinitionAsync(build.Id, cancellationToken);

                var buildWithRepo = JsonSerializer.Deserialize <Build>(buildDefinition.GetRawText(), JsonSettings.Default);
                // normalize because github/gitlab allow both urls ending in .git and without
                // and Azure DevOps builds can also use both types of urls as source for builds
                var foundUrl = Normalize(buildWithRepo.Repository.Url);
                expectedRepoUrls = expectedRepoUrls.Select(Normalize).ToArray();
                if (!expectedRepoUrls.Contains(foundUrl))
                {
                    throw new NotSupportedException($"Expected build '{build.Name}' to use one of these repos: '{string.Join(", ", expectedRepoUrls)}' as source but it uses '{buildWithRepo.Repository.Url}'");
                }

                mirrors.Add(new Mirror
                {
                    BuildName  = build.Name,
                    Id         = build.Id,
                    Repository = repo.Name
                });
            }
            if (!_buildToCloneId.HasValue)
            {
                throw new InvalidOperationException($"Could not find the build to clone '{_config.BuildToClone}' while scanning builds in Azure DevOps");
            }

            return(mirrors.ToArray());
        }