summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--cgitize/bitbucket.py6
-rw-r--r--cgitize/config.py29
-rw-r--r--cgitize/github.py11
-rw-r--r--cgitize/gitlab.py7
-rw-r--r--cgitize/repo.py53
-rw-r--r--examples/cgitize.toml12
-rwxr-xr-xtest/integration/example/test.sh59
7 files changed, 152 insertions, 25 deletions
diff --git a/cgitize/bitbucket.py b/cgitize/bitbucket.py
index f3cc4d4..851c4b2 100644
--- a/cgitize/bitbucket.py
+++ b/cgitize/bitbucket.py
@@ -8,7 +8,7 @@ import logging
from atlassian.bitbucket.cloud import Cloud
from requests.exceptions import HTTPError
-from cgitize.repo import Repo
+from cgitize.repo import Repo, Visibility
class Bitbucket:
@@ -28,10 +28,10 @@ class Bitbucket:
logging.error("Couldn't fetch repository: %s", repo.id)
raise
- def get_user_repos(self, user):
+ def get_user_repos(self, user, visibility=Visibility.ALL):
try:
workspace = self._impl.workspaces.get(user.name)
- yield from workspace.repositories.each()
+ yield from workspace.repositories.each(q=visibility.to_bitbucket_arg())
except HTTPError:
logging.error("Couldn't fetch user repositories: %s", user.name)
raise
diff --git a/cgitize/config.py b/cgitize/config.py
index 0e5fe6e..7afe9e5 100644
--- a/cgitize/config.py
+++ b/cgitize/config.py
@@ -11,7 +11,7 @@ import tomli
from cgitize.bitbucket import Bitbucket
from cgitize.github import GitHub
from cgitize.gitlab import GitLab
-from cgitize.repo import Repo
+from cgitize.repo import Repo, Visibility
class Section:
@@ -74,7 +74,8 @@ class ServiceSection(Section, ABC):
yield api.convert_repo(api.get_repo(r), cfg, r.dir)
def _enum_user_repositories(self, cfg, api, user):
- for r in api.get_user_repos(user):
+ visibility = Visibility.from_config(user.public_repos, user.private_repos)
+ for r in api.get_user_repos(user, visibility=visibility):
r = api.convert_repo(r, cfg, user.dir)
if r.name in user.skip:
continue
@@ -201,12 +202,7 @@ class RepositoriesSection(Section):
return self.impl.values()
-class User:
- def __init__(self, impl):
- if 'name' not in impl:
- raise ValueError("every user must have a 'name'")
- self._impl = impl
-
+class Entity(ABC):
@property
def name(self):
return self._impl['name']
@@ -220,7 +216,22 @@ class User:
return self._impl.get('skip', [])
-class Org(User):
+class User(Entity):
+ def __init__(self, impl):
+ if 'name' not in impl:
+ raise ValueError("every user must have a 'name'")
+ self._impl = impl
+
+ @property
+ def public_repos(self):
+ return self._impl.get('public', True)
+
+ @property
+ def private_repos(self):
+ return self._impl.get('private', False)
+
+
+class Org(Entity):
def __init__(self, impl):
if 'name' not in impl:
raise ValueError("every organization must have a 'name'")
diff --git a/cgitize/github.py b/cgitize/github.py
index affa0b6..666451f 100644
--- a/cgitize/github.py
+++ b/cgitize/github.py
@@ -7,7 +7,7 @@ import logging
from github import Auth, Github, GithubException
-from cgitize.repo import Repo
+from cgitize.repo import Repo, Visibility
class GitHub:
@@ -25,14 +25,17 @@ class GitHub:
logging.error("Couldn't fetch repository: %s", repo.id)
raise
- def get_user_repos(self, user):
+ def get_user_repos(self, user, visibility=Visibility.ALL):
+ visibility = visibility.to_github_arg()
try:
if user.name == self._username:
# To get private repositories, get_user() must be called
# without arguments:
- return self._impl.get_user().get_repos(affiliation='owner')
+ return self._impl.get_user().get_repos(
+ affiliation='owner', visibility=visibility
+ )
else:
- return self._impl.get_user(user.name).get_repos()
+ return self._impl.get_user(user.name).get_repos(visibility=visibility)
except GithubException:
logging.error("Couldn't fetch user repositories: %s", user.name)
raise
diff --git a/cgitize/gitlab.py b/cgitize/gitlab.py
index 7fb84e7..01a4310 100644
--- a/cgitize/gitlab.py
+++ b/cgitize/gitlab.py
@@ -8,7 +8,7 @@ import logging
from gitlab import Gitlab
from gitlab.exceptions import GitlabGetError
-from cgitize.repo import Repo
+from cgitize.repo import Repo, Visibility
class GitLab:
@@ -22,7 +22,8 @@ class GitLab:
logging.error("Couldn't fetch repository: %s", repo.id)
raise
- def get_user_repos(self, user):
+ def get_user_repos(self, user, visibility=Visibility.ALL):
+ visibility = visibility.to_gitlab_arg()
try:
# Strictly speaking, GitLab supports the /users/:username/projects
# endpoint, which means you shouldn't need to fetch the user first,
@@ -32,7 +33,7 @@ class GitLab:
raise RuntimeError(f"Couldn't find GitLab user: {user.name}")
assert len(users) == 1
user = users[0]
- return user.projects.list()
+ return user.projects.list(visibility=visibility)
except GitlabGetError:
logging.error("Couldn't fetch user repositories: %s", user.name)
raise
diff --git a/cgitize/repo.py b/cgitize/repo.py
index cabc7ba..b3e5ab3 100644
--- a/cgitize/repo.py
+++ b/cgitize/repo.py
@@ -3,11 +3,64 @@
# For details, see https://github.com/egor-tensin/cgitize.
# Distributed under the MIT License.
+from enum import Enum
import os.path
from cgitize.utils import url_remove_auth, url_replace_auth
+class Visibility(Enum):
+ ALL = 'all'
+ PUBLIC = 'public'
+ PRIVATE = 'private'
+
+ def __str__(self):
+ return self.name
+
+ @staticmethod
+ def from_config(public, private):
+ if public and private:
+ return Visibility.ALL
+ if not public and not private:
+ raise RuntimeError(
+ 'you need to fetch either public or private repos, or both'
+ )
+ if public:
+ return Visibility.PUBLIC
+ return Visibility.PRIVATE
+
+ def to_bitbucket_arg(self):
+ # https://developer.atlassian.com/cloud/bitbucket/rest/intro/#filtering
+ # https://developer.atlassian.com/cloud/bitbucket/rest/api-group-repositories/#api-group-repositories
+ if self is Visibility.ALL:
+ return None
+ if self is Visibility.PUBLIC:
+ return 'is_private=False'
+ if self is Visibility.PRIVATE:
+ return 'is_private=True'
+ raise NotImplementedError(f'not implemented visibility level: {self}')
+
+ def to_github_arg(self):
+ # https://docs.github.com/en/rest/repos/repos?apiVersion=2026-03-10#list-repositories-for-the-authenticated-user
+ if self is Visibility.ALL:
+ return None
+ if self is Visibility.PUBLIC:
+ return 'public'
+ if self is Visibility.PRIVATE:
+ return 'private'
+ raise NotImplementedError(f'not implemented visibility level: {self}')
+
+ def to_gitlab_arg(self):
+ # https://python-gitlab.readthedocs.io/en/stable/gl_objects/projects.html#projects
+ if self is Visibility.ALL:
+ return None
+ if self is Visibility.PUBLIC:
+ return 'public'
+ if self is Visibility.PRIVATE:
+ return 'private'
+ raise NotImplementedError(f'not implemented visibility level: {self}')
+
+
class Repo:
@staticmethod
def from_config(src, config):
diff --git a/examples/cgitize.toml b/examples/cgitize.toml
index 059e8ec..72bb135 100644
--- a/examples/cgitize.toml
+++ b/examples/cgitize.toml
@@ -34,6 +34,10 @@ dir = "github-dir"
# Repositories to skip:
skip = ["repo1", "repo2"]
+# The defaults.
+public = true
+private = false
+
[github.organizations.goauthentik]
# For GitHub, you can also specify organizations. The settings are similar to
# those for users. "goauthentik" is a random organization.
@@ -66,6 +70,10 @@ name = "cgitize-test-workspace"
dir = "bitbucket-dir"
#skip = ["repo1", "repo2"]
+# The defaults.
+public = true
+private = false
+
# Some random repositories hosted on Bitbucket:
[bitbucket.repositories.cef]
id = "chromiumembedded/cef"
@@ -89,6 +97,10 @@ name = "cgitize-test"
dir = "gitlab-dir"
#skip = ["repo1", "repo2"]
+# The defaults.
+public = true
+private = false
+
# Some random repositories hosted on Gitlab:
[gitlab.repositories.gitter]
id = "gitterHQ/webapp"
diff --git a/test/integration/example/test.sh b/test/integration/example/test.sh
index 7568936..0c4b12b 100755
--- a/test/integration/example/test.sh
+++ b/test/integration/example/test.sh
@@ -25,6 +25,14 @@ clone_via_ssh_false() {
sed -i -E -e 's/^clone_via_ssh = (true|false)$/clone_via_ssh = false/' -- "$cgitize_toml_path"
}
+private_repos_true() {
+ sed -i -E -e 's/^private = (true|false)$/private = true/' -- "$cgitize_toml_path"
+}
+
+private_repos_false() {
+ sed -i -E -e 's/^private = (true|false)$/private = false/' -- "$cgitize_toml_path"
+}
+
cleanup() {
echo
echo ----------------------------------------------------------------------
@@ -35,6 +43,8 @@ cleanup() {
rm -rf -- "$output_dir"
echo "Reverting clone_via_ssh settings: $cgitize_toml_path"
clone_via_ssh_false
+ echo "Reverting repository visibility settings: $cgitize_toml_path"
+ private_repos_false
}
cgitize() {
@@ -54,6 +64,10 @@ setup_https() {
clone_via_ssh_false
}
+setup_private_repos() {
+ private_repos_true
+}
+
verify_origin() {
if [ "$#" -ne 2 ]; then
echo "usage: ${FUNCNAME[0]} REPO URL" >&2
@@ -136,11 +150,8 @@ test_ssh() {
wireguard/wintun \
goauthentik-dir/authentik \
github-dir/public \
- github-dir/private \
bitbucket-dir/public \
- bitbucket-dir/private \
gitlab-dir/public \
- gitlab-dir/private
verify_origin lens 'git@github.com:ekmett/lens.git'
verify_origin chromiumembedded/cef 'git@bitbucket.org:chromiumembedded/cef.git'
@@ -148,11 +159,8 @@ test_ssh() {
verify_origin goauthentik-dir/authentik 'git@github.com:goauthentik/authentik.git'
verify_origin github-dir/public 'git@github.com:cgitize-test/public.git'
- verify_origin github-dir/private 'git@github.com:cgitize-test/private.git'
verify_origin bitbucket-dir/public 'git@bitbucket.org:cgitize-test-workspace/public.git'
- verify_origin bitbucket-dir/private 'git@bitbucket.org:cgitize-test-workspace/private.git'
verify_origin gitlab-dir/public 'git@gitlab.com:cgitize-test/public.git'
- verify_origin gitlab-dir/private 'git@gitlab.com:cgitize-test/private.git'
cleanup
success
@@ -174,6 +182,44 @@ test_https() {
wireguard/wintun \
goauthentik-dir/authentik \
github-dir/public \
+ bitbucket-dir/public \
+ gitlab-dir/public
+
+ verify_no_repos \
+ github-dir/private \
+ bitbucket-dir/private \
+ gitlab-dir/private
+
+ verify_origin lens 'https://github.com/ekmett/lens.git'
+ verify_origin chromiumembedded/cef 'https://bitbucket.org/chromiumembedded/cef.git'
+ verify_origin graphviz 'https://gitlab.com/graphviz/graphviz.git'
+ verify_origin goauthentik-dir/authentik 'https://github.com/goauthentik/authentik.git'
+
+ verify_origin github-dir/public 'https://github.com/cgitize-test/public.git'
+ verify_origin bitbucket-dir/public 'https://bitbucket.org/cgitize-test-workspace/public.git'
+ verify_origin gitlab-dir/public 'https://gitlab.com/cgitize-test/public.git'
+
+ cleanup
+ success
+}
+
+test_https_private() {
+ echo
+ echo ======================================================================
+ echo "${FUNCNAME[0]}"
+ echo ======================================================================
+
+ setup_https
+ setup_private_repos
+ cgitize
+
+ verify_repos \
+ lens \
+ chromiumembedded/cef \
+ graphviz \
+ wireguard/wintun \
+ goauthentik-dir/authentik \
+ github-dir/public \
github-dir/private \
bitbucket-dir/public \
bitbucket-dir/private \
@@ -214,6 +260,7 @@ main() {
trap cleanup EXIT
test_ssh
test_https
+ test_https_private
test_one_repo
}