Repository: aws/aws-cli

Issue:
Adding new profile should add newline before
Have multiple IAM users configured in `~/.aws/credentials`

Added IAM user as follows:
`aws configure --profile NEW_PROFILE_NAME`
Completed sucessfully as expected.

However, next step of running a command resulted in error: 
```
PS C:\WINDOWS\system32> aws --profile NEW_PROFILE_NAME s3 ls
Unable to locate credentials. You can configure credentials by running "aws configure".
```
Checking `~/.aws/credentials` file showed new creds were appended to file without newline as follows:
```
[OLD_PROFILE_NAME]
aws_access_key_id = AAAAAAAAAAAAAAAAAAAA
aws_secret_access_key = KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK
region=XX-east-X
toolkit_artifact_guid=11111111-1111-1111-1111-111111111111[NEW_PROFILE_NAME]
aws_access_key_id = BBBBBBBBBBBBBBBBBBBB
aws_secret_access_key = JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ
```

IMHO this is easily fixable by adding a newline echo before the new creds

CLI version: `aws-cli/1.12.2 Python/2.7.14 Windows/10 botocore/1.8.2`

Comments:

Patch:
diff --git a/.changes/next-release/bugfix-Configuration-17224.json b/.changes/next-release/bugfix-Configuration-17224.json
new file mode 100644
index 000000000..6c0270eb1
--- /dev/null
+++ b/.changes/next-release/bugfix-Configuration-17224.json
@@ -0,0 +1,5 @@
+{
+  "type": "bugfix",
+  "category": "Configuration",
+  "description": "Fixes `#2996 <https://github.com/aws/aws-cli/issues/2996>`__. Fixed a bug where config file updates would sometimes append new sections to the previous section without adding a newline."
+}
diff --git a/awscli/customizations/configure/writer.py b/awscli/customizations/configure/writer.py
index 2ab842c7a..4aedabc43 100644
--- a/awscli/customizations/configure/writer.py
+++ b/awscli/customizations/configure/writer.py
@@ -76,8 +76,22 @@ class ConfigFileWriter(object):
                                os.O_WRONLY | os.O_CREAT, 0o600), 'w'):
             pass
 
+    def _check_file_needs_newline(self, filename):
+        # check if the last byte is a newline
+        with open(filename, 'rb') as f:
+            # check if the file is empty
+            f.seek(0, os.SEEK_END)
+            if not f.tell():
+                return False
+            f.seek(-1, os.SEEK_END)
+            last = f.read()
+            return last != b'\n'
+
     def _write_new_section(self, section_name, new_values, config_filename):
+        needs_newline = self._check_file_needs_newline(config_filename)
         with open(config_filename, 'a') as f:
+            if needs_newline:
+                f.write('\n')
             f.write('[%s]\n' % section_name)
             contents = []
             self._insert_new_values(line_number=0,


Test patch:
diff --git a/tests/unit/customizations/configure/test_writer.py b/tests/unit/customizations/configure/test_writer.py
index 45ae72329..92fd0f477 100644
--- a/tests/unit/customizations/configure/test_writer.py
+++ b/tests/unit/customizations/configure/test_writer.py
@@ -356,3 +356,16 @@ class TestConfigFileWriter(unittest.TestCase):
             '[preview]\n'
             'cloudfront = true\n'
         )
+
+    def test_appends_newline_on_new_section(self):
+        original = (
+            '[preview]\n'
+            'cloudfront = true'
+        )
+        self.assert_update_config(
+            original, {'region': 'us-west-2', '__section__': 'new-section'},
+            '[preview]\n'
+            'cloudfront = true\n'
+            '[new-section]\n'
+            'region = us-west-2\n'
+        )