0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GitHubリポジトリ招待の自動化

Last updated at Posted at 2024-11-13

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月)がすこし楽になるかもしれません。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?