cgitize 8.0.5__tar.gz → 9.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.
Files changed (77) hide show
  1. {cgitize-8.0.5 → cgitize-9.0.0}/.github/workflows/ci.yml +15 -4
  2. cgitize-9.0.0/CHANGELOG.md +64 -0
  3. {cgitize-8.0.5 → cgitize-9.0.0}/DEVELOPMENT.md +3 -2
  4. {cgitize-8.0.5 → cgitize-9.0.0}/PKG-INFO +2 -2
  5. {cgitize-8.0.5 → cgitize-9.0.0}/cgitize/cgit.py +1 -1
  6. {cgitize-8.0.5 → cgitize-9.0.0}/cgitize/repo.py +32 -29
  7. {cgitize-8.0.5 → cgitize-9.0.0}/cgitize/utils.py +0 -10
  8. {cgitize-8.0.5 → cgitize-9.0.0}/cgitize.egg-info/PKG-INFO +2 -2
  9. {cgitize-8.0.5 → cgitize-9.0.0}/cgitize.egg-info/SOURCES.txt +6 -8
  10. {cgitize-8.0.5 → cgitize-9.0.0}/cgitize.egg-info/scm_file_list.json +6 -8
  11. cgitize-9.0.0/cgitize.egg-info/scm_version.json +8 -0
  12. {cgitize-8.0.5 → cgitize-9.0.0}/docker/Dockerfile +3 -5
  13. {cgitize-8.0.5 → cgitize-9.0.0}/docker/README.md +8 -5
  14. {cgitize-8.0.5 → cgitize-9.0.0}/pyproject.toml +2 -1
  15. cgitize-9.0.0/test/integration/docker/docker-compose.yml +29 -0
  16. cgitize-9.0.0/test/integration/docker/git_server/Dockerfile +16 -0
  17. cgitize-9.0.0/test/integration/docker/git_server/entrypoint.sh +64 -0
  18. cgitize-9.0.0/test/integration/docker/git_server/setup.sh +68 -0
  19. {cgitize-8.0.5 → cgitize-9.0.0}/test/integration/docker/test.sh +3 -82
  20. cgitize-8.0.5/.dockerignore +0 -5
  21. cgitize-8.0.5/cgitize.egg-info/scm_version.json +0 -8
  22. cgitize-8.0.5/docker-compose.yml +0 -25
  23. cgitize-8.0.5/examples/docker/cgitize.toml +0 -7
  24. cgitize-8.0.5/test/integration/docker/.dockerignore +0 -5
  25. cgitize-8.0.5/test/integration/docker/docker-compose.yml +0 -21
  26. cgitize-8.0.5/test/integration/docker/git_server/Dockerfile +0 -24
  27. cgitize-8.0.5/test/integration/docker/git_server/setup_repo.sh +0 -30
  28. {cgitize-8.0.5 → cgitize-9.0.0}/.git-blame-ignore-revs +0 -0
  29. {cgitize-8.0.5 → cgitize-9.0.0}/.gitattributes +0 -0
  30. {cgitize-8.0.5 → cgitize-9.0.0}/.github/dependabot.yml +0 -0
  31. {cgitize-8.0.5 → cgitize-9.0.0}/.github/workflows/maintenance.yml +0 -0
  32. {cgitize-8.0.5 → cgitize-9.0.0}/.gitignore +0 -0
  33. {cgitize-8.0.5 → cgitize-9.0.0}/.python-version +0 -0
  34. {cgitize-8.0.5 → cgitize-9.0.0}/LICENSE.txt +0 -0
  35. {cgitize-8.0.5 → cgitize-9.0.0}/Makefile +0 -0
  36. {cgitize-8.0.5 → cgitize-9.0.0}/README.md +0 -0
  37. {cgitize-8.0.5 → cgitize-9.0.0}/cgitize/__init__.py +0 -0
  38. {cgitize-8.0.5 → cgitize-9.0.0}/cgitize/bitbucket.py +0 -0
  39. {cgitize-8.0.5 → cgitize-9.0.0}/cgitize/config.py +0 -0
  40. {cgitize-8.0.5 → cgitize-9.0.0}/cgitize/git.py +0 -0
  41. {cgitize-8.0.5 → cgitize-9.0.0}/cgitize/github.py +0 -0
  42. {cgitize-8.0.5 → cgitize-9.0.0}/cgitize/gitlab.py +0 -0
  43. {cgitize-8.0.5 → cgitize-9.0.0}/cgitize/header.py +0 -0
  44. {cgitize-8.0.5 → cgitize-9.0.0}/cgitize/main.py +0 -0
  45. {cgitize-8.0.5 → cgitize-9.0.0}/cgitize/url.py +0 -0
  46. {cgitize-8.0.5 → cgitize-9.0.0}/cgitize/version.py +0 -0
  47. {cgitize-8.0.5 → cgitize-9.0.0}/cgitize.egg-info/dependency_links.txt +0 -0
  48. {cgitize-8.0.5 → cgitize-9.0.0}/cgitize.egg-info/entry_points.txt +0 -0
  49. {cgitize-8.0.5 → cgitize-9.0.0}/cgitize.egg-info/requires.txt +0 -0
  50. {cgitize-8.0.5 → cgitize-9.0.0}/cgitize.egg-info/top_level.txt +0 -0
  51. {cgitize-8.0.5 → cgitize-9.0.0}/docker/frontend/Dockerfile +0 -0
  52. {cgitize-8.0.5 → cgitize-9.0.0}/docker/frontend/cmd.sh +0 -0
  53. {cgitize-8.0.5 → cgitize-9.0.0}/docker/frontend/etc/cgit/common +0 -0
  54. {cgitize-8.0.5 → cgitize-9.0.0}/docker/frontend/etc/cgitrc +0 -0
  55. {cgitize-8.0.5 → cgitize-9.0.0}/docker/frontend/etc/nginx/conf.d/default.conf +0 -0
  56. {cgitize-8.0.5 → cgitize-9.0.0}/docker/frontend/usr/lib/cgit/filters/about-formatting.sh +0 -0
  57. {cgitize-8.0.5 → cgitize-9.0.0}/docker/frontend/usr/lib/cgit/filters/html-converters/.gitattributes +0 -0
  58. {cgitize-8.0.5 → cgitize-9.0.0}/docker/frontend/usr/lib/cgit/filters/html-converters/md2html +0 -0
  59. {cgitize-8.0.5 → cgitize-9.0.0}/docker/get_output_dir.py +0 -0
  60. {cgitize-8.0.5 → cgitize-9.0.0}/docker/in_cron.sh +0 -0
  61. /cgitize-8.0.5/docker/cgitize.sh → /cgitize-9.0.0/docker/run.sh +0 -0
  62. {cgitize-8.0.5 → cgitize-9.0.0}/docs/api.md +0 -0
  63. {cgitize-8.0.5 → cgitize-9.0.0}/docs/auth.md +0 -0
  64. {cgitize-8.0.5 → cgitize-9.0.0}/examples/cgitize.toml +0 -0
  65. {cgitize-8.0.5 → cgitize-9.0.0}/prelude.mk +0 -0
  66. {cgitize-8.0.5 → cgitize-9.0.0}/requirements.txt +0 -0
  67. {cgitize-8.0.5 → cgitize-9.0.0}/setup.cfg +0 -0
  68. {cgitize-8.0.5 → cgitize-9.0.0}/test/__init__.py +0 -0
  69. {cgitize-8.0.5/test/integration/docker/cgitize → cgitize-9.0.0/test/integration/docker}/.gitignore +0 -0
  70. {cgitize-8.0.5/test/integration/docker/cgitize → cgitize-9.0.0/test/integration/docker}/etc/cgitize.toml +0 -0
  71. {cgitize-8.0.5 → cgitize-9.0.0}/test/integration/example/test.sh +0 -0
  72. {cgitize-8.0.5 → cgitize-9.0.0}/test/integration/local/test.sh +0 -0
  73. {cgitize-8.0.5 → cgitize-9.0.0}/test/set_credentials.sh +0 -0
  74. {cgitize-8.0.5 → cgitize-9.0.0}/test/unit/__init__.py +0 -0
  75. {cgitize-8.0.5 → cgitize-9.0.0}/test/unit/test_bitbucket.py +0 -0
  76. {cgitize-8.0.5 → cgitize-9.0.0}/test/unit/test_github.py +0 -0
  77. {cgitize-8.0.5 → cgitize-9.0.0}/test/unit/test_gitlab.py +0 -0
