def main(): p = ArgumentParser(description="mass add team members to repos, optionally creating new repos") p.add_argument("fn", help=".xlsx with group info") p.add_argument("oauth", help="Oauth file") p.add_argument("-stem", help="beginning of repo names", default="") p.add_argument("-orgname", help="Github Organization", required=True) p.add_argument("-col", help="columns for Username, teamname", nargs="+", required=True) p.add_argument("-private", help="create private repos", action="store_true") p.add_argument("-create", help="create repo if not existing", action="store_true") p = p.parse_args() fn = Path(p.fn).expanduser() if fn.suffix in (".xls", ".xlsx"): teams = pandas.read_excel(fn, usecols=p.col).squeeze().dropna() elif fn.suffix == ".csv": teams = pandas.read_csv(fn, usecols=p.col).squeeze().dropna() else: raise ValueError(f"Unknown file type {fn}") if not teams.ndim == 2: raise ValueError( "need to have member names and team names. Check that -col argument matches spreadsheet." ) # %% op, sess = connect(p.oauth, p.orgname) check_api_limit(sess) adder(teams, p.stem, p.private, p.create, op, sess)
def main(oauth: Path, orgname: str, stem: str): # %% authentication user, sess = gb.connect(oauth) assert isinstance(user, github.AuthenticatedUser.AuthenticatedUser ), "unwatch is for users only, not orgs" gb.check_api_limit(sess) # %% get organization handle org = gb.user_or_org(sess, orgname) # %% prepare to loop over repos repos = gb.get_repos(org) to_act = [ repo for repo in repos if user.has_in_watched(repo) and repo.name.startswith(stem) ] if not to_act: raise SystemExit( f"There were no repos left to unwatch with {stem} in {orgname}") print("\ntype affirmative to UNWATCH", "\n".join([repo.full_name for repo in to_act])) if input() != "affirmative": raise SystemExit("Aborted") for repo in to_act: user.remove_from_watched(repo) print("UnWatched:", repo.full_name)
def main(): p = ArgumentParser( description= "mass add team members to repos, optionally creating new repos") p.add_argument("fn", help=".xlsx with group info") p.add_argument("oauth", help="Oauth file") p.add_argument("-orgname", help="Github Organization", required=True) p.add_argument("-col", help="column for GitHub Username", nargs="+", required=True) p = p.parse_args() fn = Path(p.fn).expanduser() if fn.suffix in (".xls", ".xlsx"): users = pandas.read_excel(fn, usecols=p.col).squeeze().dropna() elif fn.suffix == ".csv": users = pandas.read_csv(fn, usecols=p.col).squeeze().dropna() else: raise ValueError(f"Unknown file type {fn}") if not users.ndim == 1: raise ValueError( "need to have member names. Check that -col argument matches spreadsheet." ) # %% op, sess = connect(p.oauth, p.orgname) check_api_limit(sess) adder(users, op, sess)
def main(): p = ArgumentParser(description="List user/organization repos") p.add_argument("user", help="Git remote username / organization name") p.add_argument("oauth", help="Oauth filename", nargs="?") p.add_argument("-p", "--pattern", help="only repos with name starting with this string") p.add_argument("-settings", help="open settings page for each repo", action="store_true") p.add_argument("-alerts", help="open alerts page for each repo", action="store_true") P = p.parse_args() # %% authentication sess = gb.session(P.oauth) gb.check_api_limit(sess) # %% get user / organization handle userorg = gb.user_or_org(sess, P.user) # %% prepare to loop over repos repos = gb.get_repos(userorg) if P.pattern: repos = (repo for repo in repos if repo.name.startswith(P.pattern)) for repo in repos: print(repo.full_name) if P.settings: webbrowser.open_new_tab("https://github.com/" + repo.full_name + "/settings") if P.alerts: webbrowser.open_new_tab("https://github.com/" + repo.full_name + "/network/alerts")
def main(): p = ArgumentParser( description="Set Private GitHub repos for a user/organization with repo names matching pattern" ) p.add_argument("userorgname", help="GitHub username / organizations") p.add_argument("oauth", help="Oauth filename") p.add_argument("pattern", help="make private repos with name starting with this string") P = p.parse_args() # %% authentication sess = gb.session(P.oauth) gb.check_api_limit(sess) # %% get user / organization handle userorg = gb.user_or_org(sess, P.userorgname) # %% prepare to loop over repos repos = gb.get_repos(userorg) to_act = [repo for repo in repos if repo.name.startswith(P.pattern) and not repo.private] if not to_act: raise SystemExit( f"There were no repos left to make private with {P.pattern} in {P.userorgname}" ) print("\ntype affirmative to make PRIVATE", "\n".join([repo.full_name for repo in to_act])) if input() != "affirmative": raise SystemExit("Aborted") for repo in to_act: repo.edit(private=True) print("private:", repo.full_name)
def main(): p = ArgumentParser(description="List organziation repos not in any team") p.add_argument("oauth", help="Oauth file") p.add_argument("orgname", help="Github Organization") p.add_argument("-stem", help="repos startin with this") p.add_argument("-put_team", help="put matching repos in this team") p = p.parse_args() op, sess = gb.connect_github(p.oauth, p.orgname) gb.check_api_limit(sess) lister(op, sess, p.stem, p.put_team)
def main(username: str, oauth: str, stem: str): # %% authentication sess = gb.session(P.oauth) gb.check_api_limit(sess) # %% get user / organization handle userorg = gb.user_or_org(sess, P.user) # %% prepare to loop over repos repos = gb.get_repos(userorg) to_act = (repo for repo in repos if repo.name.startswith(stem) and not repo.archived) for repo in to_act: print(repo.full_name)
def main(): p = ArgumentParser(description="add staff to teams") p.add_argument("oauth", help="Oauth file") p.add_argument("orgname", help="Github Organization") p.add_argument("-stem", help="repos startin with this", required=True) p.add_argument("-staff", help="put matching repos in this team", nargs="+", required=True) p = p.parse_args() op, sess = gb.connect_github(p.oauth, p.orgname) gb.check_api_limit(sess) adder(op, sess, p.stem, p.staff)
def main(): p = ArgumentParser(description='Set all collaborator permission to "read"') p.add_argument("user", help="GitHub username / organizations") p.add_argument("oauth", help="Oauth filename") p.add_argument("pattern", help="modify repos with name starting with this string") p.add_argument("--omit", help="dont consider these admins", nargs="+") P = p.parse_args() # %% authentication sess = gb.session(P.oauth) gb.check_api_limit(sess) # %% get user / organization handle userorg = gb.user_or_org(sess, P.user) # %% prepare to loop over repos repos = gb.get_repos(userorg) to_modify = [repo for repo in repos if repo.name.startswith(P.pattern)] print( "\ntype affirmative to remove all collaborators from\n", "\n".join([repo.full_name for repo in to_modify]), ) modify = input() == "affirmative" for repo in to_modify: gb.check_api_limit(sess) collabs = repo.get_collaborators() admins = [c.login for c in collabs if c.login not in P.omit] if not admins: continue print("admins", repo.full_name, " ".join(admins)) if modify: if repo.archived: logging.error( f"could not remove collabs from archived {repo.full_name}") webbrowser.open_new_tab("https://github.com/" + repo.full_name + "/settings") continue for admin in admins: repo.remove_from_collaborators(admin)
def main(username: str, oauth: str, stem: str): # %% authentication sess = gb.session(P.oauth) gb.check_api_limit(sess) # %% get user / organization handle userorg = gb.user_or_org(sess, P.user) # %% prepare to loop over repos repos = gb.get_repos(userorg) # filter repos to_act = (repo for repo in repos if repo.name.startswith(stem) and repo.name != ".github" and not repo.fork and not repo.archived and repo.owner.login == userorg.login) for repo in to_act: try: repo.get_license() except github.GithubException: print(repo.full_name)
def main(user: str, oauth: Path, pattern: str, only_empty: bool) -> typing.List[str]: # %% authentication sess = gb.session(oauth) gb.check_api_limit(sess) # %% get user / organization handle userorg = gb.user_or_org(sess, user) # %% prepare to loop over repos repos = gb.get_repos(userorg) to_act = (repo for repo in repos if repo.name.startswith(pattern)) empty: typing.List[str] = [] for repo in to_act: print(f"examining {repo.name}", end="\r") authors: typing.Dict[str, int] = {} try: for commit in repo.get_commits(): if only_empty: break if not commit.stats: # GitHub API bug? continue if commit.stats.total == 0: continue if not commit.author: # GitHub API bug? continue if commit.author.login in authors: authors[commit.author.login] += commit.stats.total else: authors[commit.author.login] = commit.stats.total if not only_empty: ax = figure().gca() ax.scatter(authors.keys(), authors.values()) ax.get_yaxis().get_major_formatter().set_useOffset(False) ax.set_ylabel("total LoC changed") ax.set_yscale("log") ax.set_title(repo.name) except github.GithubException as exc: if "empty" in exc.data["message"]: empty.append(repo.name) print() # flush stdout \r return sorted(empty)
def main(): p = ArgumentParser(description="mass create repos for teams") p.add_argument("fn", help=".xlsx with group info") p.add_argument("oauth", help="Oauth file") p.add_argument("orgname", help="Github Organization") p.add_argument("-stem", help="beginning of repo names", default="") p.add_argument( "-col", help="column(s) for TeamName OR TeamNumber, TeamName", nargs="+", required=True ) p.add_argument("-private", help="create private repos", action="store_true") p = p.parse_args() fn = Path(p.fn).expanduser() teams = pandas.read_excel(fn, usecols=",".join(p.col)).squeeze().dropna().drop_duplicates() # %% op, sess = connect(p.oauth, p.orgname) check_api_limit(sess) if teams.ndim == 1: by_num(teams, p.stem, p.private, op, sess) elif teams.shape[1] == 2: by_name(teams, p.stem, p.private, op, sess)
def main(): p = ArgumentParser(description="mass copy files by language") p.add_argument("copyfn", help="file to copy into repos") p.add_argument("targetfn", help="path to copy file into in repos") p.add_argument("language", help="coding language to consider (case-sensitive)") p.add_argument("oauth", help="Oauth file") p.add_argument("userorg", help="Github Username or Organization") p.add_argument("-stem", help="beginning of repo names", default="") P = p.parse_args() language = P.language copyfn = Path(P.copyfn).expanduser().resolve(True) copy_text = copyfn.read_text() target = P.targetfn sess = gb.session(P.oauth) gb.check_api_limit(sess) # %% get user / organization handle userorg = gb.user_or_org(sess, P.userorg) # %% prepare to loop over repos repos = gb.get_repos(userorg) to_act = (repo for repo in repos if repo.name.startswith(P.stem)) for repo in to_act: # sometimes a large amount of HTML, CSS, or docs show up as first language. langs = repo.get_languages() if not langs.get(language): continue try: existing = repo.get_contents(target) existing_code = base64.b64decode(existing.content).decode("utf8") if existing_code.strip() != copy_text.strip(): print(repo.full_name, "different from", copyfn) repo.update_file(target, "update CI", copy_text, existing.sha) except github.GithubException: # file not exist on remote print("copying", copyfn, "to", target, "in", repo.full_name) repo.create_file(target, "init CI", copy_text)
def main(P): op, sess = connect(P.oauth, P.orgname) check_api_limit(sess) return get_collabs(op, sess, P.stem, P.regex)