GitHub repo.への自動招待スクリプト
手作業ベースだと・・・
- コラボレーターのGitHubアカウントリストを作成
- 各リポのsettings/accessを開いて、
- 招待をかける
このような作業をリポの数とユーザーの数分だけ繰り返す。
自動化?
APIで行ってもいいと思いますがここはブラウザをシミュレートさせる方向で・・
Seleniumで自動化できないものか?
わたくしの環境
- Windows10
- python3をWin側にインストール
- firefox browser/geckodriver
事前にインストール
- selenium
- webdriver
まずこんな感じで始めました
import os
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.firefox.service import Service
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from webdriver_manager.firefox import GeckoDriverManager
import pickle
import time
# Initialize the WebDriver
driver = webdriver.Firefox(service=Service(GeckoDriverManager().install()))
wait = WebDriverWait(driver, 20) # Explicit wait
# Load cookies if they exist
try:
cookies = pickle.load(open("cookies.pkl", "rb"))
driver.get("https://github.com")
for cookie in cookies:
driver.add_cookie(cookie)
print("Cookies loaded successfully.")
except FileNotFoundError:
print("No cookies found, you will need to log in.")
次はリストの読み込み
# Users to invite
usernames_to_invite = [
]
login
try:
# Open GitHub login page
driver.get("https://github.com/login")
# Check if already logged in by verifying the presence of a specific element
if "login" in driver.current_url:
# Enter username and password from environment variables
username_input = wait.until(EC.presence_of_element_located((By.ID, "login_field")))
username_input.send_keys(os.environ["GITHUB_USERNAME"])
password_input = wait.until(EC.presence_of_element_located((By.ID, "password")))
password_input.send_keys(os.environ["GITHUB_PASSWORD"])
password_input.send_keys(Keys.RETURN)
# Wait for two-factor authentication if needed
time.sleep(15) # Adjust based on your 2FA input
# Save the session cookies
cookies = driver.get_cookies()
pickle.dump(cookies, open("cookies.pkl", "wb"))
print("Cookies saved successfully.")
リポジトリのユーザーページに移動します
((org))/((repo))
にはご自身の組織名とリポジトリを入力してください
repo_url = "https://github.com/((org))/((repo))"
driver.get(f"{repo_url}/settings/access")
ループ部分
for username in usernames_to_invite:
# Click the "Add people" button using its ID
add_people_button = wait.until(EC.element_to_be_clickable((By.ID, "dialog-show-add-access-dialog-user")))
add_people_button.click()
# Wait for the modal to open
time.sleep(2) # Increase wait time if necessary
# Use JavaScript to focus on the input field
invite_input = wait.until(EC.visibility_of_element_located((By.NAME, "member")))
driver.execute_script("arguments[0].scrollIntoView(true); arguments[0].focus();", invite_input)
invite_input.clear()
invite_input.send_keys(username)
# Wait for suggestions to load
time.sleep(2)
# Select the first suggestion
invite_input.send_keys(Keys.DOWN)
invite_input.send_keys(Keys.RETURN)
# Wait for role selection to appear
time.sleep(2)
# Select the "Write" role
write_role = wait.until(EC.element_to_be_clickable((By.XPATH, "//span[text()='Write']")))
write_role.click()
# Send Tab key twice to focus on the "Add to repository" button, then press Return
driver.find_element(By.TAG_NAME, "body").send_keys(Keys.TAB)
driver.find_element(By.TAG_NAME, "body").send_keys(Keys.TAB)
driver.find_element(By.TAG_NAME, "body").send_keys(Keys.RETURN)
# Wait a bit before inviting the next user
time.sleep(2)
print("Invitations sent successfully!")
except Exception as e:
print(f"An error occurred: {e}")
finally:
# Close the WebDriver
time.sleep(2)
driver.quit()
個人情報さらしてないよね
コード内で個人情報さらしているよとかあったら至急ご指摘ください!
リポジトリが複数なら
こちら側もループ回してください
工夫したこと
Users' role selection and "Add to repository" buttonへの遷移がとても苦労しました。前の画面でのキーボードアクションやらせようとしていたみたいで、壮絶な勘違いでした。
感想
時間をかけてでも作っておいてよかったと思います。
わりと人の入れ替わりがある組織なので、リポジトリにユーザーを招待するのも
大変といえば大変ですね。
手作業でも大したことないっちゃないけど、精神的に弱っているときとかにこのタスクが来ると 正直うんざりしていたので、これで年度初め(=4月)がすこし楽になるかもしれません。