Skip to content

Food for thought: v2 redesign #28

Open
@guyzmo

Description

@guyzmo

Current code offers a clean and easy to implement API. But as more features gets integrated, the more the help page becomes cluttered. So a redesign of the code would be a good idea to think about.

Also, integrating new services means sensitively increasing the code base. Not everybody wants to use all existing services at once, and implementing new services shouldn't be tied to the main code base: if you want to implement support for Gogs (for example) you shouldn't ask for my permission (by doing fork+PR)!

So the main things I'm thinking to change for a possible V2 redesign are modularizing the CLI API, and extracting the services as external plugins.

Subcommands for the CLI API

So the goal would be to modularize the code for each subcommand, so that each feature comes as an independent module coming with its own help page.

As currently, each service lies in its own module, that would mean implementing a "two axis" modularization: for each service and for each command. Then the main help page would have to be generated and the output would look like:

Usage:
    git-repo [--path=<path>] [-v...] <target> <command> [options]

Options:
    <target>            service to use, using the alias (hub, lab or bb),
    <command>           command to trigger, use --help on that command to see usage.
    --path              repository to use

Commands:
    fork                 Fork a project
    create               Create a new project on the service
    delete               Delete an existing project from the service
    open                 Open the project's page with your browser
    gist                 Manage gists
    request              Manage requests

The best way to do that, would be to have for each feature a module and class following this template:

'''
git-repo : Manage gists from the service 

Usage:
    gist (list|ls) [<gist>]
    gist clone <gist>
    gist fetch <gist> [<gist_file>]
    gist create [--secret] <description> [<gist_path> <gist_path>...]
    gist delete <gist> [-f]

Commands:
    ...
'''

@register_interface
class RepositoryServiceClone:
    def get_service(self, lookup_repository):
        raise NotImplementedError

    def clone(self, user, repo, branch):
        raise NotImplementedError

@register_command('clone', __doc__)
class GitRepoCommandClone:
    def do_clone(self):
        service = self.get_service(lookup_repository=False)
        repo_path = os.path.join(self.path, self.repo_name)
        if os.path.exists(repo_path):
            raise FileExistsError('Cannot clone repository, '
                                  'a folder named {} already exists!'.format(repo_path))
        repository = Repo.init(repo_path)
        service = RepositoryService.get_service(repository, self.target)
        service.clone(self.user_name, self.repo_name, self.branch)
        log.info('Successfully cloned `{}` into `{}`!'.format(
            service.format_path(self.repo_slug),
            repo_path)
        )
        return 0

Then, each service would inherit from each interface offered by a command, raising NotImplementedError exceptions when it does not offer an implementation. All missing implementation for interfaces would be easy to list, though.

Then we could have a change in namespace so it becomes:

git_repo.commands.clone
git_repo.commands.fork
git_repo.commands.create
git_repo.commands.delete
git_repo.commands.open
git_repo.commands.gist
git_repo.commands.request

Use a plugin approach for services

To make it easier to implement new services, they could be offered as independent packages, that would populate in the git_repo.services.ext namespace, and be automagically loaded by git-repo when installed. Then one could only have the code for a single service at any time.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions