Auf dieser Seite
Fetch mit Gitlab API
Fetch mit Gitlab API
Motivation
Ich verwende gitlab und habe viele Repositories, die ich täglich oder sogar mehr als einmal pro Tag verfolgen muss. Es war erstens sehr ermüdend, alle diese Repositories zu klonen, wenn ich meinen Arbeitsrechner wechsle, und zweitens, all diese Repositories aktuell zu halten. Aus diesem Grund begann ich, ein Automatisierungsskript zu schreiben, um die langweiligen Aufgaben von meinen Schultern zu nehmen.
Prozess
Ich begann mit einem einfachen Bash-Skript, das eine For-Schleife durchläuft und die Dinge erledigt, wobei die Pfade der Repositories hardcodiert sein müssen.
#!/bin/bash
current_dir=$(pwd)
REPOS=(
# list of all repos names
)
function doit() {
for repo in ${REPOS[@]}; do
if [ ! -d "$repo" ]; then
echo " - cloning $repo ..."
# git clone $repo
else
cd $current_dir/$repo
echo " - fetching $repo ..."
git fetch
cd $current_dir
fi
done
echo "Done"
}
doit
Dies war schnell und funktionierte eine Weile, aber als ich anfing, mit mehreren Projekten zu arbeiten, und meine Kollegen ein Repository hinzufügten/entfernten/umbenannten, war es immer noch manuelle Arbeit, das Skript zu aktualisieren, und genauso langweilig wie ich war, mochte ich das nicht und suchte nach einem faulen Weg, den Prozess zu automatisieren, und öffnete die Gitlab API-Dokumentation, wo der Spaß begann.
Lösungsidee
Ein Python-Skript, das mit der Gitlab API kommuniziert und den /projects-Endpunkt verwendet, um auf die Repositories zuzugreifen.
Anforderungen:
- Gitlab Token: Erstellen Sie zunächst ein privates Token, um wie in der Dokumentation beschrieben auf die API zuzugreifen.
- Virtueller Zugriff auf die Repositories (z.B.: gitlab.com)
Optional:
- Pipenv zur Installation der Entwicklungsabhängigkeiten:
brew install pipenv
Erster Versuch: argparse
Der erste Versuch bestand darin, die Optionen als Argumente an das Skript zu übergeben:
#!/usr/local/bin/python3.7
"""
Clone/fetch projects from Gitlab using the private token
"""
import argparse
from os import path
import json
import subprocess
import shlex
from urllib.request import urlopen
IGNORE_LIST = [
'test',
'example',
'tour'
]
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--token', '-t', help='Gitlab private Token')
parser.add_argument('--url', '-u', help='Gitlab URL')
args = parser.parse_args()
if not args.token or not args.url:
parser.print_help()
exit(1)
gitlab_token = args.token
gitlab_url = args.url
projects = urlopen(
f'https://{gitlab_url}/api/v4/projects?membership=1&order_by=path&per_page=1000&private_token={gitlab_token}')
all_projects = json.loads(projects.read().decode())
for project in all_projects:
try:
url = project.get('ssh_url_to_repo')
if any([x in url for x in IGNORE_LIST]):
continue
name = project.get('name').replace(' ', '-').replace('.', '-')
repo_path = path.join(path.dirname(path.realpath(__file__)), name)
if path.isdir(repo_path):
print(f'Fetching {name}')
command = shlex.split(f'git -C {repo_path} fetch')
process = subprocess.Popen(command)
process.communicate(input=None)
else:
print(f'Cloning {name}')
command = shlex.split(f'git clone {url} {name}')
process = subprocess.Popen(command)
process.communicate(input=None)
except Exception as unexpected_exception:
print(f"Error on {url}: {str(unexpected_exception)}")
print('Done')
if __name__ == '__main__':
main()
Verwendung:
usage: main.py [-h] [--token TOKEN] [--url URL]
optional arguments:
-h, --help show this help message and exit
--token TOKEN, -t TOKEN
Gitlab private Token
--url URL, -u URL Gitlab URL<Paste>
Zweiter Versuch: JSON
Dann dachte ich, dass die Konfigurationen flexibler sein müssten, daher machte die Verwendung einer separaten Konfigurationsdatei Sinn.
Das vollständige Projekt-Repository finden Sie hier
#!/usr/local/bin/python3.7
"""
Clone/fetch projects from Gitlab using the private token
NOTE:
The gitlab url, token should be provided in a config.json
file, which should exist in the same direcotry as this script.
"""
import json
import shlex
import subprocess
import sys
from os import path
from urllib.request import urlopen
ROOT = path.dirname(path.abspath(__file__))
def read_configs():
configs = {}
try:
with open(f'{ROOT}/config.json', 'r') as config_file:
configs = json.loads(config_file.read())
except FileNotFoundError:
print('config.json cannot be found')
except json.decoder.JSONDecodeError:
print('Please provide gitlab configs in json format')
return configs
def shell(command):
process = subprocess.Popen(command)
process.communicate(input=None)
def main():
configs = read_configs()
gitlab_url = configs.get('gitlab_url')
gitlab_token = configs.get('gitlab_token')
if not(gitlab_url and gitlab_token):
print('Please provide gitlab configs in your config.json')
sys.exit(1)
ignore_list = configs.get('ignore_list')
projects = urlopen(
f'https://{gitlab_url}/api/v4/projects?membership=1&order_by=path&per_page=1000&private_token={gitlab_token}')
all_projects = json.loads(projects.read().decode())
for project in all_projects:
try:
url = project.get('ssh_url_to_repo')
if any([x in url for x in ignore_list]):
continue
name = project.get('name').replace(' ', '-').replace('.', '-')
repo_path = path.join(path.dirname(path.realpath(__file__)), name)
if path.isdir(repo_path):
print(f'Fetching {name}')
command = shlex.split(f'git -C {repo_path} fetch')
shell(command)
else:
print(f'Cloning {name}')
command = shlex.split(f'git clone {url} {name}')
shell(command)
except Exception as unexpected_exception:
print(f"Error on {url}: {str(unexpected_exception)}")
print('Done')
sys.exit(0)
if __name__ == '__main__':
main()
Verwendung
python main.py