@@ -25,7 +25,11 @@ jobs:
25
25
  runs-on: ubuntu-latest
26
26
  strategy:
27
27
  matrix:
28
- python-version: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14']
28
+ python-version:
29
+ - '3.11'
30
+ - '3.12'
31
+ - '3.13'
32
+ - '3.14'
29
33
  name: 'Test / ${{ matrix.python-version }}'
30
34
  env:
31
35
  CGITIZE_GITHUB_USERNAME: '${{ secrets.CGITIZE_GITHUB_USERNAME }}'
@@ -61,7 +65,9 @@ jobs:
61
65
  run: sudo make test/docker
62
66
 
63
67
  test_example_config:
64
- needs: [test_local, test_docker]
68
+ needs:
69
+ - test_local
70
+ - test_docker
65
71
  runs-on: ubuntu-latest
66
72
  name: 'Test / example config'
67
73
  env:
@@ -88,7 +94,11 @@ jobs:
88
94
  run: make test/example
89
95
 
90
96
  publish_docker:
91
- needs: [lint, test_local, test_example_config, test_docker]
97
+ needs:
98
+ - lint
99
+ - test_local
100
+ - test_example_config
101
+ - test_docker
92
102
  runs-on: ubuntu-latest
93
103
  strategy:
94
104
  matrix:
@@ -149,7 +159,8 @@ jobs:
149
159
  tags: '${{ steps.meta.outputs.tags }}'
150
160
 
151
161
  publish_pypi:
152
- needs: [publish_docker]
162
+ needs:
163
+ - publish_docker
153
164
  runs-on: ubuntu-latest
154
165
  name: 'Publish / PyPI'
155
166
  steps:
