Skip to content
Snippets Groups Projects
Commit 894133bf authored by Robin Keskisärkkä's avatar Robin Keskisärkkä
Browse files

Add script with examles

parent e378c32b
Branches
Tags
No related merge requests found
.DS_Store
__pycache__
.env
signup.txt
myenv/
\ No newline at end of file
general:
# URL
api_url: "https://gitlab.liu.se/api/v4"
groups:
# Main group
main:
name: "TDP013 - Webbprogrammering och interaktivitet"
path: "TDP013-Webbprogrammering-och-interaktivitet"
description: "This is the main group for the course TDP013"
# Subgroup
sub:
name: "HT2023"
path: "HT2023"
description: "This is the sub-group HT2023"
projects:
# Use a project template for new projects (optional)
template_url: "https://gitlab.liu.se/robke04/tdp013-template.git"
# Generate generic projects of the form A1, A2, ..., B1, B2, ... (optional)
groups:
prefixes: ['A', 'B', 'C', 'D']
suffixes: ['1', '2', '3', '4', '5', '6', '7', '8']
# Add members from webreg export (optional)
members:
path: "signup.txt" # File exported from webreg signup
create: true # Create the project based on the group name if it does not exist i git
\ No newline at end of file
main.py 0 → 100644
import os
import sys
from utils import *
import yaml
from dotenv import load_dotenv
def main(config_file):
with open(config_file, "r") as stream:
load_dotenv()
token = os.getenv('token')
webhook = os.getenv('webhook')
config = dotdict(yaml.safe_load(stream))
# Authentication headers
headers = {'Authorization': f"Bearer {token}" }
# Create main group
namespace_id = create_group(
config.groups.main.name,
config.groups.main.path,
config.groups.main.description,
headers,
config.general.api_url)
# Create subgroup
if config.groups.sub:
namespace_id = create_subgroup(
config.groups.sub.name,
config.groups.sub.path,
config.groups.sub.description,
namespace_id,
headers,
config.general.api_url)
# Generate projects
if config.projects.groups:
generate_projects(
config.projects.groups.prefixes,
config.projects.groups.suffixes,
namespace_id,
config.projects.template_url,
headers,
config.general.api_url)
# Add members to projects
if config.projects.members:
add_members(
config.projects.members.path,
config.projects.members.create,
namespace_id,
config.projects.template_url,
headers,
config.general.api_url)
# Add Teams integration. Notifications will be viewable for anyone in the team.
if webhook:
add_slack_integration(
webhook,
namespace_id,
headers,
config.general.api_url)
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Please provide a path to a configuration file (e.g. config.yml)")
sys.exit(0)
# Arguments passed
main(sys.argv[1])
\ No newline at end of file
python-dotenv
requests
pyyaml
\ No newline at end of file
utils.py 0 → 100644
import requests
import urllib.parse
class dotdict(dict):
"""Wrapper class that adds dot notation for dict."""
def __getattr__(self, name):
if type(self.get(name)) == dict:
return dotdict(self.get(name))
return self.get(name)
def create_group(name, path, description, headers, url):
"""Create a group and return its ID or return the group ID if it already exists.
Args:
name (str): Group name.
path (str): Group path.
description (str): Group description.
headers (dict): Request headers.
url (str): GitLab API URL.
Returns:
int: Group ID.
"""
data = {
"name": name,
"path": path,
"description": description
}
print(f"{url}/groups/{path}")
r = requests.get(f"{url}/groups/{path}", headers=headers)
if r.status_code == 200:
print(f"Group {path} already exists (id: {r.json()['id']})", )
return r.json()["id"]
r = requests.post(f"{url}/groups", data=data, headers=headers)
if r.status_code == 201:
print(f"Group {path} has been created (id: {r.json()['id']})")
return r.json()["id"]
else:
raise Exception(r.status_code, r.json())
def create_subgroup(name, path, description, parent_id, headers, url):
"""Create a group and return its ID or return the ID if the group already exists.
Args:
name (str): Subgroup name.
path (str): Subgroup path.
description (str): Subgroup description.
parent_id (int): Parent group ID.
headers (dict): Request headers.
url (str): GitLab API URL.
Returns:
int: Subgroup ID.
"""
data = {
"name": name,
"path": path,
"description": description,
"parent_id": parent_id
}
r = requests.get(f"{url}/groups/{parent_id}/subgroups", headers=headers)
if r.status_code == 200:
for group in r.json():
if group["path"] == path:
print(f"Subgroup {path} already exists (id: {group['id']})")
return group["id"]
else:
raise Exception(r.status_code, r.json()["message"])
r = requests.post(f"{url}/groups", data=data, headers=headers)
if r.status_code == 201:
print(f"Subgroup {path} has been created (id: {r.json()['id']})")
return r.json()["id"]
else:
raise Exception(r.status_code, r.json()["message"])
def create_project(namespace_id, name, path, template_url, headers, url):
"""Create a project and return its ID or return the ID if the project already exists.
Args:
namespace_id (int): Namespace ID.
name (str): Project name.
path (str): Project path.
template_url (str): URL reference to a project that will be used as a template.
headers (dict): Request headers.
url (str): GitLab API URL.
Returns:
int: Project ID.
"""
data = {
"name": name,
"path": path,
"namespace_id": namespace_id,
"import_url": template_url,
"initialize_with_readme": template_url == None
}
project_id = get_project_id(namespace_id, path, headers, url)
if project_id != None:
print(f"Project {path} already exists (id: {project_id})")
return project_id
r = requests.post(f"{url}/projects", data=data, headers=headers)
if r.status_code == 201:
print(f"Project {path} has been created (id: {r.json()['id']})")
return r.json()["id"]
else:
raise Exception(r.status_code, r.json()["message"])
def get_project_id(namespace_id, path, headers, url):
"""Get a project and return its ID or return None if the project could not be found.
Args:
namespace_id (int): Namespace ID.
path (str): Project path.
headers (dict): Request headers.
url (str): GitLab API URL.
Returns:
int: Project ID if the project is found, otherwise None.
"""
r = requests.get(f"{url}/groups/{namespace_id}/projects/?search={path}", headers=headers)
if len(r.json()) > 0:
return r.json()[0]["id"]
return None
#project_path = f"{group}%2F{subgroup}%2F{path}"
#r = requests.get(f"{url}/api/v4/projects/{project_path}", headers=headers)
#print(r, r.text)
#return None
def generate_projects(prefixes, suffixes, namespace_id, template_url, headers, url):
"""Generate projects based on list of main groups and an optional list of sub groups."""
project_names = [f"{p}{s}" for p in prefixes for s in suffixes]
for project_name in project_names:
project_path = project_name
create_project(namespace_id, project_name, project_path, template_url, headers, url)
def add_member(project_id, path, user, headers, url):
r = requests.get(f"{url}/users/?username={user}", headers=headers)
if r.json() == []:
print(f"User {user} not found")
return
user_id = r.json()[0]["id"]
data = {
"user_id": user_id,
"access_level": 40
}
r = requests.post(f"{url}/projects/{project_id}/members", data=data, headers=headers)
if r.status_code == 201:
print(f"Added {user} as maintainer to {path}")
else:
print(r.json()["message"])
def add_members(path, create, namespace_id, template_url, headers, url):
with open(path, "r") as f:
for line in f.readlines():
parts = line.strip().split(":")
user = parts[0]
path = f"{parts[-2]}{parts[-1]}"
project_id = get_project_id(namespace_id, path, headers, url)
if project_id == None:
print(f"Project {path} does not exist")
if create:
project_id = create_project(namespace_id, path, path, template_url, headers, url)
else:
continue
add_member(project_id, path, user, headers, url)
def add_slack_integration(webhook, push_events, tag_push_events, namespace_id, headers, url):
"""Set up Slack integration webhook.
Args:
webhook (str): Webhook target URL in Slack.
push_events (bool): Notifications for push events.
tag_push_events (bool): Notifications for tag push events.
namespace_id (int): A namespace id.
headers (dict): Request headers.
url (str): GitLab API URL
Returns:
bool: False if at least one webhook registration fails, True otherwise.
"""
data = {
"webhook": webhook,
"notify_only_broken_pipelines": False,
"notify_only_default_branch": False,
"branches_to_be_notified": False,
"push_events": push_events,
"issues_events": False,
"confidential_issues_events": False,
"merge_requests_events": False,
"tag_push_events": tag_push_events,
"note_events": False,
"confidential_note_events": False,
"pipeline_events": False,
"wiki_page_events": False
}
print(data)
success = True
r = requests.get(f"{url}/groups/{namespace_id}/projects", data=data, headers=headers)
if r.status_code == 200:
path_and_id = sorted([(project["path"], project["id"]) for project in r.json()])
for path, id in path_and_id:
r = requests.put(f"{url}/projects/{id}/integrations/slack", data=data, headers=headers)
if r.status_code == 200:
print(f"Teams integration webhook activated for {path}")
else:
success = False
return success
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment