Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions samcli/commands/init/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,17 @@ 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,
required_param_lists=[["location"]],
required_params_hint="The --checkout option requires --location to specify a git repository.",
incompatible_params=["package_type", "runtime", "base_image", "dependency_manager", "app_template"],
incompatible_params_hint=INCOMPATIBLE_PARAMS_HINT,
)
@click.option(
"--tracing/--no-tracing",
default=None,
Expand Down Expand Up @@ -285,6 +296,7 @@ def cli(
save_params,
config_file,
config_env,
checkout,
):
"""
`sam init` command entry point
Expand All @@ -308,6 +320,7 @@ def cli(
application_insights,
structured_logging,
output,
checkout,
) # pragma: no cover


Expand All @@ -331,6 +344,7 @@ def do_cli(
application_insights,
structured_logging,
output="text",
checkout=None,
):
"""
Implementation of the ``cli`` method
Expand Down Expand Up @@ -401,6 +415,7 @@ def do_cli(
tracing,
application_insights,
structured_logging,
checkout,
)
finally:
# Emitted even when generation failed, since a failing hook prints its diagnostics
Expand Down Expand Up @@ -466,6 +481,7 @@ def do_cli(
tracing,
application_insights,
structured_logging,
checkout,
)


Expand Down
2 changes: 1 addition & 1 deletion samcli/commands/init/core/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"]

OUTPUT_OPTIONS: List[str] = ["output"]

Expand Down
2 changes: 2 additions & 0 deletions samcli/commands/init/init_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ def do_generate(
tracing,
application_insights,
structured_logging,
checkout=None,
):
"""
Generate a project and return the directory it was created in.
Expand All @@ -41,6 +42,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
9 changes: 9 additions & 0 deletions samcli/commands/init/interactive_init_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ def do_interactive(
tracing,
application_insights,
structured_logging,
checkout=None,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[GENERAL] The checkout parameter threaded through do_interactivegenerate_application_generate_from_location/_generate_from_use_case is unreachable with a non-None value from the CLI. --checkout declares required_param_lists=[["location"]], and in do_cli any truthy location takes the if location or zip_bool or image_bool branch, so do_interactive is only ever called with checkout=None.

The one way to reach it is a samconfig.toml entry, since ClickMutex.handle_parse_result returns early when self.name not in opts and config values arrive via ctx.default_map rather than opts — bypassing the --location requirement entirely. In that case _generate_from_use_case overwrites location with templates.location_from_app_template(...) (a local cache path), and the checkout is silently dropped by cookiecutter. Either drop the interactive plumbing, or make the interactive path actually honor/reject checkout rather than silently ignoring it.

):
"""
Implementation of the ``cli`` method when --interactive is provided.
Expand Down Expand Up @@ -85,6 +86,7 @@ def do_interactive(
tracing,
application_insights,
structured_logging,
checkout,
)


Expand All @@ -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
Expand Down Expand Up @@ -156,6 +159,7 @@ def generate_application(
tracing,
application_insights,
structured_logging,
checkout,
)

else:
Expand All @@ -170,6 +174,7 @@ def generate_application(
tracing,
application_insights,
structured_logging,
checkout,
)


Expand All @@ -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 = """
Expand All @@ -207,6 +213,7 @@ def _generate_from_location(
tracing,
application_insights,
structured_logging,
checkout,
)


Expand All @@ -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
Expand Down Expand Up @@ -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:
Expand Down
9 changes: 7 additions & 2 deletions samcli/lib/init/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ def generate_project(
tracing=False,
application_insights=False,
structured_logging=False,
checkout=None,
):
"""Generates project using cookiecutter and options given

Expand Down Expand Up @@ -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

Returns
-------
Expand Down Expand Up @@ -107,6 +110,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)

Expand Down Expand Up @@ -135,9 +141,8 @@ def generate_project(
)
project_output_dir = str(Path(output_dir, name)) if name else output_dir
project_directory = generate_non_cookiecutter_project(
location=params["template"], output_dir=project_output_dir
location=params["template"], output_dir=project_output_dir, checkout=checkout
)

except UnknownRepoType as e:
raise InvalidLocationError(template=params["template"]) from e
except (CookiecutterException, OSError) as e:
Expand Down
10 changes: 8 additions & 2 deletions samcli/lib/init/arbitrary_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
)


def generate_non_cookiecutter_project(location, output_dir):
def generate_non_cookiecutter_project(location, output_dir, checkout=None):
"""
Uses Cookiecutter APIs to download a project at given ``location`` to the ``output_dir``.
This does *not* run cookiecutter on the downloaded project.
Expand All @@ -41,6 +41,9 @@ def generate_non_cookiecutter_project(location, output_dir):
output_dir : str
Directory where the project should be downloaded to

checkout: Optional[str]
Branch, tag or commit to checkout after git clone

Returns
-------
str
Expand Down Expand Up @@ -69,7 +72,10 @@ def generate_non_cookiecutter_project(location, output_dir):
# Else, treat it as a git/hg/ssh URL and try to clone
elif repository.is_repo_url(location):
LOG.debug("%s location is a source control repository", location)
download_fn = functools.partial(repository.clone, repo_url=location, no_input=no_input)
clone_kwargs = {"repo_url": location, "no_input": no_input}
if checkout:
clone_kwargs["checkout"] = checkout
download_fn = functools.partial(repository.clone, **clone_kwargs)

else:
raise ArbitraryProjectDownloadFailed(msg=BAD_LOCATION_ERROR_MSG)
Expand Down
7 changes: 6 additions & 1 deletion schema/samcli.json
Original file line number Diff line number Diff line change
Expand Up @@ -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.al2023, java17, java11.al2023, java11, java8.al2023, java8.al2, nodejs24.x, nodejs22.x, nodejs20.x, nodejs18.x, nodejs16.x, provided, provided.al2023, provided.al2, 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/java11.al2023-base, amazon/java17-base, amazon/java17.al2023-base, amazon/java21-base, amazon/java25-base, amazon/java8.al2-base, amazon/java8.al2023-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* output:\nOutput the results from the command in a given output format. Supported formats: text (default), json.\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.al2023, java17, java11.al2023, java11, java8.al2023, java8.al2, nodejs24.x, nodejs22.x, nodejs20.x, nodejs18.x, nodejs16.x, provided, provided.al2023, provided.al2, 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/java11.al2023-base, amazon/java17-base, amazon/java17.al2023-base, amazon/java21-base, amazon/java25-base, amazon/java8.al2-base, amazon/java8.al2023-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* output:\nOutput the results from the command in a given output format. Supported formats: text (default), json.\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": {
Expand Down Expand Up @@ -200,6 +200,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",
Expand Down
Loading