Skip to content

Commit 64aa1d6

Browse files
Copilotxadupre
andauthored
Support a list of repos in github_stat_pr notebook
Agent-Logs-Url: https://github.com/sdpython/teachpyx/sessions/a014fc92-18dd-45ab-bfde-5ceac46f5764 Co-authored-by: xadupre <22452781+xadupre@users.noreply.github.com>
1 parent 26a2b56 commit 64aa1d6

1 file changed

Lines changed: 47 additions & 14 deletions

File tree

_doc/practice/years/2026/github_stat_pr.ipynb

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"# Nombre de PR fusionnées par personne agrégées par semaine\n",
88
"\n",
99
"Ce notebook récupère, via l'API GitHub, le nombre de *pull requests* (PR) fusionnées\n",
10-
"pour un dépôt donné, les regroupe par auteur et par semaine sur l'année écoulée,\n",
10+
"pour **un ou plusieurs dépôts**, les regroupe par auteur et par semaine sur l'année écoulée,\n",
1111
"puis affiche le résultat sous forme de graphique.\n",
1212
"\n",
1313
"**Dépendances :** `requests`, `pandas`, `matplotlib`.\n",
@@ -43,7 +43,8 @@
4343
"source": [
4444
"## Paramètres\n",
4545
"\n",
46-
"Modifiez `OWNER` et `REPO` pour pointer vers le dépôt de votre choix."
46+
"Modifiez `REPOS` pour lister les dépôts à analyser sous la forme\n",
47+
"`[(owner, repo), ...]`. Vous pouvez ajouter autant de dépôts que vous le souhaitez."
4748
]
4849
},
4950
{
@@ -52,8 +53,10 @@
5253
"metadata": {},
5354
"outputs": [],
5455
"source": [
55-
"OWNER = \"sdpython\"\n",
56-
"REPO = \"teachpyx\"\n",
56+
"REPOS = [\n",
57+
" (\"sdpython\", \"teachpyx\"),\n",
58+
" # (\"sdpython\", \"onnx-extended\"), # ajoutez d'autres dépôts ici\n",
59+
"]\n",
5760
"\n",
5861
"# Jeton d'authentification GitHub (optionnel mais recommandé)\n",
5962
"GITHUB_TOKEN = os.environ.get(\"GITHUB_TOKEN\", \"\")"
@@ -69,7 +72,8 @@
6972
"avec `state=closed`. On filtre ensuite les PR dont le champ `merged_at` est renseigné\n",
7073
"et dont la date de fusion est dans les 12 derniers mois.\n",
7174
"\n",
72-
"La pagination est gérée via le paramètre `page`."
75+
"La pagination est gérée via le paramètre `page`.\n",
76+
"La boucle principale itère sur chaque dépôt listé dans `REPOS`."
7377
]
7478
},
7579
{
@@ -79,12 +83,12 @@
7983
"outputs": [],
8084
"source": [
8185
"def fetch_merged_prs(owner: str, repo: str, token: str = \"\") -> list[dict]:\n",
82-
" \"\"\"Récupère toutes les PR fusionnées au cours de l'année écoulée.\n",
86+
" \"\"\"Récupère toutes les PR fusionnées au cours de l'année écoulée pour un dépôt.\n",
8387
"\n",
8488
" :param owner: propriétaire du dépôt GitHub\n",
8589
" :param repo: nom du dépôt GitHub\n",
8690
" :param token: jeton d'authentification GitHub (optionnel)\n",
87-
" :return: liste de dictionnaires avec les champs ``author``, ``merged_at``\n",
91+
" :return: liste de dictionnaires avec les champs ``author``, ``merged_at``, ``repo``\n",
8892
" \"\"\"\n",
8993
" headers = {\"Accept\": \"application/vnd.github+json\"}\n",
9094
" if token:\n",
@@ -135,7 +139,7 @@
135139
" stop = True\n",
136140
" break\n",
137141
" author = (pr.get(\"user\") or {}).get(\"login\", \"unknown\")\n",
138-
" results.append({\"author\": author, \"merged_at\": merged_dt})\n",
142+
" results.append({\"author\": author, \"merged_at\": merged_dt, \"repo\": f\"{owner}/{repo}\"})\n",
139143
"\n",
140144
" if stop:\n",
141145
" break\n",
@@ -145,8 +149,13 @@
145149
" return results\n",
146150
"\n",
147151
"\n",
148-
"merged_prs = fetch_merged_prs(OWNER, REPO, GITHUB_TOKEN)\n",
149-
"print(f\"{len(merged_prs)} PR(s) fusionnée(s) trouvée(s) au cours de l'année écoulée.\")"
152+
"merged_prs = []\n",
153+
"for owner, repo in REPOS:\n",
154+
" prs = fetch_merged_prs(owner, repo, GITHUB_TOKEN)\n",
155+
" print(f\" {owner}/{repo} : {len(prs)} PR(s) fusionnée(s)\")\n",
156+
" merged_prs.extend(prs)\n",
157+
"\n",
158+
"print(f\"Total : {len(merged_prs)} PR(s) fusionnée(s) sur l'ensemble des dépôts.\")"
150159
]
151160
},
152161
{
@@ -171,7 +180,7 @@
171180
" df[\"week\"] = df[\"merged_at\"].dt.to_period(\"W\").dt.start_time\n",
172181
"\n",
173182
" weekly = (\n",
174-
" df.groupby([\"author\", \"week\"])\n",
183+
" df.groupby([\"repo\", \"author\", \"week\"])\n",
175184
" .size()\n",
176185
" .reset_index(name=\"pr_count\")\n",
177186
" )\n",
@@ -182,7 +191,7 @@
182191
"cell_type": "markdown",
183192
"metadata": {},
184193
"source": [
185-
"## Tableau croisé (auteur × semaine)"
194+
"## Tableau croisé (auteur × semaine, agrégé sur tous les dépôts)"
186195
]
187196
},
188197
{
@@ -192,6 +201,7 @@
192201
"outputs": [],
193202
"source": [
194203
"if not df.empty:\n",
204+
" # Agrégation sur tous les dépôts\n",
195205
" pivot = weekly.pivot_table(\n",
196206
" index=\"author\", columns=\"week\", values=\"pr_count\", aggfunc=\"sum\", fill_value=0\n",
197207
" )\n",
@@ -200,6 +210,29 @@
200210
" pivot"
201211
]
202212
},
213+
{
214+
"cell_type": "markdown",
215+
"metadata": {},
216+
"source": [
217+
"## Tableau croisé par dépôt"
218+
]
219+
},
220+
{
221+
"cell_type": "code",
222+
"execution_count": null,
223+
"metadata": {},
224+
"outputs": [],
225+
"source": [
226+
"if not df.empty and len(REPOS) > 1:\n",
227+
" for repo_name, grp in weekly.groupby(\"repo\"):\n",
228+
" pvt = grp.pivot_table(\n",
229+
" index=\"author\", columns=\"week\", values=\"pr_count\", aggfunc=\"sum\", fill_value=0\n",
230+
" )\n",
231+
" pvt = pvt.loc[pvt.sum(axis=1).sort_values(ascending=False).index]\n",
232+
" print(f\"\\n=== {repo_name} ===\")\n",
233+
" display(pvt)"
234+
]
235+
},
203236
{
204237
"cell_type": "markdown",
205238
"metadata": {},
@@ -234,7 +267,7 @@
234267
" plt.xticks(rotation=45, ha=\"right\")\n",
235268
" ax.set_xlabel(\"Semaine\")\n",
236269
" ax.set_ylabel(\"Nombre de PR fusionnées\")\n",
237-
" ax.set_title(f\"PR fusionnées par semaine — {OWNER}/{REPO}\")\n",
270+
" repos_label = \", \".join(f\"{o}/{r}\" for o, r in REPOS)\n ax.set_title(f\"PR fusionnées par semaine — {repos_label}\")\n",
238271
" ax.legend(loc=\"upper left\", bbox_to_anchor=(1, 1), title=\"Auteur\")\n",
239272
" plt.tight_layout()\n",
240273
" plt.show()"
@@ -269,7 +302,7 @@
269302
" [str(d)[:10] for d in pivot.columns[::step]], rotation=45, ha=\"right\"\n",
270303
" )\n",
271304
"\n",
272-
" ax.set_title(f\"Heatmap des PR fusionnées — {OWNER}/{REPO}\")\n",
305+
" repos_label = \", \".join(f\"{o}/{r}\" for o, r in REPOS)\n ax.set_title(f\"Heatmap des PR fusionnées — {repos_label}\")\n",
273306
" ax.set_xlabel(\"Semaine\")\n",
274307
" ax.set_ylabel(\"Auteur\")\n",
275308
" plt.tight_layout()\n",

0 commit comments

Comments
 (0)