Commit 57ec2a6e authored by nimrod's avatar nimrod
Browse files

rcfiles Python module.

- New Python module for rcfiles script.
- Move some code from git-namespace-backup to the new module in
  preperation for more Git infrastructure work.
parent 6fa9f281
Loading
Loading
Loading
Loading
+42 −76
Original line number Diff line number Diff line
@@ -14,11 +14,14 @@ import pathlib
import sys
import os
import os.path
import re
import gitlab  # pylint: disable=import-error
import sh  # pylint: disable=import-error
from sh.contrib import git  # pylint: disable=import-error

sys.path.append(os.path.expanduser("~/Documents/bin"))

import rcfiles.git  # noqa: E402 pylint: disable=wrong-import-position
import rcfiles.gitlab  # noqa: E402 pylint: disable=wrong-import-position


def namespace_path(namespace):
    """Returns the full path to the namespace.
@@ -35,92 +38,55 @@ def namespace_path(namespace):
    return path


def name_to_path(name):
    """Converts a name to valid path in GitLab."""
    return re.sub("[^a-zA-Z0-9_-]", "-", name).lower()
def list_repositories(namespace):
    """Returns a list of paths under the namespace that are Git
    repositories."""
    return [x for x in namespace.iterdir() if rcfiles.git.is_repo(x)]


def get_group(lab, name):
    """Returns a GitLab group object.
if __name__ == "__main__":
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("namespace", type=namespace_path)
    args = parser.parse_args()

    If a group with that name already exists, return that. Otherwise create a
    new group and return that instead.
    """
    for i in lab.groups.list():
        if i.name == name:
            print(
                "Using existing group id: {}, name: {}, path: {}.".format(
                    i.id, i.name, i.path
                ),
                file=sys.stderr,
            )
            return i
    new_group = lab.groups.create(
        {
            "name": name,
            "path": name_to_path(name),
            "visivility": "internal",
        }
    with rcfiles.gitlab.connect() as conn:
        group = rcfiles.gitlab.get_group(conn, args.namespace.name)
        if group is None:
            group = rcfiles.gitlab.create_group(
                conn, args.namespace.name, visibility="internal"
            )
            print(
                "Created new group id: {}, name: {}, path: {}.".format(
            new_group.id, new_group.name, new_group.path
                    group.id, group.name, group.path
                ),
                file=sys.stderr,
            )
    return group


def get_project(group, name):  # pylint: disable=redefined-outer-name
    """Returns a GitLab project.

    If a project with that name already exists, return that. Otherwise create a
    new project and return that instead.
    """
    for i in group.projects.list():
        if i.name == name:
        else:
            print(
                "Using existing project id: {}, name: {}, path: {}.".format(
                    i.id, i.name, i.path
                "Using existing group id: {}, name: {}, path: {}.".format(
                    group.id, group.name, group.path
                ),
                file=sys.stderr,
            )
            return i
    new_project = group.projects.gitlab.projects.create(
        {"name": name, "namespace_id": group.id}
        for repo in list_repositories(args.namespace):
            project = rcfiles.gitlab.get_project(conn, group.name, repo.name)
            if project is None:
                project = rcfiles.gitlab.create_project(
                    conn, repo.name, group.name
                )
                print(
                    "Created new project id: {}, name: {}, path: {}.".format(
            new_project.id, new_project.name, new_project.path
                        project.id, project.name, project.path
                    ),
                    file=sys.stderr,
                )
            else:
                print(
                    "Using existing project id: {}, name: {}, path: {}.".format(  # noqa: E501
                        project.id, project.name, project.path
                    ),
                    file=sys.stderr,
                )
    return project


def is_git_repo(path):
    """Returns a boolean if the path is a Git repo."""
    return path.is_dir() and pathlib.Path(path, ".git").is_dir()


def list_repositories(namespace):
    """Returns a list of paths under the namespace that are Git
    repositories."""
    return [x for x in namespace.iterdir() if is_git_repo(x)]


TOKEN = os.environ["GITLAB_PRIVATE_TOKEN"]
URL = os.environ["GITLAB_BASE_URL"].removesuffix("api/v4")

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("namespace", type=namespace_path)
    args = parser.parse_args()

    with gitlab.Gitlab(url=URL, private_token=TOKEN) as Lab:
        group = get_group(Lab, args.namespace.name)
        for repo in list_repositories(args.namespace):
            project = get_project(group, repo.name)
            with sh.pushd(repo):
                if "shore.co.il" in git.remote().splitlines():
                    print(
+20 −0
Original line number Diff line number Diff line
"""Git repository related functions."""

import os.path
import pathlib


def is_repo(path):
    """Returns a boolean if the path is a Git repo."""
    return os.path.isdir(path) and pathlib.Path(path, ".git").is_dir()


def in_repo():
    """Is the current working directory a git repo?

    Because we invoke the command as a Git command (git foo) it is run from
    the root of the repository if inside a repository so there's no need to
    traverse up the directory hierarchy to find if we're in a Git repository,
    it's enough to just check if the .git directory exists where we are.
    """
    return is_repo(".")
+79 −0
Original line number Diff line number Diff line
"""A bunch of convenience functions to deal with GitLab."""

import os
import re
import gitlab  # pylint: disable=import-error


def name_to_path(name):
    """Converts a name to valid path in GitLab."""
    return re.sub("[^a-zA-Z0-9_-]", "-", name).lower()


def get_url():
    """Return the GitLab URL."""
    return os.getenv(
        "GITLAB_BASE_URL", "https://git.shore.co.il/"
    ).removesuffix("api/v4")


def connect():
    """Return the GitLab object."""
    try:
        token = os.environ["GITLAB_TOKEN"]
    except KeyError:
        raise Exception("GITLAB_TOKEN environment variable not set.")
    url = get_url()
    conn = gitlab.Gitlab(url=url, private_token=token)
    conn.auth()
    return conn


def get_group(conn, name):
    """Return the GitLab group object with the given name."""
    for group in conn.groups.list(all=True):
        if group.name == name:
            return group
    return None


def create_group(conn, name, visibility=None, description=None):
    """Create a new GitLab group and return that object."""
    data = {
        "name": name,
        "path": name_to_path(name),
        "visibility": "public" if visibility is None else visibility,
    }
    if description is not None:
        data["description"] = description
    return conn.groups.create(data)


def get_project(conn, group, name):
    """Returns a GitLab project."""
    # pylint: disable=invalid-name
    g = get_group(conn, group)
    if g is None:
        return None
    for p in g.projects.list(all=True):
        if p.name == name:
            return p
    return None


def create_project(conn, name, group=None, description=None, visibility=None):
    """Create a new GitLab project and return that object."""
    # pylint: disable=invalid-name
    data = {
        "name": name,
    }
    if group is not None:
        g = get_group(conn, group)
        if g is None:
            return None
        data["namespace_id"] = g.id
    if description is not None:
        data["description"] = description
    if visibility is not None:
        data["visibility"] = visibility
    return conn.projects.create(data)