Example #1
0
        public List <HosterRepository> GetRepositoryList(ConfigSource config)
        {
            var repos = new List <HosterRepository>();

            this.req.SetBaseUrl("https://gitlab.com");
            this.req.AddHeader("Accept", "application/json");

            if (config.IsAuthenticated)
            {
                this.req.AddHeader("Private-Token", config.Password);
            }

            string type = "users";
            string args = string.Empty;

            if (config.Type.ToLower() != "user")
            {
                type = "groups";
                args = "?include_subgroups=true";
            }

            var scm = this.factory.Create(ScmType.Git);

            string url = string.Format("/api/v4/{0}/{1}/projects{2}", type, config.Name, args);

            while (url != null)
            {
                var result = req.Execute(url).Result;
                url = null;
                if (result.IsSuccessStatusCode)
                {
                    var response = JsonConvert.DeserializeObject <List <GitlabApiRepo> >(result.Content);

                    foreach (var apiRepo in response)
                    {
                        string cloneUrl = apiRepo.http_url_to_repo;

                        var repo = new HosterRepository(apiRepo.path_with_namespace, apiRepo.name, cloneUrl, ScmType.Git);

                        repo.SetPrivate(apiRepo.visibility == "private");

                        // wiki: the API only returns if it's enabled, but not if it actually contains pages
                        // The Git repo always exists, even when the wiki has no pages.
                        // So we can't check for the existence of the Git repo -> we need to make another API call to check if it has at least one page
                        if (apiRepo.wiki_enabled && cloneUrl.EndsWith(".git"))
                        {
                            // Rate limit of 10 requests per second per IP address (https://docs.gitlab.com/ee/user/gitlab_com/index.html#gitlabcom-specific-rate-limits)
                            // --> block long enough so that 10 requests will take longer than a second
                            Task.Delay(110).Wait();

                            string wikiUrl    = string.Format("/api/v4/projects/{0}/wikis", apiRepo.id);
                            var    wikiResult = req.Execute(wikiUrl).Result;
                            if (wikiResult.IsSuccessStatusCode)
                            {
                                var wikis = JsonConvert.DeserializeObject <List <GitlabApiWiki> >(wikiResult.Content);
                                if (wikis.Any())
                                {
                                    repo.SetWiki(true, cloneUrl.Substring(0, cloneUrl.Length - ".git".Length) + ".wiki.git");
                                }
                            }
                        }

                        // TODO: Issues
                        // _links -> issues ??
                        // issues_access_level ??

                        repos.Add(repo);
                    }

                    if (result.Headers.Contains("Link"))
                    {
                        // There are multiple links, but all in one header value
                        // https://docs.gitlab.com/ee/api/README.html#pagination-link-header
                        string links = result.Headers.GetValues("Link").First();

                        // The API returns something like this and we need the link named "next":
                        // <https://gitlab.com/api/foo>; rel="next", <https://gitlab.com/api/bar>; rel="first", <https://gitlab.com/api/baz>; rel="last"
                        foreach (var link in links.Split(','))
                        {
                            var items = link.Split(';');
                            if (items[1].Contains("next"))
                            {
                                url = items[0].Trim('<', '>', ' ');
                                break;
                            }
                        }
                    }
                }
                else
                {
                    switch (result.Status)
                    {
                    case HttpStatusCode.Unauthorized:
                        throw new AuthenticationException(string.Format(Resource.ApiAuthenticationFailed, config.AuthName));

                    case HttpStatusCode.Forbidden:
                        throw new SecurityException(Resource.ApiMissingPermissions);

                    case HttpStatusCode.NotFound:
                        throw new InvalidOperationException(string.Format(Resource.ApiInvalidUsername, config.Name));
                    }
                }
            }

            return(repos);
        }
        public List <HosterRepository> GetRepositoryList(ConfigSource source)
        {
            var    list      = new List <HosterRepository>();
            string className = this.GetType().Name;

            request.SetBaseUrl("https://api.bitbucket.org");

            if (source.IsAuthenticated)
            {
                request.AddBasicAuthHeader(source.AuthName, source.Password);
            }

            string url = "/2.0/repositories/" + source.Name;

            while (url != null)
            {
                var result = request.Execute(url).Result;

                if (result.IsSuccessStatusCode)
                {
                    var apiResponse = JsonConvert.DeserializeObject <BitbucketApiResponse>(result.Content);

                    // #60: 2 months after Bitbucket's HG deprecation, their API still returns HG repos but cloning/pulling them fails -> ignore them
                    foreach (var apiRepo in apiResponse.values.Where(x => x.scm.ToLower() != "hg"))
                    {
                        ScmType type;
                        switch (apiRepo.scm.ToLower())
                        {
                        case "git":
                            type = ScmType.Git;
                            break;

                        default:
                            throw new InvalidOperationException(string.Format(Resource.ApiInvalidScmType, apiRepo.full_name));
                        }

                        var    clone    = apiRepo.links.clone.Where(r => r.name == "https").First();
                        string cloneurl = clone.href;

                        var repo = new HosterRepository(apiRepo.full_name, apiRepo.slug, cloneurl, type);

                        repo.SetPrivate(apiRepo.is_private);

                        if (apiRepo.has_wiki)
                        {
                            string wikiUrl = cloneurl + "/wiki";
                            repo.SetWiki(true, wikiUrl.ToString());
                        }

                        // TODO: Issues

                        list.Add(repo);
                    }

                    url = apiResponse.next;
                }
                else
                {
                    switch (result.Status)
                    {
                    case HttpStatusCode.Unauthorized:
                        throw new AuthenticationException(string.Format(Resource.ApiAuthenticationFailed, source.AuthName));

                    case HttpStatusCode.Forbidden:
                        throw new SecurityException(Resource.ApiMissingPermissions);

                    case HttpStatusCode.NotFound:
                        throw new InvalidOperationException(string.Format(Resource.ApiInvalidUsername, source.Name));
                    }
                }
            }

            return(list);
        }
