Repository: aws/aws-cli

Issue:
aws cloudformation prints S3 upload progress to STDOUT
When running `aws cloudformation package`, the output must not include the S3 upload progress.

It currently includes the combined output of the S3 file upload as well as packaged CloudFormation itself making it impossible to use via STDOUT.

See the full repro at https://github.com/dnagir/cf-package-stdout-messed-up

Workaround - use `--output-template-file` option.


Discussion:
@sanathkr thoughts?
Agreed. Progress should print to stderr. Care to submit a PR? Should be a quick one. 

I don’t consider this a breaking change because the progress bar was not something someone would take a dependency on. 

Resolving patch:
diff --git a/awscli/customizations/cloudformation/artifact_exporter.py b/awscli/customizations/cloudformation/artifact_exporter.py
--- a/awscli/customizations/cloudformation/artifact_exporter.py
+++ b/awscli/customizations/cloudformation/artifact_exporter.py
@@ -427,6 +427,15 @@ class StepFunctionsStateMachineDefinitionResource(ResourceWithS3UrlDict):
     PACKAGE_NULL_PROPERTY = False
 
 
+class ServerlessStateMachineDefinitionResource(ResourceWithS3UrlDict):
+    RESOURCE_TYPE = "AWS::Serverless::StateMachine"
+    PROPERTY_NAME = "DefinitionUri"
+    BUCKET_NAME_PROPERTY = "Bucket"
+    OBJECT_KEY_PROPERTY = "Key"
+    VERSION_PROPERTY = "Version"
+    PACKAGE_NULL_PROPERTY = False
+
+
 class CloudFormationStackResource(Resource):
     """
     Represents CloudFormation::Stack resource that can refer to a nested
@@ -498,6 +507,20 @@ class GlueJobCommandScriptLocationResource(Resource):
     PROPERTY_NAME = "Command.ScriptLocation"
 
 
+class CodeCommitRepositoryS3Resource(ResourceWithS3UrlDict):
+    """
+    Represents CodeCommit::Repository resource.
+    """
+    RESOURCE_TYPE = "AWS::CodeCommit::Repository"
+    PROPERTY_NAME = "Code.S3"
+    BUCKET_NAME_PROPERTY = "Bucket"
+    OBJECT_KEY_PROPERTY = "Key"
+    VERSION_PROPERTY = "ObjectVersion"
+    # Don't package the directory if S3 is omitted.
+    PACKAGE_NULL_PROPERTY = False
+    FORCE_ZIP = True
+
+
 RESOURCES_EXPORT_LIST = [
     ServerlessFunctionResource,
     ServerlessApiResource,
@@ -514,7 +537,9 @@ class GlueJobCommandScriptLocationResource(Resource):
     ServerlessLayerVersionResource,
     LambdaLayerVersionResource,
     GlueJobCommandScriptLocationResource,
-    StepFunctionsStateMachineDefinitionResource
+    StepFunctionsStateMachineDefinitionResource,
+    ServerlessStateMachineDefinitionResource,
+    CodeCommitRepositoryS3Resource
 ]
 
 METADATA_EXPORT_LIST = [
diff --git a/awscli/customizations/s3uploader.py b/awscli/customizations/s3uploader.py
--- a/awscli/customizations/s3uploader.py
+++ b/awscli/customizations/s3uploader.py
@@ -220,8 +220,8 @@ def on_progress(self, future, bytes_transferred, **kwargs):
         with self._lock:
             self._seen_so_far += bytes_transferred
             percentage = (self._seen_so_far / self._size) * 100
-            sys.stdout.write(
+            sys.stderr.write(
                     "\rUploading to %s  %s / %s  (%.2f%%)" %
                     (self._remote_path, self._seen_so_far,
                      self._size, percentage))
-            sys.stdout.flush()
+            sys.stderr.flush()


Test patch:
diff --git a/tests/unit/customizations/cloudformation/test_artifact_exporter.py b/tests/unit/customizations/cloudformation/test_artifact_exporter.py
--- a/tests/unit/customizations/cloudformation/test_artifact_exporter.py
+++ b/tests/unit/customizations/cloudformation/test_artifact_exporter.py
@@ -29,7 +29,9 @@
     AppSyncFunctionConfigurationRequestTemplateResource, \
     AppSyncFunctionConfigurationResponseTemplateResource, \
     GlueJobCommandScriptLocationResource, \
-    StepFunctionsStateMachineDefinitionResource
+    StepFunctionsStateMachineDefinitionResource, \
+    ServerlessStateMachineDefinitionResource, \
+    CodeCommitRepositoryS3Resource
 from tests.unit.customizations.cloudformation import BaseYAMLTest
 
 
@@ -162,6 +164,12 @@ def test_is_invalid_s3_url(url):
             "Bucket": "foo", "Key": "bar", "Version": "baz"
         }
     },
+    {
+        "class": ServerlessStateMachineDefinitionResource,
+        "expected_result": {
+            "Bucket": "foo", "Key": "bar", "Version": "baz"
+        }
+    },
 ]