commit 7d486554e8ca22a642be3dbac3a2fceb37806663 Author: Clemens Klug Date: Thu May 23 17:27:10 2019 +0200 Initialer Commit diff --git a/gitea.py b/gitea.py new file mode 100644 index 0000000..27431d4 --- /dev/null +++ b/gitea.py @@ -0,0 +1,130 @@ +import argparse +import json + +import requests + +def setup_args(): + parser = argparse.ArgumentParser(description="Gitea classroom helper") + parser.add_argument("--url", "-u", default="http://git.kinf.wiai.uni-bamberg.de", help="Gitea path") + parser.add_argument("--token", "-t", help="Gitea application token", required=True) + args = parser.parse_args() + return args + +class GiteaClassRoom: + def __init__(self, host, token): + self.session = requests.Session() + self.session.headers.update({"accept": "application/json","Content-Type": "application/json"}) + self.label_id = None + self.milestone_id = None + self.host = host + self.token = token + self.validate() + + def url(self, url): + url = f"{self.host}/api/v1/{url}?token={self.token}" + #print(url) + return url + + def post(self, endpoint, data): + return self.session.post(self.url(endpoint), data=json.dumps(data)) + + def get(self, endpoint): + return self.session.get(self.url(endpoint)) + + def put(self, endpoint): + return self.session.put(self.url(endpoint)) + + def validate(self): + test = self.get("user/orgs") + if not test.ok: + raise ValueError("invalid token", test.status_code, test.text) + + def filtered(self, endpoint, filters): + data = self.get(endpoint).json() + for entry in data: + if all([entry[name] == filters[name] for name in filters]): + return entry + return None + + def add_label(self, repo, name="deliverables", color="#ff0000"): + label = self.filtered(f"repos/{repo}/labels", {"name": name}) + if not label: + label = self.post(f"repos/{repo}/labels", {"name": name, "color":color}).json() + return label["id"] + + def add_milestone(self, repo, title, description, due_on): + milestone = self.filtered(f"repos/{repo}/milestones", {"title": title, "due_on": due_on}) + if not milestone: + data = {"title": title, "description": description, "due_on": due_on} + milestone = self.post(f"repos/{repo}/milestones", data).json() + return milestone["id"] + + def add_issue(self, repo, title, body, milestone=None, labels=None): + issue = self.filtered(f"repos/{repo}/issues", {"title": title, "state": "open"}) + if not issue: + data = {"title": title, "body": body} + if milestone: + data["milestone"] = milestone + if labels: + data["labels"] = labels + issue = self.post(f"repos/{repo}/issues", data).json() + return issue + + def add_org(self, name): + print("don't forget to set the visibility to private (if you want)") + return self.post("orgs", {"username": name, "visibility": "private"}).json() + + def add_org_repo(self, org, repo): + return self.post(f"org/{org}/repos", {"name": repo,"private":True}).json() + + def add_team(self, org, name): + team = self.filtered(f"orgs/{org}/teams", {"name": name}) + if not team: + team = self.post(f"orgs/{org}/teams", {"name": name, "permission": "write", "units":["repo.code","repo.issues","repo.pulls","repo.releases","repo.wiki"]}).json() + return team["id"] + + def add_user_to_team(self, team_id, user): + return self.put(f"teams/{team_id}/members/{user}") + + def add_repo_to_team(self, team_id, repo): + return self.put(f"teams/{team_id}/repos/{repo}") + + def init_org(self, name, groups, labels={}, milestones={}, issues=[], **kwargs): + """ + name: name of the oranisation + groups: number of groups (int) or collection with group names + labels: map (key->props) for labels (name, color) + milestones: map (key->props) for milestones (title, description, due_on) + issues: list of issues (title, body, ([label_keys]), (milestone_key)) + """ + self.add_org(name) + if isinstance(groups, int): + groups = {f"Group{i}":[] for i in range(groups)} + elif isinstance(groups, list): + groups = {f"Group{i}":v for i,v in enumerate(groups)} + for group in groups: + repo = f"{name}/{group}" + self.add_org_repo(name, group) + team = self.add_team(name, group) + for user in groups[group]: + self.add_user_to_team(team, user) + self.add_repo_to_team(team, repo) + added_labels = {label: self.add_label(repo, name=label, color=labels[label]) for label in list(labels)} + added_milestones = {milestone: self.add_milestone(repo, **milestones[milestone]) for milestone in dict(milestones)} + for issue in issues: + milestone = added_milestones[issue["milestone"]] if "milestone" in issue else None + label_ids = [added_labels[label] for label in issue["labels"]] if "labels" in issue else None + self.add_issue(repo, issue["title"], issue["body"], milestone, label_ids) + +if __name__ == "__main__": + args = setup_args() + gitea = GiteaClassRoom(host=args.url, token=args.token) + + # config with json file + with open("sample.json") as src: + data = json.load(src) + gitea.init_org(**data) + + # config with python class + #from sample import Testdata + #gitea.init_org(Testdata.name, Testdata.groups, Testdata.labels, Testdata.milestones, Testdata.issues) \ No newline at end of file diff --git a/sample.json b/sample.json new file mode 100644 index 0000000..ea01d93 --- /dev/null +++ b/sample.json @@ -0,0 +1,63 @@ +{ + "name": "ScriptTest", + "groups": 6, + "ALTERNATIVE_groups_with_names_and_users": {"admin": ["cklug", "mgoetz", "ckremitzl"]}, + "ALTERNATIVE_groups_with_users": [["cklug", "mgoetz"]], + "labels": { + "deliverable": "#ff0000", + "hint": "#00f000" + }, + "milestones": { + "ms1": { + "title": "Milestone 1", + "description": "The first milestone covers the game desgin basics (game design document), a firs architectural approach (e.g. UML diagram), and assignment of responsibilities", + "due_on": "2019-05-23T13:37:00Z" + },"ms2": { + "title": "Milestone 2", + "description": "Presentation of the final geogame (walktrough, demo, video,…)", + "due_on": "2019-07-22T13:37:00Z" + } + }, + "issues": [ + { + "title": "Game design document", + "body": "Write a game design document.\nYou can use the template in the VC as starting point.", + "labels": ["hint", "deliverable"], + "milestone": "ms1" + }, + { + "title": "Assign responsibilites", + "body": "Split the project into equal parts", + "labels": ["deliverable"], + "milestone": "ms1" + }, + { + "title": "Learn Android", + "body": "Get to know Android, especially Activites with their lifecycle and Services (Remote, Local, bind/unBind, start/stop)", + "labels": ["hint"], + "milestone": "ms1" + }, + { + "title": "Create Slides", + "body": "Presenting a word document (or A4 PDF) is cumbersome", + "labels": ["hint"], + "milestone": "ms1" + }, + { + "title": "Implement App", + "body": "Do it", + "labels": ["deliverable"], + "milestone": "ms2" + }, + { + "title": "Game design document", + "body": "Write a game design document.\nYou can use the template in the VC as starting point.", + "labels": ["hint", "deliverable"], + "milestone": "ms1" + }, + { + "title": "have fun", + "body": "'nuff said" + } + ] +} \ No newline at end of file diff --git a/sample.py b/sample.py new file mode 100644 index 0000000..df395d0 --- /dev/null +++ b/sample.py @@ -0,0 +1,62 @@ +class Testdata: + name = "ScriptTest" + groups = 5 # Group0, Group1, Group2 + #groups = {"admin": ["cklug", "mgoetz", "ckremitzl"]} # "admin" with 3 members + #groups = [["cklug", "mgoetz"]] # Group0 with 2 members + labels = { + "deliverable": "#ff0000", + "hint": "#00f000" + } + milestones = { + "ms1": { + "title": "Milestone 1", + "description": "The first milestone covers the game desgin basics (game design document), a firs architectural approach (e.g. UML diagram), and assignment of responsibilities", + "due_on": "2019-05-23T13:37:00Z" + },"ms2": { + "title": "Milestone 2", + "description": "Presentation of the final geogame (walktrough, demo, video,…)", + "due_on": "2019-07-22T13:37:00Z" + } + } + issues = [ + { + "title": "Game design document", + "body": "Write a game design document.\nYou can use the template in the VC as starting point.", + "labels": ["hint", "deliverable"], + "milestone": "ms1" + }, + { + "title": "Assign responsibilites", + "body": "Split the project into equal parts", + "labels": ["deliverable"], + "milestone": "ms1" + }, + { + "title": "Learn Android", + "body": "Get to know Android, especially Activites with their lifecycle and Services (Remote, Local, bind/unBind, start/stop)", + "labels": ["hint"], + "milestone": "ms1" + }, + { + "title": "Create Slides", + "body": "Presenting a word document (or A4 PDF) is cumbersome", + "labels": ["hint"], + "milestone": "ms1" + }, + { + "title": "Implement App", + "body": "Do it", + "labels": ["deliverable"], + "milestone": "ms2" + }, + { + "title": "Game design document", + "body": "Write a game design document.\nYou can use the template in the VC as starting point.", + "labels": ["hint", "deliverable"], + "milestone": "ms1" + }, + { + "title": "have fun", + "body": "'nuff said" + } + ] \ No newline at end of file