diff --git a/samcli/commands/init/command.py b/samcli/commands/init/command.py index cb5d4520b42..7e15965df28 100644 --- a/samcli/commands/init/command.py +++ b/samcli/commands/init/command.py @@ -217,6 +217,15 @@ def wrapped(*args, **kwargs): """ """, required=False, ) +@click.option( + "--checkout", + default=None, + help="Branch, tag or commit to checkout after git clone.", + required=False, + cls=ClickMutex, + incompatible_params=["package_type", "runtime", "base_image", "dependency_manager", "app_template"], + incompatible_params_hint=INCOMPATIBLE_PARAMS_HINT, +) @click.option( "--tracing/--no-tracing", default=None, @@ -253,6 +262,7 @@ def cli( app_template, no_input, extra_context, + checkout, tracing, application_insights, structured_logging, @@ -278,6 +288,7 @@ def cli( app_template, no_input, extra_context, + checkout, tracing, application_insights, structured_logging, @@ -300,6 +311,7 @@ def do_cli( app_template, no_input, extra_context, + checkout, tracing, application_insights, structured_logging, @@ -356,6 +368,7 @@ def do_cli( tracing, application_insights, structured_logging, + checkout, ) else: if not (pt_explicit or runtime or dependency_manager or base_image or architecture): @@ -377,6 +390,7 @@ def do_cli( tracing, application_insights, structured_logging, + checkout, ) diff --git a/samcli/commands/init/core/options.py b/samcli/commands/init/core/options.py index f6c2c8ce2e6..6b9e8629f44 100644 --- a/samcli/commands/init/core/options.py +++ b/samcli/commands/init/core/options.py @@ -22,7 +22,7 @@ ] # Can be used instead of the options in the first list -NON_INTERACTIVE_OPTIONS: List[str] = ["no_interactive", "no_input", "extra_context"] +NON_INTERACTIVE_OPTIONS: List[str] = ["no_interactive", "no_input", "extra_context", "checkout"] CONFIGURATION_OPTION_NAMES: List[str] = ["config_env", "config_file"] + SAVE_PARAMS_OPTIONS diff --git a/samcli/commands/init/init_generator.py b/samcli/commands/init/init_generator.py index 454405615b1..1d418e0998a 100644 --- a/samcli/commands/init/init_generator.py +++ b/samcli/commands/init/init_generator.py @@ -19,6 +19,7 @@ def do_generate( tracing, application_insights, structured_logging, + checkout=None, ): try: generate_project( @@ -33,6 +34,7 @@ def do_generate( tracing, application_insights, structured_logging, + checkout, ) except InitErrorException as e: raise UserException(str(e), wrapped_from=e.__class__.__name__) from e diff --git a/samcli/commands/init/interactive_init_flow.py b/samcli/commands/init/interactive_init_flow.py index 245aead5cbf..3bdc07e024f 100644 --- a/samcli/commands/init/interactive_init_flow.py +++ b/samcli/commands/init/interactive_init_flow.py @@ -57,6 +57,7 @@ def do_interactive( tracing, application_insights, structured_logging, + checkout=None, ): """ Implementation of the ``cli`` method when --interactive is provided. @@ -85,6 +86,7 @@ def do_interactive( tracing, application_insights, structured_logging, + checkout, ) @@ -104,6 +106,7 @@ def generate_application( tracing, application_insights, structured_logging, + checkout=None, ): # pylint: disable=too-many-arguments """ The method holds the decision logic for generating an application @@ -156,6 +159,7 @@ def generate_application( tracing, application_insights, structured_logging, + checkout, ) else: @@ -170,6 +174,7 @@ def generate_application( tracing, application_insights, structured_logging, + checkout, ) @@ -185,6 +190,7 @@ def _generate_from_location( tracing, application_insights, structured_logging, + checkout=None, ): location = click.prompt("\nTemplate location (git, mercurial, http(s), zip, path)", type=str) summary_msg = """ @@ -207,6 +213,7 @@ def _generate_from_location( tracing, application_insights, structured_logging, + checkout, ) @@ -225,6 +232,7 @@ def _generate_from_use_case( tracing: Optional[bool], application_insights: Optional[bool], structured_logging: Optional[bool], + checkout: Optional[str] = None, ) -> None: templates = InitTemplates() runtime_or_base_image = runtime if runtime else base_image @@ -315,6 +323,7 @@ def _generate_from_use_case( tracing, application_insights, structured_logging, + checkout, ) # executing event_bridge logic if call is for Schema dynamic template if is_dynamic_schemas_template: diff --git a/samcli/lib/init/__init__.py b/samcli/lib/init/__init__.py index 922b4fa6754..f1ca3cdb5a0 100644 --- a/samcli/lib/init/__init__.py +++ b/samcli/lib/init/__init__.py @@ -40,6 +40,7 @@ def generate_project( tracing=False, application_insights=False, structured_logging=False, + checkout=None, ): """Generates project using cookiecutter and options given @@ -74,6 +75,8 @@ def generate_project( Enable or disable AppInsights Monitoring structured_logging: Optional[bool] boolean value to determine if Json structured logging should be enabled or not + checkout: Optional[str] + Branch, tag or commit to checkout after git clone Raises ------ @@ -98,6 +101,9 @@ def generate_project( if extra_context: params["extra_context"] = extra_context + if checkout: + params["checkout"] = checkout + LOG.debug("Parameters dict created with input given") LOG.debug("%s", params) diff --git a/schema/samcli.json b/schema/samcli.json index b7e3f1ec7e3..a76545e4c62 100644 --- a/schema/samcli.json +++ b/schema/samcli.json @@ -54,7 +54,7 @@ "properties": { "parameters": { "title": "Parameters for the init command", - "description": "Available parameters for the init command:\n* no_interactive:\nDisable interactive prompting for init parameters. (fail if any required values are missing)\n* architecture:\nArchitectures for Lambda functions.\n\nArchitectures: ['arm64', 'x86_64']\n* location:\nTemplate location (git, mercurial, http(s), zip, path).\n* runtime:\nLambda runtime for application.\n\nRuntimes: dotnet10, dotnet8, dotnet6, go1.x, java25, java21, java17, java11, java8.al2, nodejs24.x, nodejs22.x, nodejs20.x, nodejs18.x, nodejs16.x, provided, provided.al2, provided.al2023, python3.9, python3.8, python3.14, python3.13, python3.12, python3.11, python3.10, ruby4.0, ruby3.4, ruby3.3, ruby3.2\n* package_type:\nLambda deployment package type.\n\nPackage Types: Zip, Image\n* base_image:\nLambda base image for deploying IMAGE based package type.\n\nBase images: amazon/dotnet10-base, amazon/dotnet6-base, amazon/dotnet8-base, amazon/go-provided.al2-base, amazon/go-provided.al2023-base, amazon/go1.x-base, amazon/java11-base, amazon/java17-base, amazon/java21-base, amazon/java25-base, amazon/java8.al2-base, amazon/nodejs16.x-base, amazon/nodejs18.x-base, amazon/nodejs20.x-base, amazon/nodejs22.x-base, amazon/nodejs24.x-base, amazon/python3.10-base, amazon/python3.11-base, amazon/python3.12-base, amazon/python3.13-base, amazon/python3.14-base, amazon/python3.8-base, amazon/python3.9-base, amazon/ruby3.2-base, amazon/ruby3.3-base, amazon/ruby3.4-base, amazon/ruby4.0-base\n* dependency_manager:\nDependency manager for Lambda runtime.\n\nDependency managers: bundler, cli-package, gradle, maven, mod, npm, pip\n* output_dir:\nDirectory to initialize AWS SAM application.\n* name:\nName of AWS SAM Application.\n* app_template:\nIdentifier of the managed application template to be used. Alternatively, run '$ sam init' without options for an interactive workflow.\n* no_input:\nDisable Cookiecutter prompting and accept default values defined in the cookiecutter config.\n* extra_context:\nOverride custom parameters in the template's cookiecutter.json configuration e.g. {\"customParam1\": \"customValue1\", \"customParam2\":\"customValue2\"}\n* tracing:\nEnable AWS X-Ray tracing for application.\n* application_insights:\nEnable CloudWatch Application Insights monitoring for application.\n* structured_logging:\nEnable Structured Logging for application.\n* beta_features:\nEnable/Disable beta features.\n* debug:\nTurn on debug logging to print debug message generated by AWS SAM CLI and display timestamps.\n* save_params:\nSave the parameters provided via the command line to the configuration file.", + "description": "Available parameters for the init command:\n* no_interactive:\nDisable interactive prompting for init parameters. (fail if any required values are missing)\n* architecture:\nArchitectures for Lambda functions.\n\nArchitectures: ['arm64', 'x86_64']\n* location:\nTemplate location (git, mercurial, http(s), zip, path).\n* runtime:\nLambda runtime for application.\n\nRuntimes: dotnet10, dotnet8, dotnet6, go1.x, java25, java21, java17, java11, java8.al2, nodejs24.x, nodejs22.x, nodejs20.x, nodejs18.x, nodejs16.x, provided, provided.al2, provided.al2023, python3.9, python3.8, python3.14, python3.13, python3.12, python3.11, python3.10, ruby4.0, ruby3.4, ruby3.3, ruby3.2\n* package_type:\nLambda deployment package type.\n\nPackage Types: Zip, Image\n* base_image:\nLambda base image for deploying IMAGE based package type.\n\nBase images: amazon/dotnet10-base, amazon/dotnet6-base, amazon/dotnet8-base, amazon/go-provided.al2-base, amazon/go-provided.al2023-base, amazon/go1.x-base, amazon/java11-base, amazon/java17-base, amazon/java21-base, amazon/java25-base, amazon/java8.al2-base, amazon/nodejs16.x-base, amazon/nodejs18.x-base, amazon/nodejs20.x-base, amazon/nodejs22.x-base, amazon/nodejs24.x-base, amazon/python3.10-base, amazon/python3.11-base, amazon/python3.12-base, amazon/python3.13-base, amazon/python3.14-base, amazon/python3.8-base, amazon/python3.9-base, amazon/ruby3.2-base, amazon/ruby3.3-base, amazon/ruby3.4-base, amazon/ruby4.0-base\n* dependency_manager:\nDependency manager for Lambda runtime.\n\nDependency managers: bundler, cli-package, gradle, maven, mod, npm, pip\n* output_dir:\nDirectory to initialize AWS SAM application.\n* name:\nName of AWS SAM Application.\n* app_template:\nIdentifier of the managed application template to be used. Alternatively, run '$ sam init' without options for an interactive workflow.\n* no_input:\nDisable Cookiecutter prompting and accept default values defined in the cookiecutter config.\n* extra_context:\nOverride custom parameters in the template's cookiecutter.json configuration e.g. {\"customParam1\": \"customValue1\", \"customParam2\":\"customValue2\"}\n* checkout:\nBranch, tag or commit to checkout after git clone.\n* tracing:\nEnable AWS X-Ray tracing for application.\n* application_insights:\nEnable CloudWatch Application Insights monitoring for application.\n* structured_logging:\nEnable Structured Logging for application.\n* beta_features:\nEnable/Disable beta features.\n* debug:\nTurn on debug logging to print debug message generated by AWS SAM CLI and display timestamps.\n* save_params:\nSave the parameters provided via the command line to the configuration file.", "type": "object", "properties": { "no_interactive": { @@ -194,6 +194,11 @@ "type": "string", "description": "Override custom parameters in the template's cookiecutter.json configuration e.g. {\"customParam1\": \"customValue1\", \"customParam2\":\"customValue2\"}" }, + "checkout": { + "title": "checkout", + "type": "string", + "description": "Branch, tag or commit to checkout after git clone." + }, "tracing": { "title": "tracing", "type": "boolean", diff --git a/tests/unit/commands/init/test_cli.py b/tests/unit/commands/init/test_cli.py index 3b7ad9b4dfa..3c460a31f70 100644 --- a/tests/unit/commands/init/test_cli.py +++ b/tests/unit/commands/init/test_cli.py @@ -121,6 +121,7 @@ def test_init_cli(self, generate_project_patch, git_repo_clone_mock): tracing=False, application_insights=False, structured_logging=True, + checkout=None, ) # THEN we should receive no errors @@ -138,6 +139,7 @@ def test_init_cli(self, generate_project_patch, git_repo_clone_mock): False, False, True, + None, ) @patch("samcli.lib.utils.git_repo.GitRepo.clone") @@ -163,6 +165,7 @@ def test_init_cli_node(self, generate_project_patch, git_repo_clone_mock): tracing=False, application_insights=False, structured_logging=False, + checkout=None, ) # THEN we should receive no errors @@ -179,6 +182,7 @@ def test_init_cli_node(self, generate_project_patch, git_repo_clone_mock): False, False, False, + None, ) @patch("samcli.lib.utils.git_repo.GitRepo.clone") @@ -204,6 +208,7 @@ def test_init_image_cli(self, generate_project_patch, git_repo_clone_mock): tracing=False, application_insights=False, structured_logging=False, + checkout=None, ) # THEN we should receive no errors @@ -220,6 +225,7 @@ def test_init_image_cli(self, generate_project_patch, git_repo_clone_mock): False, False, False, + None, ) @patch("samcli.lib.utils.git_repo.GitRepo.clone") @@ -245,6 +251,7 @@ def test_init_cli_with_tracing(self, generate_project_patch, git_repo_clone_mock tracing=True, application_insights=False, structured_logging=False, + checkout=None, ) # THEN we should receive no errors @@ -262,6 +269,7 @@ def test_init_cli_with_tracing(self, generate_project_patch, git_repo_clone_mock True, False, False, + None, ) @patch("samcli.lib.utils.git_repo.GitRepo.clone") @@ -287,6 +295,7 @@ def test_init_cli_with_application_insights(self, generate_project_patch, git_re tracing=False, application_insights=True, structured_logging=False, + checkout=None, ) # THEN we should receive no errors @@ -304,6 +313,7 @@ def test_init_cli_with_application_insights(self, generate_project_patch, git_re False, True, False, + None, ) @patch("samcli.lib.utils.git_repo.GitRepo.clone") @@ -329,6 +339,7 @@ def test_init_image_java_cli(self, generate_project_patch, git_repo_clone_mock): tracing=False, application_insights=False, structured_logging=True, + checkout=None, ) # THEN we should receive no errors @@ -345,6 +356,7 @@ def test_init_image_java_cli(self, generate_project_patch, git_repo_clone_mock): False, False, True, + None, ) @patch("samcli.lib.utils.git_repo.GitRepo.clone") @@ -370,6 +382,7 @@ def test_init_fails_invalid_template(self, git_repo_clone_mock): tracing=False, application_insights=False, structured_logging=False, + checkout=None, ) @patch("samcli.lib.utils.git_repo.GitRepo.clone") @@ -395,6 +408,7 @@ def test_init_fails_invalid_dep_mgr(self, git_repo_clone_mock): tracing=False, application_insights=False, structured_logging=False, + checkout=None, ) @patch("samcli.lib.utils.git_repo.GitRepo.clone") @@ -426,6 +440,7 @@ def test_init_cli_generate_project_fails(self, generate_project_patch, git_repo_ tracing=False, application_insights=False, structured_logging=False, + checkout=None, ) generate_project_patch.assert_called_with( @@ -469,6 +484,7 @@ def test_init_cli_generate_project_image_fails(self, generate_project_patch, git tracing=False, application_insights=False, structured_logging=False, + checkout=None, ) generate_project_patch.assert_called_with( @@ -506,6 +522,7 @@ def test_init_cli_with_extra_context_parameter_not_passed(self, generate_project tracing=False, application_insights=False, structured_logging=False, + checkout=None, ) # THEN we should receive no errors @@ -522,6 +539,7 @@ def test_init_cli_with_extra_context_parameter_not_passed(self, generate_project False, False, False, + None, ) @patch("samcli.lib.utils.git_repo.GitRepo.clone") @@ -547,6 +565,7 @@ def test_init_cli_with_extra_context_parameter_passed(self, generate_project_pat tracing=False, application_insights=False, structured_logging=False, + checkout=None, ) # THEN we should receive no errors and right extra_context should be passed @@ -568,6 +587,7 @@ def test_init_cli_with_extra_context_parameter_passed(self, generate_project_pat False, False, False, + None, ) @patch("samcli.lib.utils.git_repo.GitRepo.clone") @@ -595,6 +615,7 @@ def test_init_cli_with_extra_context_not_overriding_default_parameter( tracing=False, application_insights=False, structured_logging=False, + checkout=None, ) # THEN extra_context should have not overridden default_parameters(name, runtime) @@ -616,6 +637,7 @@ def test_init_cli_with_extra_context_not_overriding_default_parameter( False, False, False, + None, ) @patch("samcli.lib.utils.git_repo.GitRepo.clone") @@ -641,6 +663,7 @@ def test_init_cli_with_extra_context_input_as_wrong_json_raises_exception(self, tracing=False, application_insights=False, structured_logging=False, + checkout=None, ) @patch("samcli.commands.init.init_generator.generate_project") @@ -665,6 +688,7 @@ def test_init_cli_must_set_default_context_when_location_is_provided(self, gener tracing=False, application_insights=False, structured_logging=False, + checkout=None, ) # THEN should set default parameter(name, runtime) as extra_context @@ -686,6 +710,7 @@ def test_init_cli_must_set_default_context_when_location_is_provided(self, gener False, False, False, + None, ) @patch("samcli.commands.init.init_generator.generate_project") @@ -710,6 +735,7 @@ def test_init_cli_must_only_set_passed_project_name_when_location_is_provided(se tracing=False, application_insights=False, structured_logging=True, + checkout=None, ) # THEN extra_context should be without runtime @@ -730,6 +756,7 @@ def test_init_cli_must_only_set_passed_project_name_when_location_is_provided(se False, False, True, + None, ) @patch("samcli.commands.init.init_generator.generate_project") @@ -754,6 +781,7 @@ def test_init_cli_must_only_set_passed_runtime_when_location_is_provided(self, g tracing=False, application_insights=False, structured_logging=True, + checkout=None, ) # THEN extra_context should be without name @@ -774,6 +802,7 @@ def test_init_cli_must_only_set_passed_runtime_when_location_is_provided(self, g False, False, True, + None, ) @patch("samcli.lib.utils.git_repo.GitRepo.clone") @@ -801,6 +830,8 @@ def test_init_cli_with_extra_context_parameter_passed_as_escaped(self, generate_ application_insights= False, structured_logging=False # fmt: on + , + checkout=None, ) # THEN we should receive no errors and right extra_context should be passed @@ -822,6 +853,7 @@ def test_init_cli_with_extra_context_parameter_passed_as_escaped(self, generate_ False, False, False, + None, ) @patch.object(InitTemplates, "__init__", MockInitTemplates.__init__) @@ -967,6 +999,7 @@ def test_init_cli_int_with_event_bridge_app_template( False, False, False, + None, ) get_schemas_client_mock.assert_called_once_with(None, "ap-northeast-1") do_extract_and_merge_schemas_code_mock.do_extract_and_merge_schemas_code_mock( @@ -1039,6 +1072,7 @@ def test_init_cli_int_with_image_app_template( False, False, True, + None, ) @patch.object(InitTemplates, "__init__", MockInitTemplates.__init__) @@ -1189,6 +1223,7 @@ def test_init_cli_int_with_event_bridge_app_template_and_aws_configuration( False, False, False, + None, ) get_schemas_client_mock.assert_called_once_with("default", "us-east-1") do_extract_and_merge_schemas_code_mock.do_extract_and_merge_schemas_code("result.zip", ".", "test-project", ANY) @@ -1446,6 +1481,7 @@ def test_init_cli_int_with_download_manager_raises_exception( False, False, False, + None, ) get_schemas_client_mock.assert_called_once_with(None, "ap-northeast-1") do_extract_and_merge_schemas_code_mock.do_extract_and_merge_schemas_code_mock( @@ -1597,6 +1633,7 @@ def test_init_passes_dynamic_event_bridge_template(self, generate_project_patch, tracing=False, application_insights=False, structured_logging=False, + checkout=None, ) self.extra_context_as_json["architectures"] = {"value": [ARM64]} @@ -1613,6 +1650,7 @@ def test_init_passes_dynamic_event_bridge_template(self, generate_project_patch, False, False, False, + None, ) @patch("samcli.lib.utils.git_repo.GitRepo.clone") @@ -1645,6 +1683,7 @@ def test_init_cli_int_from_location(self, generate_project_patch, git_repo_clone None, None, None, + None, ) @patch("samcli.commands.init.init_templates.InitTemplates._get_manifest") @@ -1680,7 +1719,7 @@ def test_init_cli_no_package_type(self, generate_project_patch, git_repo_clone_m # THEN we should receive no errors self.assertFalse(result.exception) generate_project_patch.assert_called_once_with( - ANY, IMAGE, "python3.8", "pip", ".", "untitled6", True, ANY, False, False, False + ANY, IMAGE, "python3.8", "pip", ".", "untitled6", True, ANY, False, False, False, None ) @patch.object(InitTemplates, "__init__", MockInitTemplates.__init__) @@ -1724,6 +1763,7 @@ def test_init_cli_image_pool_with_base_image_having_multiple_managed_template_bu tracing=False, application_insights=False, structured_logging=False, + checkout=None, ) @patch.object(InitTemplates, "__init__", MockInitTemplates.__init__) @@ -1767,6 +1807,7 @@ def test_init_cli_image_pool_with_base_image_having_multiple_managed_template_an tracing=False, application_insights=False, structured_logging=False, + checkout=None, ) @patch.object(InitTemplates, "__init__", MockInitTemplates.__init__) @@ -1811,6 +1852,7 @@ def test_init_cli_image_pool_with_base_image_having_multiple_managed_template_wi tracing=False, application_insights=False, structured_logging=False, + checkout=None, ) generate_project_patch.assert_called_once_with( ANY, # location @@ -1824,6 +1866,7 @@ def test_init_cli_image_pool_with_base_image_having_multiple_managed_template_wi False, False, False, + None, ) @patch.object(InitTemplates, "__init__", MockInitTemplates.__init__) @@ -1861,6 +1904,7 @@ def test_init_cli_image_pool_with_base_image_having_one_managed_template_does_no application_insights=False, architecture=None, structured_logging=False, + checkout=None, ) generate_project_patch.assert_called_once_with( ANY, # location @@ -1874,6 +1918,7 @@ def test_init_cli_image_pool_with_base_image_having_one_managed_template_does_no False, False, False, + None, ) @patch.object(InitTemplates, "__init__", MockInitTemplates.__init__) @@ -1911,6 +1956,7 @@ def test_init_cli_image_pool_with_base_image_having_one_managed_template_with_pr application_insights=False, architecture=None, structured_logging=False, + checkout=None, ) generate_project_patch.assert_called_once_with( ANY, # location @@ -1924,6 +1970,7 @@ def test_init_cli_image_pool_with_base_image_having_one_managed_template_with_pr False, False, False, + None, ) @patch.object(InitTemplates, "__init__", MockInitTemplates.__init__) @@ -1962,6 +2009,7 @@ def test_init_cli_image_pool_with_base_image_having_one_managed_template_with_pr application_insights=False, architecture=None, structured_logging=False, + checkout=None, ) @patch("samcli.lib.utils.git_repo.GitRepo.clone") @@ -1991,7 +2039,7 @@ def test_init_cli_must_pass_with_architecture_and_base_image(self, generate_proj # THEN we should receive no errors self.assertFalse(result.exception) generate_project_patch.assert_called_once_with( - ANY, IMAGE, "java11", "gradle", ".", "untitled6", True, ANY, None, None, None + ANY, IMAGE, "java11", "gradle", ".", "untitled6", True, ANY, None, None, None, None ) PackageType.explicit = ( False # Other tests fail after we pass --packge-type in this test, so let's reset this variable @@ -2086,6 +2134,7 @@ def test_init_cli_generate_default_hello_world_app( False, False, False, + None, ) @patch("samcli.commands.init.init_templates.InitTemplates.get_preprocessed_manifest") @@ -2177,6 +2226,7 @@ def test_init_cli_must_not_generate_default_hello_world_app( False, False, False, + None, ) def test_must_return_runtime_from_base_image_name(self): @@ -2358,6 +2408,7 @@ def test_init_fails_unsupported_dep_mgr_for_runtime(self, git_repo_clone_mock, c application_insights=False, architecture=X86_64, structured_logging=False, + checkout=None, ) expected_error_message = ( "Lambda Runtime java8.al2 and dependency manager pip does not have an available initialization template." @@ -2470,6 +2521,7 @@ def test_init_cli_int_with_multiple_app_templates( False, False, False, + None, ) @patch("samcli.commands.init.init_templates.LOG") @@ -2687,6 +2739,7 @@ def test_init_cli_generate_hello_world_app_without_default_prompt( False, False, False, + None, ) @patch.object(InitTemplates, "__init__", MockInitTemplates.__init__) @@ -2780,6 +2833,7 @@ def test_init_cli_generate_app_template_provide_via_options( False, False, False, + None, ) def does_template_meet_filter_criteria(self): @@ -2865,6 +2919,7 @@ def test_init_cli_generate_app_template_from_local_cli_templates( False, False, False, + None, ) @patch("samcli.local.common.runtime_template.INIT_RUNTIMES") @@ -2956,6 +3011,7 @@ def test_init_cli_generate_app_template_with_custom_runtime( False, False, False, + None, ) @patch("samcli.commands.init.init_templates.InitTemplates._get_manifest") @@ -3039,6 +3095,7 @@ def test_init_cli_generate_app_template_with_custom_runtime_using_options( False, False, False, + None, ) @patch("samcli.commands.init.init_templates.InitTemplates.get_preprocessed_manifest") @@ -3126,6 +3183,7 @@ def test_init_cli_generate_app_template_provide_via_tracing_options( True, False, False, + None, ) @patch("samcli.commands.init.init_templates.InitTemplates.get_preprocessed_manifest") @@ -3213,6 +3271,7 @@ def test_init_cli_generate_app_template_provide_via_application_insights_options False, True, False, + None, ) @parameterized.expand( diff --git a/tests/unit/commands/samconfig/test_samconfig.py b/tests/unit/commands/samconfig/test_samconfig.py index 443aa3b998e..6ad9d1b0e7a 100644 --- a/tests/unit/commands/samconfig/test_samconfig.py +++ b/tests/unit/commands/samconfig/test_samconfig.py @@ -82,6 +82,7 @@ def test_init(self, do_cli_mock): True, '{"key": "value", "key2": "value2"}', None, + None, ANY, None, ) diff --git a/tests/unit/lib/init/test_init.py b/tests/unit/lib/init/test_init.py index d8e076c9a34..3da43c0c415 100644 --- a/tests/unit/lib/init/test_init.py +++ b/tests/unit/lib/init/test_init.py @@ -229,3 +229,67 @@ def test_doesnt_modify_samconfig_already_exists(self, is_file_mock, samconfig_mo is_file_mock.return_value = True _create_default_samconfig("zip", "outdir", "sam-app") samconfig_mock.assert_not_called() + + @patch("samcli.lib.init._create_default_samconfig") + @patch("samcli.lib.init.cookiecutter") + def test_generate_project_with_checkout_and_git_location(self, cookiecutter_patch, default_samconfig_mock): + """Test that checkout is passed to cookiecutter for a git location""" + # GIVEN a git location and checkout parameter + git_location = "https://github.com/aws-samples/cookiecutter-aws-sam-python.git" + checkout_ref = "improv/cleanup" + + # WHEN generate_project is called with checkout and git location + generate_project( + location=git_location, + checkout=checkout_ref, + output_dir=self.output_dir, + no_input=self.no_input, + ) + + # THEN cookiecutter should be called with the remote URL and checkout ref + cookiecutter_patch.assert_called_once() + call_kwargs = cookiecutter_patch.call_args.kwargs + self.assertEqual(call_kwargs.get("template"), git_location) + self.assertEqual(call_kwargs.get("checkout"), checkout_ref) + + @patch("samcli.lib.init._create_default_samconfig") + @patch("samcli.lib.init.cookiecutter") + def test_generate_project_without_checkout_uses_remote_url(self, cookiecutter_patch, default_samconfig_mock): + """Test that without checkout, remote URL is passed to cookiecutter""" + # GIVEN a git location without checkout parameter + git_location = "https://github.com/aws-samples/cookiecutter-aws-sam-python.git" + + # WHEN generate_project is called without checkout + generate_project( + location=git_location, + output_dir=self.output_dir, + no_input=self.no_input, + ) + + # AND cookiecutter should be called with the remote URL and no checkout + cookiecutter_patch.assert_called_once() + call_kwargs = cookiecutter_patch.call_args.kwargs + self.assertEqual(call_kwargs.get("template"), git_location) + self.assertFalse(call_kwargs.get("checkout")) + + @patch("samcli.lib.init._create_default_samconfig") + @patch("samcli.lib.init.cookiecutter") + def test_generate_project_with_checkout_and_non_git_location(self, cookiecutter_patch, default_samconfig_mock): + """Test that checkout is passed to cookiecutter for non-git locations""" + # GIVEN a non-git (local) location and checkout parameter + local_location = "/path/to/local/template" + checkout_ref = "branch-name" + + # WHEN generate_project is called + generate_project( + location=local_location, + checkout=checkout_ref, + output_dir=self.output_dir, + no_input=self.no_input, + ) + + # THEN cookiecutter should be called with both the location and checkout parameter + cookiecutter_patch.assert_called_once() + call_kwargs = cookiecutter_patch.call_args.kwargs + self.assertEqual(call_kwargs.get("template"), local_location) + self.assertEqual(call_kwargs.get("checkout"), checkout_ref)