cgitize 6.0.5__tar.gz → 8.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cgitize-6.0.5 → cgitize-8.0.0}/.github/workflows/ci.yml +10 -11
- {cgitize-6.0.5 → cgitize-8.0.0}/.github/workflows/maintenance.yml +3 -6
- {cgitize-6.0.5 → cgitize-8.0.0}/.pylintrc +5 -1
- cgitize-8.0.0/.python-version +1 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/DEVELOPMENT.md +3 -3
- {cgitize-6.0.5 → cgitize-8.0.0}/PKG-INFO +1 -1
- {cgitize-6.0.5 → cgitize-8.0.0}/cgitize/bitbucket.py +5 -5
- {cgitize-6.0.5 → cgitize-8.0.0}/cgitize/config.py +25 -19
- {cgitize-6.0.5 → cgitize-8.0.0}/cgitize/github.py +14 -4
- {cgitize-6.0.5 → cgitize-8.0.0}/cgitize/gitlab.py +4 -3
- {cgitize-6.0.5 → cgitize-8.0.0}/cgitize/repo.py +78 -7
- {cgitize-6.0.5 → cgitize-8.0.0}/cgitize/utils.py +9 -5
- {cgitize-6.0.5 → cgitize-8.0.0}/cgitize.egg-info/PKG-INFO +1 -1
- {cgitize-6.0.5 → cgitize-8.0.0}/docker/README.md +2 -2
- {cgitize-6.0.5 → cgitize-8.0.0}/docs/api.md +6 -4
- {cgitize-6.0.5 → cgitize-8.0.0}/docs/auth.md +3 -5
- {cgitize-6.0.5 → cgitize-8.0.0}/examples/cgitize.toml +26 -14
- {cgitize-6.0.5 → cgitize-8.0.0}/requirements.txt +6 -6
- {cgitize-6.0.5 → cgitize-8.0.0}/test/integration/example/test.sh +92 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/test/set_credentials.sh +3 -1
- {cgitize-6.0.5 → cgitize-8.0.0}/test/unit/test_bitbucket.py +20 -1
- {cgitize-6.0.5 → cgitize-8.0.0}/test/unit/test_github.py +2 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/test/unit/test_gitlab.py +2 -0
- cgitize-6.0.5/.python-version +0 -1
- {cgitize-6.0.5 → cgitize-8.0.0}/.dockerignore +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/.gitattributes +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/.github/dependabot.yml +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/.gitignore +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/LICENSE.txt +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/Makefile +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/README.md +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/cgitize/__init__.py +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/cgitize/cgit.py +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/cgitize/git.py +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/cgitize/header.py +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/cgitize/main.py +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/cgitize/version.py +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/cgitize.egg-info/SOURCES.txt +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/cgitize.egg-info/dependency_links.txt +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/cgitize.egg-info/entry_points.txt +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/cgitize.egg-info/requires.txt +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/cgitize.egg-info/top_level.txt +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/docker/Dockerfile +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/docker/cgitize.sh +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/docker/frontend/Dockerfile +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/docker/frontend/cmd.sh +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/docker/frontend/etc/cgit/common +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/docker/frontend/etc/cgitrc +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/docker/frontend/etc/nginx/conf.d/default.conf +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/docker/frontend/usr/lib/cgit/filters/about-formatting.sh +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/docker/frontend/usr/lib/cgit/filters/html-converters/.gitattributes +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/docker/frontend/usr/lib/cgit/filters/html-converters/md2html +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/docker/get_output_dir.py +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/docker/in_cron.sh +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/docker-compose.yml +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/examples/docker/cgitize.toml +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/prelude.mk +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/pyproject.toml +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/setup.cfg +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/test/__init__.py +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/test/integration/docker/.dockerignore +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/test/integration/docker/cgitize/.gitignore +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/test/integration/docker/cgitize/etc/cgitize.toml +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/test/integration/docker/docker-compose.yml +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/test/integration/docker/git_server/Dockerfile +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/test/integration/docker/git_server/setup_repo.sh +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/test/integration/docker/test.sh +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/test/integration/local/test.sh +0 -0
- {cgitize-6.0.5 → cgitize-8.0.0}/test/unit/__init__.py +0 -0
|
@@ -21,19 +21,18 @@ jobs:
|
|
|
21
21
|
uses: psf/black@stable
|
|
22
22
|
|
|
23
23
|
test_local:
|
|
24
|
-
needs: [lint]
|
|
25
24
|
runs-on: ubuntu-latest
|
|
26
25
|
strategy:
|
|
27
26
|
matrix:
|
|
28
27
|
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14']
|
|
29
28
|
name: 'Test / ${{ matrix.python-version }}'
|
|
30
29
|
env:
|
|
31
|
-
CGITIZE_GITHUB_USERNAME:
|
|
30
|
+
CGITIZE_GITHUB_USERNAME: '${{ secrets.CGITIZE_GITHUB_USERNAME }}'
|
|
32
31
|
CGITIZE_GITHUB_TOKEN: '${{ secrets.CGITIZE_GITHUB_TOKEN }}'
|
|
33
|
-
|
|
32
|
+
CGITIZE_BITBUCKET_EMAIL: '${{ secrets.CGITIZE_BITBUCKET_EMAIL }}'
|
|
34
33
|
CGITIZE_BITBUCKET_TOKEN: '${{ secrets.CGITIZE_BITBUCKET_TOKEN }}'
|
|
35
|
-
CGITIZE_GITLAB_USERNAME:
|
|
36
|
-
CGITIZE_GITLAB_TOKEN: '${{ secrets.CGITIZE_GITLAB_TOKEN}}'
|
|
34
|
+
CGITIZE_GITLAB_USERNAME: '${{ secrets.CGITIZE_GITLAB_USERNAME }}'
|
|
35
|
+
CGITIZE_GITLAB_TOKEN: '${{ secrets.CGITIZE_GITLAB_TOKEN }}'
|
|
37
36
|
steps:
|
|
38
37
|
- name: Checkout
|
|
39
38
|
uses: actions/checkout@v6
|
|
@@ -65,12 +64,12 @@ jobs:
|
|
|
65
64
|
runs-on: ubuntu-latest
|
|
66
65
|
name: 'Test / example config'
|
|
67
66
|
env:
|
|
68
|
-
CGITIZE_GITHUB_USERNAME:
|
|
67
|
+
CGITIZE_GITHUB_USERNAME: '${{ secrets.CGITIZE_GITHUB_USERNAME }}'
|
|
69
68
|
CGITIZE_GITHUB_TOKEN: '${{ secrets.CGITIZE_GITHUB_TOKEN }}'
|
|
70
|
-
|
|
69
|
+
CGITIZE_BITBUCKET_EMAIL: '${{ secrets.CGITIZE_BITBUCKET_EMAIL }}'
|
|
71
70
|
CGITIZE_BITBUCKET_TOKEN: '${{ secrets.CGITIZE_BITBUCKET_TOKEN }}'
|
|
72
|
-
CGITIZE_GITLAB_USERNAME:
|
|
73
|
-
CGITIZE_GITLAB_TOKEN: '${{ secrets.CGITIZE_GITLAB_TOKEN}}'
|
|
71
|
+
CGITIZE_GITLAB_USERNAME: '${{ secrets.CGITIZE_GITLAB_USERNAME }}'
|
|
72
|
+
CGITIZE_GITLAB_TOKEN: '${{ secrets.CGITIZE_GITLAB_TOKEN }}'
|
|
74
73
|
steps:
|
|
75
74
|
- name: Checkout
|
|
76
75
|
uses: actions/checkout@v6
|
|
@@ -88,7 +87,7 @@ jobs:
|
|
|
88
87
|
run: make test/example
|
|
89
88
|
|
|
90
89
|
publish_docker:
|
|
91
|
-
needs: [test_local, test_example_config, test_docker]
|
|
90
|
+
needs: [lint, test_local, test_example_config, test_docker]
|
|
92
91
|
runs-on: ubuntu-latest
|
|
93
92
|
strategy:
|
|
94
93
|
matrix:
|
|
@@ -149,7 +148,7 @@ jobs:
|
|
|
149
148
|
tags: '${{ steps.meta.outputs.tags }}'
|
|
150
149
|
|
|
151
150
|
publish_pypi:
|
|
152
|
-
needs: [
|
|
151
|
+
needs: [publish_docker]
|
|
153
152
|
runs-on: ubuntu-latest
|
|
154
153
|
name: 'Publish / PyPI'
|
|
155
154
|
steps:
|
|
@@ -16,8 +16,6 @@ jobs:
|
|
|
16
16
|
with:
|
|
17
17
|
# I think that by default, pushes don't trigger other workflows, and
|
|
18
18
|
# you need a separate token for that: https://github.com/orgs/community/discussions/37103
|
|
19
|
-
#
|
|
20
|
-
# Re-using the Jekyll projects token here BTW:
|
|
21
19
|
token: '${{ secrets.GH_TOKEN }}'
|
|
22
20
|
- name: Set up ssh-agent
|
|
23
21
|
uses: webfactory/ssh-agent@v0.10.0
|
|
@@ -27,11 +25,10 @@ jobs:
|
|
|
27
25
|
uses: actions/setup-python@v6
|
|
28
26
|
with:
|
|
29
27
|
python-version-file: .python-version
|
|
30
|
-
- name:
|
|
31
|
-
id: maintenance
|
|
28
|
+
- name: Configure git
|
|
32
29
|
run: |
|
|
33
30
|
# See https://github.com/actions/checkout#push-a-commit-using-the-built-in-token
|
|
34
31
|
git config user.name "github-actions[bot]"
|
|
35
32
|
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
- name: Run maintenance
|
|
34
|
+
run: make maintenance
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.13.13
|
|
@@ -18,11 +18,11 @@ test.
|
|
|
18
18
|
You need to set the following environment variables for the authenticated
|
|
19
19
|
access tests to work:
|
|
20
20
|
|
|
21
|
-
* `
|
|
21
|
+
* `CGITIZE_BITBUCKET_EMAIL`
|
|
22
22
|
* `CGITIZE_BITBUCKET_TOKEN`
|
|
23
|
-
* `CGITIZE_GITHUB_USERNAME
|
|
23
|
+
* `CGITIZE_GITHUB_USERNAME`
|
|
24
24
|
* `CGITIZE_GITHUB_TOKEN`
|
|
25
|
-
* `CGITIZE_GITLAB_USERNAME
|
|
25
|
+
* `CGITIZE_GITLAB_USERNAME`
|
|
26
26
|
* `CGITIZE_GITLAB_TOKEN`
|
|
27
27
|
|
|
28
28
|
You can run `. test/set_credentials.sh`; it'll ask you to fill in the secrets.
|
|
@@ -8,12 +8,12 @@ import logging
|
|
|
8
8
|
from atlassian.bitbucket.cloud import Cloud
|
|
9
9
|
from requests.exceptions import HTTPError
|
|
10
10
|
|
|
11
|
-
from cgitize.repo import Repo
|
|
11
|
+
from cgitize.repo import Repo, Visibility
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
class Bitbucket:
|
|
15
|
-
def __init__(self,
|
|
16
|
-
self._impl = Cloud(username=
|
|
15
|
+
def __init__(self, email=None, token=None):
|
|
16
|
+
self._impl = Cloud(username=email, password=token, cloud=True)
|
|
17
17
|
|
|
18
18
|
def get_repo(self, repo):
|
|
19
19
|
try:
|
|
@@ -28,10 +28,10 @@ class Bitbucket:
|
|
|
28
28
|
logging.error("Couldn't fetch repository: %s", repo.id)
|
|
29
29
|
raise
|
|
30
30
|
|
|
31
|
-
def get_user_repos(self, user):
|
|
31
|
+
def get_user_repos(self, user, visibility=Visibility.ALL):
|
|
32
32
|
try:
|
|
33
33
|
workspace = self._impl.workspaces.get(user.name)
|
|
34
|
-
yield from workspace.repositories.each()
|
|
34
|
+
yield from workspace.repositories.each(q=visibility.to_bitbucket_arg())
|
|
35
35
|
except HTTPError:
|
|
36
36
|
logging.error("Couldn't fetch user repositories: %s", user.name)
|
|
37
37
|
raise
|
|
@@ -5,13 +5,14 @@
|
|
|
5
5
|
|
|
6
6
|
from abc import ABC, abstractmethod
|
|
7
7
|
import os
|
|
8
|
+
from urllib.parse import quote
|
|
8
9
|
|
|
9
10
|
import tomli
|
|
10
11
|
|
|
11
12
|
from cgitize.bitbucket import Bitbucket
|
|
12
13
|
from cgitize.github import GitHub
|
|
13
14
|
from cgitize.gitlab import GitLab
|
|
14
|
-
from cgitize.repo import Repo
|
|
15
|
+
from cgitize.repo import Repo, Visibility
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
class Section:
|
|
@@ -74,7 +75,8 @@ class ServiceSection(Section, ABC):
|
|
|
74
75
|
yield api.convert_repo(api.get_repo(r), cfg, r.dir)
|
|
75
76
|
|
|
76
77
|
def _enum_user_repositories(self, cfg, api, user):
|
|
77
|
-
|
|
78
|
+
visibility = Visibility.from_config(user.public_repos, user.private_repos)
|
|
79
|
+
for r in api.get_user_repos(user, visibility=visibility):
|
|
78
80
|
r = api.convert_repo(r, cfg, user.dir)
|
|
79
81
|
if r.name in user.skip:
|
|
80
82
|
continue
|
|
@@ -109,7 +111,7 @@ class GitHubSection(ServiceSection):
|
|
|
109
111
|
|
|
110
112
|
@property
|
|
111
113
|
def url_auth(self):
|
|
112
|
-
return self.token
|
|
114
|
+
return (self.token, None)
|
|
113
115
|
|
|
114
116
|
def _enum_org_repositories(self, cfg, api, org):
|
|
115
117
|
for repo in api.get_org_repos(org):
|
|
@@ -134,12 +136,6 @@ class GitHubSection(ServiceSection):
|
|
|
134
136
|
return GitHub(username, token)
|
|
135
137
|
|
|
136
138
|
|
|
137
|
-
def two_part_url_auth(username, password):
|
|
138
|
-
if username is None or password is None:
|
|
139
|
-
return None
|
|
140
|
-
return f'{username}:{password}'
|
|
141
|
-
|
|
142
|
-
|
|
143
139
|
class BitbucketSection(ServiceSection):
|
|
144
140
|
@property
|
|
145
141
|
def token(self):
|
|
@@ -147,11 +143,11 @@ class BitbucketSection(ServiceSection):
|
|
|
147
143
|
|
|
148
144
|
@property
|
|
149
145
|
def username(self):
|
|
150
|
-
return self._get_config_or_env('
|
|
146
|
+
return self._get_config_or_env('email', 'CGITIZE_BITBUCKET_EMAIL')
|
|
151
147
|
|
|
152
148
|
@property
|
|
153
149
|
def url_auth(self):
|
|
154
|
-
return
|
|
150
|
+
return (self.username, self.token)
|
|
155
151
|
|
|
156
152
|
def connect_to_service(self):
|
|
157
153
|
username = self.username
|
|
@@ -174,7 +170,7 @@ class GitLabSection(ServiceSection):
|
|
|
174
170
|
|
|
175
171
|
@property
|
|
176
172
|
def url_auth(self):
|
|
177
|
-
return
|
|
173
|
+
return (self.username, self.token)
|
|
178
174
|
|
|
179
175
|
def connect_to_service(self):
|
|
180
176
|
username = self.username
|
|
@@ -201,12 +197,7 @@ class RepositoriesSection(Section):
|
|
|
201
197
|
return self.impl.values()
|
|
202
198
|
|
|
203
199
|
|
|
204
|
-
class
|
|
205
|
-
def __init__(self, impl):
|
|
206
|
-
if 'name' not in impl:
|
|
207
|
-
raise ValueError("every user must have a 'name'")
|
|
208
|
-
self._impl = impl
|
|
209
|
-
|
|
200
|
+
class Entity(ABC):
|
|
210
201
|
@property
|
|
211
202
|
def name(self):
|
|
212
203
|
return self._impl['name']
|
|
@@ -220,7 +211,22 @@ class User:
|
|
|
220
211
|
return self._impl.get('skip', [])
|
|
221
212
|
|
|
222
213
|
|
|
223
|
-
class
|
|
214
|
+
class User(Entity):
|
|
215
|
+
def __init__(self, impl):
|
|
216
|
+
if 'name' not in impl:
|
|
217
|
+
raise ValueError("every user must have a 'name'")
|
|
218
|
+
self._impl = impl
|
|
219
|
+
|
|
220
|
+
@property
|
|
221
|
+
def public_repos(self):
|
|
222
|
+
return self._impl.get('public', True)
|
|
223
|
+
|
|
224
|
+
@property
|
|
225
|
+
def private_repos(self):
|
|
226
|
+
return self._impl.get('private', False)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
class Org(Entity):
|
|
224
230
|
def __init__(self, impl):
|
|
225
231
|
if 'name' not in impl:
|
|
226
232
|
raise ValueError("every organization must have a 'name'")
|
|
@@ -7,7 +7,7 @@ import logging
|
|
|
7
7
|
|
|
8
8
|
from github import Auth, Github, GithubException
|
|
9
9
|
|
|
10
|
-
from cgitize.repo import Repo
|
|
10
|
+
from cgitize.repo import Repo, Visibility
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class GitHub:
|
|
@@ -25,14 +25,24 @@ class GitHub:
|
|
|
25
25
|
logging.error("Couldn't fetch repository: %s", repo.id)
|
|
26
26
|
raise
|
|
27
27
|
|
|
28
|
-
def get_user_repos(self, user):
|
|
28
|
+
def get_user_repos(self, user, visibility=Visibility.ALL):
|
|
29
|
+
visibility = visibility.to_github_arg()
|
|
30
|
+
|
|
31
|
+
# Not actually certain how it works, but just passing None as the
|
|
32
|
+
# named visibility parameter fails with an internal assert error. I
|
|
33
|
+
# honestly thought that that passing parameters like that and as a
|
|
34
|
+
# None makes no difference.
|
|
35
|
+
kwargs = {}
|
|
36
|
+
if visibility is not None:
|
|
37
|
+
kwargs['visibility'] = visibility
|
|
38
|
+
|
|
29
39
|
try:
|
|
30
40
|
if user.name == self._username:
|
|
31
41
|
# To get private repositories, get_user() must be called
|
|
32
42
|
# without arguments:
|
|
33
|
-
return self._impl.get_user().get_repos(affiliation='owner')
|
|
43
|
+
return self._impl.get_user().get_repos(affiliation='owner', **kwargs)
|
|
34
44
|
else:
|
|
35
|
-
return self._impl.get_user(user.name).get_repos()
|
|
45
|
+
return self._impl.get_user(user.name).get_repos(**kwargs)
|
|
36
46
|
except GithubException:
|
|
37
47
|
logging.error("Couldn't fetch user repositories: %s", user.name)
|
|
38
48
|
raise
|
|
@@ -8,7 +8,7 @@ import logging
|
|
|
8
8
|
from gitlab import Gitlab
|
|
9
9
|
from gitlab.exceptions import GitlabGetError
|
|
10
10
|
|
|
11
|
-
from cgitize.repo import Repo
|
|
11
|
+
from cgitize.repo import Repo, Visibility
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
class GitLab:
|
|
@@ -22,7 +22,8 @@ class GitLab:
|
|
|
22
22
|
logging.error("Couldn't fetch repository: %s", repo.id)
|
|
23
23
|
raise
|
|
24
24
|
|
|
25
|
-
def get_user_repos(self, user):
|
|
25
|
+
def get_user_repos(self, user, visibility=Visibility.ALL):
|
|
26
|
+
visibility = visibility.to_gitlab_arg()
|
|
26
27
|
try:
|
|
27
28
|
# Strictly speaking, GitLab supports the /users/:username/projects
|
|
28
29
|
# endpoint, which means you shouldn't need to fetch the user first,
|
|
@@ -32,7 +33,7 @@ class GitLab:
|
|
|
32
33
|
raise RuntimeError(f"Couldn't find GitLab user: {user.name}")
|
|
33
34
|
assert len(users) == 1
|
|
34
35
|
user = users[0]
|
|
35
|
-
return user.projects.list()
|
|
36
|
+
return user.projects.list(visibility=visibility)
|
|
36
37
|
except GitlabGetError:
|
|
37
38
|
logging.error("Couldn't fetch user repositories: %s", user.name)
|
|
38
39
|
raise
|
|
@@ -3,11 +3,64 @@
|
|
|
3
3
|
# For details, see https://github.com/egor-tensin/cgitize.
|
|
4
4
|
# Distributed under the MIT License.
|
|
5
5
|
|
|
6
|
+
from enum import Enum
|
|
6
7
|
import os.path
|
|
7
8
|
|
|
8
9
|
from cgitize.utils import url_remove_auth, url_replace_auth
|
|
9
10
|
|
|
10
11
|
|
|
12
|
+
class Visibility(Enum):
|
|
13
|
+
ALL = 'all'
|
|
14
|
+
PUBLIC = 'public'
|
|
15
|
+
PRIVATE = 'private'
|
|
16
|
+
|
|
17
|
+
def __str__(self):
|
|
18
|
+
return self.name
|
|
19
|
+
|
|
20
|
+
@staticmethod
|
|
21
|
+
def from_config(public, private):
|
|
22
|
+
if public and private:
|
|
23
|
+
return Visibility.ALL
|
|
24
|
+
if not public and not private:
|
|
25
|
+
raise RuntimeError(
|
|
26
|
+
'you need to fetch either public or private repos, or both'
|
|
27
|
+
)
|
|
28
|
+
if public:
|
|
29
|
+
return Visibility.PUBLIC
|
|
30
|
+
return Visibility.PRIVATE
|
|
31
|
+
|
|
32
|
+
def to_bitbucket_arg(self):
|
|
33
|
+
# https://developer.atlassian.com/cloud/bitbucket/rest/intro/#filtering
|
|
34
|
+
# https://developer.atlassian.com/cloud/bitbucket/rest/api-group-repositories/#api-group-repositories
|
|
35
|
+
if self is Visibility.ALL:
|
|
36
|
+
return None
|
|
37
|
+
if self is Visibility.PUBLIC:
|
|
38
|
+
return 'is_private=False'
|
|
39
|
+
if self is Visibility.PRIVATE:
|
|
40
|
+
return 'is_private=True'
|
|
41
|
+
raise NotImplementedError(f'not implemented visibility level: {self}')
|
|
42
|
+
|
|
43
|
+
def to_github_arg(self):
|
|
44
|
+
# https://docs.github.com/en/rest/repos/repos?apiVersion=2026-03-10#list-repositories-for-the-authenticated-user
|
|
45
|
+
if self is Visibility.ALL:
|
|
46
|
+
return None
|
|
47
|
+
if self is Visibility.PUBLIC:
|
|
48
|
+
return 'public'
|
|
49
|
+
if self is Visibility.PRIVATE:
|
|
50
|
+
return 'private'
|
|
51
|
+
raise NotImplementedError(f'not implemented visibility level: {self}')
|
|
52
|
+
|
|
53
|
+
def to_gitlab_arg(self):
|
|
54
|
+
# https://python-gitlab.readthedocs.io/en/stable/gl_objects/projects.html#projects
|
|
55
|
+
if self is Visibility.ALL:
|
|
56
|
+
return None
|
|
57
|
+
if self is Visibility.PUBLIC:
|
|
58
|
+
return 'public'
|
|
59
|
+
if self is Visibility.PRIVATE:
|
|
60
|
+
return 'private'
|
|
61
|
+
raise NotImplementedError(f'not implemented visibility level: {self}')
|
|
62
|
+
|
|
63
|
+
|
|
11
64
|
class Repo:
|
|
12
65
|
@staticmethod
|
|
13
66
|
def from_config(src, config):
|
|
@@ -34,8 +87,12 @@ class Repo:
|
|
|
34
87
|
|
|
35
88
|
https_url = src.clone_url
|
|
36
89
|
ssh_url = src.ssh_url
|
|
37
|
-
|
|
38
|
-
|
|
90
|
+
|
|
91
|
+
clone_url = ssh_url
|
|
92
|
+
url_auth = None
|
|
93
|
+
if not config.main.clone_via_ssh:
|
|
94
|
+
clone_url = https_url
|
|
95
|
+
url_auth = config.github.url_auth
|
|
39
96
|
|
|
40
97
|
return Repo(
|
|
41
98
|
name,
|
|
@@ -60,7 +117,7 @@ class Repo:
|
|
|
60
117
|
if len(https_urls) != 1:
|
|
61
118
|
raise RuntimeError(f"no https:// clone URL for repository '{name}'?!")
|
|
62
119
|
# Bitbucket leaves the username in the URL... Sigh.
|
|
63
|
-
https_url = url_remove_auth(https_urls[0]['href'])
|
|
120
|
+
api_auth, https_url = url_remove_auth(https_urls[0]['href'])
|
|
64
121
|
|
|
65
122
|
ssh_urls = [
|
|
66
123
|
link for link in src.data['links']['clone'] if link['name'] == 'ssh'
|
|
@@ -69,8 +126,18 @@ class Repo:
|
|
|
69
126
|
raise RuntimeError(f"no ssh:// clone URL for repository '{name}'?!")
|
|
70
127
|
ssh_url = ssh_urls[0]['href']
|
|
71
128
|
|
|
72
|
-
clone_url = ssh_url
|
|
73
|
-
url_auth = None
|
|
129
|
+
clone_url = ssh_url
|
|
130
|
+
url_auth = None
|
|
131
|
+
if not config.main.clone_via_ssh:
|
|
132
|
+
clone_url = https_url
|
|
133
|
+
url_auth = config.bitbucket.url_auth
|
|
134
|
+
# Bitbucket, since deprecating app passwords, now requires that
|
|
135
|
+
# users authenticate with their Atlassian email & API token.
|
|
136
|
+
# Unfortunately (sigh...), if you want to clone a repo via HTTPS,
|
|
137
|
+
# you can't use the very same email + token combo in the URL, you
|
|
138
|
+
# have to use your username (double sigh...). Luckily, for some
|
|
139
|
+
# reason, Bitbucket leaves the relevant username in the API response.
|
|
140
|
+
url_auth = api_auth[0], url_auth[1]
|
|
74
141
|
|
|
75
142
|
return Repo(
|
|
76
143
|
name,
|
|
@@ -91,8 +158,12 @@ class Repo:
|
|
|
91
158
|
|
|
92
159
|
https_url = src.http_url_to_repo
|
|
93
160
|
ssh_url = src.ssh_url_to_repo
|
|
94
|
-
|
|
95
|
-
|
|
161
|
+
|
|
162
|
+
clone_url = ssh_url
|
|
163
|
+
url_auth = None
|
|
164
|
+
if not config.main.clone_via_ssh:
|
|
165
|
+
clone_url = https_url
|
|
166
|
+
url_auth = config.gitlab.url_auth
|
|
96
167
|
|
|
97
168
|
return Repo(
|
|
98
169
|
name,
|
|
@@ -9,7 +9,7 @@ import os
|
|
|
9
9
|
import stat
|
|
10
10
|
import subprocess
|
|
11
11
|
import sys
|
|
12
|
-
from urllib.parse import urlsplit, urlunsplit
|
|
12
|
+
from urllib.parse import quote, urlsplit, urlunsplit
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
@contextmanager
|
|
@@ -97,11 +97,12 @@ def protected_file(path):
|
|
|
97
97
|
os.unlink(path)
|
|
98
98
|
|
|
99
99
|
|
|
100
|
-
def url_replace_auth(url,
|
|
100
|
+
def url_replace_auth(url, auth):
|
|
101
|
+
username, password = auth
|
|
101
102
|
parts = urlsplit(url)
|
|
102
|
-
netloc = username
|
|
103
|
+
netloc = quote(username)
|
|
103
104
|
if password is not None:
|
|
104
|
-
netloc += f':{password}'
|
|
105
|
+
netloc += f':{quote(password)}'
|
|
105
106
|
netloc += f'@{parts.hostname}'
|
|
106
107
|
if parts.port is not None:
|
|
107
108
|
netloc += f':{parts.port}'
|
|
@@ -111,6 +112,9 @@ def url_replace_auth(url, username, password=None):
|
|
|
111
112
|
|
|
112
113
|
def url_remove_auth(url):
|
|
113
114
|
parts = urlsplit(url)
|
|
115
|
+
auth = parts.username, parts.password
|
|
114
116
|
netloc = parts.hostname
|
|
117
|
+
if parts.port is not None:
|
|
118
|
+
netloc += f':{parts.port}'
|
|
115
119
|
parts = parts._replace(netloc=netloc)
|
|
116
|
-
return urlunsplit(parts)
|
|
120
|
+
return auth, urlunsplit(parts)
|
|
@@ -48,13 +48,13 @@ Here's an example docker-compose.yml file:
|
|
|
48
48
|
SCHEDULE: '0 */3 * * *'
|
|
49
49
|
# Set CGITIZE_{GITHUB,BITBUCKET,GITLAB}_{USERNAME,TOKEN} variables
|
|
50
50
|
# here or in the config file.
|
|
51
|
-
image: egortensin/cgitize:
|
|
51
|
+
image: egortensin/cgitize:8
|
|
52
52
|
restart: unless-stopped
|
|
53
53
|
volumes:
|
|
54
54
|
- ./example.toml:/etc/cgitize/cgitize.toml:ro
|
|
55
55
|
- /srv/volumes/cgitize:/mnt/cgitize
|
|
56
56
|
frontend:
|
|
57
|
-
image: egortensin/cgitize-frontend:
|
|
57
|
+
image: egortensin/cgitize-frontend:8
|
|
58
58
|
ports:
|
|
59
59
|
- '127.0.0.1:80:80'
|
|
60
60
|
restart: unless-stopped
|
|
@@ -4,10 +4,9 @@ unfortunately, peculiar in their own way.
|
|
|
4
4
|
Tokens
|
|
5
5
|
------
|
|
6
6
|
|
|
7
|
-
All of the forges support access tokens, of course
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
the token:
|
|
7
|
+
All of the forges support access tokens, of course. They can be used to do
|
|
8
|
+
`git clone https://` with authentication info in the URL. For GitHub, it's
|
|
9
|
+
enough to just specify the token:
|
|
11
10
|
|
|
12
11
|
git clone https://TOKEN@github.com/USER/REPO.git
|
|
13
12
|
|
|
@@ -16,6 +15,9 @@ token in the URL:
|
|
|
16
15
|
|
|
17
16
|
git clone https://USER:TOKEN@bitbucket.org/USER/REPO.git
|
|
18
17
|
|
|
18
|
+
(For Bitbucket, since they deprecated their "app passwords", you need to
|
|
19
|
+
specify not the username, but rather the Atlassian account email.)
|
|
20
|
+
|
|
19
21
|
Terminology
|
|
20
22
|
-----------
|
|
21
23
|
|
|
@@ -22,11 +22,9 @@ When using HTTPS, there're multiple options to access the private repositories.
|
|
|
22
22
|
|
|
23
23
|
2. Use OAuth. I thought this was too complicated to implement quickly.
|
|
24
24
|
|
|
25
|
-
3. Use
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
used by a single app only. They allow to bypass the 2FA also. Let's do
|
|
29
|
-
this!
|
|
25
|
+
3. Use application access tokens. This option is pretty cool. Both GitHub
|
|
26
|
+
and Bitbucket support creating read-only tokens. They allow to bypass the
|
|
27
|
+
2FA also. Let's do this!
|
|
30
28
|
|
|
31
29
|
Passing the access tokens to Git is tricky though. First, simply including
|
|
32
30
|
them in the clone URL would be incredibly stupid, since that URL is going to be
|
|
@@ -7,8 +7,8 @@ output_dir = "/tmp/cgitize"
|
|
|
7
7
|
# repository's directory path.
|
|
8
8
|
clone_url = "https://yourhost.com/git/{repo}"
|
|
9
9
|
|
|
10
|
-
# Clones via SSH by default.
|
|
11
|
-
clone_via_ssh =
|
|
10
|
+
# Clones via SSH by default (instead of Git-over-HTTPS).
|
|
11
|
+
clone_via_ssh = true
|
|
12
12
|
|
|
13
13
|
# Unless this is specified, cgit is going to derive the owner from the
|
|
14
14
|
# repository's directory ownership.
|
|
@@ -19,8 +19,10 @@ owner = "Your Name"
|
|
|
19
19
|
|
|
20
20
|
[github]
|
|
21
21
|
# If some of the repositories hosted on GitHub are private (or if you hit the
|
|
22
|
-
# request rate limit), use
|
|
23
|
-
# CGITIZE_GITHUB_TOKEN environment variable.
|
|
22
|
+
# request rate limit), use a personal access token. Set in the config or using
|
|
23
|
+
# the CGITIZE_GITHUB_TOKEN environment variable.
|
|
24
|
+
# Required scopes:
|
|
25
|
+
# * repo
|
|
24
26
|
#token = "XXX"
|
|
25
27
|
# Set the username that owns the token here or using the environment variable
|
|
26
28
|
# CGITIZE_GITHUB_USERNAME.
|
|
@@ -34,6 +36,10 @@ dir = "github-dir"
|
|
|
34
36
|
# Repositories to skip:
|
|
35
37
|
skip = ["repo1", "repo2"]
|
|
36
38
|
|
|
39
|
+
# The defaults.
|
|
40
|
+
public = true
|
|
41
|
+
private = false
|
|
42
|
+
|
|
37
43
|
[github.organizations.goauthentik]
|
|
38
44
|
# For GitHub, you can also specify organizations. The settings are similar to
|
|
39
45
|
# those for users. "goauthentik" is a random organization.
|
|
@@ -52,20 +58,23 @@ dir = "python"
|
|
|
52
58
|
# Bitbucket
|
|
53
59
|
# =========
|
|
54
60
|
|
|
55
|
-
# Bitbucket settings are similar to those for GitHub.
|
|
56
|
-
|
|
57
61
|
[bitbucket]
|
|
58
|
-
#
|
|
59
|
-
#
|
|
62
|
+
# Atlassian API token (environment variable CGITIZE_BITBUCKET_TOKEN).
|
|
63
|
+
# Required scopes:
|
|
64
|
+
# * read:workspace:bitbucket
|
|
65
|
+
# * read:repository:bitbucket
|
|
60
66
|
#token = "XXX"
|
|
61
|
-
#
|
|
62
|
-
#
|
|
67
|
+
# Atlassian account email address (environment variable CGITIZE_BITBUCKET_EMAIL).
|
|
68
|
+
#email = "your-email"
|
|
63
69
|
|
|
64
70
|
[bitbucket.users.me]
|
|
65
71
|
name = "cgitize-test-workspace"
|
|
66
72
|
dir = "bitbucket-dir"
|
|
67
73
|
#skip = ["repo1", "repo2"]
|
|
68
74
|
|
|
75
|
+
public = true
|
|
76
|
+
private = false
|
|
77
|
+
|
|
69
78
|
# Some random repositories hosted on Bitbucket:
|
|
70
79
|
[bitbucket.repositories.cef]
|
|
71
80
|
id = "chromiumembedded/cef"
|
|
@@ -76,12 +85,12 @@ id = "berkeleylab/upc-runtime"
|
|
|
76
85
|
# GitLab
|
|
77
86
|
# ======
|
|
78
87
|
|
|
79
|
-
# GitLab settings are similar to those for GitHub.
|
|
80
|
-
|
|
81
88
|
[gitlab]
|
|
82
|
-
#
|
|
89
|
+
# Personal access token (environment variable CGITIZE_GITLAB_TOKEN).
|
|
90
|
+
# Required scopes (for legacy tokens):
|
|
91
|
+
# * read_api
|
|
83
92
|
#token = "XXX"
|
|
84
|
-
#
|
|
93
|
+
# Gitlab username (environment variable CGITIZE_GITLAB_USERNAME).
|
|
85
94
|
#username = "your-username"
|
|
86
95
|
|
|
87
96
|
[gitlab.users.me]
|
|
@@ -89,6 +98,9 @@ name = "cgitize-test"
|
|
|
89
98
|
dir = "gitlab-dir"
|
|
90
99
|
#skip = ["repo1", "repo2"]
|
|
91
100
|
|
|
101
|
+
public = true
|
|
102
|
+
private = false
|
|
103
|
+
|
|
92
104
|
# Some random repositories hosted on Gitlab:
|
|
93
105
|
[gitlab.repositories.gitter]
|
|
94
106
|
id = "gitterHQ/webapp"
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
atlassian-python-api==4.0.7
|
|
2
|
-
beautifulsoup4==4.
|
|
3
|
-
certifi==2026.
|
|
2
|
+
beautifulsoup4==4.15.0
|
|
3
|
+
certifi==2026.5.20
|
|
4
4
|
cffi==2.0.0
|
|
5
5
|
charset-normalizer==3.4.7
|
|
6
6
|
cryptography==48.0.0
|
|
7
7
|
Deprecated==1.3.1
|
|
8
|
-
idna==3.
|
|
8
|
+
idna==3.18
|
|
9
9
|
jmespath==1.1.0
|
|
10
10
|
oauthlib==3.3.1
|
|
11
11
|
pycparser==3.0
|
|
12
12
|
PyGithub==2.9.1
|
|
13
|
-
PyJWT==2.
|
|
13
|
+
PyJWT==2.13.0
|
|
14
14
|
PyNaCl==1.6.2
|
|
15
15
|
python-gitlab==6.5.0
|
|
16
16
|
requests==2.34.2
|
|
17
17
|
requests-oauthlib==2.0.0
|
|
18
18
|
requests-toolbelt==1.0.0
|
|
19
|
-
soupsieve==2.8.
|
|
19
|
+
soupsieve==2.8.4
|
|
20
20
|
tomli==2.4.1
|
|
21
21
|
typing_extensions==4.15.0
|
|
22
22
|
urllib3==2.7.0
|
|
23
|
-
wrapt==2.1
|
|
23
|
+
wrapt==2.2.1
|
|
@@ -25,6 +25,14 @@ clone_via_ssh_false() {
|
|
|
25
25
|
sed -i -E -e 's/^clone_via_ssh = (true|false)$/clone_via_ssh = false/' -- "$cgitize_toml_path"
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
private_repos_true() {
|
|
29
|
+
sed -i -E -e 's/^private = (true|false)$/private = true/' -- "$cgitize_toml_path"
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
private_repos_false() {
|
|
33
|
+
sed -i -E -e 's/^private = (true|false)$/private = false/' -- "$cgitize_toml_path"
|
|
34
|
+
}
|
|
35
|
+
|
|
28
36
|
cleanup() {
|
|
29
37
|
echo
|
|
30
38
|
echo ----------------------------------------------------------------------
|
|
@@ -35,6 +43,8 @@ cleanup() {
|
|
|
35
43
|
rm -rf -- "$output_dir"
|
|
36
44
|
echo "Reverting clone_via_ssh settings: $cgitize_toml_path"
|
|
37
45
|
clone_via_ssh_false
|
|
46
|
+
echo "Reverting repository visibility settings: $cgitize_toml_path"
|
|
47
|
+
private_repos_false
|
|
38
48
|
}
|
|
39
49
|
|
|
40
50
|
cgitize() {
|
|
@@ -54,6 +64,10 @@ setup_https() {
|
|
|
54
64
|
clone_via_ssh_false
|
|
55
65
|
}
|
|
56
66
|
|
|
67
|
+
setup_private_repos() {
|
|
68
|
+
private_repos_true
|
|
69
|
+
}
|
|
70
|
+
|
|
57
71
|
verify_origin() {
|
|
58
72
|
if [ "$#" -ne 2 ]; then
|
|
59
73
|
echo "usage: ${FUNCNAME[0]} REPO URL" >&2
|
|
@@ -129,6 +143,44 @@ test_ssh() {
|
|
|
129
143
|
setup_ssh
|
|
130
144
|
cgitize
|
|
131
145
|
|
|
146
|
+
verify_repos \
|
|
147
|
+
lens \
|
|
148
|
+
chromiumembedded/cef \
|
|
149
|
+
graphviz \
|
|
150
|
+
wireguard/wintun \
|
|
151
|
+
goauthentik-dir/authentik \
|
|
152
|
+
github-dir/public \
|
|
153
|
+
bitbucket-dir/public \
|
|
154
|
+
gitlab-dir/public
|
|
155
|
+
|
|
156
|
+
verify_no_repos \
|
|
157
|
+
github-dir/private \
|
|
158
|
+
bitbucket-dir/private \
|
|
159
|
+
gitlab-dir/private
|
|
160
|
+
|
|
161
|
+
verify_origin lens 'git@github.com:ekmett/lens.git'
|
|
162
|
+
verify_origin chromiumembedded/cef 'git@bitbucket.org:chromiumembedded/cef.git'
|
|
163
|
+
verify_origin graphviz 'git@gitlab.com:graphviz/graphviz.git'
|
|
164
|
+
verify_origin goauthentik-dir/authentik 'git@github.com:goauthentik/authentik.git'
|
|
165
|
+
|
|
166
|
+
verify_origin github-dir/public 'git@github.com:cgitize-test/public.git'
|
|
167
|
+
verify_origin bitbucket-dir/public 'git@bitbucket.org:cgitize-test-workspace/public.git'
|
|
168
|
+
verify_origin gitlab-dir/public 'git@gitlab.com:cgitize-test/public.git'
|
|
169
|
+
|
|
170
|
+
cleanup
|
|
171
|
+
success
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
test_ssh_private() {
|
|
175
|
+
echo
|
|
176
|
+
echo ======================================================================
|
|
177
|
+
echo "${FUNCNAME[0]}"
|
|
178
|
+
echo ======================================================================
|
|
179
|
+
|
|
180
|
+
setup_ssh
|
|
181
|
+
setup_private_repos
|
|
182
|
+
cgitize
|
|
183
|
+
|
|
132
184
|
verify_repos \
|
|
133
185
|
lens \
|
|
134
186
|
chromiumembedded/cef \
|
|
@@ -167,6 +219,44 @@ test_https() {
|
|
|
167
219
|
setup_https
|
|
168
220
|
cgitize
|
|
169
221
|
|
|
222
|
+
verify_repos \
|
|
223
|
+
lens \
|
|
224
|
+
chromiumembedded/cef \
|
|
225
|
+
graphviz \
|
|
226
|
+
wireguard/wintun \
|
|
227
|
+
goauthentik-dir/authentik \
|
|
228
|
+
github-dir/public \
|
|
229
|
+
bitbucket-dir/public \
|
|
230
|
+
gitlab-dir/public
|
|
231
|
+
|
|
232
|
+
verify_no_repos \
|
|
233
|
+
github-dir/private \
|
|
234
|
+
bitbucket-dir/private \
|
|
235
|
+
gitlab-dir/private
|
|
236
|
+
|
|
237
|
+
verify_origin lens 'https://github.com/ekmett/lens.git'
|
|
238
|
+
verify_origin chromiumembedded/cef 'https://bitbucket.org/chromiumembedded/cef.git'
|
|
239
|
+
verify_origin graphviz 'https://gitlab.com/graphviz/graphviz.git'
|
|
240
|
+
verify_origin goauthentik-dir/authentik 'https://github.com/goauthentik/authentik.git'
|
|
241
|
+
|
|
242
|
+
verify_origin github-dir/public 'https://github.com/cgitize-test/public.git'
|
|
243
|
+
verify_origin bitbucket-dir/public 'https://bitbucket.org/cgitize-test-workspace/public.git'
|
|
244
|
+
verify_origin gitlab-dir/public 'https://gitlab.com/cgitize-test/public.git'
|
|
245
|
+
|
|
246
|
+
cleanup
|
|
247
|
+
success
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
test_https_private() {
|
|
251
|
+
echo
|
|
252
|
+
echo ======================================================================
|
|
253
|
+
echo "${FUNCNAME[0]}"
|
|
254
|
+
echo ======================================================================
|
|
255
|
+
|
|
256
|
+
setup_https
|
|
257
|
+
setup_private_repos
|
|
258
|
+
cgitize
|
|
259
|
+
|
|
170
260
|
verify_repos \
|
|
171
261
|
lens \
|
|
172
262
|
chromiumembedded/cef \
|
|
@@ -213,7 +303,9 @@ test_one_repo() {
|
|
|
213
303
|
main() {
|
|
214
304
|
trap cleanup EXIT
|
|
215
305
|
test_ssh
|
|
306
|
+
test_ssh_private
|
|
216
307
|
test_https
|
|
308
|
+
test_https_private
|
|
217
309
|
test_one_repo
|
|
218
310
|
}
|
|
219
311
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
IFS= read -r -s -p 'Bitbucket email: ' CGITIZE_BITBUCKET_EMAIL
|
|
2
|
+
echo
|
|
1
3
|
IFS= read -r -s -p 'Bitbucket token: ' CGITIZE_BITBUCKET_TOKEN
|
|
2
4
|
echo
|
|
3
5
|
IFS= read -r -s -p 'GitHub token: ' CGITIZE_GITHUB_TOKEN
|
|
@@ -5,7 +7,7 @@ echo
|
|
|
5
7
|
IFS= read -r -s -p 'GitLab token: ' CGITIZE_GITLAB_TOKEN
|
|
6
8
|
echo
|
|
7
9
|
|
|
8
|
-
export
|
|
10
|
+
export CGITIZE_BITBUCKET_EMAIL
|
|
9
11
|
export CGITIZE_BITBUCKET_TOKEN
|
|
10
12
|
export CGITIZE_GITHUB_USERNAME=cgitize-test
|
|
11
13
|
export CGITIZE_GITHUB_TOKEN
|
|
@@ -13,7 +13,7 @@ from requests.exceptions import HTTPError
|
|
|
13
13
|
class BitbucketTests(unittest.TestCase):
|
|
14
14
|
def setUp(self):
|
|
15
15
|
self.bitbucket = Cloud(
|
|
16
|
-
username=os.environ.get('
|
|
16
|
+
username=os.environ.get('CGITIZE_BITBUCKET_EMAIL'),
|
|
17
17
|
password=os.environ.get('CGITIZE_BITBUCKET_TOKEN'),
|
|
18
18
|
cloud=True,
|
|
19
19
|
)
|
|
@@ -30,6 +30,8 @@ class BitbucketTests(unittest.TestCase):
|
|
|
30
30
|
self.assertEqual(r.data['workspace']['name'], 'Test cgitize workspace')
|
|
31
31
|
self.assertEqual(r.data['workspace']['slug'], 'cgitize-test-workspace')
|
|
32
32
|
|
|
33
|
+
self.assertFalse(r.data['is_private'])
|
|
34
|
+
|
|
33
35
|
self.assertEqual(
|
|
34
36
|
r.get_link('html'), 'https://bitbucket.org/cgitize-test-workspace/public'
|
|
35
37
|
)
|
|
@@ -57,10 +59,27 @@ class BitbucketTests(unittest.TestCase):
|
|
|
57
59
|
self.assertEqual(r.data['workspace']['name'], 'Test cgitize workspace')
|
|
58
60
|
self.assertEqual(r.data['workspace']['slug'], 'cgitize-test-workspace')
|
|
59
61
|
|
|
62
|
+
self.assertTrue(r.data['is_private'])
|
|
63
|
+
|
|
60
64
|
self.assertEqual(
|
|
61
65
|
r.get_link('html'), 'https://bitbucket.org/cgitize-test-workspace/private'
|
|
62
66
|
)
|
|
63
67
|
|
|
68
|
+
clone_urls = [
|
|
69
|
+
link for link in r.data['links']['clone'] if link['name'] == 'https'
|
|
70
|
+
]
|
|
71
|
+
self.assertEqual(len(clone_urls), 1)
|
|
72
|
+
self.assertEqual(
|
|
73
|
+
clone_urls[0]['href'],
|
|
74
|
+
'https://cgitize-test@bitbucket.org/cgitize-test-workspace/private.git',
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
ssh_urls = [link for link in r.data['links']['clone'] if link['name'] == 'ssh']
|
|
78
|
+
self.assertEqual(len(ssh_urls), 1)
|
|
79
|
+
self.assertEqual(
|
|
80
|
+
ssh_urls[0]['href'], 'git@bitbucket.org:cgitize-test-workspace/private.git'
|
|
81
|
+
)
|
|
82
|
+
|
|
64
83
|
def test_user(self):
|
|
65
84
|
w = self.bitbucket.workspaces.get('cgitize-test-workspace')
|
|
66
85
|
self.assertEqual(
|
|
@@ -23,6 +23,7 @@ class GitHubTests(unittest.TestCase):
|
|
|
23
23
|
self.assertEqual(r.description, 'Public test cgitize repository')
|
|
24
24
|
self.assertEqual(r.owner.name, 'Test cgitize user')
|
|
25
25
|
self.assertEqual(r.owner.login, 'cgitize-test')
|
|
26
|
+
self.assertEqual(r.visibility, 'public')
|
|
26
27
|
self.assertEqual(r.html_url, 'https://github.com/cgitize-test/public')
|
|
27
28
|
self.assertEqual(r.clone_url, 'https://github.com/cgitize-test/public.git')
|
|
28
29
|
self.assertEqual(r.ssh_url, 'git@github.com:cgitize-test/public.git')
|
|
@@ -33,6 +34,7 @@ class GitHubTests(unittest.TestCase):
|
|
|
33
34
|
self.assertEqual(r.description, 'Private test cgitize repository')
|
|
34
35
|
self.assertEqual(r.owner.name, 'Test cgitize user')
|
|
35
36
|
self.assertEqual(r.owner.login, 'cgitize-test')
|
|
37
|
+
self.assertEqual(r.visibility, 'private')
|
|
36
38
|
self.assertEqual(r.html_url, 'https://github.com/cgitize-test/private')
|
|
37
39
|
self.assertEqual(r.clone_url, 'https://github.com/cgitize-test/private.git')
|
|
38
40
|
self.assertEqual(r.ssh_url, 'git@github.com:cgitize-test/private.git')
|
|
@@ -26,6 +26,7 @@ class GitLabTests(unittest.TestCase):
|
|
|
26
26
|
self.assertEqual(r.description, 'Public test cgitize repository')
|
|
27
27
|
self.assertEqual(r.namespace['name'], 'Test cgitize user')
|
|
28
28
|
self.assertEqual(r.namespace['path'], 'cgitize-test')
|
|
29
|
+
self.assertEqual(r.visibility, 'public')
|
|
29
30
|
self.assertEqual(r.web_url, 'https://gitlab.com/cgitize-test/public')
|
|
30
31
|
self.assertEqual(
|
|
31
32
|
r.http_url_to_repo, 'https://gitlab.com/cgitize-test/public.git'
|
|
@@ -38,6 +39,7 @@ class GitLabTests(unittest.TestCase):
|
|
|
38
39
|
self.assertEqual(r.description, 'Private test cgitize repository')
|
|
39
40
|
self.assertEqual(r.namespace['name'], 'Test cgitize user')
|
|
40
41
|
self.assertEqual(r.namespace['path'], 'cgitize-test')
|
|
42
|
+
self.assertEqual(r.visibility, 'private')
|
|
41
43
|
self.assertEqual(r.web_url, 'https://gitlab.com/cgitize-test/private')
|
|
42
44
|
self.assertEqual(
|
|
43
45
|
r.http_url_to_repo, 'https://gitlab.com/cgitize-test/private.git'
|
cgitize-6.0.5/.python-version
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
3.10.10
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cgitize-6.0.5 → cgitize-8.0.0}/docker/frontend/usr/lib/cgit/filters/html-converters/.gitattributes
RENAMED
|
File without changes
|
{cgitize-6.0.5 → cgitize-8.0.0}/docker/frontend/usr/lib/cgit/filters/html-converters/md2html
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|