Example #3
0
        public List <HosterRepository> GetRepositoryList(ConfigSource source)
        {
            var    list      = new List <HosterRepository>();
            string className = this.GetType().Name;

            request.SetBaseUrl("https://api.bitbucket.org");

            if (source.IsAuthenticated)
            {
                request.AddBasicAuthHeader(source.AuthName, source.Password);
            }

            string url         = string.Empty;
            string apiUsername = null;

            // Issue #32: from Apr 29 2019, usernames (not team names) must be replaced by UUIDs
            if (source.Type.ToLower() == "user")
            {
                url = "/2.0/users/" + source.Name;

                var result = request.Execute(url).Result;

                if (result.IsSuccessStatusCode)
                {
                    var apiResponse = JsonConvert.DeserializeObject <BitbucketApiUserResponse>(result.Content);
                    if (apiResponse != null)
                    {
                        apiUsername = Uri.EscapeUriString(apiResponse.uuid);
                    }
                }

                if (string.IsNullOrWhiteSpace(apiUsername))
                {
                    throw new InvalidOperationException(string.Format(Resource.ApiBitbucketCantGetUuid, source.Name));
                }
            }
            else
            {
                apiUsername = source.Name;
            }


            url = "/2.0/repositories/" + apiUsername;

            while (url != null)
            {
                var result = request.Execute(url).Result;

                if (result.IsSuccessStatusCode)
                {
                    var apiResponse = JsonConvert.DeserializeObject <BitbucketApiResponse>(result.Content);

                    foreach (var apiRepo in apiResponse.values)
                    {
                        ScmType type;
                        switch (apiRepo.scm.ToLower())
                        {
                        case "hg":
                            type = ScmType.Mercurial;
                            break;

                        case "git":
                            type = ScmType.Git;
                            break;

                        default:
                            throw new InvalidOperationException(string.Format(Resource.ApiInvalidScmType, apiRepo.full_name));
                        }

                        var    clone    = apiRepo.links.clone.Where(r => r.name == "https").First();
                        string cloneurl = clone.href;

                        var repo = new HosterRepository(apiRepo.full_name, apiRepo.slug, cloneurl, type);

                        repo.SetPrivate(apiRepo.is_private);

                        if (apiRepo.has_wiki)
                        {
                            string wikiUrl = cloneurl + "/wiki";
                            repo.SetWiki(true, wikiUrl.ToString());
                        }

                        // TODO: Issues

                        list.Add(repo);
                    }

                    url = apiResponse.next;
                }
                else
                {
                    switch (result.Status)
                    {
                    case HttpStatusCode.Unauthorized:
                        throw new AuthenticationException(string.Format(Resource.ApiAuthenticationFailed, source.AuthName));

                    case HttpStatusCode.Forbidden:
                        throw new SecurityException(Resource.ApiMissingPermissions);

                    case HttpStatusCode.NotFound:
                        throw new InvalidOperationException(string.Format(Resource.ApiInvalidUsername, source.Name));
                    }
                }
            }

            return(list);
        }