@@ -0,0 +1,64 @@
1
+ v9.0
2
+ ====
3
+
4
+ ### Breaking changes
5
+
6
+ * Docker images: SSH agent should now be mapped to /ssh/agent.sock (instead of
7
+ /ssh-agent.sock).
8
+
9
+ v8.0
10
+ ====
11
+
12
+ ### Breaking changes
13
+
14
+ * Since Bitbucket deprecated "app passwords", an Atlassian API token is now
15
+ required in place of those.
16
+ * In cgitize.toml, the field `bitbucket.username` is replaced with
17
+ `bitbucket.email`, since the API tokens are tied to the Atlassian account now.
18
+
19
+ v7.0
20
+ ====
21
+
22
+ ### Breaking changes
23
+
24
+ * For forge users, only publicly visible repositories are fetched by default.
25
+ * New fields in cgitize.toml `{github,bitbucket,gitlab}.users.*.{public,private}`
26
+ control whether to fetch public or private repositories, or both.
27
+ * The `public` field is set to `true` by default; `private` is `false`.
28
+
29
+ v6.0
30
+ ====
31
+
32
+ * Major version bumps for the dependencies.
33
+ * Otherwise, no breaking changes.
34
+
35
+ v5.0
36
+ ====
37
+
38
+ ### Breaking changes
39
+
40
+ * GitHub: private user repositories are also cloned now.
41
+ * This change is consistent with how Gitlab and Bitbucket backend work.
42
+ * If `github.token` is set in cgitize.toml, `github.username` must also be
43
+ set.
44
+
45
+ v5.1
46
+ ----
47
+
48
+ ### New features
49
+
50
+ * In case of an error, a message is displayed in the frontend's header.
51
+
52
+ v4.0
53
+ ====
54
+
55
+ ### Breaking changes
56
+
57
+ * Fields `access_token` & `app_password` in cgitize.toml renamed to simply
58
+ `token`.
59
+ * Repositories are cloned into directories with the ".git" suffix now.
60
+
61
+ v3.0
62
+ ====
63
+
64
+ * The latest release that I'm still not too lazy to look up.
@@ -61,9 +61,10 @@ Upgrading dependencies
61
61
  Releases
62
62
  --------
63
63
 
64
- * Make a new tag using the semantic versioning policy (you can use [tag-release]
65
- to do that), review and push it.
66
64
  * For a new major version, update the version in the docker-compose definition
67
65
  in docker/README.md.
66
+ * Update CHANGELOG.md if necessary.
67
+ * Make a new tag using the semantic versioning policy (you can use [tag-release]
68
+ to do that), review and push it.
68
69
 
69
70
  [tag-release]: https://github.com/egor-tensin/tag-release
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cgitize
3
- Version: 8.0.5
3
+ Version: 9.0.0
4
4
  Summary: Self-host your repositories using cgit
5
5
  Author-email: Egor Tensin <egor@tensin.name>
6
6
  License-Expression: MIT
@@ -9,7 +9,7 @@ Project-URL: Bug Tracker, https://github.com/egor-tensin/cgitize/issues
9
9
  Classifier: Development Status :: 5 - Production/Stable
10
10
  Classifier: Programming Language :: Python :: 3
11
11
  Classifier: Topic :: Software Development :: Version Control :: Git
12
- Requires-Python: >=3.9
12
+ Requires-Python: >=3.11
13
13
  Description-Content-Type: text/markdown
14
14
  License-File: LICENSE.txt
15
15
  Requires-Dist: atlassian-python-api~=4.0
@@ -3,12 +3,12 @@
3
3
  # For details, see https://github.com/egor-tensin/cgitize
4
4
  # Distributed under the MIT License.
5
5
 
6
+ from contextlib import chdir
6
7
  import logging
7
8
  import os
8
9
  import shutil
9
10
 
10
11
  from cgitize.git import Git
11
- from cgitize.utils import chdir
12
12
 
13
13
 
14
14
  class CGitServer:
@@ -3,19 +3,16 @@
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
+ from enum import auto, StrEnum
7
7
  import os.path
8
8
 
9
9
  from cgitize import url
10
10
 
11
11
 
12
- class Visibility(Enum):
13
- ALL = "all"
14
- PUBLIC = "public"
15
- PRIVATE = "private"
16
-
17
- def __str__(self):
18
- return self.name
12
+ class Visibility(StrEnum):
13
+ ALL = auto()
14
+ PUBLIC = auto()
15
+ PRIVATE = auto()
19
16
 
20
17
  @staticmethod
21
18
  def from_config(public, private):
@@ -32,33 +29,39 @@ class Visibility(Enum):
32
29
  def to_bitbucket_arg(self):
33
30
  # https://developer.atlassian.com/cloud/bitbucket/rest/intro/#filtering
34
31
  # 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}")
32
+ match self:
33
+ case Visibility.ALL:
34
+ return None
35
+ case Visibility.PUBLIC:
36
+ return "is_private=False"
37
+ case Visibility.PRIVATE:
38
+ return "is_private=True"
39
+ case _:
40
+ raise NotImplementedError(f"not implemented visibility level: {self}")
42
41
 
43
42
  def to_github_arg(self):
44
43
  # 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}")
44
+ match self:
45
+ case Visibility.ALL:
46
+ return None
47
+ case Visibility.PUBLIC:
48
+ return "public"
49
+ case Visibility.PRIVATE:
50
+ return "private"
51
+ case _:
52
+ raise NotImplementedError(f"not implemented visibility level: {self}")
52
53
 
