Updated: refactor git management utils
This commit is contained in:
Родитель
76a305a349
Коммит
1f17815227
|
@ -0,0 +1,7 @@
|
|||
class BaseException(Exception):
|
||||
def __init__(self, message=None):
|
||||
self.message = message
|
||||
|
||||
|
||||
class GitOperationException(BaseException):
|
||||
pass
|
|
@ -0,0 +1,74 @@
|
|||
import re
|
||||
|
||||
# Backward Compatible with Python 2.7
|
||||
try:
|
||||
from subprocess import DEVNULL
|
||||
except ImportError:
|
||||
DEVNULL = open(os.devnull, 'w')
|
||||
from subprocess import STDOUT, check_call, check_output, CalledProcessError
|
||||
from ..exceptions import GitOperationException
|
||||
|
||||
def does_git_exist():
|
||||
try:
|
||||
check_call("git", stdout=DEVNULL, stderr=STDOUT)
|
||||
except CalledProcessError:
|
||||
return False
|
||||
return True
|
||||
|
||||
def does_git_remote_exist(remote_name):
|
||||
command = ["git", "remote", "show"]
|
||||
return remote_name in check_output(command).decode('utf-8')
|
||||
|
||||
def git_init():
|
||||
command = ["git", "init"]
|
||||
try:
|
||||
check_call(command, stdout=DEVNULL, stderr=STDOUT)
|
||||
except CalledProcessError:
|
||||
raise GitOperationException(message=" ".join(command));
|
||||
|
||||
def git_add_remote(remote_name, remote_url):
|
||||
command = ["git", "remote", "add", remote_name, remote_url]
|
||||
try:
|
||||
check_call(command, stdout=DEVNULL, stderr=STDOUT)
|
||||
except CalledProcessError:
|
||||
raise GitOperationException(message=" ".join(command))
|
||||
|
||||
def git_stage_all():
|
||||
command = ["git", "add", "--all"]
|
||||
try:
|
||||
check_call(command, stdout=DEVNULL, stderr=STDOUT)
|
||||
except CalledProcessError:
|
||||
raise GitOperationException(message=" ".join(command))
|
||||
|
||||
def git_commit(message):
|
||||
command = ["git", "commit", "--allow-empty", "--message", message]
|
||||
try:
|
||||
check_call(command, stdout=DEVNULL, stderr=STDOUT)
|
||||
except CalledProcessError:
|
||||
raise GitOperationException(message=" ".join(command))
|
||||
|
||||
def git_push(remote_name):
|
||||
command = ["git", "push", "--all", remote_name]
|
||||
try:
|
||||
check_call(command, stdout=DEVNULL, stderr=STDOUT)
|
||||
except CalledProcessError:
|
||||
raise GitOperationException(message=" ".join(command))
|
||||
|
||||
def _sanitize_git_remote_name(organization_name, project_name, repository_name):
|
||||
concatenated_remote_name = f"{organization_name}_{project_name}_{repository_name}"
|
||||
sanitized_remote_name = re.sub(r"[^A-Za-z0-9_-]|\s", "-", concatenated_remote_name)
|
||||
return sanitized_remote_name
|
||||
|
||||
def construct_git_remote_name(organization_name, project_name, repository_name, remote_prefix):
|
||||
remote_name = "_{prefix}_{name}".format(
|
||||
prefix=remote_prefix,
|
||||
name=_sanitized_remote_name(organization_name, project_name, repository_name))
|
||||
return remote_name
|
||||
|
||||
def construct_git_remote_url(organization_name, project_name, repository_name, domain_name="dev.azure.com"):
|
||||
url = "https://{domain}/{org}/{proj}/_git/{repo}".format(
|
||||
domain=domain_name,
|
||||
org=organization_name,
|
||||
proj=project_name,
|
||||
repo=repository_name)
|
||||
return url
|
|
@ -3,9 +3,7 @@
|
|||
# Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
# --------------------------------------------------------------------------------------------
|
||||
|
||||
from .repository_response import RepositoryResponse
|
||||
from .github_connection import GithubConnection
|
||||
__all__ = [
|
||||
'RepositoryResponse',
|
||||
'GithubConnection'
|
||||
]
|
|
@ -1,10 +0,0 @@
|
|||
# --------------------------------------------------------------------------------------------
|
||||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
# --------------------------------------------------------------------------------------------
|
||||
|
||||
class RepositoryResponse(object):
|
||||
|
||||
def __init__(self, message, succeeded):
|
||||
self.message = message
|
||||
self.succeeded = succeeded
|
|
@ -3,13 +3,11 @@
|
|||
# Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
# --------------------------------------------------------------------------------------------
|
||||
import os
|
||||
|
||||
# In python2.7 devnull is not defined in subprocess
|
||||
# Backward Compatible with Python 2.7
|
||||
try:
|
||||
from subprocess import DEVNULL
|
||||
except ImportError:
|
||||
DEVNULL = open(os.devnull, 'w')
|
||||
|
||||
from subprocess import STDOUT, check_call, check_output, CalledProcessError
|
||||
from msrest.service_client import ServiceClient
|
||||
from msrest import Configuration, Deserializer
|
||||
|
@ -18,7 +16,16 @@ import vsts.git.v4_1.models.git_repository_create_options as git_repository_crea
|
|||
|
||||
from ..base.base_manager import BaseManager
|
||||
from . import models
|
||||
|
||||
from .local_git_utils import (
|
||||
git_init,
|
||||
git_add_remote,
|
||||
git_stage_all,
|
||||
git_commit,
|
||||
does_git_exist,
|
||||
does_git_remote_exist,
|
||||
construct_git_remote_name,
|
||||
construct_git_remote_url
|
||||
)
|
||||
|
||||
class RepositoryManager(BaseManager):
|
||||
""" Manage DevOps repositories
|
||||
|
@ -35,6 +42,9 @@ class RepositoryManager(BaseManager):
|
|||
self._deserialize = Deserializer(client_models)
|
||||
super(RepositoryManager, self).__init__(creds, organization_name=organization_name, project_name=project_name)
|
||||
|
||||
def check_if_git_exist(self) -> bool:
|
||||
return does_git_exist()
|
||||
|
||||
def create_repository(self, repository_name):
|
||||
"""Create a new azure functions git repository"""
|
||||
project = self._get_project_by_name(self._project_name)
|
||||
|
@ -51,58 +61,41 @@ class RepositoryManager(BaseManager):
|
|||
repository = self._get_repository_by_name(project, repository_name)
|
||||
return self._git_client.get_commits(repository.id, None, project=project.id)
|
||||
|
||||
def setup_remote(self, repository_name, remote_name):
|
||||
def get_local_git_remote_name(self, repository_name, remote_prefix):
|
||||
return construct_git_remote_name(self._organization_name, self._project_name, repository_name, remote_prefix)
|
||||
|
||||
# Since the portal url and remote url are same. We only need one function to handle portal access and git push
|
||||
def get_azure_devops_repo_url(self, repository_name):
|
||||
return construct_git_remote_url(self._organization_name, self._project_name, repository_name)
|
||||
|
||||
# Check if the git repository exists first. If it does, check if the git remote exists.
|
||||
def check_if_local_git_remote_exists(self, repository_name, remote_prefix):
|
||||
if not self._repository_exists():
|
||||
return False
|
||||
|
||||
remote_name = construct_git_remote_name(self._organization_name, self._project_name, repository_name, remote_prefix)
|
||||
return does_git_remote_exist(remote_name)
|
||||
|
||||
# The function will initialize a git repo, create git remote, stage all changes, commit and push to remote
|
||||
# Exceptions: GitOperationException
|
||||
def setup_local_git_repository(self, repository_name, remote_prefix):
|
||||
"""This command sets up a remote. It is normally used if a user already has a repository locally that they don't wish to get rid of"""
|
||||
if self._remote_exists(remote_name):
|
||||
message = """There is already an remote with this name."""
|
||||
succeeded = False
|
||||
else:
|
||||
origin_command = ["git", "remote", "add", remote_name, "https://" + self._organization_name + \
|
||||
".visualstudio.com/" + self._project_name + "/_git/" + repository_name]
|
||||
check_call(origin_command, stdout=DEVNULL, stderr=STDOUT)
|
||||
check_call('git add -A'.split(), stdout=DEVNULL, stderr=STDOUT)
|
||||
try:
|
||||
check_call(["git", "commit", "-a", "-m", "\"creating functions app\""], stdout=DEVNULL, stderr=STDOUT)
|
||||
except CalledProcessError:
|
||||
print("no need to commit anything")
|
||||
check_call(('git push ' + remote_name + ' --all').split(), stdout=DEVNULL, stderr=STDOUT)
|
||||
message = "succeeded"
|
||||
succeeded = True
|
||||
return models.repository_response.RepositoryResponse(message, succeeded)
|
||||
|
||||
def setup_repository(self, repository_name):
|
||||
"""This command sets up the repository locally - it initialises the git file and creates the initial push ect"""
|
||||
remote_name = construct_git_remote_name(self._organization_name, self._project_name, repository_name, remote_prefix)
|
||||
remote_url = construct_git_remote_url(self._organization_name, self._project_name, repository_name)
|
||||
|
||||
if self._repository_exists():
|
||||
message = """There is already an existing repository in this folder."""
|
||||
succeeded = False
|
||||
else:
|
||||
origin_command = ["git", "remote", "add", "origin", "https://" + self._organization_name + \
|
||||
".visualstudio.com/" + self._project_name + "/_git/" + repository_name]
|
||||
check_call('git init'.split(), stdout=DEVNULL, stderr=STDOUT)
|
||||
check_call('git add -A'.split(), stdout=DEVNULL, stderr=STDOUT)
|
||||
check_call(["git", "commit", "-a", "-m", "\"creating functions app\""], stdout=DEVNULL, stderr=STDOUT)
|
||||
check_call(origin_command, stdout=DEVNULL, stderr=STDOUT)
|
||||
check_call('git push -u origin --all'.split(), stdout=DEVNULL, stderr=STDOUT)
|
||||
message = "succeeded"
|
||||
succeeded = True
|
||||
return models.repository_response.RepositoryResponse(message, succeeded)
|
||||
git_init()
|
||||
|
||||
def setup_github_repository(self):
|
||||
check_call('git add -A'.split(), stdout=DEVNULL, stderr=STDOUT)
|
||||
check_call(["git", "commit", "-a", "-m", "\"creating functions app\""], stdout=DEVNULL, stderr=STDOUT)
|
||||
check_call('git push'.split(), stdout=DEVNULL, stderr=STDOUT)
|
||||
git_add_remote(remote_name, remote_url)
|
||||
git_stage_all()
|
||||
git_commit("Create function app with azure devops build. Remote repository url: {url}".format(url=remote_url))
|
||||
git_push(remote_name)
|
||||
|
||||
def _repository_exists(self):
|
||||
"""Helper to see if gitfile exists"""
|
||||
return bool(os.path.exists('.git'))
|
||||
|
||||
def _remote_exists(self, remote_name):
|
||||
lines = (check_output('git remote show'.split())).decode('utf-8').split('\n')
|
||||
for line in lines:
|
||||
if line == remote_name:
|
||||
return True
|
||||
return False
|
||||
|
||||
def list_github_repositories(self):
|
||||
"""List github repositories if there are any from the current connection"""
|
||||
project = self._get_project_by_name(self._project_name)
|
||||
|
|
|
@ -44,6 +44,8 @@ class ServiceEndpointManager(BaseManager):
|
|||
|
||||
return self._service_endpoint_client.create_service_endpoint(service_endpoint, project.id)
|
||||
|
||||
# This function requires user permission of Microsoft.Authorization/roleAssignments/write
|
||||
# i.e. only the owner of the subscription can use this function
|
||||
def create_service_endpoint(self, servicePrincipalName):
|
||||
"""Create a new service endpoint within a project with an associated service principal"""
|
||||
project = self._get_project_by_name(self._project_name)
|
||||
|
@ -59,7 +61,7 @@ class ServiceEndpointManager(BaseManager):
|
|||
data["scopeLevel"] = "Subscription"
|
||||
|
||||
# A service principal name has to include the http to be valid
|
||||
servicePrincipalNameHttp = "http://" + servicePrincipalName
|
||||
servicePrincipalNameHttp = "https://dev.azure.com/" + servicePrincipalName
|
||||
command = "az ad sp create-for-rbac --o json --name " + servicePrincipalNameHttp
|
||||
token_resp = subprocess.check_output(command, shell=True).decode()
|
||||
token_resp_dict = json.loads(token_resp)
|
||||
|
|
Загрузка…
Ссылка в новой задаче