Add support for codebuild (#5282)
This commit is contained in:
parent
c1bdd764c7
commit
79af23aeb7
@ -338,7 +338,7 @@
|
||||
|
||||
## autoscaling
|
||||
<details>
|
||||
<summary>49% implemented</summary>
|
||||
<summary>50% implemented</summary>
|
||||
|
||||
- [X] attach_instances
|
||||
- [X] attach_load_balancer_target_groups
|
||||
@ -382,7 +382,7 @@
|
||||
- [X] detach_load_balancer_target_groups
|
||||
- [X] detach_load_balancers
|
||||
- [ ] disable_metrics_collection
|
||||
- [ ] enable_metrics_collection
|
||||
- [X] enable_metrics_collection
|
||||
- [ ] enter_standby
|
||||
- [X] execute_policy
|
||||
- [ ] exit_standby
|
||||
@ -462,6 +462,47 @@
|
||||
- [ ] update_subscriber
|
||||
</details>
|
||||
|
||||
## ce
|
||||
<details>
|
||||
<summary>11% implemented</summary>
|
||||
|
||||
- [ ] create_anomaly_monitor
|
||||
- [ ] create_anomaly_subscription
|
||||
- [X] create_cost_category_definition
|
||||
- [ ] delete_anomaly_monitor
|
||||
- [ ] delete_anomaly_subscription
|
||||
- [X] delete_cost_category_definition
|
||||
- [X] describe_cost_category_definition
|
||||
- [ ] get_anomalies
|
||||
- [ ] get_anomaly_monitors
|
||||
- [ ] get_anomaly_subscriptions
|
||||
- [ ] get_cost_and_usage
|
||||
- [ ] get_cost_and_usage_with_resources
|
||||
- [ ] get_cost_categories
|
||||
- [ ] get_cost_forecast
|
||||
- [ ] get_dimension_values
|
||||
- [ ] get_reservation_coverage
|
||||
- [ ] get_reservation_purchase_recommendation
|
||||
- [ ] get_reservation_utilization
|
||||
- [ ] get_rightsizing_recommendation
|
||||
- [ ] get_savings_plans_coverage
|
||||
- [ ] get_savings_plans_purchase_recommendation
|
||||
- [ ] get_savings_plans_utilization
|
||||
- [ ] get_savings_plans_utilization_details
|
||||
- [ ] get_tags
|
||||
- [ ] get_usage_forecast
|
||||
- [ ] list_cost_allocation_tags
|
||||
- [ ] list_cost_category_definitions
|
||||
- [ ] list_tags_for_resource
|
||||
- [ ] provide_anomaly_feedback
|
||||
- [ ] tag_resource
|
||||
- [ ] untag_resource
|
||||
- [ ] update_anomaly_monitor
|
||||
- [ ] update_anomaly_subscription
|
||||
- [ ] update_cost_allocation_tags_status
|
||||
- [X] update_cost_category_definition
|
||||
</details>
|
||||
|
||||
## cloudformation
|
||||
<details>
|
||||
<summary>30% implemented</summary>
|
||||
@ -709,6 +750,57 @@
|
||||
- [X] untag_resource
|
||||
</details>
|
||||
|
||||
## codebuild
|
||||
<details>
|
||||
<summary>17% implemented</summary>
|
||||
|
||||
- [ ] batch_delete_builds
|
||||
- [ ] batch_get_build_batches
|
||||
- [X] batch_get_builds
|
||||
- [ ] batch_get_projects
|
||||
- [ ] batch_get_report_groups
|
||||
- [ ] batch_get_reports
|
||||
- [X] create_project
|
||||
- [ ] create_report_group
|
||||
- [ ] create_webhook
|
||||
- [ ] delete_build_batch
|
||||
- [X] delete_project
|
||||
- [ ] delete_report
|
||||
- [ ] delete_report_group
|
||||
- [ ] delete_resource_policy
|
||||
- [ ] delete_source_credentials
|
||||
- [ ] delete_webhook
|
||||
- [ ] describe_code_coverages
|
||||
- [ ] describe_test_cases
|
||||
- [ ] get_report_group_trend
|
||||
- [ ] get_resource_policy
|
||||
- [ ] import_source_credentials
|
||||
- [ ] invalidate_project_cache
|
||||
- [ ] list_build_batches
|
||||
- [ ] list_build_batches_for_project
|
||||
- [X] list_builds
|
||||
- [X] list_builds_for_project
|
||||
- [ ] list_curated_environment_images
|
||||
- [X] list_projects
|
||||
- [ ] list_report_groups
|
||||
- [ ] list_reports
|
||||
- [ ] list_reports_for_report_group
|
||||
- [ ] list_shared_projects
|
||||
- [ ] list_shared_report_groups
|
||||
- [ ] list_source_credentials
|
||||
- [ ] put_resource_policy
|
||||
- [ ] retry_build
|
||||
- [ ] retry_build_batch
|
||||
- [X] start_build
|
||||
- [ ] start_build_batch
|
||||
- [X] stop_build
|
||||
- [ ] stop_build_batch
|
||||
- [ ] update_project
|
||||
- [ ] update_project_visibility
|
||||
- [ ] update_report_group
|
||||
- [ ] update_webhook
|
||||
</details>
|
||||
|
||||
## codecommit
|
||||
<details>
|
||||
<summary>3% implemented</summary>
|
||||
@ -1289,7 +1381,7 @@
|
||||
|
||||
## ds
|
||||
<details>
|
||||
<summary>18% implemented</summary>
|
||||
<summary>19% implemented</summary>
|
||||
|
||||
- [ ] accept_shared_directory
|
||||
- [ ] add_ip_routes
|
||||
@ -1320,7 +1412,6 @@
|
||||
- [ ] describe_event_topics
|
||||
- [ ] describe_ldaps_settings
|
||||
- [ ] describe_regions
|
||||
- [ ] describe_settings
|
||||
- [ ] describe_shared_directories
|
||||
- [ ] describe_snapshots
|
||||
- [ ] describe_trusts
|
||||
@ -1353,7 +1444,6 @@
|
||||
- [ ] update_conditional_forwarder
|
||||
- [ ] update_number_of_domain_controllers
|
||||
- [ ] update_radius
|
||||
- [ ] update_settings
|
||||
- [ ] update_trust
|
||||
- [ ] verify_trust
|
||||
</details>
|
||||
@ -2457,7 +2547,7 @@
|
||||
|
||||
## emr-serverless
|
||||
<details>
|
||||
<summary>71% implemented</summary>
|
||||
<summary>50% implemented</summary>
|
||||
|
||||
- [ ] cancel_job_run
|
||||
- [X] create_application
|
||||
@ -2468,7 +2558,7 @@
|
||||
- [ ] list_job_runs
|
||||
- [ ] list_tags_for_resource
|
||||
- [X] start_application
|
||||
- [X] start_job_run
|
||||
- [ ] start_job_run
|
||||
- [X] stop_application
|
||||
- [ ] tag_resource
|
||||
- [ ] untag_resource
|
||||
@ -2828,7 +2918,6 @@
|
||||
- [ ] import_catalog_to_glue
|
||||
- [ ] list_blueprints
|
||||
- [X] list_crawlers
|
||||
- [ ] list_crawls
|
||||
- [ ] list_custom_entity_types
|
||||
- [ ] list_dev_endpoints
|
||||
- [X] list_jobs
|
||||
@ -5998,7 +6087,6 @@
|
||||
- backup-gateway
|
||||
- billingconductor
|
||||
- braket
|
||||
- ce
|
||||
- chime
|
||||
- chime-sdk-identity
|
||||
- chime-sdk-media-pipelines
|
||||
@ -6012,7 +6100,6 @@
|
||||
- cloudsearch
|
||||
- cloudsearchdomain
|
||||
- codeartifact
|
||||
- codebuild
|
||||
- codedeploy
|
||||
- codeguru-reviewer
|
||||
- codeguruprofiler
|
||||
@ -6040,7 +6127,6 @@
|
||||
- drs
|
||||
- ecr-public
|
||||
- elastic-inference
|
||||
- emr-serverless
|
||||
- evidently
|
||||
- finspace
|
||||
- finspace-data
|
||||
@ -6138,6 +6224,7 @@
|
||||
- qldb-session
|
||||
- rbin
|
||||
- rds-data
|
||||
- redshiftserverless
|
||||
- resiliencehub
|
||||
- robomaker
|
||||
- route53-recovery-cluster
|
||||
|
75
docs/docs/services/codebuild.rst
Normal file
75
docs/docs/services/codebuild.rst
Normal file
@ -0,0 +1,75 @@
|
||||
.. _implementedservice_codebuild:
|
||||
|
||||
.. |start-h3| raw:: html
|
||||
|
||||
<h3>
|
||||
|
||||
.. |end-h3| raw:: html
|
||||
|
||||
</h3>
|
||||
|
||||
=========
|
||||
codebuild
|
||||
=========
|
||||
|
||||
.. autoclass:: moto.codebuild.models.CodeBuildBackend
|
||||
|
||||
|start-h3| Example usage |end-h3|
|
||||
|
||||
.. sourcecode:: python
|
||||
|
||||
@mock_codebuild
|
||||
def test_codebuild_behaviour:
|
||||
boto3.client("codebuild")
|
||||
...
|
||||
|
||||
|
||||
|
||||
|start-h3| Implemented features for this service |end-h3|
|
||||
|
||||
- [ ] batch_delete_builds
|
||||
- [ ] batch_get_build_batches
|
||||
- [X] batch_get_builds
|
||||
- [ ] batch_get_projects
|
||||
- [ ] batch_get_report_groups
|
||||
- [ ] batch_get_reports
|
||||
- [X] create_project
|
||||
- [ ] create_report_group
|
||||
- [ ] create_webhook
|
||||
- [ ] delete_build_batch
|
||||
- [X] delete_project
|
||||
- [ ] delete_report
|
||||
- [ ] delete_report_group
|
||||
- [ ] delete_resource_policy
|
||||
- [ ] delete_source_credentials
|
||||
- [ ] delete_webhook
|
||||
- [ ] describe_code_coverages
|
||||
- [ ] describe_test_cases
|
||||
- [ ] get_report_group_trend
|
||||
- [ ] get_resource_policy
|
||||
- [ ] import_source_credentials
|
||||
- [ ] invalidate_project_cache
|
||||
- [ ] list_build_batches
|
||||
- [ ] list_build_batches_for_project
|
||||
- [X] list_builds
|
||||
- [X] list_builds_for_project
|
||||
- [ ] list_curated_environment_images
|
||||
- [X] list_projects
|
||||
- [ ] list_report_groups
|
||||
- [ ] list_reports
|
||||
- [ ] list_reports_for_report_group
|
||||
- [ ] list_shared_projects
|
||||
- [ ] list_shared_report_groups
|
||||
- [ ] list_source_credentials
|
||||
- [ ] put_resource_policy
|
||||
- [ ] retry_build
|
||||
- [ ] retry_build_batch
|
||||
- [X] start_build
|
||||
- [ ] start_build_batch
|
||||
- [X] stop_build
|
||||
- [ ] stop_build_batch
|
||||
- [ ] update_project
|
||||
- [ ] update_project_visibility
|
||||
- [ ] update_report_group
|
||||
- [ ] update_webhook
|
||||
|
@ -63,6 +63,7 @@ mock_cloudfront = lazy_load(".cloudfront", "mock_cloudfront")
|
||||
mock_cloudtrail = lazy_load(".cloudtrail", "mock_cloudtrail")
|
||||
mock_cloudwatch = lazy_load(".cloudwatch", "mock_cloudwatch")
|
||||
mock_codecommit = lazy_load(".codecommit", "mock_codecommit")
|
||||
mock_codebuild = lazy_load(".codebuild", "mock_codebuild")
|
||||
mock_codepipeline = lazy_load(".codepipeline", "mock_codepipeline")
|
||||
mock_cognitoidentity = lazy_load(
|
||||
".cognitoidentity", "mock_cognitoidentity", boto3_name="cognito-identity"
|
||||
|
@ -18,6 +18,7 @@ backend_url_patterns = [
|
||||
("cloudfront", re.compile("https?://cloudfront\\.amazonaws\\.com")),
|
||||
("cloudtrail", re.compile("https?://cloudtrail\\.(.+)\\.amazonaws\\.com")),
|
||||
("cloudwatch", re.compile("https?://monitoring\\.(.+)\\.amazonaws.com")),
|
||||
("codebuild", re.compile("https?://codebuild\\.(.+)\\.amazonaws\\.com")),
|
||||
("codecommit", re.compile("https?://codecommit\\.(.+)\\.amazonaws\\.com")),
|
||||
("codepipeline", re.compile("https?://codepipeline\\.(.+)\\.amazonaws\\.com")),
|
||||
(
|
||||
|
4
moto/codebuild/__init__.py
Normal file
4
moto/codebuild/__init__.py
Normal file
@ -0,0 +1,4 @@
|
||||
from .models import codebuild_backends
|
||||
from ..core.models import base_decorator
|
||||
|
||||
mock_codebuild = base_decorator(codebuild_backends)
|
24
moto/codebuild/exceptions.py
Normal file
24
moto/codebuild/exceptions.py
Normal file
@ -0,0 +1,24 @@
|
||||
from moto.core.exceptions import JsonRESTError
|
||||
|
||||
""" will need exceptions for each api endpoint hit """
|
||||
|
||||
|
||||
class InvalidInputException(JsonRESTError):
|
||||
code = 400
|
||||
|
||||
def __init__(self, message):
|
||||
super().__init__("InvalidInputException", message)
|
||||
|
||||
|
||||
class ResourceNotFoundException(JsonRESTError):
|
||||
code = 400
|
||||
|
||||
def __init__(self, message):
|
||||
super().__init__("ResourceNotFoundException", message)
|
||||
|
||||
|
||||
class ResourceAlreadyExistsException(JsonRESTError):
|
||||
code = 400
|
||||
|
||||
def __init__(self, message):
|
||||
super().__init__("ResourceAlreadyExistsException", message)
|
263
moto/codebuild/models.py
Normal file
263
moto/codebuild/models.py
Normal file
@ -0,0 +1,263 @@
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
from moto.core.utils import iso_8601_datetime_with_milliseconds, BackendDict
|
||||
from moto.core import get_account_id
|
||||
from collections import defaultdict
|
||||
from random import randint
|
||||
from dateutil import parser
|
||||
import datetime
|
||||
import uuid
|
||||
|
||||
|
||||
class CodeBuildProjectMetadata(BaseModel):
|
||||
def __init__(self, project_name, source_version, artifacts, build_id, service_role):
|
||||
current_date = iso_8601_datetime_with_milliseconds(datetime.datetime.utcnow())
|
||||
self.build_metadata = dict()
|
||||
|
||||
self.build_metadata["id"] = build_id
|
||||
self.build_metadata["arn"] = "arn:aws:codebuild:eu-west-2:{0}:build/{1}".format(
|
||||
get_account_id(), build_id
|
||||
)
|
||||
|
||||
self.build_metadata["buildNumber"] = randint(1, 100)
|
||||
self.build_metadata["startTime"] = current_date
|
||||
self.build_metadata["currentPhase"] = "QUEUED"
|
||||
self.build_metadata["buildStatus"] = "IN_PROGRESS"
|
||||
self.build_metadata["sourceVersion"] = (
|
||||
source_version if source_version else "refs/heads/main"
|
||||
)
|
||||
self.build_metadata["projectName"] = project_name
|
||||
|
||||
self.build_metadata["phases"] = [
|
||||
{
|
||||
"phaseType": "SUBMITTED",
|
||||
"phaseStatus": "SUCCEEDED",
|
||||
"startTime": current_date,
|
||||
"endTime": current_date,
|
||||
"durationInSeconds": 0,
|
||||
},
|
||||
{"phaseType": "QUEUED", "startTime": current_date},
|
||||
]
|
||||
|
||||
self.build_metadata["source"] = {
|
||||
"type": "CODECOMMIT", # should be different based on what you pass in
|
||||
"location": "https://git-codecommit.eu-west-2.amazonaws.com/v1/repos/testing",
|
||||
"gitCloneDepth": 1,
|
||||
"gitSubmodulesConfig": {"fetchSubmodules": False},
|
||||
"buildspec": "buildspec/stuff.yaml", # should present in the codebuild project somewhere
|
||||
"insecureSsl": False,
|
||||
}
|
||||
|
||||
self.build_metadata["secondarySources"] = []
|
||||
self.build_metadata["secondarySourceVersions"] = []
|
||||
self.build_metadata["artifacts"] = artifacts
|
||||
self.build_metadata["secondaryArtifacts"] = []
|
||||
self.build_metadata["cache"] = {"type": "NO_CACHE"}
|
||||
|
||||
self.build_metadata["environment"] = {
|
||||
"type": "LINUX_CONTAINER",
|
||||
"image": "aws/codebuild/amazonlinux2-x86_64-standard:3.0",
|
||||
"computeType": "BUILD_GENERAL1_SMALL",
|
||||
"environmentVariables": [],
|
||||
"privilegedMode": False,
|
||||
"imagePullCredentialsType": "CODEBUILD",
|
||||
}
|
||||
|
||||
self.build_metadata["serviceRole"] = service_role
|
||||
|
||||
self.build_metadata["logs"] = {
|
||||
"deepLink": "https://console.aws.amazon.com/cloudwatch/home?region=eu-west-2#logEvent:group=null;stream=null",
|
||||
"cloudWatchLogsArn": "arn:aws:logs:eu-west-2:{0}:log-group:null:log-stream:null".format(
|
||||
get_account_id()
|
||||
),
|
||||
"cloudWatchLogs": {"status": "ENABLED"},
|
||||
"s3Logs": {"status": "DISABLED", "encryptionDisabled": False},
|
||||
}
|
||||
|
||||
self.build_metadata["timeoutInMinutes"] = 45
|
||||
self.build_metadata["queuedTimeoutInMinutes"] = 480
|
||||
self.build_metadata["buildComplete"] = False
|
||||
self.build_metadata["initiator"] = "rootme"
|
||||
self.build_metadata[
|
||||
"encryptionKey"
|
||||
] = "arn:aws:kms:eu-west-2:{0}:alias/aws/s3".format(get_account_id())
|
||||
|
||||
|
||||
class CodeBuild(BaseModel):
|
||||
def __init__(
|
||||
self,
|
||||
region,
|
||||
project_name,
|
||||
project_source,
|
||||
artifacts,
|
||||
environment,
|
||||
serviceRole="some_role",
|
||||
):
|
||||
current_date = iso_8601_datetime_with_milliseconds(datetime.datetime.utcnow())
|
||||
self.project_metadata = dict()
|
||||
|
||||
self.project_metadata["name"] = project_name
|
||||
self.project_metadata["arn"] = "arn:aws:codebuild:{0}:{1}:project/{2}".format(
|
||||
region, get_account_id(), self.project_metadata["name"]
|
||||
)
|
||||
self.project_metadata[
|
||||
"encryptionKey"
|
||||
] = "arn:aws:kms:{0}:{1}:alias/aws/s3".format(region, get_account_id())
|
||||
self.project_metadata[
|
||||
"serviceRole"
|
||||
] = "arn:aws:iam::{0}:role/service-role/{1}".format(
|
||||
get_account_id(), serviceRole
|
||||
)
|
||||
self.project_metadata["lastModifiedDate"] = current_date
|
||||
self.project_metadata["created"] = current_date
|
||||
self.project_metadata["badge"] = dict()
|
||||
self.project_metadata["badge"][
|
||||
"badgeEnabled"
|
||||
] = False # this false needs to be a json false not a python false
|
||||
self.project_metadata["environment"] = environment
|
||||
self.project_metadata["artifacts"] = artifacts
|
||||
self.project_metadata["source"] = project_source
|
||||
self.project_metadata["cache"] = dict()
|
||||
self.project_metadata["cache"]["type"] = "NO_CACHE"
|
||||
self.project_metadata["timeoutInMinutes"] = ""
|
||||
self.project_metadata["queuedTimeoutInMinutes"] = ""
|
||||
|
||||
|
||||
class CodeBuildBackend(BaseBackend):
|
||||
def __init__(self, region_name, account_id):
|
||||
super().__init__(region_name, account_id)
|
||||
self.codebuild_projects = dict()
|
||||
self.build_history = dict()
|
||||
self.build_metadata = dict()
|
||||
self.build_metadata_history = defaultdict(list)
|
||||
|
||||
def create_project(
|
||||
self, project_name, project_source, artifacts, environment, service_role
|
||||
):
|
||||
# required in other functions that don't
|
||||
self.project_name = project_name
|
||||
self.service_role = service_role
|
||||
|
||||
self.codebuild_projects[project_name] = CodeBuild(
|
||||
self.region_name,
|
||||
project_name,
|
||||
project_source,
|
||||
artifacts,
|
||||
environment,
|
||||
service_role,
|
||||
)
|
||||
|
||||
# empty build history
|
||||
self.build_history[project_name] = list()
|
||||
|
||||
return self.codebuild_projects[project_name].project_metadata
|
||||
|
||||
def list_projects(self):
|
||||
|
||||
projects = []
|
||||
|
||||
for project in self.codebuild_projects.keys():
|
||||
projects.append(project)
|
||||
|
||||
return projects
|
||||
|
||||
def start_build(self, project_name, source_version=None, artifact_override=None):
|
||||
|
||||
build_id = "{0}:{1}".format(project_name, uuid.uuid4())
|
||||
|
||||
# construct a new build
|
||||
self.build_metadata[project_name] = CodeBuildProjectMetadata(
|
||||
project_name, source_version, artifact_override, build_id, self.service_role
|
||||
)
|
||||
|
||||
self.build_history[project_name].append(build_id)
|
||||
|
||||
# update build histroy with metadata for build id
|
||||
self.build_metadata_history[project_name].append(
|
||||
self.build_metadata[project_name].build_metadata
|
||||
)
|
||||
|
||||
return self.build_metadata[project_name].build_metadata
|
||||
|
||||
def _set_phases(self, phases):
|
||||
current_date = iso_8601_datetime_with_milliseconds(datetime.datetime.utcnow())
|
||||
# No phaseStatus for QUEUED on first start
|
||||
for existing_phase in phases:
|
||||
if existing_phase["phaseType"] == "QUEUED":
|
||||
existing_phase["phaseStatus"] = "SUCCEEDED"
|
||||
|
||||
statuses = [
|
||||
"PROVISIONING",
|
||||
"DOWNLOAD_SOURCE",
|
||||
"INSTALL",
|
||||
"PRE_BUILD",
|
||||
"BUILD",
|
||||
"POST_BUILD",
|
||||
"UPLOAD_ARTIFACTS",
|
||||
"FINALIZING",
|
||||
"COMPLETED",
|
||||
]
|
||||
|
||||
for status in statuses:
|
||||
phase = dict()
|
||||
phase["phaseType"] = status
|
||||
phase["phaseStatus"] = "SUCCEEDED"
|
||||
phase["startTime"] = current_date
|
||||
phase["endTime"] = current_date
|
||||
phase["durationInSeconds"] = randint(10, 100)
|
||||
phases.append(phase)
|
||||
|
||||
return phases
|
||||
|
||||
def batch_get_builds(self, ids):
|
||||
batch_build_metadata = []
|
||||
|
||||
for metadata in self.build_metadata_history.values():
|
||||
for build in metadata:
|
||||
if build["id"] in ids:
|
||||
build["phases"] = self._set_phases(build["phases"])
|
||||
build["endTime"] = iso_8601_datetime_with_milliseconds(
|
||||
parser.parse(build["startTime"])
|
||||
+ datetime.timedelta(minutes=randint(1, 5))
|
||||
)
|
||||
build["currentPhase"] = "COMPLETED"
|
||||
build["buildStatus"] = "SUCCEEDED"
|
||||
|
||||
batch_build_metadata.append(build)
|
||||
|
||||
return batch_build_metadata
|
||||
|
||||
def list_builds_for_project(self, project_name):
|
||||
try:
|
||||
return self.build_history[project_name]
|
||||
except KeyError:
|
||||
return list()
|
||||
|
||||
def list_builds(self):
|
||||
ids = []
|
||||
|
||||
for build_ids in self.build_history.values():
|
||||
ids += build_ids
|
||||
return ids
|
||||
|
||||
def delete_project(self, project_name):
|
||||
self.build_metadata.pop(project_name, None)
|
||||
self.codebuild_projects.pop(project_name, None)
|
||||
|
||||
def stop_build(self, build_id):
|
||||
|
||||
for metadata in self.build_metadata_history.values():
|
||||
for build in metadata:
|
||||
if build["id"] == build_id:
|
||||
# set completion properties with variable completion time
|
||||
build["phases"] = self._set_phases(build["phases"])
|
||||
build["endTime"] = iso_8601_datetime_with_milliseconds(
|
||||
parser.parse(build["startTime"])
|
||||
+ datetime.timedelta(minutes=randint(1, 5))
|
||||
)
|
||||
build["currentPhase"] = "COMPLETED"
|
||||
build["buildStatus"] = "STOPPED"
|
||||
|
||||
return build
|
||||
|
||||
|
||||
codebuild_backends = BackendDict(CodeBuildBackend, "codebuild")
|
195
moto/codebuild/responses.py
Normal file
195
moto/codebuild/responses.py
Normal file
@ -0,0 +1,195 @@
|
||||
from moto.core.responses import BaseResponse
|
||||
from .models import codebuild_backends
|
||||
from .exceptions import (
|
||||
InvalidInputException,
|
||||
ResourceAlreadyExistsException,
|
||||
ResourceNotFoundException,
|
||||
)
|
||||
from moto.core import get_account_id
|
||||
import json
|
||||
import re
|
||||
|
||||
|
||||
def _validate_required_params_source(source):
|
||||
if source["type"] not in [
|
||||
"BITBUCKET",
|
||||
"CODECOMMIT",
|
||||
"CODEPIPELINE",
|
||||
"GITHUB",
|
||||
"GITHUB_ENTERPRISE",
|
||||
"NO_SOURCE",
|
||||
"S3",
|
||||
]:
|
||||
raise InvalidInputException("Invalid type provided: Project source type")
|
||||
|
||||
if "location" not in source:
|
||||
raise InvalidInputException("Project source location is required")
|
||||
|
||||
if source["location"] == "":
|
||||
raise InvalidInputException("Project source location is required")
|
||||
|
||||
|
||||
def _validate_required_params_service_role(service_role):
|
||||
if (
|
||||
"arn:aws:iam::{0}:role/service-role/".format(get_account_id())
|
||||
not in service_role
|
||||
):
|
||||
raise InvalidInputException(
|
||||
"Invalid service role: Service role account ID does not match caller's account"
|
||||
)
|
||||
|
||||
|
||||
def _validate_required_params_artifacts(artifacts):
|
||||
|
||||
if artifacts["type"] not in ["CODEPIPELINE", "S3", "NO_ARTIFACTS"]:
|
||||
raise InvalidInputException("Invalid type provided: Artifact type")
|
||||
|
||||
if artifacts["type"] == "NO_ARTIFACTS":
|
||||
if "location" in artifacts:
|
||||
raise InvalidInputException(
|
||||
"Invalid artifacts: artifact type NO_ARTIFACTS should have null location"
|
||||
)
|
||||
elif "location" not in artifacts or artifacts["location"] == "":
|
||||
raise InvalidInputException("Project source location is required")
|
||||
|
||||
|
||||
def _validate_required_params_environment(environment):
|
||||
|
||||
if environment["type"] not in [
|
||||
"WINDOWS_CONTAINER",
|
||||
"LINUX_CONTAINER",
|
||||
"LINUX_GPU_CONTAINER",
|
||||
"ARM_CONTAINER",
|
||||
]:
|
||||
raise InvalidInputException(
|
||||
"Invalid type provided: {0}".format(environment["type"])
|
||||
)
|
||||
|
||||
if environment["computeType"] not in [
|
||||
"BUILD_GENERAL1_SMALL",
|
||||
"BUILD_GENERAL1_MEDIUM",
|
||||
"BUILD_GENERAL1_LARGE",
|
||||
"BUILD_GENERAL1_2XLARGE",
|
||||
]:
|
||||
raise InvalidInputException(
|
||||
"Invalid compute type provided: {0}".format(environment["computeType"])
|
||||
)
|
||||
|
||||
|
||||
def _validate_required_params_project_name(name):
|
||||
if len(name) >= 150:
|
||||
raise InvalidInputException(
|
||||
"Only alphanumeric characters, dash, and underscore are supported"
|
||||
)
|
||||
|
||||
if not re.match(r"^[A-Za-z]{1}.*[^!£$%^&*()+=|?`¬{}@~#:;<>\\/\[\]]$", name):
|
||||
raise InvalidInputException(
|
||||
"Only alphanumeric characters, dash, and underscore are supported"
|
||||
)
|
||||
|
||||
|
||||
def _validate_required_params_id(build_id, build_ids):
|
||||
if ":" not in build_id:
|
||||
raise InvalidInputException("Invalid build ID provided")
|
||||
|
||||
if build_id not in build_ids:
|
||||
raise ResourceNotFoundException("Build {0} does not exist".format(build_id))
|
||||
|
||||
|
||||
class CodeBuildResponse(BaseResponse):
|
||||
@property
|
||||
def codebuild_backend(self):
|
||||
return codebuild_backends[self.region]
|
||||
|
||||
def list_builds_for_project(self):
|
||||
_validate_required_params_project_name(self._get_param("projectName"))
|
||||
|
||||
if (
|
||||
self._get_param("projectName")
|
||||
not in self.codebuild_backend.codebuild_projects.keys()
|
||||
):
|
||||
raise ResourceNotFoundException(
|
||||
"The provided project arn:aws:codebuild:{0}:{1}:project/{2} does not exist".format(
|
||||
self.region, get_account_id(), self._get_param("projectName")
|
||||
)
|
||||
)
|
||||
|
||||
ids = self.codebuild_backend.list_builds_for_project(
|
||||
self._get_param("projectName")
|
||||
)
|
||||
|
||||
return json.dumps({"ids": ids})
|
||||
|
||||
def create_project(self):
|
||||
_validate_required_params_source(self._get_param("source"))
|
||||
_validate_required_params_service_role(self._get_param("serviceRole"))
|
||||
_validate_required_params_artifacts(self._get_param("artifacts"))
|
||||
_validate_required_params_environment(self._get_param("environment"))
|
||||
_validate_required_params_project_name(self._get_param("name"))
|
||||
|
||||
if self._get_param("name") in self.codebuild_backend.codebuild_projects.keys():
|
||||
raise ResourceAlreadyExistsException(
|
||||
"Project already exists: arn:aws:codebuild:{0}:{1}:project/{2}".format(
|
||||
self.region, get_account_id(), self._get_param("name")
|
||||
)
|
||||
)
|
||||
|
||||
project_metadata = self.codebuild_backend.create_project(
|
||||
self._get_param("name"),
|
||||
self._get_param("source"),
|
||||
self._get_param("artifacts"),
|
||||
self._get_param("environment"),
|
||||
self._get_param("serviceRole"),
|
||||
)
|
||||
|
||||
return json.dumps({"project": project_metadata})
|
||||
|
||||
def list_projects(self):
|
||||
project_metadata = self.codebuild_backend.list_projects()
|
||||
return json.dumps({"projects": project_metadata})
|
||||
|
||||
def start_build(self):
|
||||
_validate_required_params_project_name(self._get_param("projectName"))
|
||||
|
||||
if (
|
||||
self._get_param("projectName")
|
||||
not in self.codebuild_backend.codebuild_projects.keys()
|
||||
):
|
||||
raise ResourceNotFoundException(
|
||||
"Project cannot be found: arn:aws:codebuild:{0}:{1}:project/{2}".format(
|
||||
self.region, get_account_id(), self._get_param("projectName")
|
||||
)
|
||||
)
|
||||
|
||||
metadata = self.codebuild_backend.start_build(
|
||||
self._get_param("projectName"),
|
||||
self._get_param("sourceVersion"),
|
||||
self._get_param("artifactsOverride"),
|
||||
)
|
||||
return json.dumps({"build": metadata})
|
||||
|
||||
def batch_get_builds(self):
|
||||
for build_id in self._get_param("ids"):
|
||||
if ":" not in build_id:
|
||||
raise InvalidInputException("Invalid build ID provided")
|
||||
|
||||
metadata = self.codebuild_backend.batch_get_builds(self._get_param("ids"))
|
||||
return json.dumps({"builds": metadata})
|
||||
|
||||
def list_builds(self):
|
||||
ids = self.codebuild_backend.list_builds()
|
||||
return json.dumps({"ids": ids})
|
||||
|
||||
def delete_project(self):
|
||||
_validate_required_params_project_name(self._get_param("name"))
|
||||
|
||||
self.codebuild_backend.delete_project(self._get_param("name"))
|
||||
return
|
||||
|
||||
def stop_build(self):
|
||||
_validate_required_params_id(
|
||||
self._get_param("id"), self.codebuild_backend.list_builds()
|
||||
)
|
||||
|
||||
metadata = self.codebuild_backend.stop_build(self._get_param("id"))
|
||||
return json.dumps({"build": metadata})
|
5
moto/codebuild/urls.py
Normal file
5
moto/codebuild/urls.py
Normal file
@ -0,0 +1,5 @@
|
||||
from .responses import CodeBuildResponse
|
||||
|
||||
url_bases = [r"https?://codebuild\.(.+)\.amazonaws\.com"]
|
||||
|
||||
url_paths = {"{0}/$": CodeBuildResponse.dispatch}
|
699
tests/test_codebuild/test_codebuild.py
Normal file
699
tests/test_codebuild/test_codebuild.py
Normal file
@ -0,0 +1,699 @@
|
||||
import boto3
|
||||
import sure # noqa # pylint: disable=unused-import
|
||||
from moto import mock_codebuild
|
||||
from moto.core import ACCOUNT_ID
|
||||
from botocore.exceptions import ClientError, ParamValidationError
|
||||
from uuid import uuid1
|
||||
import pytest
|
||||
|
||||
|
||||
@mock_codebuild
|
||||
def test_codebuild_create_project_s3_artifacts():
|
||||
client = boto3.client("codebuild", region_name="eu-central-1")
|
||||
|
||||
name = "some_project"
|
||||
source = dict()
|
||||
source["type"] = "S3"
|
||||
# repository location for S3
|
||||
source["location"] = "bucketname/path/file.zip"
|
||||
# output artifacts
|
||||
artifacts = dict()
|
||||
artifacts["type"] = "S3"
|
||||
artifacts["location"] = "bucketname"
|
||||
|
||||
environment = dict()
|
||||
environment["type"] = "LINUX_CONTAINER"
|
||||
environment["image"] = "contents_not_validated"
|
||||
environment["computeType"] = "BUILD_GENERAL1_SMALL"
|
||||
|
||||
service_role = (
|
||||
"arn:aws:iam::{0}:role/service-role/my-codebuild-service-role".format(
|
||||
ACCOUNT_ID
|
||||
)
|
||||
)
|
||||
|
||||
response = client.create_project(
|
||||
name=name,
|
||||
source=source,
|
||||
artifacts=artifacts,
|
||||
environment=environment,
|
||||
serviceRole=service_role,
|
||||
)
|
||||
|
||||
response.should_not.be.none
|
||||
response["project"].should_not.be.none
|
||||
response["project"]["serviceRole"].should_not.be.none
|
||||
response["project"]["name"].should_not.be.none
|
||||
|
||||
response["project"]["environment"].should.equal(
|
||||
{
|
||||
"computeType": "BUILD_GENERAL1_SMALL",
|
||||
"image": "contents_not_validated",
|
||||
"type": "LINUX_CONTAINER",
|
||||
}
|
||||
)
|
||||
|
||||
response["project"]["source"].should.equal(
|
||||
{"location": "bucketname/path/file.zip", "type": "S3"}
|
||||
)
|
||||
|
||||
response["project"]["artifacts"].should.equal(
|
||||
{"location": "bucketname", "type": "S3"}
|
||||
)
|
||||
|
||||
|
||||
@mock_codebuild
|
||||
def test_codebuild_create_project_no_artifacts():
|
||||
client = boto3.client("codebuild", region_name="eu-central-1")
|
||||
|
||||
name = "some_project"
|
||||
source = dict()
|
||||
source["type"] = "S3"
|
||||
# repository location for S3
|
||||
source["location"] = "bucketname/path/file.zip"
|
||||
# output artifacts
|
||||
artifacts = {"type": "NO_ARTIFACTS"}
|
||||
|
||||
environment = dict()
|
||||
environment["type"] = "LINUX_CONTAINER"
|
||||
environment["image"] = "contents_not_validated"
|
||||
environment["computeType"] = "BUILD_GENERAL1_SMALL"
|
||||
service_role = (
|
||||
"arn:aws:iam::{0}:role/service-role/my-codebuild-service-role".format(
|
||||
ACCOUNT_ID
|
||||
)
|
||||
)
|
||||
|
||||
response = client.create_project(
|
||||
name=name,
|
||||
source=source,
|
||||
artifacts=artifacts,
|
||||
environment=environment,
|
||||
serviceRole=service_role,
|
||||
)
|
||||
|
||||
response.should_not.be.none
|
||||
response["project"].should_not.be.none
|
||||
response["project"]["serviceRole"].should_not.be.none
|
||||
response["project"]["name"].should_not.be.none
|
||||
|
||||
response["project"]["environment"].should.equal(
|
||||
{
|
||||
"computeType": "BUILD_GENERAL1_SMALL",
|
||||
"image": "contents_not_validated",
|
||||
"type": "LINUX_CONTAINER",
|
||||
}
|
||||
)
|
||||
|
||||
response["project"]["source"].should.equal(
|
||||
{"location": "bucketname/path/file.zip", "type": "S3"}
|
||||
)
|
||||
|
||||
response["project"]["artifacts"].should.equal({"type": "NO_ARTIFACTS"})
|
||||
|
||||
|
||||
@mock_codebuild
|
||||
def test_codebuild_create_project_with_invalid_name():
|
||||
client = boto3.client("codebuild", region_name="eu-central-1")
|
||||
|
||||
name = "!some_project"
|
||||
source = dict()
|
||||
source["type"] = "S3"
|
||||
# repository location for S3
|
||||
source["location"] = "bucketname/path/file.zip"
|
||||
# output artifacts
|
||||
artifacts = {"type": "NO_ARTIFACTS"}
|
||||
|
||||
environment = dict()
|
||||
environment["type"] = "LINUX_CONTAINER"
|
||||
environment["image"] = "contents_not_validated"
|
||||
environment["computeType"] = "BUILD_GENERAL1_SMALL"
|
||||
service_role = (
|
||||
"arn:aws:iam::{0}:role/service-role/my-codebuild-service-role".format(
|
||||
ACCOUNT_ID
|
||||
)
|
||||
)
|
||||
|
||||
with pytest.raises(client.exceptions.from_code("InvalidInputException")) as err:
|
||||
client.create_project(
|
||||
name=name,
|
||||
source=source,
|
||||
artifacts=artifacts,
|
||||
environment=environment,
|
||||
serviceRole=service_role,
|
||||
)
|
||||
err.value.response["Error"]["Code"].should.equal("InvalidInputException")
|
||||
|
||||
|
||||
@mock_codebuild
|
||||
def test_codebuild_create_project_with_invalid_name_length():
|
||||
client = boto3.client("codebuild", region_name="eu-central-1")
|
||||
|
||||
name = "some_project_" * 12
|
||||
source = dict()
|
||||
source["type"] = "S3"
|
||||
# repository location for S3
|
||||
source["location"] = "bucketname/path/file.zip"
|
||||
# output artifacts
|
||||
artifacts = {"type": "NO_ARTIFACTS"}
|
||||
|
||||
environment = dict()
|
||||
environment["type"] = "LINUX_CONTAINER"
|
||||
environment["image"] = "contents_not_validated"
|
||||
environment["computeType"] = "BUILD_GENERAL1_SMALL"
|
||||
service_role = (
|
||||
"arn:aws:iam::{0}:role/service-role/my-codebuild-service-role".format(
|
||||
ACCOUNT_ID
|
||||
)
|
||||
)
|
||||
|
||||
with pytest.raises(client.exceptions.from_code("InvalidInputException")) as err:
|
||||
client.create_project(
|
||||
name=name,
|
||||
source=source,
|
||||
artifacts=artifacts,
|
||||
environment=environment,
|
||||
serviceRole=service_role,
|
||||
)
|
||||
err.value.response["Error"]["Code"].should.equal("InvalidInputException")
|
||||
|
||||
|
||||
@mock_codebuild
|
||||
def test_codebuild_create_project_when_exists():
|
||||
client = boto3.client("codebuild", region_name="eu-central-1")
|
||||
|
||||
name = "some_project"
|
||||
source = dict()
|
||||
source["type"] = "S3"
|
||||
# repository location for S3
|
||||
source["location"] = "bucketname/path/file.zip"
|
||||
artifacts = {"type": "NO_ARTIFACTS"}
|
||||
|
||||
environment = dict()
|
||||
environment["type"] = "LINUX_CONTAINER"
|
||||
environment["image"] = "contents_not_validated"
|
||||
environment["computeType"] = "BUILD_GENERAL1_SMALL"
|
||||
service_role = (
|
||||
"arn:aws:iam::{0}:role/service-role/my-codebuild-service-role".format(
|
||||
ACCOUNT_ID
|
||||
)
|
||||
)
|
||||
|
||||
client.create_project(
|
||||
name=name,
|
||||
source=source,
|
||||
artifacts=artifacts,
|
||||
environment=environment,
|
||||
serviceRole=service_role,
|
||||
)
|
||||
|
||||
with pytest.raises(ClientError) as err:
|
||||
client.create_project(
|
||||
name=name,
|
||||
source=source,
|
||||
artifacts=artifacts,
|
||||
environment=environment,
|
||||
serviceRole=service_role,
|
||||
)
|
||||
err.value.response["Error"]["Code"].should.equal("ResourceAlreadyExistsException")
|
||||
|
||||
|
||||
@mock_codebuild
|
||||
def test_codebuild_list_projects():
|
||||
client = boto3.client("codebuild", region_name="eu-central-1")
|
||||
|
||||
source = dict()
|
||||
source["type"] = "S3"
|
||||
# repository location for S3
|
||||
source["location"] = "bucketname/path/file.zip"
|
||||
# output artifacts
|
||||
artifacts = dict()
|
||||
artifacts["type"] = "S3"
|
||||
artifacts["location"] = "bucketname"
|
||||
|
||||
environment = dict()
|
||||
environment["type"] = "LINUX_CONTAINER"
|
||||
environment["image"] = "contents_not_validated"
|
||||
environment["computeType"] = "BUILD_GENERAL1_SMALL"
|
||||
service_role = (
|
||||
"arn:aws:iam::{0}:role/service-role/my-codebuild-service-role".format(
|
||||
ACCOUNT_ID
|
||||
)
|
||||
)
|
||||
|
||||
client.create_project(
|
||||
name="project1",
|
||||
source=source,
|
||||
artifacts=artifacts,
|
||||
environment=environment,
|
||||
serviceRole=service_role,
|
||||
)
|
||||
client.create_project(
|
||||
name="project2",
|
||||
source=source,
|
||||
artifacts=artifacts,
|
||||
environment=environment,
|
||||
serviceRole=service_role,
|
||||
)
|
||||
|
||||
projects = client.list_projects()
|
||||
|
||||
projects["projects"].should_not.be.none
|
||||
projects["projects"].should.equal(["project1", "project2"])
|
||||
|
||||
|
||||
@mock_codebuild
|
||||
def test_codebuild_list_builds_for_project_no_history():
|
||||
client = boto3.client("codebuild", region_name="eu-central-1")
|
||||
|
||||
name = "some_project"
|
||||
source = dict()
|
||||
source["type"] = "S3"
|
||||
# repository location for S3
|
||||
source["location"] = "bucketname/path/file.zip"
|
||||
artifacts = {"type": "NO_ARTIFACTS"}
|
||||
|
||||
environment = dict()
|
||||
environment["type"] = "LINUX_CONTAINER"
|
||||
environment["image"] = "contents_not_validated"
|
||||
environment["computeType"] = "BUILD_GENERAL1_SMALL"
|
||||
service_role = (
|
||||
"arn:aws:iam::{0}:role/service-role/my-codebuild-service-role".format(
|
||||
ACCOUNT_ID
|
||||
)
|
||||
)
|
||||
|
||||
client.create_project(
|
||||
name=name,
|
||||
source=source,
|
||||
artifacts=artifacts,
|
||||
environment=environment,
|
||||
serviceRole=service_role,
|
||||
)
|
||||
history = client.list_builds_for_project(projectName=name)
|
||||
|
||||
# no build history if it's never started
|
||||
history["ids"].should.be.empty
|
||||
|
||||
|
||||
@mock_codebuild
|
||||
def test_codebuild_list_builds_for_project_with_history():
|
||||
client = boto3.client("codebuild", region_name="eu-central-1")
|
||||
|
||||
name = "some_project"
|
||||
source = dict()
|
||||
source["type"] = "S3"
|
||||
# repository location for S3
|
||||
source["location"] = "bucketname/path/file.zip"
|
||||
artifacts = {"type": "NO_ARTIFACTS"}
|
||||
|
||||
environment = dict()
|
||||
environment["type"] = "LINUX_CONTAINER"
|
||||
environment["image"] = "contents_not_validated"
|
||||
environment["computeType"] = "BUILD_GENERAL1_SMALL"
|
||||
service_role = (
|
||||
"arn:aws:iam::{0}:role/service-role/my-codebuild-service-role".format(
|
||||
ACCOUNT_ID
|
||||
)
|
||||
)
|
||||
|
||||
client.create_project(
|
||||
name=name,
|
||||
source=source,
|
||||
artifacts=artifacts,
|
||||
environment=environment,
|
||||
serviceRole=service_role,
|
||||
)
|
||||
client.start_build(projectName=name)
|
||||
response = client.list_builds_for_project(projectName=name)
|
||||
|
||||
response["ids"].should_not.be.empty
|
||||
|
||||
|
||||
# project never started
|
||||
@mock_codebuild
|
||||
def test_codebuild_get_batch_builds_for_project_no_history():
|
||||
client = boto3.client("codebuild", region_name="eu-central-1")
|
||||
|
||||
name = "some_project"
|
||||
source = dict()
|
||||
source["type"] = "S3"
|
||||
# repository location for S3
|
||||
source["location"] = "bucketname/path/file.zip"
|
||||
artifacts = {"type": "NO_ARTIFACTS"}
|
||||
|
||||
environment = dict()
|
||||
environment["type"] = "LINUX_CONTAINER"
|
||||
environment["image"] = "contents_not_validated"
|
||||
environment["computeType"] = "BUILD_GENERAL1_SMALL"
|
||||
service_role = (
|
||||
"arn:aws:iam::{0}:role/service-role/my-codebuild-service-role".format(
|
||||
ACCOUNT_ID
|
||||
)
|
||||
)
|
||||
|
||||
client.create_project(
|
||||
name=name,
|
||||
source=source,
|
||||
artifacts=artifacts,
|
||||
environment=environment,
|
||||
serviceRole=service_role,
|
||||
)
|
||||
|
||||
response = client.list_builds_for_project(projectName=name)
|
||||
response.should_not.be.none
|
||||
response["ids"].should.be.empty
|
||||
|
||||
with pytest.raises(ParamValidationError) as err:
|
||||
client.batch_get_builds(ids=response["ids"])
|
||||
err.typename.should.equal("ParamValidationError")
|
||||
|
||||
|
||||
@mock_codebuild
|
||||
def test_codebuild_start_build_no_project():
|
||||
|
||||
client = boto3.client("codebuild", region_name="eu-central-1")
|
||||
|
||||
name = "some_project"
|
||||
|
||||
with pytest.raises(client.exceptions.from_code("ResourceNotFoundException")) as err:
|
||||
client.start_build(projectName=name)
|
||||
err.value.response["Error"]["Code"].should.equal("ResourceNotFoundException")
|
||||
|
||||
|
||||
@mock_codebuild
|
||||
def test_codebuild_start_build_no_overrides():
|
||||
|
||||
client = boto3.client("codebuild", region_name="eu-central-1")
|
||||
|
||||
name = "some_project"
|
||||
source = dict()
|
||||
source["type"] = "S3"
|
||||
# repository location for S3
|
||||
source["location"] = "bucketname/path/file.zip"
|
||||
artifacts = {"type": "NO_ARTIFACTS"}
|
||||
|
||||
environment = dict()
|
||||
environment["type"] = "LINUX_CONTAINER"
|
||||
environment["image"] = "contents_not_validated"
|
||||
environment["computeType"] = "BUILD_GENERAL1_SMALL"
|
||||
service_role = (
|
||||
"arn:aws:iam::{0}:role/service-role/my-codebuild-service-role".format(
|
||||
ACCOUNT_ID
|
||||
)
|
||||
)
|
||||
|
||||
client.create_project(
|
||||
name=name,
|
||||
source=source,
|
||||
artifacts=artifacts,
|
||||
environment=environment,
|
||||
serviceRole=service_role,
|
||||
)
|
||||
response = client.start_build(projectName=name)
|
||||
|
||||
response.should_not.be.none
|
||||
response["build"].should_not.be.none
|
||||
response["build"]["sourceVersion"].should.equal("refs/heads/main")
|
||||
|
||||
|
||||
@mock_codebuild
|
||||
def test_codebuild_start_build_multiple_times():
|
||||
client = boto3.client("codebuild", region_name="eu-central-1")
|
||||
|
||||
name = "some_project"
|
||||
source = dict()
|
||||
source["type"] = "S3"
|
||||
# repository location for S3
|
||||
source["location"] = "bucketname/path/file.zip"
|
||||
artifacts = {"type": "NO_ARTIFACTS"}
|
||||
|
||||
environment = dict()
|
||||
environment["type"] = "LINUX_CONTAINER"
|
||||
environment["image"] = "contents_not_validated"
|
||||
environment["computeType"] = "BUILD_GENERAL1_SMALL"
|
||||
service_role = (
|
||||
"arn:aws:iam::{0}:role/service-role/my-codebuild-service-role".format(
|
||||
ACCOUNT_ID
|
||||
)
|
||||
)
|
||||
|
||||
client.create_project(
|
||||
name=name,
|
||||
source=source,
|
||||
artifacts=artifacts,
|
||||
environment=environment,
|
||||
serviceRole=service_role,
|
||||
)
|
||||
|
||||
client.start_build(projectName=name)
|
||||
client.start_build(projectName=name)
|
||||
client.start_build(projectName=name)
|
||||
|
||||
len(client.list_builds()["ids"]).should.equal(3)
|
||||
|
||||
|
||||
@mock_codebuild
|
||||
def test_codebuild_start_build_with_overrides():
|
||||
|
||||
client = boto3.client("codebuild", region_name="eu-central-1")
|
||||
|
||||
name = "some_project"
|
||||
source = dict()
|
||||
source["type"] = "S3"
|
||||
# repository location for S3
|
||||
source["location"] = "bucketname/path/file.zip"
|
||||
artifacts = {"type": "NO_ARTIFACTS"}
|
||||
|
||||
environment = dict()
|
||||
environment["type"] = "LINUX_CONTAINER"
|
||||
environment["image"] = "contents_not_validated"
|
||||
environment["computeType"] = "BUILD_GENERAL1_SMALL"
|
||||
service_role = (
|
||||
"arn:aws:iam::{0}:role/service-role/my-codebuild-service-role".format(
|
||||
ACCOUNT_ID
|
||||
)
|
||||
)
|
||||
|
||||
branch_override = "fix/testing"
|
||||
artifacts_override = {"type": "NO_ARTIFACTS"}
|
||||
|
||||
client.create_project(
|
||||
name=name,
|
||||
source=source,
|
||||
artifacts=artifacts,
|
||||
environment=environment,
|
||||
serviceRole=service_role,
|
||||
)
|
||||
response = client.start_build(
|
||||
projectName=name,
|
||||
sourceVersion=branch_override,
|
||||
artifactsOverride=artifacts_override,
|
||||
)
|
||||
|
||||
response.should_not.be.none
|
||||
response["build"].should_not.be.none
|
||||
response["build"]["sourceVersion"].should.equal("fix/testing")
|
||||
|
||||
|
||||
@mock_codebuild
|
||||
def test_codebuild_batch_get_builds_1_project():
|
||||
client = boto3.client("codebuild", region_name="eu-central-1")
|
||||
|
||||
name = "some_project"
|
||||
source = dict()
|
||||
source["type"] = "S3"
|
||||
# repository location for S3
|
||||
source["location"] = "bucketname/path/file.zip"
|
||||
artifacts = {"type": "NO_ARTIFACTS"}
|
||||
|
||||
environment = dict()
|
||||
environment["type"] = "LINUX_CONTAINER"
|
||||
environment["image"] = "contents_not_validated"
|
||||
environment["computeType"] = "BUILD_GENERAL1_SMALL"
|
||||
service_role = (
|
||||
"arn:aws:iam::{0}:role/service-role/my-codebuild-service-role".format(
|
||||
ACCOUNT_ID
|
||||
)
|
||||
)
|
||||
|
||||
client.create_project(
|
||||
name=name,
|
||||
source=source,
|
||||
artifacts=artifacts,
|
||||
environment=environment,
|
||||
serviceRole=service_role,
|
||||
)
|
||||
client.start_build(projectName=name)
|
||||
|
||||
history = client.list_builds_for_project(projectName=name)
|
||||
response = client.batch_get_builds(ids=history["ids"])
|
||||
|
||||
response.should_not.be.none
|
||||
response["builds"].should_not.be.none
|
||||
response["builds"][0]["currentPhase"].should.equal("COMPLETED")
|
||||
response["builds"][0]["buildNumber"].should.be.a(int)
|
||||
response["builds"][0]["phases"].should_not.be.none
|
||||
len(response["builds"][0]["phases"]).should.equal(11)
|
||||
|
||||
|
||||
@mock_codebuild
|
||||
def test_codebuild_batch_get_builds_2_projects():
|
||||
client = boto3.client("codebuild", region_name="eu-central-1")
|
||||
|
||||
source = dict()
|
||||
source["type"] = "S3"
|
||||
# repository location for S3
|
||||
source["location"] = "bucketname/path/file.zip"
|
||||
artifacts = {"type": "NO_ARTIFACTS"}
|
||||
|
||||
environment = dict()
|
||||
environment["type"] = "LINUX_CONTAINER"
|
||||
environment["image"] = "contents_not_validated"
|
||||
environment["computeType"] = "BUILD_GENERAL1_SMALL"
|
||||
service_role = (
|
||||
"arn:aws:iam::{0}:role/service-role/my-codebuild-service-role".format(
|
||||
ACCOUNT_ID
|
||||
)
|
||||
)
|
||||
|
||||
client.create_project(
|
||||
name="project-1",
|
||||
source=source,
|
||||
artifacts=artifacts,
|
||||
environment=environment,
|
||||
serviceRole=service_role,
|
||||
)
|
||||
client.start_build(projectName="project-1")
|
||||
|
||||
client.create_project(
|
||||
name="project-2",
|
||||
source=source,
|
||||
artifacts=artifacts,
|
||||
environment=environment,
|
||||
serviceRole=service_role,
|
||||
)
|
||||
client.start_build(projectName="project-2")
|
||||
|
||||
response = client.list_builds()
|
||||
response["ids"].should_not.be.empty
|
||||
|
||||
"project-1".should.be.within(response["ids"][0])
|
||||
"project-2".should.be.within(response["ids"][1])
|
||||
|
||||
metadata = client.batch_get_builds(ids=response["ids"])["builds"]
|
||||
metadata.should_not.be.none
|
||||
"project-1".should.be.within(metadata[0]["id"])
|
||||
"project-2".should.be.within(metadata[1]["id"])
|
||||
|
||||
|
||||
@mock_codebuild
|
||||
def test_codebuild_batch_get_builds_invalid_build_id():
|
||||
client = boto3.client("codebuild", region_name="eu-central-1")
|
||||
|
||||
with pytest.raises(client.exceptions.InvalidInputException) as err:
|
||||
client.batch_get_builds(ids=["some_project{}".format(uuid1())])
|
||||
err.value.response["Error"]["Code"].should.equal("InvalidInputException")
|
||||
|
||||
|
||||
@mock_codebuild
|
||||
def test_codebuild_batch_get_builds_empty_build_id():
|
||||
client = boto3.client("codebuild", region_name="eu-central-1")
|
||||
|
||||
with pytest.raises(ParamValidationError) as err:
|
||||
client.batch_get_builds(ids=[])
|
||||
err.typename.should.equal("ParamValidationError")
|
||||
|
||||
|
||||
@mock_codebuild
|
||||
def test_codebuild_delete_project():
|
||||
client = boto3.client("codebuild", region_name="eu-central-1")
|
||||
|
||||
name = "some_project"
|
||||
source = dict()
|
||||
source["type"] = "S3"
|
||||
# repository location for S3
|
||||
source["location"] = "bucketname/path/file.zip"
|
||||
artifacts = {"type": "NO_ARTIFACTS"}
|
||||
|
||||
environment = dict()
|
||||
environment["type"] = "LINUX_CONTAINER"
|
||||
environment["image"] = "contents_not_validated"
|
||||
environment["computeType"] = "BUILD_GENERAL1_SMALL"
|
||||
service_role = (
|
||||
"arn:aws:iam::{0}:role/service-role/my-codebuild-service-role".format(
|
||||
ACCOUNT_ID
|
||||
)
|
||||
)
|
||||
|
||||
client.create_project(
|
||||
name=name,
|
||||
source=source,
|
||||
artifacts=artifacts,
|
||||
environment=environment,
|
||||
serviceRole=service_role,
|
||||
)
|
||||
client.start_build(projectName=name)
|
||||
|
||||
response = client.list_builds_for_project(projectName=name)
|
||||
response["ids"].should_not.be.empty
|
||||
|
||||
client.delete_project(name=name)
|
||||
|
||||
with pytest.raises(ClientError) as err:
|
||||
client.list_builds_for_project(projectName=name)
|
||||
err.value.response["Error"]["Code"].should.equal("ResourceNotFoundException")
|
||||
|
||||
|
||||
@mock_codebuild
|
||||
def test_codebuild_stop_build():
|
||||
client = boto3.client("codebuild", region_name="eu-central-1")
|
||||
|
||||
name = "some_project"
|
||||
source = dict()
|
||||
source["type"] = "S3"
|
||||
# repository location for S3
|
||||
source["location"] = "bucketname/path/file.zip"
|
||||
artifacts = {"type": "NO_ARTIFACTS"}
|
||||
|
||||
environment = dict()
|
||||
environment["type"] = "LINUX_CONTAINER"
|
||||
environment["image"] = "contents_not_validated"
|
||||
environment["computeType"] = "BUILD_GENERAL1_SMALL"
|
||||
service_role = (
|
||||
"arn:aws:iam::{0}:role/service-role/my-codebuild-service-role".format(
|
||||
ACCOUNT_ID
|
||||
)
|
||||
)
|
||||
|
||||
client.create_project(
|
||||
name=name,
|
||||
source=source,
|
||||
artifacts=artifacts,
|
||||
environment=environment,
|
||||
serviceRole=service_role,
|
||||
)
|
||||
client.start_build(projectName=name)
|
||||
|
||||
builds = client.list_builds()
|
||||
|
||||
response = client.stop_build(id=builds["ids"][0])
|
||||
response["build"]["buildStatus"].should.equal("STOPPED")
|
||||
|
||||
|
||||
@mock_codebuild
|
||||
def test_codebuild_stop_build_no_build():
|
||||
client = boto3.client("codebuild", region_name="eu-central-1")
|
||||
|
||||
with pytest.raises(client.exceptions.ResourceNotFoundException) as err:
|
||||
client.stop_build(id="some_project:{0}".format(uuid1()))
|
||||
err.value.response["Error"]["Code"].should.equal("ResourceNotFoundException")
|
||||
|
||||
|
||||
@mock_codebuild
|
||||
def test_codebuild_stop_build_bad_uid():
|
||||
client = boto3.client("codebuild", region_name="eu-central-1")
|
||||
|
||||
with pytest.raises(client.exceptions.InvalidInputException) as err:
|
||||
client.stop_build(id="some_project{0}".format(uuid1()))
|
||||
err.value.response["Error"]["Code"].should.equal("InvalidInputException")
|
Loading…
Reference in New Issue
Block a user