Skip to content

Commit 41142e5

Browse files
committed
TutorTask555: Minor code changes and documentation
Pre-commit checks: All checks passed ✅
1 parent 9d1af74 commit 41142e5

3 files changed

Lines changed: 116 additions & 1 deletion
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<!-- toc -->
2+
3+
- [`TutorialsTask76_automate_collaborator_invitations_from_gsheet.py` Explanation](#tutorialstask76_automate_collaborator_invitations_from_gsheetpy-explanation)
4+
* [Public interface](#public-interface)
5+
* [Execution flow](#execution-flow)
6+
* [Key implementation choices](#key-implementation-choices)
7+
8+
<!-- tocstop -->
9+
10+
# `TutorialsTask76_automate_collaborator_invitations_from_gsheet.py` Explanation
11+
12+
This document is about how this script works and flows.
13+
14+
## Public interface
15+
16+
```bash
17+
TutorialsTask76_automate_collaborator_invitations_from_gsheet.py \
18+
--drive_url <google‑sheet‑url> \
19+
--gh_token <github‑pat> \
20+
--org_name <github‑org> \
21+
--repo_name <repo> \
22+
[--log_level 20]
23+
```
24+
25+
- **`drive_url`** – Spreadsheet containing a `GitHub user` column.
26+
- **`gh_token`** – PAT with `repo` scope (or fine‑grained "Repository
27+
administration").
28+
- **`org_name` / `repo_name`** – identify the target repository.
29+
- **`log_level`** – standard Python numeric levels (10 = DEBUG, 20 = INFO).
30+
31+
The module can also be imported:
32+
33+
```python
34+
import DATA605.TutorialsTask76_automate_collaborator_invitations_from_gsheet as dtacifrgs
35+
usernames = dtacifrgs.extract_usernames_from_gsheet(sheet_url)
36+
dtacifrgs.send_invitations(usernames, token, repo, org)
37+
```
38+
39+
## Execution flow
40+
41+
```mermaid
42+
flowchart TD
43+
A[parse CLI args] --> B[init logging]
44+
B --> C[extract_usernames_from_gsheet]
45+
C -->|"list[str]"| D[send_invitations]
46+
D --> E{already collaborator?}
47+
E -- yes --> F[skip + log]
48+
E -- no --> G[_invite wrapper]
49+
G -->|add_to_collaborators| H[GitHub API]
50+
subgraph Rate-limit
51+
direction TB
52+
G
53+
note("@ratelimit.limits 50 calls / 24h → sleep_and_retry if exceeded")
54+
end
55+
```
56+
57+
## Key implementation choices
58+
59+
- **Dependency auto‑install** – the small `pip install` loop avoids a separate
60+
requirements file when the script runs in fresh environments, at the cost of
61+
start‑up time.
62+
- **Service‑account auth** – credentials path is hard‑coded but can be fed via
63+
env‑var if desired; the helper supports both.
64+
- **Idempotence**`repo.has_in_collaborators()` prevents duplicate invites
65+
counting toward the daily quota.
66+
- **Sleep strategy** – we rely entirely on `ratelimit.sleep_and_retry`, so the
67+
process may block for hours. Even if the process is terminated, the
68+
idempotence measure will prevent the added names from contributing to the
69+
quota
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<!-- toc -->
2+
3+
- [Inviting GitHub Collaborators from Google Sheets](#inviting-github-collaborators-from-google-sheets)
4+
* [Prerequisites](#prerequisites)
5+
* [Running the script](#running-the-script)
6+
7+
<!-- tocstop -->
8+
9+
# Inviting GitHub Collaborators from Google Sheets
10+
11+
## Prerequisites
12+
13+
- **GitHub personal‑access token** (PAT) with the classic **`repo`** scope, or a
14+
fine‑grained token granting Repository administration for the target
15+
repository.
16+
17+
```bash
18+
export GH_PAT=github_pat_...
19+
```
20+
21+
- **Google service‑account JSON key**
22+
- Create a service account in Google Cloud.
23+
- Enable the _Drive API_ on that project.
24+
- Download the key as JSON and place it at `/app/DATA605/google_secret.json`
25+
(or change the path in the script).
26+
- Share the spreadsheet with the service‑account address.
27+
28+
## Running the script
29+
30+
```bash
31+
python automate_collaborator_invitations.py \
32+
--drive_url "https://docs.google.com/spreadsheets/d/..." \
33+
--gh_token "$GH_PAT" \
34+
--org_name causify-ai \
35+
--repo_name tutorials \
36+
--log_level 20 # INFO
37+
```
38+
39+
- **`--drive_url`** – full URL of the Google Sheet containing a column named
40+
`GitHub user`.
41+
- **`--gh_token`** – your PAT (or set `GH_PAT` and pass `--gh_token "$GH_PAT"`).
42+
- **`--org_name` / `--repo_name`** – where the invitations will be sent.
43+
- Increase `--log_level` to `10` for verbose debug logs.

DATA605/TutorialsTask76_automate_collaborator_invitations_from_gsheet.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ def send_invitations(
9797
repo = gh.get_repo(f"{org_name}/{repo_name}")
9898
# Send invitations.
9999
for username in usernames:
100+
if repo.has_in_collaborators(username):
101+
_LOG.info("User %s is already a collaborator", username)
102+
continue
100103
try:
101104
_invite(repo, username)
102105
except github.GithubException as exc:
@@ -107,7 +110,7 @@ def send_invitations(
107110

108111
def _parse() -> argparse.Namespace:
109112
parser = argparse.ArgumentParser(
110-
description="Invite GitHub collaborators from a Google Sheet, respecting the 50‑per‑day limit.", # noqa: E501
113+
description="Invite GitHub collaborators from a Google Sheet, respecting the 50‑per‑day limit.",
111114
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
112115
)
113116
parser.add_argument(

0 commit comments

Comments
 (0)