github-org-manager 0.7.6__tar.gz → 0.7.7__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.
- {github_org_manager-0.7.6 → github_org_manager-0.7.7}/PKG-INFO +11 -18
- {github_org_manager-0.7.6 → github_org_manager-0.7.7}/gh_org_mgr/__init__.py +1 -1
- {github_org_manager-0.7.6 → github_org_manager-0.7.7}/gh_org_mgr/_config.py +20 -19
- {github_org_manager-0.7.6 → github_org_manager-0.7.7}/gh_org_mgr/_gh_api.py +10 -11
- {github_org_manager-0.7.6 → github_org_manager-0.7.7}/gh_org_mgr/_gh_org.py +114 -115
- {github_org_manager-0.7.6 → github_org_manager-0.7.7}/gh_org_mgr/_helpers.py +19 -21
- {github_org_manager-0.7.6 → github_org_manager-0.7.7}/gh_org_mgr/_setup_team.py +11 -9
- {github_org_manager-0.7.6 → github_org_manager-0.7.7}/gh_org_mgr/_stats.py +36 -37
- {github_org_manager-0.7.6 → github_org_manager-0.7.7}/gh_org_mgr/manage.py +9 -8
- github_org_manager-0.7.7/pyproject.toml +116 -0
- github_org_manager-0.7.6/LICENSE.txt +0 -202
- github_org_manager-0.7.6/LICENSES/Apache-2.0.txt +0 -202
- github_org_manager-0.7.6/LICENSES/CC-BY-4.0.txt +0 -156
- github_org_manager-0.7.6/LICENSES/CC0-1.0.txt +0 -121
- github_org_manager-0.7.6/LICENSES/MIT.txt +0 -9
- github_org_manager-0.7.6/pyproject.toml +0 -73
- {github_org_manager-0.7.6 → github_org_manager-0.7.7}/README.md +0 -0
|
@@ -1,35 +1,29 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: github-org-manager
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.7
|
|
4
4
|
Summary: Manage a GitHub Organization, its teams, repository permissions, and more
|
|
5
|
-
License: Apache-2.0
|
|
6
|
-
License-File: LICENSE.txt
|
|
7
|
-
License-File: LICENSES/Apache-2.0.txt
|
|
8
|
-
License-File: LICENSES/CC-BY-4.0.txt
|
|
9
|
-
License-File: LICENSES/CC0-1.0.txt
|
|
10
|
-
License-File: LICENSES/MIT.txt
|
|
11
5
|
Keywords: github,github-management,permissions,access-control
|
|
12
6
|
Author: Max Mehl
|
|
13
|
-
Author-email: max.mehl@deutschebahn.com
|
|
14
|
-
|
|
7
|
+
Author-email: Max Mehl <max.mehl@deutschebahn.com>
|
|
8
|
+
License-Expression: Apache-2.0
|
|
15
9
|
Classifier: Development Status :: 5 - Production/Stable
|
|
16
10
|
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Topic :: Software Development :: Version Control :: Git
|
|
12
|
+
Classifier: Topic :: Utilities
|
|
17
13
|
Classifier: Intended Audience :: Developers
|
|
18
14
|
Classifier: Intended Audience :: System Administrators
|
|
19
|
-
Classifier: License :: OSI Approved :: Apache Software License
|
|
20
15
|
Classifier: Programming Language :: Python :: 3
|
|
21
16
|
Classifier: Programming Language :: Python :: 3.10
|
|
22
17
|
Classifier: Programming Language :: Python :: 3.11
|
|
23
18
|
Classifier: Programming Language :: Python :: 3.12
|
|
24
19
|
Classifier: Programming Language :: Python :: 3.13
|
|
25
20
|
Classifier: Programming Language :: Python :: 3.14
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
Requires-Dist:
|
|
29
|
-
Requires-Dist:
|
|
30
|
-
Requires-Dist:
|
|
31
|
-
Requires-
|
|
32
|
-
Requires-Dist: requests (>=2.32.5,<3.0.0)
|
|
21
|
+
Requires-Dist: pygithub>=2.8.1,<3
|
|
22
|
+
Requires-Dist: pyyaml>=6.0.3,<7
|
|
23
|
+
Requires-Dist: requests>=2.32.5,<3
|
|
24
|
+
Requires-Dist: python-slugify>=8.0.4,<9
|
|
25
|
+
Requires-Dist: jsonschema>=4.25.1,<5
|
|
26
|
+
Requires-Python: >=3.10, <4
|
|
33
27
|
Project-URL: Repository, https://github.com/OpenRailAssociation/github-org-manager
|
|
34
28
|
Description-Content-Type: text/markdown
|
|
35
29
|
|
|
@@ -125,4 +119,3 @@ The content of this repository is licensed under the [Apache 2.0 license](https:
|
|
|
125
119
|
There may be components under different, but compatible licenses or from different copyright holders. The project is REUSE compliant which makes these portions transparent. You will find all used licenses in the [LICENSES](./LICENSES/) directory.
|
|
126
120
|
|
|
127
121
|
The project is has been started by the [OpenRail Association](https://openrailassociation.org). You are welcome to [contribute](./CONTRIBUTING.md)!
|
|
128
|
-
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
#
|
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
|
|
5
|
-
"""Handling the private and organisation configuration"""
|
|
5
|
+
"""Handling the private and organisation configuration."""
|
|
6
6
|
|
|
7
7
|
import logging
|
|
8
|
-
import os
|
|
9
8
|
import re
|
|
10
9
|
import sys
|
|
10
|
+
from pathlib import Path
|
|
11
11
|
from typing import Any
|
|
12
12
|
|
|
13
13
|
import yaml
|
|
@@ -100,21 +100,22 @@ TEAM_CONFIG_SCHEMA = {
|
|
|
100
100
|
|
|
101
101
|
|
|
102
102
|
def _find_matching_files(directory: str, pattern: str, only_one: bool = False) -> list[str]:
|
|
103
|
-
"""
|
|
104
|
-
Get all files in a directory matching a regex pattern.
|
|
103
|
+
"""Get all files in a directory matching a regex pattern.
|
|
105
104
|
|
|
106
105
|
Args:
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
106
|
+
directory: Path to the directory.
|
|
107
|
+
pattern: Regular expression pattern to match filenames.
|
|
108
|
+
only_one: Whether only the first match shall be returned.
|
|
110
109
|
|
|
111
110
|
Returns:
|
|
112
|
-
|
|
111
|
+
List of filenames matching the pattern.
|
|
113
112
|
"""
|
|
114
113
|
matching_files: list[str] = []
|
|
115
114
|
|
|
115
|
+
dir_path = Path(directory)
|
|
116
|
+
|
|
116
117
|
# Validate directory existence
|
|
117
|
-
if not
|
|
118
|
+
if not dir_path.is_dir():
|
|
118
119
|
logging.error("'%s' is not a valid directory", directory)
|
|
119
120
|
|
|
120
121
|
else:
|
|
@@ -122,16 +123,15 @@ def _find_matching_files(directory: str, pattern: str, only_one: bool = False) -
|
|
|
122
123
|
regex_pattern = re.compile(pattern + "$")
|
|
123
124
|
|
|
124
125
|
# Traverse the directory and find matching files
|
|
125
|
-
for
|
|
126
|
-
if regex_pattern.match(
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
matching_files.append(file_path)
|
|
126
|
+
for entry in dir_path.iterdir():
|
|
127
|
+
if regex_pattern.match(entry.name):
|
|
128
|
+
if entry.is_file():
|
|
129
|
+
matching_files.append(str(entry))
|
|
130
130
|
else:
|
|
131
131
|
logging.warning(
|
|
132
132
|
"'%s' looks like a file we searched for, but it's not. "
|
|
133
133
|
"Will not consider its contents",
|
|
134
|
-
|
|
134
|
+
entry,
|
|
135
135
|
)
|
|
136
136
|
|
|
137
137
|
if only_one and len(matching_files) > 1:
|
|
@@ -154,7 +154,7 @@ def _find_matching_files(directory: str, pattern: str, only_one: bool = False) -
|
|
|
154
154
|
|
|
155
155
|
|
|
156
156
|
def _read_config_file(file: str) -> dict:
|
|
157
|
-
"""Return dict of a YAML file"""
|
|
157
|
+
"""Return dict of a YAML file."""
|
|
158
158
|
logging.debug("Attempting to parse YAML file %s", file)
|
|
159
159
|
with open(file, encoding="UTF-8") as yamlfile:
|
|
160
160
|
config: dict = yaml.safe_load(yamlfile)
|
|
@@ -166,7 +166,7 @@ def _read_config_file(file: str) -> dict:
|
|
|
166
166
|
|
|
167
167
|
|
|
168
168
|
def _validate_config_schema(file: str, cfg: dict, schema: dict) -> None:
|
|
169
|
-
"""Validate the config against a JSON schema"""
|
|
169
|
+
"""Validate the config against a JSON schema."""
|
|
170
170
|
try:
|
|
171
171
|
validate(instance=cfg, schema=schema, format_checker=FormatChecker())
|
|
172
172
|
except ValidationError as e:
|
|
@@ -177,11 +177,12 @@ def _validate_config_schema(file: str, cfg: dict, schema: dict) -> None:
|
|
|
177
177
|
|
|
178
178
|
def parse_config_files(path: str) -> tuple[dict[str, str | dict[str, str]], dict, dict]:
|
|
179
179
|
"""Parse all relevant files in the configuration directory. Returns a tuple
|
|
180
|
-
of org config, app config, and merged teams config
|
|
180
|
+
of org config, app config, and merged teams config.
|
|
181
|
+
"""
|
|
181
182
|
# Find the relevant config files for app, org, and teams
|
|
182
183
|
cfg_app_files = _find_matching_files(path, APP_CONFIG_FILE, only_one=True)
|
|
183
184
|
cfg_org_files = _find_matching_files(path, ORG_CONFIG_FILE, only_one=True)
|
|
184
|
-
cfg_teams_files = _find_matching_files(
|
|
185
|
+
cfg_teams_files = _find_matching_files(str(Path(path) / TEAM_CONFIG_DIR), TEAM_CONFIG_FILES)
|
|
185
186
|
|
|
186
187
|
# Read and parse config files for app and org
|
|
187
188
|
cfg_app = _read_config_file(cfg_app_files[0])
|
|
@@ -2,20 +2,21 @@
|
|
|
2
2
|
#
|
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
|
|
5
|
-
"""
|
|
6
|
-
Functions for interacting with the GitHub API
|
|
7
|
-
"""
|
|
5
|
+
"""Functions for interacting with the GitHub API."""
|
|
8
6
|
|
|
7
|
+
import contextlib
|
|
9
8
|
import logging
|
|
10
9
|
import os
|
|
11
10
|
import sys
|
|
11
|
+
from http import HTTPStatus
|
|
12
|
+
from typing import Any
|
|
12
13
|
|
|
13
14
|
import requests
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
def get_github_secrets_from_env(env_variable: str, secret: str | int) -> str:
|
|
17
|
-
"""Get GitHub secrets from config or environment, while environment overrides"""
|
|
18
|
-
if
|
|
18
|
+
"""Get GitHub secrets from config or environment, while environment overrides."""
|
|
19
|
+
if os.environ.get(env_variable):
|
|
19
20
|
logging.debug("GitHub secret taken from environment variable %s", env_variable)
|
|
20
21
|
secret = os.environ[env_variable]
|
|
21
22
|
elif secret:
|
|
@@ -25,8 +26,8 @@ def get_github_secrets_from_env(env_variable: str, secret: str | int) -> str:
|
|
|
25
26
|
|
|
26
27
|
|
|
27
28
|
# Function to execute GraphQL query
|
|
28
|
-
def run_graphql_query(query, variables, token):
|
|
29
|
-
"""Run a query against the GitHub GraphQL API"""
|
|
29
|
+
def run_graphql_query(query: str, variables: dict[str, Any], token: str) -> dict | str:
|
|
30
|
+
"""Run a query against the GitHub GraphQL API."""
|
|
30
31
|
headers = {"Authorization": f"Bearer {token}"}
|
|
31
32
|
request = requests.post(
|
|
32
33
|
"https://api.github.com/graphql",
|
|
@@ -37,12 +38,10 @@ def run_graphql_query(query, variables, token):
|
|
|
37
38
|
|
|
38
39
|
# Get JSON result
|
|
39
40
|
json_return = "No valid JSON return"
|
|
40
|
-
|
|
41
|
+
with contextlib.suppress(requests.exceptions.JSONDecodeError):
|
|
41
42
|
json_return = request.json()
|
|
42
|
-
except requests.exceptions.JSONDecodeError:
|
|
43
|
-
pass
|
|
44
43
|
|
|
45
|
-
if request.status_code ==
|
|
44
|
+
if request.status_code == HTTPStatus.OK:
|
|
46
45
|
return json_return
|
|
47
46
|
|
|
48
47
|
# Debug information in case of errors
|