Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
fb485ef
Initial skeleton code and ecr get-login check implementation.
aemous Sep 5, 2025
fb63718
Fix tests.
aemous Sep 5, 2025
2e8adc8
Fix tests.
aemous Sep 5, 2025
9bc7cd3
Update .changes/next-release/enhancement-Migration-48043.json
aemous Sep 11, 2025
a5022c8
Revise based on feedback.
aemous Sep 17, 2025
75bc2ec
Add TODO for api_versions check.
aemous Sep 24, 2025
8c1be9f
Revised based on feedback.
aemous Sep 26, 2025
1fee97f
Merge pull request #9703 from aemous/debug-migration
aemous Oct 6, 2025
911eddb
Implement v2-debug checks for args, config, customizations, s3, and e…
aemous Oct 21, 2025
75104fe
Merge remote-tracking branch 'origin/develop' into merge-debug-migrat…
aemous Oct 22, 2025
f9963e8
Update unit test based on upstream changes in `develop`.
aemous Oct 22, 2025
db28bd8
Merge pull request #9808 from aemous/merge-debug-migration-branch
aemous Oct 22, 2025
5300c21
Add tests and pagination updates.
aemous Oct 9, 2025
5c865bd
Switch migration warnings to use stderr.
aemous Oct 10, 2025
0e4b4e9
Revise based on feedback.
aemous Oct 14, 2025
ad99177
Add tests to verify register feature ID.
aemous Oct 13, 2025
d407cb7
Progress.
aemous Oct 15, 2025
25a2e63
Progress.
aemous Oct 17, 2025
74fb5c2
Make cfn deploy false-positive category to reduce change of service-d…
aemous Oct 17, 2025
37d656d
Progress
aemous Oct 17, 2025
6a6a1ce
Add 'wire' as a valid value for cli_timestamp_format.
aemous Oct 17, 2025
a230d85
Update from feedback
aemous Oct 17, 2025
78e4a64
Upgrade scalarparse debug warning to only print if the user did not c…
aemous Oct 17, 2025
34ae9f0
Update binary-params runtime check so that it no longer depends on st…
aemous Oct 22, 2025
8e6b127
Keep uni_print in customizations.
aemous Oct 22, 2025
b502ead
Remove changelog for already-released change.
aemous Oct 22, 2025
1657364
Revert local changes to requirements.txt made for testing
aemous Oct 22, 2025
53d972f
Update changelog entry based on feedback.
aemous Dec 4, 2025
b9700c6
Fix bug with cli_follow_urlparam.
aemous Dec 4, 2025
af65f6b
Fix bug with us-east-1 S3 global endpoint breaking change for modeled…
aemous Dec 4, 2025
4ab5fb8
Remove no-v2-debug flag.
aemous Dec 4, 2025
5a98bdf
Add missing URL to sigv2 S3 warning.
aemous Dec 5, 2025
6fc681d
Merge pull request #9810 from aemous/debug-migration-metrics-rebased
aemous Dec 7, 2025
9e83e02
Reduced false positive upgrade warnings for URL parameters.
aemous Dec 8, 2025
46eee3c
Add more spacing around upgrade warnings.
aemous Dec 8, 2025
cab3033
Update tests based on changes to function interfaces.
aemous Dec 8, 2025
5972fae
Update wordings for each warning.
aemous Dec 10, 2025
ebc837a
Update tests based on updated wording in warnings.
aemous Dec 10, 2025
62f1bda
Merge pull request #9899 from aemous/debug_migration_url_params
aemous Dec 10, 2025
d2f3f51
Modify us-east-1 S3 endpoint check to only check the hostname.
aemous Dec 10, 2025
ba5c0d0
Switch changelog entry to feature.
aemous Dec 10, 2025
c1a9fc0
Patch us-east-1 detection logic.
aemous Dec 10, 2025
7365324
Patch us-east-1 detection based on extra conditions.
aemous Dec 10, 2025
5d99f67
Remake feature changelog entry.
aemous Dec 10, 2025
49688a6
Remove endpoint-url check
aemous Dec 11, 2025
57d0a24
Merge pull request #9906 from aemous/debug-migration-patch
aemous Dec 11, 2025
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
5 changes: 5 additions & 0 deletions .changes/next-release/feature-Migration-29690.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"type": "feature",
"category": "Migration",
"description": "Implement a ``--v2-debug`` flag and ``AWS_CLI_UPGRADE_DEBUG_MODE`` environment variable that detects breaking changes for AWS CLI v2 for entered commands."
}
6 changes: 3 additions & 3 deletions awscli/alias.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ def __call__(self, args, parsed_globals):
parsed_alias_args, remaining = self._parser.parse_known_args(
alias_args
)
self._update_parsed_globals(parsed_alias_args, parsed_globals)
self._update_parsed_globals(parsed_alias_args, parsed_globals, remaining)
# Take any of the remaining arguments that were not parsed out and
# prepend them to the remaining args provided to the alias.
remaining.extend(args)
Expand Down Expand Up @@ -228,7 +228,7 @@ def _get_alias_args(self):
)
return alias_args

