Skip to content

Commit 6969e7a

Browse files
committed
update README.md
1 parent 77a19db commit 6969e7a

File tree

1 file changed

+172
-1
lines changed

1 file changed

+172
-1
lines changed

README.md

Lines changed: 172 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,173 @@
11
# python-gitlab-submodule
2-
List project submodules and get the commits they point to with python-gitlab
2+
List project submodules and get the commits they point to with python-gitlab.
3+
4+
5+
The [Gitlab REST API V4](https://docs.gitlab.com/ee/api/api_resources.html)
6+
doesn't implement anything for submodule inspection yet. The only thing we can
7+
currently do is [updating a submodule to a new commit id](https://docs.gitlab.com/ee/api/repository_submodules.html),
8+
but how can we decide to do such update if we don't know the current commit
9+
id of our submodule?
10+
11+
If you're using `python-gitlab` and you're distributing shared code using
12+
submodules, you've probably run into this issue already.
13+
14+
This package provides minimal utils to list the submodules present in a
15+
Gitlab project, and more importantly to get the commits they're pointing to
16+
(when the submodules are Gitlab projects themselves, otherwise we cannot
17+
access the project via their URLs with `python-gitlab` only).
18+
19+
Internally, it reads and parses the `.gitmodules` file at the root of the
20+
Project. To get the commit id of a submodule, it finds the last commit that
21+
updated the submodule and parses its diff.
22+
23+
## Requirements
24+
- Python >= __3.7__ (required by `python-gitlab` since version `3.0.0`)
25+
26+
## Dependencies
27+
- [python-gitlab](https://github.com/python-gitlab/python-gitlab)
28+
- [giturlparse](https://github.com/nephila/giturlparse)
29+
30+
## Install
31+
```
32+
pip install python-gitlab-gitmodule
33+
```
34+
or directly from Github:
35+
```
36+
pip install git+git://github.com/ValentinFrancois/python-gitlab-submodule#egg=python-gitlab-submodule
37+
```
38+
39+
## Usage example
40+
- Iterate the submodules of the Gitlab [Inkscape](https://gitlab.com/inkscape/inkscape) project
41+
- For each submodule, print:
42+
- its path in the project
43+
- its own Gitlab project SSH URL
44+
- the current commit sha that the Inkscape project is pointing to
45+
```python
46+
from gitlab import Gitlab
47+
from gitlab_submodule import iterate_subprojects
48+
49+
gl = Gitlab()
50+
inkscape = gl.projects.get('inkscape/inkscape')
51+
subprojects = iterate_subprojects(
52+
inkscape,
53+
gl,
54+
# current HEAD of master as I'm writing this
55+
ref='e371b2f826adcba316f2e64bbf2f697043373d0b')
56+
for subproject in subprojects:
57+
print('- {} ({}) -> {}'.format(
58+
subproject.submodule.path,
59+
subproject.project.url,
60+
subproject.commit.id))
61+
```
62+
Output:
63+
```
64+
- share/extensions (git@gitlab.com:inkscape/extensions.git) -> 6c9b68507be427bffba23507bbaacf3f8a0f3752
65+
- src/3rdparty/2geom (git@gitlab.com:inkscape/lib2geom.git) -> 9d38946b7d7a0486a4a75669008112d306309d9e
66+
- share/themes (git@gitlab.com:inkscape/themes.git) -> 2fc6ece138323f905c9b475c3bcdef0d007eb233
67+
```
68+
69+
## Available functions and objects
70+
71+
### `iterate_subprojects(...)`
72+
What you'll probably use most of the time.<br/>
73+
- Yields `Subproject` objects that describe the submodules.
74+
- Ignores submodules that are not hosted on Gitlab. If you want to list all
75+
modules present in the `.gitmodules` file but without mapping them to
76+
`gitlab.v4.objects.Project` objects, use list_submodules(...) instead.
77+
```python
78+
iterate_subprojects(
79+
project: Project,
80+
gl: Union[Gitlab, ProjectManager],
81+
ref: Optional[str] = None,
82+
get_latest_commit_possible_if_not_found: bool = False,
83+
get_latest_commit_possible_ref: Optional[str] = None
84+
) -> Generator[Subproject, None, None]
85+
```
86+
Parameters:
87+
- `project`: a `gitlab.v4.objects.Project` object
88+
- `gitlab`: the `gitlab.Gitlab` instance that you used to authenticate, or its
89+
`projects: gitlab.v4.objects.ProjectManager` attribute
90+
- `ref`: (optional) a ref to a branch, commit, tag etc. Defaults to the
91+
HEAD of the project default branch.
92+
- `get_latest_commit_possible_if_not_found`: in some rare cases, there
93+
won't be any `Subproject commit ...` info in the diff of the last commit
94+
that updated the submodules. Set this option to `True` if you want to get
95+
instead the most recent commit in the subproject that is anterior to the
96+
commit that updated the submodules of the project. If your goal is to
97+
check that your submodules are up-to-date, you might want to use this.
98+
- `get_latest_commit_possible_ref`: in case you set
99+
`get_latest_commit_possible_if_not_found` to `True`, you can specify a ref for the
100+
subproject (for instance your submodule could point to a different branch
101+
than the main one). By default, the main branch of the subproject will be
102+
used.
103+
104+
Returns: Generator of `Subproject` objects
105+
106+
### `list_subprojects(...)`
107+
Same parameters as `iterate_subprojects(...)` but returns a `list` or
108+
`Subproject` objects.
109+
110+
### class `Subproject`
111+
Basic objects that contain the info about a Gitlab subproject.
112+
113+
Attributes:
114+
- `project: gitlab.v4.objects.Project`: the Gitlab project that the submodule links to
115+
- `submodule`: `Submodule`: a basic object that contains the info found in
116+
the `.gitmodules` file (name, path, url).
117+
- `commit: gitlab.v4.objects.ProjectCommit`: the commit that the submodule points to
118+
- `commit_is_exact: bool`: `True` most of the time, `False` only if the commit
119+
had to be guessed via the `get_latest_commit_possible_if_not_found` option
120+
121+
Example `str()` output:
122+
```
123+
<class 'Subproject'> => {
124+
'submodule': <class 'Submodule'> => {'name': 'share/extensions', 'parent_project': <class 'gitlab.v4.objects.projects.Project'> => {'id': 3472737, 'description': 'Inkscape vector image editor', 'name': 'inkscape', 'name_with_namespace': 'Inkscape / inkscape', 'path': 'inkscape', 'path_with_namespace': 'inkscape/inkscape', 'created_at': '2017-06-09T14:16:35.615Z', 'default_branch': 'master', 'tag_list': [], 'topics': [], 'ssh_url_to_repo': 'git@gitlab.com:inkscape/inkscape.git', 'http_url_to_repo': 'https://gitlab.com/inkscape/inkscape.git', 'web_url': 'https://gitlab.com/inkscape/inkscape', 'readme_url': 'https://gitlab.com/inkscape/inkscape/-/blob/master/README.md', 'avatar_url': 'https://gitlab.com/uploads/-/system/project/avatar/3472737/inkscape.png', 'forks_count': 900, 'star_count': 2512, 'last_activity_at': '2022-01-29T23:45:49.894Z', 'namespace': {'id': 470642, 'name': 'Inkscape', 'path': 'inkscape', 'kind': 'group', 'full_path': 'inkscape', 'parent_id': None, 'avatar_url': '/uploads/-/system/group/avatar/470642/inkscape.png', 'web_url': 'https://gitlab.com/groups/inkscape'}}, 'parent_ref': 'e371b2f826adcba316f2e64bbf2f697043373d0b', 'path': 'share/extensions', 'url': 'https://gitlab.com/inkscape/extensions.git'},
125+
'project': <class 'gitlab.v4.objects.projects.Project'> => {'id': 5833962, 'description': 'Python extensions for Inkscape core, separated out from main repository.', 'name': 'extensions', 'name_with_namespace': 'Inkscape / extensions', 'path': 'extensions', 'path_with_namespace': 'inkscape/extensions', 'created_at': '2018-03-22T00:29:09.053Z', 'default_branch': 'master', 'tag_list': ['addin', 'additional', 'addon', 'core', 'extension', 'inkscape', 'python'], 'topics': ['addin', 'additional', 'addon', 'core', 'extension', 'inkscape', 'python'], 'ssh_url_to_repo': 'git@gitlab.com:inkscape/extensions.git', 'http_url_to_repo': 'https://gitlab.com/inkscape/extensions.git', 'web_url': 'https://gitlab.com/inkscape/extensions', 'readme_url': 'https://gitlab.com/inkscape/extensions/-/blob/master/README.md', 'avatar_url': 'https://gitlab.com/uploads/-/system/project/avatar/5833962/addons.png', 'forks_count': 89, 'star_count': 41, 'last_activity_at': '2022-01-29T19:10:13.502Z', 'namespace': {'id': 470642, 'name': 'Inkscape', 'path': 'inkscape', 'kind': 'group', 'full_path': 'inkscape', 'parent_id': None, 'avatar_url': '/uploads/-/system/group/avatar/470642/inkscape.png', 'web_url': 'https://gitlab.com/groups/inkscape'}},
126+
'commit': <class 'gitlab.v4.objects.commits.ProjectCommit'> => {'id': '6c9b68507be427bffba23507bbaacf3f8a0f3752', 'short_id': '6c9b6850', 'created_at': '2021-11-28T22:23:47.000+00:00', 'parent_ids': ['fdda3f18b3ddda61a19f5046ce21a6e2147791f5', '8769b39a55f94d42ac0d9b24757540a88f2865cc'], 'title': "Merge branch 'add-issue-template-bug-report' into 'master'", 'message': "Merge branch 'add-issue-template-bug-report' into 'master'\n\nadd issue template for GitLab for bug reports\n\nSee merge request inkscape/extensions!377", 'author_name': 'Martin Owens', 'author_email': 'doctormo@geek-2.com', 'authored_date': '2021-11-28T22:23:47.000+00:00', 'committer_name': 'Martin Owens', 'committer_email': 'doctormo@geek-2.com', 'committed_date': '2021-11-28T22:23:47.000+00:00', 'trailers': {}, 'web_url': 'https://gitlab.com/inkscape/extensions/-/commit/6c9b68507be427bffba23507bbaacf3f8a0f3752', 'stats': {'additions': 25, 'deletions': 0, 'total': 25}, 'status': 'success', 'project_id': 5833962, 'last_pipeline': {'id': 417958828, 'iid': 924, 'project_id': 5833962, 'sha': '6c9b68507be427bffba23507bbaacf3f8a0f3752', 'ref': 'master', 'status': 'success', 'source': 'push', 'created_at': '2021-11-28T22:23:48.313Z', 'updated_at': '2021-11-28T22:31:49.083Z', 'web_url': 'https://gitlab.com/inkscape/extensions/-/pipelines/417958828'}, 'is_exact': True}
127+
}
128+
```
129+
130+
### `list_submodules(...)`
131+
Lists the info about the project submodules found in the `.gitmodules` file.
132+
```python
133+
list_project_submodules(
134+
project: Project,
135+
ref: Optional[str] = None) -> List[Submodule]
136+
```
137+
Parameters:
138+
- `project`: a `gitlab.v4.objects.Project` object
139+
- `ref`: (optional) a ref to a branch, commit, tag etc. Defaults to the
140+
HEAD of the project default branch.
141+
142+
Returns: list of `Submodule` objects
143+
144+
### class `Submodule`
145+
Represents the `.gitmodules` config of a submodule + adds info about the
146+
parent project
147+
148+
Attributes:
149+
- `parent_project: gitlab.v4.objects.Project`: project that uses the submodule
150+
- `parent_ref: str`: ref where the `.gitmodules` file was read
151+
- `name: str`: local name used by git for the submodule
152+
- `path: str`: local path pointing to the submodule directory in the project
153+
- `url: str`: URL linking to the location of the repo of the submodule (not
154+
necessarily Gitlab)
155+
156+
Example `str()` output:
157+
```
158+
<class 'Submodule'> => {'name': 'share/extensions', 'parent_project': <class 'gitlab.v4.objects.projects.Project'> => {'id': 3472737, 'description': 'Inkscape vector image editor', 'name': 'inkscape', 'name_with_namespace': 'Inkscape / inkscape', 'path': 'inkscape', 'path_with_namespace': 'inkscape/inkscape', 'created_at': '2017-06-09T14:16:35.615Z', 'default_branch': 'master', 'tag_list': [], 'topics': [], 'ssh_url_to_repo': 'git@gitlab.com:inkscape/inkscape.git', 'http_url_to_repo': 'https://gitlab.com/inkscape/inkscape.git', 'web_url': 'https://gitlab.com/inkscape/inkscape', 'readme_url': 'https://gitlab.com/inkscape/inkscape/-/blob/master/README.md', 'avatar_url': 'https://gitlab.com/uploads/-/system/project/avatar/3472737/inkscape.png', 'forks_count': 900, 'star_count': 2512, 'last_activity_at': '2022-01-29T23:45:49.894Z', 'namespace': {'id': 470642, 'name': 'Inkscape', 'path': 'inkscape', 'kind': 'group', 'full_path': 'inkscape', 'parent_id': None, 'avatar_url': '/uploads/-/system/group/avatar/470642/inkscape.png', 'web_url': 'https://gitlab.com/groups/inkscape'}}, 'parent_ref': 'e371b2f826adcba316f2e64bbf2f697043373d0b', 'path': 'share/extensions', 'url': 'https://gitlab.com/inkscape/extensions.git'}
159+
```
160+
161+
### `submodule_to_subproject(...)`
162+
Converts a `Submodule` object to a `Subproject` object, assuming it's
163+
hosted on Gitlab.
164+
165+
```python
166+
submodule_to_subproject(
167+
gitmodules_submodule: Submodule,
168+
gl: Union[Gitlab, ProjectManager],
169+
get_latest_commit_possible_if_not_found: bool = False,
170+
get_latest_commit_possible_ref: Optional[str] = None
171+
) -> Subproject
172+
```
173+
Parameters: See `iterate_subprojects(...)`

0 commit comments

Comments
 (0)