Merge pull request #2655 from levinine/add-codecommit
add codecommit create, get and delete repository
This commit is contained in:
commit
d0d95420e7
@ -1240,14 +1240,14 @@
|
||||
- [ ] create_commit
|
||||
- [ ] create_pull_request
|
||||
- [ ] create_pull_request_approval_rule
|
||||
- [ ] create_repository
|
||||
- [X] create_repository
|
||||
- [ ] create_unreferenced_merge_commit
|
||||
- [ ] delete_approval_rule_template
|
||||
- [ ] delete_branch
|
||||
- [ ] delete_comment_content
|
||||
- [ ] delete_file
|
||||
- [ ] delete_pull_request_approval_rule
|
||||
- [ ] delete_repository
|
||||
- [X] delete_repository
|
||||
- [ ] describe_merge_conflicts
|
||||
- [ ] describe_pull_request_events
|
||||
- [ ] disassociate_approval_rule_template_from_repository
|
||||
@ -1268,7 +1268,7 @@
|
||||
- [ ] get_pull_request
|
||||
- [ ] get_pull_request_approval_states
|
||||
- [ ] get_pull_request_override_state
|
||||
- [ ] get_repository
|
||||
- [X] get_repository
|
||||
- [ ] get_repository_triggers
|
||||
- [ ] list_approval_rule_templates
|
||||
- [ ] list_associated_approval_rule_templates_for_repository
|
||||
|
@ -9,6 +9,7 @@ from .batch import mock_batch # noqa
|
||||
from .cloudformation import mock_cloudformation # noqa
|
||||
from .cloudformation import mock_cloudformation_deprecated # noqa
|
||||
from .cloudwatch import mock_cloudwatch, mock_cloudwatch_deprecated # noqa
|
||||
from .codecommit import mock_codecommit # noqa
|
||||
from .codepipeline import mock_codepipeline # noqa
|
||||
from .cognitoidentity import mock_cognitoidentity # noqa
|
||||
from .cognitoidentity import mock_cognitoidentity_deprecated # noqa
|
||||
|
@ -8,6 +8,7 @@ from moto.awslambda import lambda_backends
|
||||
from moto.batch import batch_backends
|
||||
from moto.cloudformation import cloudformation_backends
|
||||
from moto.cloudwatch import cloudwatch_backends
|
||||
from moto.codecommit import codecommit_backends
|
||||
from moto.codepipeline import codepipeline_backends
|
||||
from moto.cognitoidentity import cognitoidentity_backends
|
||||
from moto.cognitoidp import cognitoidp_backends
|
||||
@ -62,6 +63,7 @@ BACKENDS = {
|
||||
"batch": batch_backends,
|
||||
"cloudformation": cloudformation_backends,
|
||||
"cloudwatch": cloudwatch_backends,
|
||||
"codecommit": codecommit_backends,
|
||||
"codepipeline": codepipeline_backends,
|
||||
"cognito-identity": cognitoidentity_backends,
|
||||
"cognito-idp": cognitoidp_backends,
|
||||
|
4
moto/codecommit/__init__.py
Normal file
4
moto/codecommit/__init__.py
Normal file
@ -0,0 +1,4 @@
|
||||
from .models import codecommit_backends
|
||||
from ..core.models import base_decorator
|
||||
|
||||
mock_codecommit = base_decorator(codecommit_backends)
|
35
moto/codecommit/exceptions.py
Normal file
35
moto/codecommit/exceptions.py
Normal file
@ -0,0 +1,35 @@
|
||||
from moto.core.exceptions import JsonRESTError
|
||||
|
||||
|
||||
class RepositoryNameExistsException(JsonRESTError):
|
||||
code = 400
|
||||
|
||||
def __init__(self, repository_name):
|
||||
super(RepositoryNameExistsException, self).__init__(
|
||||
"RepositoryNameExistsException",
|
||||
"Repository named {0} already exists".format(repository_name),
|
||||
)
|
||||
|
||||
|
||||
class RepositoryDoesNotExistException(JsonRESTError):
|
||||
code = 400
|
||||
|
||||
def __init__(self, repository_name):
|
||||
super(RepositoryDoesNotExistException, self).__init__(
|
||||
"RepositoryDoesNotExistException",
|
||||
"{0} does not exist".format(repository_name),
|
||||
)
|
||||
|
||||
|
||||
class InvalidRepositoryNameException(JsonRESTError):
|
||||
code = 400
|
||||
|
||||
def __init__(self):
|
||||
super(InvalidRepositoryNameException, self).__init__(
|
||||
"InvalidRepositoryNameException",
|
||||
"The repository name is not valid. Repository names can be any valid "
|
||||
"combination of letters, numbers, "
|
||||
"periods, underscores, and dashes between 1 and 100 characters in "
|
||||
"length. Names are case sensitive. "
|
||||
"For more information, see Limits in the AWS CodeCommit User Guide. ",
|
||||
)
|
69
moto/codecommit/models.py
Normal file
69
moto/codecommit/models.py
Normal file
@ -0,0 +1,69 @@
|
||||
from boto3 import Session
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
from moto.core.utils import iso_8601_datetime_with_milliseconds
|
||||
from datetime import datetime
|
||||
from moto.iam.models import ACCOUNT_ID
|
||||
from .exceptions import RepositoryDoesNotExistException, RepositoryNameExistsException
|
||||
import uuid
|
||||
|
||||
|
||||
class CodeCommit(BaseModel):
|
||||
def __init__(self, region, repository_description, repository_name):
|
||||
current_date = iso_8601_datetime_with_milliseconds(datetime.utcnow())
|
||||
self.repository_metadata = dict()
|
||||
self.repository_metadata["repositoryName"] = repository_name
|
||||
self.repository_metadata[
|
||||
"cloneUrlSsh"
|
||||
] = "ssh://git-codecommit.{0}.amazonaws.com/v1/repos/{1}".format(
|
||||
region, repository_name
|
||||
)
|
||||
self.repository_metadata[
|
||||
"cloneUrlHttp"
|
||||
] = "https://git-codecommit.{0}.amazonaws.com/v1/repos/{1}".format(
|
||||
region, repository_name
|
||||
)
|
||||
self.repository_metadata["creationDate"] = current_date
|
||||
self.repository_metadata["lastModifiedDate"] = current_date
|
||||
self.repository_metadata["repositoryDescription"] = repository_description
|
||||
self.repository_metadata["repositoryId"] = str(uuid.uuid4())
|
||||
self.repository_metadata["Arn"] = "arn:aws:codecommit:{0}:{1}:{2}".format(
|
||||
region, ACCOUNT_ID, repository_name
|
||||
)
|
||||
self.repository_metadata["accountId"] = ACCOUNT_ID
|
||||
|
||||
|
||||
class CodeCommitBackend(BaseBackend):
|
||||
def __init__(self):
|
||||
self.repositories = {}
|
||||
|
||||
def create_repository(self, region, repository_name, repository_description):
|
||||
repository = self.repositories.get(repository_name)
|
||||
if repository:
|
||||
raise RepositoryNameExistsException(repository_name)
|
||||
|
||||
self.repositories[repository_name] = CodeCommit(
|
||||
region, repository_description, repository_name
|
||||
)
|
||||
|
||||
return self.repositories[repository_name].repository_metadata
|
||||
|
||||
def get_repository(self, repository_name):
|
||||
repository = self.repositories.get(repository_name)
|
||||
if not repository:
|
||||
raise RepositoryDoesNotExistException(repository_name)
|
||||
|
||||
return repository.repository_metadata
|
||||
|
||||
def delete_repository(self, repository_name):
|
||||
repository = self.repositories.get(repository_name)
|
||||
|
||||
if repository:
|
||||
self.repositories.pop(repository_name)
|
||||
return repository.repository_metadata.get("repositoryId")
|
||||
|
||||
return None
|
||||
|
||||
|
||||
codecommit_backends = {}
|
||||
for region in Session().get_available_regions("codecommit"):
|
||||
codecommit_backends[region] = CodeCommitBackend()
|
57
moto/codecommit/responses.py
Normal file
57
moto/codecommit/responses.py
Normal file
@ -0,0 +1,57 @@
|
||||
import json
|
||||
import re
|
||||
|
||||
from moto.core.responses import BaseResponse
|
||||
from .models import codecommit_backends
|
||||
from .exceptions import InvalidRepositoryNameException
|
||||
|
||||
|
||||
def _is_repository_name_valid(repository_name):
|
||||
name_regex = re.compile(r"[\w\.-]+")
|
||||
result = name_regex.split(repository_name)
|
||||
if len(result) > 0:
|
||||
for match in result:
|
||||
if len(match) > 0:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
class CodeCommitResponse(BaseResponse):
|
||||
@property
|
||||
def codecommit_backend(self):
|
||||
return codecommit_backends[self.region]
|
||||
|
||||
def create_repository(self):
|
||||
if not _is_repository_name_valid(self._get_param("repositoryName")):
|
||||
raise InvalidRepositoryNameException()
|
||||
|
||||
repository_metadata = self.codecommit_backend.create_repository(
|
||||
self.region,
|
||||
self._get_param("repositoryName"),
|
||||
self._get_param("repositoryDescription"),
|
||||
)
|
||||
|
||||
return json.dumps({"repositoryMetadata": repository_metadata})
|
||||
|
||||
def get_repository(self):
|
||||
if not _is_repository_name_valid(self._get_param("repositoryName")):
|
||||
raise InvalidRepositoryNameException()
|
||||
|
||||
repository_metadata = self.codecommit_backend.get_repository(
|
||||
self._get_param("repositoryName")
|
||||
)
|
||||
|
||||
return json.dumps({"repositoryMetadata": repository_metadata})
|
||||
|
||||
def delete_repository(self):
|
||||
if not _is_repository_name_valid(self._get_param("repositoryName")):
|
||||
raise InvalidRepositoryNameException()
|
||||
|
||||
repository_id = self.codecommit_backend.delete_repository(
|
||||
self._get_param("repositoryName")
|
||||
)
|
||||
|
||||
if repository_id:
|
||||
return json.dumps({"repositoryId": repository_id})
|
||||
|
||||
return json.dumps({})
|
6
moto/codecommit/urls.py
Normal file
6
moto/codecommit/urls.py
Normal file
@ -0,0 +1,6 @@
|
||||
from __future__ import unicode_literals
|
||||
from .responses import CodeCommitResponse
|
||||
|
||||
url_bases = ["https?://codecommit.(.+).amazonaws.com"]
|
||||
|
||||
url_paths = {"{0}/$": CodeCommitResponse.dispatch}
|
222
tests/test_codecommit/test_codecommit.py
Normal file
222
tests/test_codecommit/test_codecommit.py
Normal file
@ -0,0 +1,222 @@
|
||||
import boto3
|
||||
|
||||
import sure # noqa
|
||||
from moto import mock_codecommit
|
||||
from moto.iam.models import ACCOUNT_ID
|
||||
from botocore.exceptions import ClientError
|
||||
from nose.tools import assert_raises
|
||||
|
||||
|
||||
@mock_codecommit
|
||||
def test_create_repository():
|
||||
client = boto3.client("codecommit", region_name="eu-central-1")
|
||||
response = client.create_repository(
|
||||
repositoryName="repository_one", repositoryDescription="description repo one"
|
||||
)
|
||||
|
||||
response.should_not.be.none
|
||||
response["repositoryMetadata"].should_not.be.none
|
||||
response["repositoryMetadata"]["creationDate"].should_not.be.none
|
||||
response["repositoryMetadata"]["lastModifiedDate"].should_not.be.none
|
||||
response["repositoryMetadata"]["repositoryId"].should_not.be.empty
|
||||
response["repositoryMetadata"]["repositoryName"].should.equal("repository_one")
|
||||
response["repositoryMetadata"]["repositoryDescription"].should.equal(
|
||||
"description repo one"
|
||||
)
|
||||
response["repositoryMetadata"]["cloneUrlSsh"].should.equal(
|
||||
"ssh://git-codecommit.{0}.amazonaws.com/v1/repos/{1}".format(
|
||||
"eu-central-1", "repository_one"
|
||||
)
|
||||
)
|
||||
response["repositoryMetadata"]["cloneUrlHttp"].should.equal(
|
||||
"https://git-codecommit.{0}.amazonaws.com/v1/repos/{1}".format(
|
||||
"eu-central-1", "repository_one"
|
||||
)
|
||||
)
|
||||
response["repositoryMetadata"]["Arn"].should.equal(
|
||||
"arn:aws:codecommit:{0}:{1}:{2}".format(
|
||||
"eu-central-1", ACCOUNT_ID, "repository_one"
|
||||
)
|
||||
)
|
||||
response["repositoryMetadata"]["accountId"].should.equal(ACCOUNT_ID)
|
||||
|
||||
|
||||
@mock_codecommit
|
||||
def test_create_repository_without_description():
|
||||
client = boto3.client("codecommit", region_name="eu-central-1")
|
||||
|
||||
response = client.create_repository(repositoryName="repository_two")
|
||||
|
||||
response.should_not.be.none
|
||||
response.get("repositoryMetadata").should_not.be.none
|
||||
response.get("repositoryMetadata").get("repositoryName").should.equal(
|
||||
"repository_two"
|
||||
)
|
||||
response.get("repositoryMetadata").get("repositoryDescription").should.be.none
|
||||
response["repositoryMetadata"].should_not.be.none
|
||||
response["repositoryMetadata"]["creationDate"].should_not.be.none
|
||||
response["repositoryMetadata"]["lastModifiedDate"].should_not.be.none
|
||||
response["repositoryMetadata"]["repositoryId"].should_not.be.empty
|
||||
response["repositoryMetadata"]["cloneUrlSsh"].should.equal(
|
||||
"ssh://git-codecommit.{0}.amazonaws.com/v1/repos/{1}".format(
|
||||
"eu-central-1", "repository_two"
|
||||
)
|
||||
)
|
||||
response["repositoryMetadata"]["cloneUrlHttp"].should.equal(
|
||||
"https://git-codecommit.{0}.amazonaws.com/v1/repos/{1}".format(
|
||||
"eu-central-1", "repository_two"
|
||||
)
|
||||
)
|
||||
response["repositoryMetadata"]["Arn"].should.equal(
|
||||
"arn:aws:codecommit:{0}:{1}:{2}".format(
|
||||
"eu-central-1", ACCOUNT_ID, "repository_two"
|
||||
)
|
||||
)
|
||||
response["repositoryMetadata"]["accountId"].should.equal(ACCOUNT_ID)
|
||||
|
||||
|
||||
@mock_codecommit
|
||||
def test_create_repository_repository_name_exists():
|
||||
client = boto3.client("codecommit", region_name="eu-central-1")
|
||||
|
||||
client.create_repository(repositoryName="repository_two")
|
||||
|
||||
with assert_raises(ClientError) as e:
|
||||
client.create_repository(
|
||||
repositoryName="repository_two",
|
||||
repositoryDescription="description repo two",
|
||||
)
|
||||
ex = e.exception
|
||||
ex.operation_name.should.equal("CreateRepository")
|
||||
ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
|
||||
ex.response["Error"]["Code"].should.contain("RepositoryNameExistsException")
|
||||
ex.response["Error"]["Message"].should.equal(
|
||||
"Repository named {0} already exists".format("repository_two")
|
||||
)
|
||||
|
||||
|
||||
@mock_codecommit
|
||||
def test_create_repository_invalid_repository_name():
|
||||
client = boto3.client("codecommit", region_name="eu-central-1")
|
||||
|
||||
with assert_raises(ClientError) as e:
|
||||
client.create_repository(repositoryName="in_123_valid_@#$_characters")
|
||||
ex = e.exception
|
||||
ex.operation_name.should.equal("CreateRepository")
|
||||
ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
|
||||
ex.response["Error"]["Code"].should.contain("InvalidRepositoryNameException")
|
||||
ex.response["Error"]["Message"].should.equal(
|
||||
"The repository name is not valid. Repository names can be any valid "
|
||||
"combination of letters, numbers, "
|
||||
"periods, underscores, and dashes between 1 and 100 characters in "
|
||||
"length. Names are case sensitive. "
|
||||
"For more information, see Limits in the AWS CodeCommit User Guide. "
|
||||
)
|
||||
|
||||
|
||||
@mock_codecommit
|
||||
def test_get_repository():
|
||||
client = boto3.client("codecommit", region_name="eu-central-1")
|
||||
|
||||
repository_name = "repository_one"
|
||||
|
||||
client.create_repository(
|
||||
repositoryName=repository_name, repositoryDescription="description repo one"
|
||||
)
|
||||
|
||||
response = client.get_repository(repositoryName=repository_name)
|
||||
|
||||
response.should_not.be.none
|
||||
response.get("repositoryMetadata").should_not.be.none
|
||||
response.get("repositoryMetadata").get("creationDate").should_not.be.none
|
||||
response.get("repositoryMetadata").get("lastModifiedDate").should_not.be.none
|
||||
response.get("repositoryMetadata").get("repositoryId").should_not.be.empty
|
||||
response.get("repositoryMetadata").get("repositoryName").should.equal(
|
||||
repository_name
|
||||
)
|
||||
response.get("repositoryMetadata").get("repositoryDescription").should.equal(
|
||||
"description repo one"
|
||||
)
|
||||
response.get("repositoryMetadata").get("cloneUrlSsh").should.equal(
|
||||
"ssh://git-codecommit.{0}.amazonaws.com/v1/repos/{1}".format(
|
||||
"eu-central-1", "repository_one"
|
||||
)
|
||||
)
|
||||
response.get("repositoryMetadata").get("cloneUrlHttp").should.equal(
|
||||
"https://git-codecommit.{0}.amazonaws.com/v1/repos/{1}".format(
|
||||
"eu-central-1", "repository_one"
|
||||
)
|
||||
)
|
||||
response.get("repositoryMetadata").get("Arn").should.equal(
|
||||
"arn:aws:codecommit:{0}:{1}:{2}".format(
|
||||
"eu-central-1", ACCOUNT_ID, "repository_one"
|
||||
)
|
||||
)
|
||||
response.get("repositoryMetadata").get("accountId").should.equal(ACCOUNT_ID)
|
||||
|
||||
client = boto3.client("codecommit", region_name="us-east-1")
|
||||
|
||||
with assert_raises(ClientError) as e:
|
||||
client.get_repository(repositoryName=repository_name)
|
||||
ex = e.exception
|
||||
ex.operation_name.should.equal("GetRepository")
|
||||
ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
|
||||
ex.response["Error"]["Code"].should.contain("RepositoryDoesNotExistException")
|
||||
ex.response["Error"]["Message"].should.equal(
|
||||
"{0} does not exist".format(repository_name)
|
||||
)
|
||||
|
||||
|
||||
@mock_codecommit
|
||||
def test_get_repository_invalid_repository_name():
|
||||
client = boto3.client("codecommit", region_name="eu-central-1")
|
||||
|
||||
with assert_raises(ClientError) as e:
|
||||
client.get_repository(repositoryName="repository_one-@#@")
|
||||
ex = e.exception
|
||||
ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
|
||||
ex.response["Error"]["Code"].should.contain("InvalidRepositoryNameException")
|
||||
ex.response["Error"]["Message"].should.equal(
|
||||
"The repository name is not valid. Repository names can be any valid "
|
||||
"combination of letters, numbers, "
|
||||
"periods, underscores, and dashes between 1 and 100 characters in "
|
||||
"length. Names are case sensitive. "
|
||||
"For more information, see Limits in the AWS CodeCommit User Guide. "
|
||||
)
|
||||
|
||||
|
||||
@mock_codecommit
|
||||
def test_delete_repository():
|
||||
client = boto3.client("codecommit", region_name="us-east-1")
|
||||
|
||||
response = client.create_repository(repositoryName="repository_one")
|
||||
|
||||
repository_id_create = response.get("repositoryMetadata").get("repositoryId")
|
||||
|
||||
response = client.delete_repository(repositoryName="repository_one")
|
||||
|
||||
response.get("repositoryId").should_not.be.none
|
||||
repository_id_create.should.equal(response.get("repositoryId"))
|
||||
|
||||
response = client.delete_repository(repositoryName="unknown_repository")
|
||||
|
||||
response.get("repositoryId").should.be.none
|
||||
|
||||
|
||||
@mock_codecommit
|
||||
def test_delete_repository_invalid_repository_name():
|
||||
client = boto3.client("codecommit", region_name="us-east-1")
|
||||
|
||||
with assert_raises(ClientError) as e:
|
||||
client.delete_repository(repositoryName="_rep@ository_one")
|
||||
ex = e.exception
|
||||
ex.operation_name.should.equal("DeleteRepository")
|
||||
ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
|
||||
ex.response["Error"]["Code"].should.contain("InvalidRepositoryNameException")
|
||||
ex.response["Error"]["Message"].should.equal(
|
||||
"The repository name is not valid. Repository names can be any valid "
|
||||
"combination of letters, numbers, "
|
||||
"periods, underscores, and dashes between 1 and 100 characters in "
|
||||
"length. Names are case sensitive. "
|
||||
"For more information, see Limits in the AWS CodeCommit User Guide. "
|
||||
)
|
Loading…
Reference in New Issue
Block a user