|
4 | 4 | import sys |
5 | 5 | import urllib |
6 | 6 | from pathlib import Path |
| 7 | +import re |
| 8 | +import shlex |
| 9 | +import subprocess |
| 10 | +from tempfile import TemporaryDirectory |
7 | 11 | from subprocess import PIPE |
8 | 12 | from subprocess import run |
9 | 13 |
|
@@ -153,6 +157,112 @@ def get_activity( |
153 | 157 | return query_data |
154 | 158 |
|
155 | 159 |
|
| 160 | +def generate_all_activity_md( |
| 161 | + target, |
| 162 | + pattern=r'(v?\d+\.\d+\.\d+)$', |
| 163 | + kind=None, |
| 164 | + auth=None, |
| 165 | + tags=None, |
| 166 | + include_issues=False, |
| 167 | + include_opened=False, |
| 168 | + strip_brackets=False, |
| 169 | + branch=None, |
| 170 | +): |
| 171 | + """Generate a full markdown changelog of GitHub activity of a repo based on release tags. |
| 172 | +
|
| 173 | + Parameters |
| 174 | + ---------- |
| 175 | + target : string |
| 176 | + The GitHub organization/repo for which you want to grab recent issues/PRs. |
| 177 | + Can either be *just* and organization (e.g., `jupyter`) or a combination |
| 178 | + organization and repo (e.g., `jupyter/notebook`). If the former, all |
| 179 | + repositories for that org will be used. If the latter, only the specified |
| 180 | + repository will be used. Can also be a URL to a GitHub org or repo. |
| 181 | + pattern: str |
| 182 | + The expression used to match a release tag |
| 183 | + kind : ["issue", "pr"] | None |
| 184 | + Return only issues or PRs. If None, both will be returned. |
| 185 | + auth : string | None |
| 186 | + An authentication token for GitHub. If None, then the environment |
| 187 | + variable `GITHUB_ACCESS_TOKEN` will be tried. |
| 188 | + tags : list of strings | None |
| 189 | + A list of the tags to use in generating subsets of PRs for the markdown report. |
| 190 | + Must be one of: |
| 191 | +
|
| 192 | + ['enhancement', 'bugs', 'maintenance', 'documentation', 'api_change'] |
| 193 | +
|
| 194 | + If None, all of the above tags will be used. |
| 195 | + include_issues : bool |
| 196 | + Include Issues in the markdown output. Default is False. |
| 197 | + include_opened : bool |
| 198 | + Include a list of opened items in the markdown output. Default is False. |
| 199 | + strip_brackets : bool |
| 200 | + If True, strip any text between brackets at the beginning of the issue/PR title. |
| 201 | + E.g., [MRG], [DOC], etc. |
| 202 | + branch : string | None |
| 203 | + The branch or reference name to filter pull requests by |
| 204 | +
|
| 205 | + Returns |
| 206 | + ------- |
| 207 | + entry: str |
| 208 | + The markdown changelog entry for all of the release tags in the repo. |
| 209 | + """ |
| 210 | + with TemporaryDirectory() as td: |
| 211 | + |
| 212 | + subprocess.run(shlex.split(f'git clone git@github.com:{target}.git repo'), cwd=td) |
| 213 | + repo = os.path.join(td, 'repo') |
| 214 | + subprocess.run(shlex.split('git fetch upstream --tags'), cwd=repo) |
| 215 | + |
| 216 | + cmd = 'git log --tags --simplify-by-decoration --pretty="format:%h | %D"' |
| 217 | + data = subprocess.check_output(shlex.split(cmd), cwd=repo).decode('utf-8').splitlines() |
| 218 | + |
| 219 | + pattern = f'tag: {pattern}' |
| 220 | + |
| 221 | + def filter(datum): |
| 222 | + _, tag = datum |
| 223 | + return re.match(pattern, tag) is not None |
| 224 | + |
| 225 | + data = [d.split(' | ') for (i, d) in enumerate(data)] |
| 226 | + data = [d for d in data if filter(d)] |
| 227 | + output = "" |
| 228 | + |
| 229 | + for i in range(len(data) - 1): |
| 230 | + curr_data = data[i] |
| 231 | + prev_data = data[i + 1] |
| 232 | + |
| 233 | + since = prev_data[0] |
| 234 | + until = curr_data[0] |
| 235 | + |
| 236 | + match = re.search(pattern, curr_data[1]) |
| 237 | + tag = match.groups()[0] |
| 238 | + |
| 239 | + print(f'\n({i + 1}/{len(data)})', since, until, tag, file=sys.stderr) |
| 240 | + md = generate_activity_md( |
| 241 | + target, |
| 242 | + since=since, |
| 243 | + heading_level=2, |
| 244 | + until=until, |
| 245 | + auth=auth, |
| 246 | + kind=kind, |
| 247 | + include_issues=include_issues, |
| 248 | + include_opened=include_opened, |
| 249 | + strip_brackets=strip_brackets, |
| 250 | + branch=branch |
| 251 | + ) |
| 252 | + |
| 253 | + if not md: |
| 254 | + continue |
| 255 | + |
| 256 | + # Replace the header line with our version tag |
| 257 | + md = '\n'.join(md.splitlines()[1:]) |
| 258 | + |
| 259 | + output += f""" |
| 260 | +## {tag} |
| 261 | +{md} |
| 262 | +""" |
| 263 | + return output |
| 264 | + |
| 265 | + |
156 | 266 | def generate_activity_md( |
157 | 267 | target, |
158 | 268 | since=None, |
@@ -212,9 +322,8 @@ def generate_activity_md( |
212 | 322 |
|
213 | 323 | Returns |
214 | 324 | ------- |
215 | | - query_data : pandas DataFrame |
216 | | - A munged collection of data returned from your query. This |
217 | | - will be a combination of issues and PRs. |
| 325 | + entry: str |
| 326 | + The markdown changelog entry |
218 | 327 | """ |
219 | 328 | org, repo = _parse_target(target) |
220 | 329 |
|
@@ -574,3 +683,4 @@ def _get_latest_tag(): |
574 | 683 | out = run("git describe --tags".split(), stdout=PIPE) |
575 | 684 | tag = out.stdout.decode().rsplit("-", 2)[0] |
576 | 685 | return tag |
| 686 | + |
0 commit comments