53
54
  def to_gitlab_arg(self):
54
55
  # 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}")
56
+ match self:
57
+ case Visibility.ALL:
58
+ return None
59
+ case Visibility.PUBLIC:
60
+ return "public"
61
+ case Visibility.PRIVATE:
62
+ return "private"
63
+ case _:
64
+ raise NotImplementedError(f"not implemented visibility level: {self}")
62
65
 
63
66
 
64
67
  class Repo:
@@ -77,16 +77,6 @@ def try_capture(*args, **kwargs):
77
77
  return e.returncode == 0, e.output
78
78
 
79
79
 
80
- @contextmanager
81
- def chdir(new_cwd):
82
- old_cwd = os.getcwd()
83
- os.chdir(new_cwd)
84
- try:
85
- yield
86
- finally:
87
- os.chdir(old_cwd)
88
-
89
-
90
80
  @contextmanager
91
81
  def protected_file(path):
92
82
  # 0600:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cgitize
3
- Version: 8.0.5
3
+ Version: 9.0.0
4
4
  Summary: Self-host your repositories using cgit
5
5
  Author-email: Egor Tensin <egor@tensin.name>
6
6
  License-Expression: MIT
@@ -9,7 +9,7 @@ Project-URL: Bug Tracker, https://github.com/egor-tensin/cgitize/issues
9
9
  Classifier: Development Status :: 5 - Production/Stable
10
10
  Classifier: Programming Language :: Python :: 3
11
11
  Classifier: Topic :: Software Development :: Version Control :: Git
12
- Requires-Python: >=3.9
12
+ Requires-Python: >=3.11
13
13
  Description-Content-Type: text/markdown
14
14
  License-File: LICENSE.txt
15
15
  Requires-Dist: atlassian-python-api~=4.0
@@ -1,13 +1,12 @@
1
- .dockerignore
2
1
  .git-blame-ignore-revs
3
2
  .gitattributes
4
3
  .gitignore
5
4
  .python-version
5
+ CHANGELOG.md
6
6
  DEVELOPMENT.md
7
7
  LICENSE.txt
8
8
  Makefile
9
9
  README.md
10
- docker-compose.yml
11
10
  prelude.mk
12
11
  pyproject.toml
13
12
  requirements.txt
@@ -37,9 +36,9 @@ cgitize.egg-info/scm_version.json
37
36
  cgitize.egg-info/top_level.txt
38
37
  docker/Dockerfile
39
38
  docker/README.md
40
- docker/cgitize.sh
41
39
  docker/get_output_dir.py
42
40
  docker/in_cron.sh
41
+ docker/run.sh
43
42
  docker/frontend/Dockerfile
44
43
  docker/frontend/cmd.sh
45
44
  docker/frontend/etc/cgitrc
@@ -51,16 +50,15 @@ docker/frontend/usr/lib/cgit/filters/html-converters/md2html
51
50
  docs/api.md
52
51
  docs/auth.md
53
52
  examples/cgitize.toml
54
- examples/docker/cgitize.toml
55
53
  test/__init__.py
56
54
  test/set_credentials.sh
57
- test/integration/docker/.dockerignore
55
+ test/integration/docker/.gitignore
58
56
  test/integration/docker/docker-compose.yml
59
57
  test/integration/docker/test.sh
60
- test/integration/docker/cgitize/.gitignore
61
- test/integration/docker/cgitize/etc/cgitize.toml
58
+ test/integration/docker/etc/cgitize.toml
62
59
  test/integration/docker/git_server/Dockerfile
63
- test/integration/docker/git_server/setup_repo.sh
60
+ test/integration/docker/git_server/entrypoint.sh
61
+ test/integration/docker/git_server/setup.sh
64
62
  test/integration/example/test.sh
65
63
  test/integration/local/test.sh
66
64
  test/unit/__init__.py