def _update_parsed_globals(self, parsed_alias_args, parsed_globals):
def _update_parsed_globals(self, parsed_alias_args, parsed_globals, remaining):
global_params_to_update = self._get_global_parameters_to_update(
parsed_alias_args
)
Expand All @@ -237,7 +237,7 @@ def _update_parsed_globals(self, parsed_alias_args, parsed_globals):
# global parameters provided in the alias before updating
# the original provided global parameter values
# and passing those onto subsequent commands.
emit_top_level_args_parsed_event(self._session, parsed_alias_args)
emit_top_level_args_parsed_event(self._session, parsed_alias_args, remaining)
for param_name in global_params_to_update:
updated_param_value = getattr(parsed_alias_args, param_name)
setattr(parsed_globals, param_name, updated_param_value)
Expand Down
3 changes: 2 additions & 1 deletion awscli/argprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class TooComplexError(Exception):


def unpack_argument(
session, service_name, operation_name, cli_argument, value
session, service_name, operation_name, cli_argument, value, parsed_globals
):
"""
Unpack an argument's value from the commandline. This is part one of a two
Expand All @@ -83,6 +83,7 @@ def unpack_argument(
value=value,
service_name=service_name,
operation_name=operation_name,
parsed_globals=parsed_globals,
)

if value_override is not None:
Expand Down
64 changes: 55 additions & 9 deletions awscli/clidriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
ServiceHelpCommand,
)
from awscli.plugin import load_plugins
from awscli.utils import emit_top_level_args_parsed_event, write_exception, create_nested_client
from awscli.utils import emit_top_level_args_parsed_event, write_exception, create_nested_client, resolve_v2_debug_mode
from botocore import __version__ as botocore_version
from botocore import xform_name

Expand Down Expand Up @@ -225,7 +225,7 @@ def main(self, args=None):
# that exceptions can be raised, which should have the same
# general exception handling logic as calling into the
# command table. This is why it's in the try/except clause.
self._handle_top_level_args(parsed_args)
self._handle_top_level_args(parsed_args, remaining)
self._emit_session_event(parsed_args)
HISTORY_RECORDER.record(
'CLI_VERSION', self.session.user_agent(), 'CLI'
Expand Down Expand Up @@ -279,8 +279,8 @@ def _show_error(self, msg):
sys.stderr.write(msg)
sys.stderr.write('\n')

def _handle_top_level_args(self, args):
emit_top_level_args_parsed_event(self.session, args)
def _handle_top_level_args(self, args, remaining):
emit_top_level_args_parsed_event(self.session, args, remaining)
if args.profile:
self.session.set_config_variable('profile', args.profile)
if args.region:
Expand Down Expand Up @@ -542,9 +542,15 @@ def __call__(self, args, parsed_globals):
event, parsed_args=parsed_args, parsed_globals=parsed_globals
)
call_parameters = self._build_call_parameters(
parsed_args, self.arg_table
parsed_args, self.arg_table, parsed_globals
)

self._detect_binary_file_migration_change(
self._session,
parsed_args,
parsed_globals,
self.arg_table
)
event = f'calling-command.{self._parent_name}.{self._name}'
override = self._emit_first_non_none_response(
event,
Expand Down Expand Up @@ -590,7 +596,7 @@ def _add_help(self, parser):
# CLIArguments for values.
parser.add_argument('help', nargs='?')

def _build_call_parameters(self, args, arg_table):
def _build_call_parameters(self, args, arg_table, parsed_globals):
# We need to convert the args specified on the command
# line as valid **kwargs we can hand to botocore.
service_params = {}
Expand All @@ -601,19 +607,19 @@ def _build_call_parameters(self, args, arg_table):
py_name = arg_object.py_name
if py_name in parsed_args:
value = parsed_args[py_name]
value = self._unpack_arg(arg_object, value)
value = self._unpack_arg(arg_object, value, parsed_globals)
arg_object.add_to_params(service_params, value)
return service_params

def _unpack_arg(self, cli_argument, value):
def _unpack_arg(self, cli_argument, value, parsed_globals):
# Unpacks a commandline argument into a Python value by firing the
# load-cli-arg.service-name.operation-name event.
session = self._session
service_name = self._operation_model.service_model.endpoint_prefix
operation_name = xform_name(self._name, '-')

return unpack_argument(
session, service_name, operation_name, cli_argument, value
session, service_name, operation_name, cli_argument, value, parsed_globals
)

def _create_argument_table(self):
Expand Down Expand Up @@ -661,6 +667,46 @@ def _create_operation_parser(self, arg_table):
parser = ArgTableArgParser(arg_table)
return parser

def _detect_binary_file_migration_change(
self,
session,
parsed_args,
parsed_globals,
arg_table
):
if (
session.get_scoped_config()
.get('cli_binary_format', None) == 'raw-in-base64-out'
):
# if cli_binary_format is set to raw-in-base64-out, then v2 behavior will
# be the same as v1, so there is no breaking change in this case.
return
if resolve_v2_debug_mode(parsed_globals):
parsed_args_to_check = {
arg: getattr(parsed_args, arg)
for arg in vars(parsed_args) if getattr(parsed_args, arg)
}

arg_values_to_check = [
arg.py_name for arg in arg_table.values()
if arg.py_name in parsed_args_to_check
and arg.argument_model.type_name == 'blob'
]
if arg_values_to_check:
print(
'\nAWS CLI v2 UPGRADE WARNING: When specifying a '
'blob-type parameter, AWS CLI v2 will assume the '
'parameter value is base64-encoded. This is different '
'from v1 behavior, where the AWS CLI will automatically '
'encode the value to base64. To retain v1 behavior in '
'AWS CLI v2, set the `cli_binary_format` configuration '
'variable to `raw-in-base64-out`. See '
'https://docs.aws.amazon.com/cli/latest/userguide/'
'cliv2-migration-changes.html'
'#cliv2-migration-binaryparam.\n',
file=sys.stderr
)


class CLIOperationCaller:
"""Call an AWS operation and format the response."""
Expand Down
4 changes: 4 additions & 0 deletions awscli/customizations/cliinputjson.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ def add_to_call_parameters(self, call_parameters, parsed_args,
try:
# Try to load the JSON string into a python dictionary
input_data = json.loads(retrieved_json)
self._session.register(
f"get-cli-input-json-data",
lambda **inner_kwargs: input_data
)
except ValueError as e:
raise ParamError(
self.name, "Invalid JSON: %s\nJSON received: %s"
Expand Down
22 changes: 19 additions & 3 deletions awscli/customizations/cloudformation/deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@

from awscli.customizations.commands import BasicCommand
from awscli.compat import get_stdout_text_writer
from awscli.utils import create_nested_client, write_exception
from awscli.customizations.utils import uni_print
from awscli.utils import create_nested_client, write_exception, resolve_v2_debug_mode

LOG = logging.getLogger(__name__)

Expand Down Expand Up @@ -316,18 +317,33 @@ def _run_main(self, parsed_args, parsed_globals):
s3_uploader = None

deployer = Deployer(cloudformation_client)
v2_debug = resolve_v2_debug_mode(parsed_globals)
return self.deploy(deployer, stack_name, template_str,
parameters, parsed_args.capabilities,
parsed_args.execute_changeset, parsed_args.role_arn,
parsed_args.notification_arns, s3_uploader,
tags, parsed_args.fail_on_empty_changeset,
parsed_args.disable_rollback)
parsed_args.disable_rollback, v2_debug)

def deploy(self, deployer, stack_name, template_str,
parameters, capabilities, execute_changeset, role_arn,
notification_arns, s3_uploader, tags,
fail_on_empty_changeset=True, disable_rollback=False):
fail_on_empty_changeset=True, disable_rollback=False,
v2_debug=False):
try:
if v2_debug and fail_on_empty_changeset:
uni_print(
'\nAWS CLI v2 UPGRADE WARNING: In AWS CLI v2, deploying '
'an AWS CloudFormation Template that results in an empty '
'changeset will NOT result in an error by default. This '
'is different from v1 behavior, where empty changesets '
'result in an error by default. To migrate to v2 behavior '
'and resolve this warning, you can add the '
'`--no-fail-on-empty-changeset` flag to the command. '
'See https://docs.aws.amazon.com/cli/latest/userguide/'
'cliv2-migration-changes.html#cliv2-migration-cfn.\n',
out_file=sys.stderr
)
result = deployer.create_and_wait_for_changeset(
stack_name=stack_name,
cfn_template=template_str,
Expand Down
3 changes: 2 additions & 1 deletion awscli/customizations/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,8 @@ def __call__(self, args, parsed_globals):
'custom',
self.name,
cli_argument,
value
value,
parsed_globals
)

# If this parameter has a schema defined, then allow plugins
Expand Down
Loading