Add support for codebuild (#5282)
This commit is contained in:
parent
c1bdd764c7
commit
79af23aeb7
@ -338,7 +338,7 @@
|
|||||||
|
|
||||||
## autoscaling
|
## autoscaling
|
||||||
<details>
|
<details>
|
||||||
<summary>49% implemented</summary>
|
<summary>50% implemented</summary>
|
||||||
|
|
||||||
- [X] attach_instances
|
- [X] attach_instances
|
||||||
- [X] attach_load_balancer_target_groups
|
- [X] attach_load_balancer_target_groups
|
||||||
@ -382,7 +382,7 @@
|
|||||||
- [X] detach_load_balancer_target_groups
|
- [X] detach_load_balancer_target_groups
|
||||||
- [X] detach_load_balancers
|
- [X] detach_load_balancers
|
||||||
- [ ] disable_metrics_collection
|
- [ ] disable_metrics_collection
|
||||||
- [ ] enable_metrics_collection
|
- [X] enable_metrics_collection
|
||||||
- [ ] enter_standby
|
- [ ] enter_standby
|
||||||
- [X] execute_policy
|
- [X] execute_policy
|
||||||
- [ ] exit_standby
|
- [ ] exit_standby
|
||||||
@ -462,6 +462,47 @@
|
|||||||
- [ ] update_subscriber
|
- [ ] update_subscriber
|
||||||
</details>
|
</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
|
## cloudformation
|
||||||
<details>
|
<details>
|
||||||
<summary>30% implemented</summary>
|
<summary>30% implemented</summary>
|
||||||
@ -709,6 +750,57 @@
|
|||||||
- [X] untag_resource
|
- [X] untag_resource
|
||||||
</details>
|
</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
|
## codecommit
|
||||||
<details>
|
<details>
|
||||||
<summary>3% implemented</summary>
|
<summary>3% implemented</summary>
|
||||||
@ -1289,7 +1381,7 @@
|
|||||||
|
|
||||||
## ds
|
## ds
|
||||||
<details>
|
<details>
|
||||||
<summary>18% implemented</summary>
|
<summary>19% implemented</summary>
|
||||||
|
|
||||||
- [ ] accept_shared_directory
|
- [ ] accept_shared_directory
|
||||||
- [ ] add_ip_routes
|
- [ ] add_ip_routes
|
||||||
@ -1320,7 +1412,6 @@
|
|||||||
- [ ] describe_event_topics
|
- [ ] describe_event_topics
|
||||||
- [ ] describe_ldaps_settings
|
- [ ] describe_ldaps_settings
|
||||||
- [ ] describe_regions
|
- [ ] describe_regions
|
||||||
- [ ] describe_settings
|
|
||||||
- [ ] describe_shared_directories
|
- [ ] describe_shared_directories
|
||||||
- [ ] describe_snapshots
|
- [ ] describe_snapshots
|
||||||
- [ ] describe_trusts
|
- [ ] describe_trusts
|
||||||
@ -1353,7 +1444,6 @@
|
|||||||
- [ ] update_conditional_forwarder
|
- [ ] update_conditional_forwarder
|
||||||
- [ ] update_number_of_domain_controllers
|
- [ ] update_number_of_domain_controllers
|
||||||
- [ ] update_radius
|
- [ ] update_radius
|
||||||
- [ ] update_settings
|
|
||||||
- [ ] update_trust
|
- [ ] update_trust
|
||||||
- [ ] verify_trust
|
- [ ] verify_trust
|
||||||
</details>
|
</details>
|
||||||
@ -2457,7 +2547,7 @@
|
|||||||
|
|
||||||
## emr-serverless
|
## emr-serverless
|
||||||
<details>
|
<details>
|
||||||
<summary>71% implemented</summary>
|
<summary>50% implemented</summary>
|
||||||
|
|
||||||
- [ ] cancel_job_run
|
- [ ] cancel_job_run
|
||||||
- [X] create_application
|
- [X] create_application
|
||||||
@ -2468,7 +2558,7 @@
|
|||||||
- [ ] list_job_runs
|
- [ ] list_job_runs
|
||||||
- [ ] list_tags_for_resource
|
- [ ] list_tags_for_resource
|
||||||
- [X] start_application
|
- [X] start_application
|
||||||
- [X] start_job_run
|
- [ ] start_job_run
|
||||||
- [X] stop_application
|
- [X] stop_application
|
||||||
- [ ] tag_resource
|
- [ ] tag_resource
|
||||||
- [ ] untag_resource
|
- [ ] untag_resource
|
||||||
@ -2828,7 +2918,6 @@
|
|||||||
- [ ] import_catalog_to_glue
|
- [ ] import_catalog_to_glue
|
||||||
- [ ] list_blueprints
|
- [ ] list_blueprints
|
||||||
- [X] list_crawlers
|
- [X] list_crawlers
|
||||||
- [ ] list_crawls
|
|
||||||
- [ ] list_custom_entity_types
|
- [ ] list_custom_entity_types
|
||||||
- [ ] list_dev_endpoints
|
- [ ] list_dev_endpoints
|
||||||
- [X] list_jobs
|
- [X] list_jobs
|
||||||
@ -5998,7 +6087,6 @@
|
|||||||
- backup-gateway
|
- backup-gateway
|
||||||
- billingconductor
|
- billingconductor
|
||||||
- braket
|
- braket
|
||||||
- ce
|
|
||||||
- chime
|
- chime
|
||||||
- chime-sdk-identity
|
- chime-sdk-identity
|
||||||
- chime-sdk-media-pipelines
|
- chime-sdk-media-pipelines
|
||||||
@ -6012,7 +6100,6 @@
|
|||||||
- cloudsearch
|
- cloudsearch
|
||||||
- cloudsearchdomain
|
- cloudsearchdomain
|
||||||
- codeartifact
|
- codeartifact
|
||||||
- codebuild
|
|
||||||
- codedeploy
|
- codedeploy
|
||||||
- codeguru-reviewer
|
- codeguru-reviewer
|
||||||
- codeguruprofiler
|
- codeguruprofiler
|
||||||
@ -6040,7 +6127,6 @@
|
|||||||
- drs
|
- drs
|
||||||
- ecr-public
|
- ecr-public
|
||||||
- elastic-inference
|
- elastic-inference
|
||||||
- emr-serverless
|
|
||||||
- evidently
|
- evidently
|
||||||
- finspace
|
- finspace
|
||||||
- finspace-data
|
- finspace-data
|
||||||
@ -6138,6 +6224,7 @@
|
|||||||
- qldb-session
|
- qldb-session
|
||||||
- rbin
|
- rbin
|
||||||
- rds-data
|
- rds-data
|
||||||
|
- redshiftserverless
|
||||||
- resiliencehub
|
- resiliencehub
|
||||||
- robomaker
|
- robomaker
|
||||||
- route53-recovery-cluster
|
- 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_cloudtrail = lazy_load(".cloudtrail", "mock_cloudtrail")
|
||||||
mock_cloudwatch = lazy_load(".cloudwatch", "mock_cloudwatch")
|
mock_cloudwatch = lazy_load(".cloudwatch", "mock_cloudwatch")
|
||||||
mock_codecommit = lazy_load(".codecommit", "mock_codecommit")
|
mock_codecommit = lazy_load(".codecommit", "mock_codecommit")
|
||||||
|
mock_codebuild = lazy_load(".codebuild", "mock_codebuild")
|
||||||
mock_codepipeline = lazy_load(".codepipeline", "mock_codepipeline")
|
mock_codepipeline = lazy_load(".codepipeline", "mock_codepipeline")
|
||||||
mock_cognitoidentity = lazy_load(
|
mock_cognitoidentity = lazy_load(
|
||||||
".cognitoidentity", "mock_cognitoidentity", boto3_name="cognito-identity"
|
".cognitoidentity", "mock_cognitoidentity", boto3_name="cognito-identity"
|
||||||
|
@ -18,6 +18,7 @@ backend_url_patterns = [
|
|||||||
("cloudfront", re.compile("https?://cloudfront\\.amazonaws\\.com")),
|
("cloudfront", re.compile("https?://cloudfront\\.amazonaws\\.com")),
|
||||||
("cloudtrail", re.compile("https?://cloudtrail\\.(.+)\\.amazonaws\\.com")),
|
("cloudtrail", re.compile("https?://cloudtrail\\.(.+)\\.amazonaws\\.com")),
|
||||||
("cloudwatch", re.compile("https?://monitoring\\.(.+)\\.amazonaws.com")),
|
("cloudwatch", re.compile("https?://monitoring\\.(.+)\\.amazonaws.com")),
|
||||||
|
("codebuild", re.compile("https?://codebuild\\.(.+)\\.amazonaws\\.com")),
|
||||||
("codecommit", re.compile("https?://codecommit\\.(.+)\\.amazonaws\\.com")),
|
("codecommit", re.compile("https?://codecommit\\.(.+)\\.amazonaws\\.com")),
|
||||||
("codepipeline", re.compile("https?://codepipeline\\.(.+)\\.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…
x
Reference in New Issue
Block a user