@@ -1,6 +1,5 @@
1
1
  {
2
2
  "files": [
3
- ".dockerignore",
4
3
  ".git-blame-ignore-revs",
5
4
  ".gitattributes",
6
5
  ".github/dependabot.yml",
@@ -8,6 +7,7 @@
8
7
  ".github/workflows/maintenance.yml",
9
8
  ".gitignore",
10
9
  ".python-version",
10
+ "CHANGELOG.md",
11
11
  "DEVELOPMENT.md",
12
12
  "LICENSE.txt",
13
13
  "Makefile",
@@ -25,10 +25,8 @@
25
25
  "cgitize/url.py",
26
26
  "cgitize/utils.py",
27
27
  "cgitize/version.py",
28
- "docker-compose.yml",
29
28
  "docker/Dockerfile",
30
29
  "docker/README.md",
31
- "docker/cgitize.sh",
32
30
  "docker/frontend/Dockerfile",
33
31
  "docker/frontend/cmd.sh",
34
32
  "docker/frontend/etc/cgit/common",
@@ -39,20 +37,20 @@
39
37
  "docker/frontend/usr/lib/cgit/filters/html-converters/md2html",
40
38
  "docker/get_output_dir.py",
41
39
  "docker/in_cron.sh",
40
+ "docker/run.sh",
42
41
  "docs/api.md",
43
42
  "docs/auth.md",
44
43
  "examples/cgitize.toml",
45
- "examples/docker/cgitize.toml",
46
44
  "prelude.mk",
47
45
  "pyproject.toml",
48
46
  "requirements.txt",
49
47
  "test/__init__.py",
50
- "test/integration/docker/.dockerignore",
51
- "test/integration/docker/cgitize/.gitignore",
52
- "test/integration/docker/cgitize/etc/cgitize.toml",
48
+ "test/integration/docker/.gitignore",
53
49
  "test/integration/docker/docker-compose.yml",
50
+ "test/integration/docker/etc/cgitize.toml",
54
51
  "test/integration/docker/git_server/Dockerfile",
55
- "test/integration/docker/git_server/setup_repo.sh",
52
+ "test/integration/docker/git_server/entrypoint.sh",
53
+ "test/integration/docker/git_server/setup.sh",
56
54
  "test/integration/docker/test.sh",
57
55
  "test/integration/example/test.sh",
58
56
  "test/integration/local/test.sh",
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "9.0.0",
3
+ "distance": 0,
4
+ "node": "gbcfde716275d94b1767a309fe8e35f4c90b834f2",
5
+ "dirty": false,
6
+ "branch": "HEAD",
7
+ "node_date": "2026-10-14"
8
+ }
@@ -35,11 +35,9 @@ RUN apk add -q --no-cache bash git openssh-client tini
35
35
  COPY --from=build ["/deps", "/deps/"]
36
36
  ENV PYTHONPATH="/deps:/usr/src"
37
37
 
38
- ARG ssh_sock_dir=/
39
- ARG ssh_sock_path="$ssh_sock_dir/ssh-agent.sock"
40
- ENV SSH_AUTH_SOCK="$ssh_sock_path"
38
+ ENV SSH_AUTH_SOCK="/ssh/agent.sock"
41
39
 
42
- COPY ["docker/cgitize.sh", "/"]
40
+ COPY ["docker/run.sh", "/"]
43
41
  COPY ["docker/get_output_dir.py", "/"]
44
42
  COPY ["docker/in_cron.sh", "/"]
45
43
  COPY ["cgitize/", "/usr/src/cgitize/"]
@@ -48,6 +46,6 @@ ENV SCHEDULE_ON_START=1
48
46
  ENTRYPOINT ["/sbin/tini", "--", "/in_cron.sh"]
49
47
 
50
48
  WORKDIR /usr/src
51
- CMD ["/cgitize.sh"]
49
+ CMD ["/run.sh"]
52
50
 
53
51
  HEALTHCHECK --interval=5m --retries=3 CMD ! test -f /fail
@@ -8,7 +8,7 @@ The `SCHEDULE` environment variable controls how often it gets run (see below).
8
8
  * Volumes:
9
9
  * `/etc/cgitize/cgitize.toml`: configuration file path.
10
10
  * `/mnt/cgitize`: by default, cloned repositories will be written here.
11
- * `/ssh-agent.sock`: if you use SSH, map the agent socket here.
11
+ * `/ssh/agent.sock`: if you use SSH, map the agent socket here.
12
12
  * Environment variables:
13
13
  * `SCHEDULE`: defaults to "once", which makes the container exit after the
14
14
  first run.
@@ -49,18 +49,21 @@ services:
49
49
  SCHEDULE: '0 */3 * * *'
50
50
  # Set CGITIZE_{GITHUB,BITBUCKET,GITLAB}_{USERNAME,TOKEN} variables
51
51
  # here or in the config file.
52
- image: egortensin/cgitize:8
52
+ image: egortensin/cgitize:9
53
53
  restart: unless-stopped
54
54
  volumes:
55
55
  - ./example.toml:/etc/cgitize/cgitize.toml:ro
56
- - /srv/volumes/cgitize:/mnt/cgitize
56
+ - repositories:/mnt/cgitize
57
57
  frontend:
58
- image: egortensin/cgitize-frontend:8
58
+ image: egortensin/cgitize-frontend:9
59
59
  ports:
60
60
  - '127.0.0.1:80:80'
61
61
  restart: unless-stopped
62
62
  volumes:
63
- - /srv/volumes/cgitize:/mnt/cgitize:ro
63
+ - repositories:/mnt/cgitize:ro
64
+
65
+ volumes:
66
+ repositories:
64
67
  ```
65
68
 
66
69
  In this configuration, cgitize pulls repositories defined in example.toml every
@@ -12,7 +12,8 @@ license-files = ["LICENSE.txt"]
12
12
  dynamic = ["version"]
13
13
  authors = [{name = "Egor Tensin", email = "egor@tensin.name"}]
14
14
  readme = "README.md"
15
- requires-python = ">=3.9"
15
+ requires-python = ">=3.11"
16
+ # ^^^ For enum.StrEnum/contextlib.chdir, at least?
16
17
 
17
18
  dependencies = [
18
19
  "atlassian-python-api ~= 4.0",
@@ -0,0 +1,29 @@
1
+ services:
2
+ git_server:
3
+ build:
4
+ context: .
5
+ dockerfile: git_server/Dockerfile
6
+ volumes:
7
+ - ssh:/ssh
8
+ cgitize:
9
+ build:
10
+ context: ../../..
11
+ dockerfile: docker/Dockerfile
12
+ depends_on:
13
+ - git_server
14
+ environment:
15
+ SCHEDULE: once
16
+ volumes:
17
+ - ./etc:/etc/cgitize:ro
18
+ - ./output:/mnt/cgitize
19
+ - ssh:/ssh:ro
20
+ frontend:
21
+ build:
22
+ context: ../../../docker/frontend
23
+ ports:
24
+ - '127.0.0.1:80:80'
25
+ volumes:
26
+ - ./output:/mnt/cgitize:ro
27
+
28
+ volumes:
29
+ ssh:
@@ -0,0 +1,16 @@
1
+ FROM alpine:3.24
2
+
3
+ RUN apk add -q --no-cache bash git openssh-client-common openssh-server tini && \
4
+ echo 'root:root' | chpasswd && \
5
+ sed -ri 's/^#?PermitRootLogin\s+.*/PermitRootLogin yes/' /etc/ssh/sshd_config
6
+
7
+ USER root
8
+ WORKDIR /root
9
+
10
+ COPY ["git_server/setup.sh", "./"]
11
+ RUN ./setup.sh
12
+
13
+ COPY ["git_server/entrypoint.sh", "/"]
14
+ ENTRYPOINT ["/sbin/tini", "--", "/entrypoint.sh"]
15
+
16
+ CMD ["/usr/sbin/sshd", "-D"]
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -o errexit -o nounset -o pipefail
4
+ shopt -s inherit_errexit lastpipe
5
+
6
+ script_name="$( basename -- "${BASH_SOURCE[0]}" )"
7
+ readonly script_name
8
+
9
+ dump() {
10
+ local prefix="${FUNCNAME[0]}"
11
+ [ "${#FUNCNAME[@]}" -gt 1 ] && prefix="${FUNCNAME[1]}"
12
+
13
+ local msg
14
+ for msg; do
15
+ echo "$script_name: $prefix: $msg"
16
+ done
17
+ }
18
+
19
+ readonly ssh_dir=/ssh
20
+ readonly ssh_client_key="$ssh_dir/client_key"
21
+ readonly ssh_client_password='password'
22
+
23
+ spawn_ssh_agent() {
24
+ if ! command -v ssh-agent > /dev/null 2>&1; then
25
+ dump "could not find ssh-agent" >&2
26
+ return 1
27
+ fi
28
+
29
+ local output
30
+ output="$( ssh-agent -s -a "$ssh_dir/agent.sock" )"
31
+
32
+ echo "$output"
33
+ eval "$output"
34
+
35
+ if [ -z "${SSH_AGENT_PID:+x}" ]; then
36
+ dump "could not start ssh-agent" >&2
37
+ return 1
38
+ fi
39
+ }
40
+
41
+ setup_ssh_agent() {
42
+ echo
43
+ echo ----------------------------------------------------------------------
44
+ echo Setting up ssh-agent
45
+ echo ----------------------------------------------------------------------
46
+
47
+ spawn_ssh_agent
48
+
49
+ local askpass_path
50
+ askpass_path="$( mktemp )"
51
+ chmod 0700 -- "$askpass_path"
52
+
53
+ echo "#!/usr/bin/env sh" >> "$askpass_path"
54
+ printf -- 'echo %q' "$ssh_client_password" >> "$askpass_path"
55
+
56
+ SSH_ASKPASS="$askpass_path" SSH_ASKPASS_REQUIRE=force DISPLAY= ssh-add "$ssh_client_key" < /dev/null
57
+ }
58
+
59
+ main() {
60
+ setup_ssh_agent
61
+ exec "$@"
62
+ }
63
+
64
+ main "$@"
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -o errexit -o nounset -o pipefail
4
+ shopt -s inherit_errexit lastpipe
5
+
6
+ readonly ssh_dir=/ssh
7
+ readonly ssh_client_password='password'
8
+
9
+ configure_git() {
10
+ echo
11
+ echo ----------------------------------------------------------------------
12
+ echo Configuring git
13
+ echo ----------------------------------------------------------------------
14
+
15
+ git config --global user.name 'John Doe'
16
+ git config --global user.email 'John.Doe@example.com'
17
+ git config --global init.defaultBranch main
18
+ }
19
+
20
+ generate_ssh_keys() {
21
+ echo
22
+ echo ----------------------------------------------------------------------
23
+ echo Generating SSH keys
24
+ echo ----------------------------------------------------------------------
25
+
26
+ mkdir -p -- "$ssh_dir"
27
+
28
+ ssh-keygen -t rsa -b 4096 -f "$ssh_dir/client_key" -N "$ssh_client_password"
29
+ ssh-keygen -t rsa -b 4096 -f "$ssh_dir/server_key" -N ''
30
+
31
+ mkdir ~/.ssh
32
+
33
+ cp "$ssh_dir/server_key" /etc/ssh/ssh_host_ed25519_key
34
+ cp "$ssh_dir/server_key.pub" /etc/ssh/ssh_host_ed25519_key.pub
35
+ cp "$ssh_dir/client_key.pub" ~/.ssh/authorized_keys
36
+
37
+ chmod 0600 -- /etc/ssh/ssh_host_ed25519_key
38
+ chmod 0700 -- ~/.ssh/
39
+ chmod 0600 -- ~/.ssh/authorized_keys
40
+ }
41
+
42
+ readonly repo_path="$HOME/test_repo"
43
+
44
+ create_repo() {
45
+ echo
46
+ echo ----------------------------------------------------------------------
47
+ echo Setting up upstream repository
48
+ echo ----------------------------------------------------------------------
49
+
50
+ mkdir -p -- "$repo_path"
51
+ pushd -- "$repo_path" > /dev/null
52
+ git init
53
+ echo '1' > 1.txt
54
+ git add .
55
+ git commit -m 'first commit'
56
+ echo '2' > 2.txt
57
+ git add .
58
+ git commit -m 'second commit'
59
+ popd > /dev/null
60
+ }
61
+
62
+ main() {
63
+ configure_git
64
+ generate_ssh_keys
65
+ create_repo
66
+ }
67
+
68
+ main
@@ -12,10 +12,8 @@ readonly script_name
12
12
  # This is still required with older Compose versions to use TARGETARCH:
13
13
  export DOCKER_BUILDKIT=1
14
14
 
15
- readonly ssh_dir="$script_dir/ssh"
16
- readonly client_key_password='password'
17
- readonly output_dir="$script_dir/cgitize/output"
18
- readonly frontend_host=localhost
15
+ readonly output_dir="$script_dir/output"
16
+ readonly frontend_host=127.0.0.1
19
17
 
20
18
  dump() {
21
19
  local prefix="${FUNCNAME[0]}"
@@ -40,8 +38,6 @@ cleanup() {
40
38
  echo Cleaning up
41
39
  echo ----------------------------------------------------------------------
42
40
 
43
- remove_ssh_keys
44
- kill_ssh_agent
45
41
  docker_cleanup
46
42
 
47
43
  rm -rf -- "$output_dir"
@@ -85,74 +81,6 @@ curl_check_code() {
85
81
  fi
86
82
  }
87
83
 
88
- generate_ssh_keys() {
89
- echo
90
- echo ----------------------------------------------------------------------
91
- echo Generating SSH keys
92
- echo ----------------------------------------------------------------------
93
-
94
- mkdir -p -- "$ssh_dir"
95
-
96
- ssh-keygen -t rsa -b 4096 -f "$ssh_dir/client_key" -N "$client_key_password"
97
- ssh-keygen -t rsa -b 4096 -f "$ssh_dir/server_key" -N ''
98
- }
99
-
100
- remove_ssh_keys() {
101
- rm -rf -- "$ssh_dir"
102
- }
103
-
104
- kill_ssh_agent() {
105
- [ -n "${this_ssh_agent_pid:+x}" ] || return 0
106
- dump "killing ssh-agent with PID $this_ssh_agent_pid"
107
- kill "$this_ssh_agent_pid"
108
- }
109
-
110
- spawn_ssh_agent() {
111
- if ! command -v ssh-agent > /dev/null 2>&1; then
112
- dump "could not find ssh-agent" >&2
113
- return 1
114
- fi
115
-
116
- local output
117
- output="$( ssh-agent -s )"
118
-
119
- eval "$output"
120
-
121
- if [ -z "${SSH_AGENT_PID:+x}" ]; then
122
- dump "could not start ssh-agent" >&2
123
- return 1
124
- fi
125
-
126
- this_ssh_agent_pid="$SSH_AGENT_PID"
127
- }
128
-
129
- setup_ssh_agent() {
130
- echo
131
- echo ----------------------------------------------------------------------
132
- echo Setting up ssh-agent
133
- echo ----------------------------------------------------------------------
134
-
135
- spawn_ssh_agent
136
-
137
- local key="$ssh_dir/client_key"
138
- chmod 0600 -- "$key"
139
-
140
- local askpass_path
141
- askpass_path="$( mktemp --tmpdir="$script_dir" )"
142
-
143
- local askpass_rm
144
- askpass_rm="$( printf -- 'rm -- %q; trap - RETURN' "$askpass_path" )"
145
- trap "$askpass_rm" RETURN
146
-
147
- chmod 0700 -- "$askpass_path"
148
-
149
- local echo_password
150
- echo_password="$( printf -- 'echo %q' "$client_key_password" )"
151
- echo "$echo_password" > "$askpass_path"
152
-
153
- SSH_ASKPASS="$askpass_path" SSH_ASKPASS_REQUIRE=force DISPLAY= ssh-add "$key" < /dev/null
154
- }
155
-
156
84
  docker_build() {
157
85
  echo
158
86
  echo ----------------------------------------------------------------------
@@ -169,8 +97,6 @@ docker_cleanup() {
169
97
  }
170
98
 
171
99
  setup() {
172
- generate_ssh_keys
173
- setup_ssh_agent
174
100
  docker_build
175
101
  }
176
102
 
@@ -189,11 +115,6 @@ run_cgitize() {
189
115
  echo Running cgitize
190
116
  echo ----------------------------------------------------------------------
191
117
 
192
- if [ -z "${SSH_AUTH_SOCK:+x}" ]; then
193
- dump 'SSH_AUTH_SOCK is not defined' >&2
194
- return 1
195
- fi
196
- dump "SSH_AUTH_SOCK: $SSH_AUTH_SOCK"
197
118
  docker compose run --rm cgitize
198
119
  }
199
120
 
@@ -219,7 +140,7 @@ verify_git() {
219
140
  echo Checking the pulled repository
220
141
  echo ----------------------------------------------------------------------
221
142
 
222
- pushd -- "$script_dir/cgitize/output/test_repo.git" > /dev/null
143
+ pushd -- "$script_dir/output/test_repo.git" > /dev/null
223
144
  git log --oneline
224
145
  popd > /dev/null
225
146
  }
@@ -1,5 +0,0 @@
1
- *
2
-
3
- !/cgitize/**
4
- !/docker/**
5
- !/requirements.txt
@@ -1,8 +0,0 @@
1
- {
2
- "tag": "8.0.5",
3
- "distance": 0,
4
- "node": "ga96d5e0f409c764f259df0963319ae4155436f12",
5
- "dirty": false,
6
- "branch": "HEAD",
7
- "node_date": "2026-10-12"
8
- }
@@ -1,25 +0,0 @@
1
- services:
2
- cgitize:
3
- build:
4
- context: .
5
- dockerfile: docker/Dockerfile
6
- environment:
7
- # Every 3 hours:
8
- SCHEDULE: '0 */3 * * *'
9
- image: egortensin/cgitize:latest
10
- restart: unless-stopped
11
- volumes:
12
- - ./examples/docker:/etc/cgitize:ro
13
- - repositories:/mnt/cgitize
14
- frontend:
15
- build:
16
- context: ./docker/frontend
17
- image: egortensin/cgitize-frontend:latest
18
- ports:
19
- - '127.0.0.1:80:80'
20
- restart: unless-stopped
21
- volumes:
22
- - repositories:/mnt/cgitize:ro
23
-
24
- volumes:
25
- repositories:
@@ -1,7 +0,0 @@
1
- clone_via_ssh = false
2
- clone_url = "http://localhost/{repo}"
3
-
4
- [github]
5
-
6
- [github.users.me]
7
- name = "egor-tensin"
@@ -1,5 +0,0 @@
1
- *
2
-
3
- !/git_server/**
4
- /git_server/Dockerfile
5
- !/ssh/**
@@ -1,21 +0,0 @@
1
- services:
2
- git_server:
3
- build:
4
- context: .
5
- dockerfile: git_server/Dockerfile
6
- cgitize:
7
- extends:
8
- file: ../../../docker-compose.yml
9
- service: cgitize
10
- environment:
11
- SCHEDULE: once
12
- volumes:
13
- - ./cgitize/etc:/etc/cgitize:ro
14
- - "$SSH_AUTH_SOCK:/ssh-agent.sock"
15
- - ./cgitize/output:/mnt/cgitize
16
- frontend:
17
- extends:
18
- file: ../../../docker-compose.yml
19
- service: frontend
20
- volumes:
21
- - ./cgitize/output:/mnt/cgitize:ro
@@ -1,24 +0,0 @@
1
- FROM alpine:3.24
2
-
3
- RUN apk add -q --no-cache bash git openssh-server tini && \
4
- echo 'root:root' | chpasswd && \
5
- git config --global user.name 'John Doe' && \
6
- git config --global user.email 'John.Doe@example.com' && \
7
- git config --global init.defaultBranch main && \
8
- sed -ri 's/^#?PermitRootLogin\s+.*/PermitRootLogin yes/' /etc/ssh/sshd_config
9
-
10
- WORKDIR /root
11
-
12
- COPY ["ssh/server_key", "/etc/ssh/ssh_host_ed25519_key"]
13
- COPY ["ssh/server_key.pub", "/etc/ssh/ssh_host_ed25519_key.pub"]
14
- COPY ["ssh/client_key.pub", "./.ssh/authorized_keys"]
15
-
16
- RUN chmod 0600 -- /etc/ssh/ssh_host_ed25519_key && \
17
- chmod 0700 -- ./.ssh/ && \
18
- chmod 0600 -- ./.ssh/authorized_keys
19
-
20
- COPY ["git_server/setup_repo.sh", "./"]
21
- RUN ./setup_repo.sh
22
-
23
- ENTRYPOINT ["/sbin/tini", "--"]
24
- CMD ["/usr/sbin/sshd", "-D"]
@@ -1,30 +0,0 @@
1
- #!/usr/bin/env bash
2
-
3
- set -o errexit -o nounset -o pipefail
4
- shopt -s inherit_errexit lastpipe
5
-
6
- readonly local_repo_path="$HOME/test_repo"
7
-
8
- setup_local_repo() {
9
- echo
10
- echo ----------------------------------------------------------------------
11
- echo Setting up upstream repository
12
- echo ----------------------------------------------------------------------
13
-
14
- mkdir -p -- "$local_repo_path"
15
- pushd -- "$local_repo_path" > /dev/null
16
- git init
17
- echo '1' > 1.txt
18
- git add .
19
- git commit -m 'first commit'
20
- echo '2' > 2.txt
21
- git add .
22
- git commit -m 'second commit'
23
- popd > /dev/null
24
- }
25
-
26
- main() {
27
- setup_local_repo
28
- }
29
-
30
- main
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
File without changes
File without changes
File without changes