From 5a5ed70921ba33d8176b1be2354b2d9ebf7f4fc2 Mon Sep 17 00:00:00 2001 From: cornelius Date: Thu, 26 Oct 2017 21:21:31 -0400 Subject: [PATCH 001/112] Add .env_sample --- .env_sample | 1 + .gitignore | 1 + README.md | 12 ++++++++++++ 3 files changed, 14 insertions(+) create mode 100644 .env_sample diff --git a/.env_sample b/.env_sample new file mode 100644 index 0000000..937e999 --- /dev/null +++ b/.env_sample @@ -0,0 +1 @@ +export SENDGRID_API_KEY='' diff --git a/.gitignore b/.gitignore index b14d298..e1b4fb6 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ sdist bin/ include/ lib/ +.env diff --git a/README.md b/README.md index 009e752..35acf87 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,18 @@ All updates to this module is documented in our [CHANGELOG](https://github.com/s pip install smtpapi ``` +## Setup Environment Variables + +Update the development environment with your [SENDGRID_API_KEY](https://app.sendgrid.com/settings/api_keys), for example: + + +```bash +cp .env_sample .env +``` +In `.env` set `SENDGRID_API_KEY` to your own API key. + + + # Quick Start From 13f3ac447ac6feaf97d75f5ebd1b6d65781b0c8d Mon Sep 17 00:00:00 2001 From: Prashu Chaudhary Date: Sat, 28 Oct 2017 16:28:30 +0530 Subject: [PATCH 002/112] Created Code Climate YML file --- .codeclimate.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .codeclimate.yml diff --git a/.codeclimate.yml b/.codeclimate.yml new file mode 100644 index 0000000..856ca97 --- /dev/null +++ b/.codeclimate.yml @@ -0,0 +1,25 @@ +--- +engines: + duplication: + enabled: true + config: + languages: + - ruby + - javascript + - python + - php + fixme: + enabled: true + radon: + enabled: true +ratings: + paths: + - "**.inc" + - "**.js" + - "**.jsx" + - "**.module" + - "**.php" + - "**.py" + - "**.rb" +exclude_paths: +- test/ From 24f144cf0418545d98ed8a869e0fd5958262a7f9 Mon Sep 17 00:00:00 2001 From: Bertus Steenberg Date: Sat, 28 Oct 2017 21:10:32 +0200 Subject: [PATCH 003/112] Add unittest to check that specific files exists in repo Issue #40 --- test/__init__.py | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/test/__init__.py b/test/__init__.py index 315fc88..af9cc6f 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -1,6 +1,7 @@ -import unittest, json, decimal +import unittest, json, decimal, os from smtpapi import SMTPAPIHeader + class TestSMTPAPI(unittest.TestCase): def setUp(self): @@ -72,5 +73,40 @@ def test_drop_empty(self): self.assertEqual(self.dropsHeader, json.loads(header.json_string())) +class TestRepository(unittest.TestCase): + + def setUp(self): + + self.required_files = [ + ['./Docker', './docker/Docker'], + ['./docker-compose.yml', './docker/docker-compose.yml'], + './.codeclimate.yml', + './.env_sample', + './.github/ISSUE_TEMPLATE', + './.github/PULL_REQUEST_TEMPLATE', + './.gitignore', + './.travis.yml', + './CHANGELOG.md', + './CODE_OF_CONDUCT.md', + './CONTRIBUTING.md', + './LICENSE.md', + './README.md', + './TROUBLESHOOTING.md', + './USAGE.md', + './USE_CASES.md', + ] + + self.file_not_found_message = 'File "{}" does not exist in repo!' + + def test_repository_files_exists(self): + + for file_path in self.required_files: + if isinstance(file_path, list): + self.assertTrue(any(os.path.exists(f) for f in file_path), + msg=self.file_not_found_message.format('" or "'.join(file_path))) + else: + self.assertTrue(os.path.exists(file_path), msg=self.file_not_found_message.format(file_path)) + + if __name__ == '__main__': unittest.main() From db3d61ece1c28b0a828f894f383a40b11e6568c1 Mon Sep 17 00:00:00 2001 From: Bertus Steenberg Date: Sat, 28 Oct 2017 21:24:32 +0200 Subject: [PATCH 004/112] comment --- test/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/__init__.py b/test/__init__.py index af9cc6f..b99acd1 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -102,6 +102,7 @@ def test_repository_files_exists(self): for file_path in self.required_files: if isinstance(file_path, list): + # multiple file paths: assert that any one of the files exists self.assertTrue(any(os.path.exists(f) for f in file_path), msg=self.file_not_found_message.format('" or "'.join(file_path))) else: From b9312128184dfd901d362f606cbe4164e052ba99 Mon Sep 17 00:00:00 2001 From: Bertus Steenberg Date: Sun, 29 Oct 2017 10:04:24 +0200 Subject: [PATCH 005/112] python2.6 format index --- test/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/__init__.py b/test/__init__.py index b99acd1..77b0ce2 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -96,7 +96,7 @@ def setUp(self): './USE_CASES.md', ] - self.file_not_found_message = 'File "{}" does not exist in repo!' + self.file_not_found_message = 'File "{0}" does not exist in repo!' def test_repository_files_exists(self): From 34ebdcf7551601d97cd115cfdce46b813fcfd2df Mon Sep 17 00:00:00 2001 From: riyasp Date: Sun, 29 Oct 2017 14:38:21 +0530 Subject: [PATCH 006/112] added unittest to check for specific repo files --- test/__init__.py | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/test/__init__.py b/test/__init__.py index 315fc88..4790116 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -1,6 +1,11 @@ -import unittest, json, decimal +import decimal +import json +import os +import unittest + from smtpapi import SMTPAPIHeader + class TestSMTPAPI(unittest.TestCase): def setUp(self): @@ -72,5 +77,37 @@ def test_drop_empty(self): self.assertEqual(self.dropsHeader, json.loads(header.json_string())) +class TestFilesExist(unittest.TestCase): + def setUp(self): + self.files_required = [ + ['./Docker', 'docker/Docker'], + ['./docker-compose.yml', './docker/docker-compose.yml'], + './.env_sample', + './.gitignore', + './.travis.yml', + './.codeclimate.yml', + './CHANGELOG.md', + './CODE_OF_CONDUCT.md', + './CONTRIBUTING.md', + './.github/ISSUE_TEMPLATE', + './LICENSE.md', + './.github/PULL_REQUEST_TEMPLATE', + './README.md', + './TROUBLESHOOTING.md', + './USAGE.md', + './USE_CASES.md' + ] + self.file_missing_msg = '"{}" missing in repo' + + def test_file_exists(self): + + for file in self.files_required: + if isinstance(file, list): + self.assertTrue(any(os.path.exists(f) for f in file), + msg=self.file_missing_msg.format('" or "'.join(file))) + else: + self.assertTrue(os.path.exists(file), msg=self.file_missing_msg.format(file)) + + if __name__ == '__main__': unittest.main() From 931cdbcc9010535123f61e104b2348c112458787 Mon Sep 17 00:00:00 2001 From: garuna-m6 Date: Mon, 30 Oct 2017 00:57:47 +0530 Subject: [PATCH 007/112] added test_project.py for testing files in dir --- test/test_project.py | 75 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 test/test_project.py diff --git a/test/test_project.py b/test/test_project.py new file mode 100644 index 0000000..e99b4da --- /dev/null +++ b/test/test_project.py @@ -0,0 +1,75 @@ +import os + +try: + import unittest2 as unittest +except ImportError: + import unittest + +class ProjectTests(unittest.TestCase): + + # ./Docker or docker/Docker + def test_docker_dir(self): + self.assertEqual(True, os.path.isdir("./Docker")) + + # ./docker-compose.yml or ./docker/docker-compose.yml + def test_docker_compose(self): + self.assertEqual(True, os.path.isfile('docker-compose.yml')) + + # ./.env_sample + def test_env(self): + self.assertEqual(True, os.path.isfile('./env_sample')) + + # ./.gitignore + def test_gitignore(self): + self.assertEqual(True, os.path.isfile('./.gitignore')) + + # ./.travis.yml + def test_travis(self): + self.assertEqual(True, os.path.isfile('./.travis.yml')) + + # ./.codeclimate.yml + def test_codeclimate(self): + self.assertEqual(True, os.path.isfile('./.codeclimate.yml')) + + # ./CHANGELOG.md + def test_changelog(self): + self.assertEqual(True, os.path.isfile('./CHANGELOG.md')) + + # ./CODE_OF_CONDUCT.md + def test_code_of_conduct(self): + self.assertEqual(True, os.path.isfile('./CODE_OF_CONDUCT.md')) + + # ./CONTRIBUTING.md + def test_contributing(self): + self.assertEqual(True, os.path.isfile('./CONTRIBUTING.md')) + + # ./.github/ISSUE_TEMPLATE + def test_issue_template(self): + self.assertEqual(True, os.path.isfile('./.github/ISSUE_TEMPLATE')) + + # ./LICENSE.md + def test_license(self): + self.assertEqual(True, os.path.isfile('./LICENSE.md')) + + # ./.github/PULL_REQUEST_TEMPLATE + def test_pr_template(self): + self.assertEqual(True, os.path.isfile('./.github/PULL_REQUEST_TEMPLATE')) + + # ./README.md + def test_readme(self): + self.assertEqual(True, os.path.isfile('./README.md')) + + # ./TROUBLESHOOTING.md + def test_troubleshooting(self): + self.assertEqual(True, os.path.isfile('./TROUBLESHOOTING.md')) + + # ./USAGE.md + def test_usage(self): + self.assertEqual(True, os.path.isfile('./USAGE.md')) + + # ./USE_CASES.md + def test_use_cases(self): + self.assertEqual(True, os.path.isfile('./USE_CASES.md')) + +if __name__ == '__main__': +unittest.main() \ No newline at end of file From fc35caec5515cfc0063d4c1a3b2825e8608be6ff Mon Sep 17 00:00:00 2001 From: parth-p Date: Mon, 30 Oct 2017 20:19:02 +0530 Subject: [PATCH 008/112] Test added for checking license year --- test/test_lisence.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 test/test_lisence.py diff --git a/test/test_lisence.py b/test/test_lisence.py new file mode 100644 index 0000000..d47c309 --- /dev/null +++ b/test/test_lisence.py @@ -0,0 +1,20 @@ +import sendgrid +from sendgrid.helpers.mail import * +from sendgrid.version import __version__ +try: + import unittest2 as unittest +except ImportError: + import unittest +import os +import subprocess +import sys +import time +import datetime + +host = "http://localhost:4010" + +def test_license_year(self): + LICENSE_FILE = 'license.txt' + with open(LICENSE_FILE, 'r') as f: + copyright_line = f.readline().rstrip() + self.assertEqual('Copyright (c) 2012-%s SendGrid, Inc.' % datetime.datetime.now().year, copyright_line) From af66dd2d8cf65bdd0a84f1f3a271b2680ee79a11 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 30 Oct 2017 20:06:30 +0200 Subject: [PATCH 009/112] Update travis - add codecov --- .travis.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 61cf4db..ad8f1b6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,8 +4,14 @@ python: - '2.7' - '3.4' - '3.5' -install: python setup.py install -script: python test/__init__.py +install: + - python setup.py install + - pip install codecov +script: + - python test/__init__.py + - coverage run test/__init__.py +after_success: + - codecov notifications: hipchat: rooms: From 82116862416f5c03a4d34584d921c701376896a1 Mon Sep 17 00:00:00 2001 From: Matt Bernier Date: Mon, 30 Oct 2017 13:49:20 -0600 Subject: [PATCH 010/112] added note about sourcing the file --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 35acf87..93408a3 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,9 @@ cp .env_sample .env ``` In `.env` set `SENDGRID_API_KEY` to your own API key. +You can add your environment variables to your environment by sourcing the file: + +```source .env``` From d56d3f0759419e0cd0cbf739982135c1a2dd89e6 Mon Sep 17 00:00:00 2001 From: Matt Bernier Date: Mon, 30 Oct 2017 21:34:32 -0600 Subject: [PATCH 011/112] Docker->Dockerfile This was my fault - my apologies --- test/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/__init__.py b/test/__init__.py index 77b0ce2..fd66b72 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -78,7 +78,7 @@ class TestRepository(unittest.TestCase): def setUp(self): self.required_files = [ - ['./Docker', './docker/Docker'], + ['./Dockerfile', './docker/Dockerfile'], ['./docker-compose.yml', './docker/docker-compose.yml'], './.codeclimate.yml', './.env_sample', From d1d2168065a403d0cd62dc24e9f3bb50ea50d76b Mon Sep 17 00:00:00 2001 From: Matt Bernier Date: Tue, 31 Oct 2017 22:12:35 -0600 Subject: [PATCH 012/112] Added License.txt --- test/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/__init__.py b/test/__init__.py index fd66b72..53db34a 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -89,7 +89,7 @@ def setUp(self): './CHANGELOG.md', './CODE_OF_CONDUCT.md', './CONTRIBUTING.md', - './LICENSE.md', + ['./LICENSE.md', './License.txt'], './README.md', './TROUBLESHOOTING.md', './USAGE.md', From a0443e3e19228c64490f32e770c9175da3fe67b3 Mon Sep 17 00:00:00 2001 From: Matt Bernier Date: Thu, 2 Nov 2017 12:34:03 -0700 Subject: [PATCH 013/112] I made a mistake in the issue, fixed that here. --- test/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/__init__.py b/test/__init__.py index 4790116..9e6f531 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -80,7 +80,7 @@ def test_drop_empty(self): class TestFilesExist(unittest.TestCase): def setUp(self): self.files_required = [ - ['./Docker', 'docker/Docker'], + ['./Dockerfile', 'docker/Dockerfile'], ['./docker-compose.yml', './docker/docker-compose.yml'], './.env_sample', './.gitignore', @@ -90,7 +90,7 @@ def setUp(self): './CODE_OF_CONDUCT.md', './CONTRIBUTING.md', './.github/ISSUE_TEMPLATE', - './LICENSE.md', + ['./LICENSE.md', '.LICENSE.txt'], './.github/PULL_REQUEST_TEMPLATE', './README.md', './TROUBLESHOOTING.md', From 96422b9d8338920fa1ba94858817a606668f087b Mon Sep 17 00:00:00 2001 From: pushkyn Date: Sat, 28 Oct 2017 19:10:30 +0300 Subject: [PATCH 014/112] update LICENSE - fix year --- LICENSE.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE.txt b/LICENSE.txt index c02b767..1e1037a 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013-2016 SendGrid, Inc. +Copyright (c) 2013-2017 SendGrid, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From bb9f452697e7a035876ed69e1c5f5d86bde5ed4b Mon Sep 17 00:00:00 2001 From: pushkyn Date: Mon, 30 Oct 2017 00:13:19 +0300 Subject: [PATCH 015/112] add unit test for license year --- test/__init__.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/__init__.py b/test/__init__.py index 53db34a..85d269f 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -1,4 +1,5 @@ import unittest, json, decimal, os +import datetime from smtpapi import SMTPAPIHeader @@ -72,6 +73,15 @@ def test_drop_empty(self): header.add_filter('testFilter', 'filter', 'filterValue') self.assertEqual(self.dropsHeader, json.loads(header.json_string())) + def test_license_year(self): + LICENSE_FILE = 'LICENSE.txt' + copyright_line = '' + with open(LICENSE_FILE, 'r') as f: + for line in f: + if line.startswith('Copyright'): + copyright_line = line.strip() + break + self.assertEqual('Copyright (c) 2013-%s SendGrid, Inc.' % datetime.datetime.now().year, copyright_line) class TestRepository(unittest.TestCase): From 8529f173fb15fdef197edc67a634337a5f3ad00b Mon Sep 17 00:00:00 2001 From: mbernier Date: Wed, 15 Nov 2017 15:47:34 -0700 Subject: [PATCH 016/112] updated from example here https://github.com/codeclimate/python-test-reporter/blob/master/.codeclimate.yml --- .codeclimate.yml | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/.codeclimate.yml b/.codeclimate.yml index 856ca97..3d89c6a 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -1,25 +1,19 @@ ---- engines: duplication: enabled: true config: languages: - - ruby - - javascript - python - - php fixme: enabled: true + markdownlint: + enabled: true + pep8: + enabled: true radon: enabled: true ratings: paths: - "**.inc" - - "**.js" - - "**.jsx" - "**.module" - - "**.php" - - "**.py" - - "**.rb" -exclude_paths: -- test/ + - "**.py" \ No newline at end of file From b26031be27a36460758259e74b4b372a8b2ff07d Mon Sep 17 00:00:00 2001 From: Matt Bernier Date: Tue, 21 Nov 2017 08:13:31 -0700 Subject: [PATCH 017/112] Updated for misnaming and OR statements The misnames are on me, the OR statements look like they were left off - it's fixed :) --- test/test_project.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/test_project.py b/test/test_project.py index e99b4da..88da5a4 100644 --- a/test/test_project.py +++ b/test/test_project.py @@ -9,11 +9,11 @@ class ProjectTests(unittest.TestCase): # ./Docker or docker/Docker def test_docker_dir(self): - self.assertEqual(True, os.path.isdir("./Docker")) + self.assertEqual(True, os.path.isdir("./Dockerfile") || os.path.isdir("./docker/Dockerfile")) # ./docker-compose.yml or ./docker/docker-compose.yml def test_docker_compose(self): - self.assertEqual(True, os.path.isfile('docker-compose.yml')) + self.assertEqual(True, os.path.isfile('./docker-compose.yml') || os.path.isfile('./docker/docker-compose.yml')) # ./.env_sample def test_env(self): @@ -49,7 +49,7 @@ def test_issue_template(self): # ./LICENSE.md def test_license(self): - self.assertEqual(True, os.path.isfile('./LICENSE.md')) + self.assertEqual(True, os.path.isfile('./LICENSE.md') || os.path.isfile('./LICENSE.txt')) # ./.github/PULL_REQUEST_TEMPLATE def test_pr_template(self): @@ -72,4 +72,4 @@ def test_use_cases(self): self.assertEqual(True, os.path.isfile('./USE_CASES.md')) if __name__ == '__main__': -unittest.main() \ No newline at end of file +unittest.main() From d02fe16a952abe6ce47310a6c9b413f390963aba Mon Sep 17 00:00:00 2001 From: thepriefy Date: Fri, 15 Dec 2017 07:45:17 +0700 Subject: [PATCH 018/112] Fix "Complexity" issue in examples/example.py --- examples/example.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/examples/example.py b/examples/example.py index 965a1d0..cd09eb3 100644 --- a/examples/example.py +++ b/examples/example.py @@ -1,5 +1,6 @@ # Python 2/3 compatible codebase from __future__ import absolute_import, division, print_function +from smtpapi import SMTPAPIHeader import time @@ -8,28 +9,27 @@ sys.path.append(path.dirname(path.dirname(path.abspath(__file__)))) from smtpapi import SMTPAPIHeader -from smtpapi import SMTPAPIHeader header = SMTPAPIHeader() # [To](http://sendgrid.com/docs/API_Reference/SMTP_API/index.html) -#header.add_to('test@example.com') +# header.add_to('test@example.com') header.set_tos(['test1@example.com', 'test2@example.com']) # [Substitutions](http://sendgrid.com/docs/API_Reference/SMTP_API/substitution_tags.html) -#header.add_substitution('key', 'value') +# header.add_substitution('key', 'value') header.set_substitutions({'key': ['value1', 'value2']}) # [Unique Arguments](http://sendgrid.com/docs/API_Reference/SMTP_API/unique_arguments.html) -#header.add_unique_arg('key', 'value') +# header.add_unique_arg('key', 'value') header.set_unique_args({'key':'value'}) # [Categories](http://sendgrid.com/docs/API_Reference/SMTP_API/categories.html) -#header.add_category('category') +# header.add_category('category') header.set_categories(['category1', 'category2']) # [Sections](http://sendgrid.com/docs/API_Reference/SMTP_API/section_tags.html) -#header.add_section('key', 'section') -header.set_sections({'key1':'section1', 'key2':'section2'}) +# header.add_section('key', 'section') +header.set_sections({'key1': 'section1', 'key2': 'section2'}) # [Filters](http://sendgrid.com/docs/API_Reference/SMTP_API/apps.html) header.add_filter('filter', 'setting', 'value') @@ -41,8 +41,8 @@ header.set_ip_pool("testPool") # [Scheduling Parameters](https://sendgrid.com/docs/API_Reference/SMTP_API/scheduling_parameters.html) -#header.add_send_each_at(unix_timestamp) # must be a unix timestamp -#header.set_send_each_at([]) # must be a unix timestamp -header.set_send_at(int(time.time())) # must be a unix timestamp +# header.add_send_each_at(unix_timestamp) # must be a unix timestamp +# header.set_send_each_at([]) # must be a unix timestamp +header.set_send_at(int(time.time())) # must be a unix timestamp -print(header.json_string()) \ No newline at end of file +print(header.json_string()) From e3c94201b97b126b6756de47ed745d73e7221db5 Mon Sep 17 00:00:00 2001 From: uppe-r <12294525+uppe-r@users.noreply.github.com> Date: Mon, 1 Oct 2018 18:29:00 +0100 Subject: [PATCH 019/112] Update LICENSE.txt Simple update to the current year on LICENSE.txt --- LICENSE.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE.txt b/LICENSE.txt index 1e1037a..7756fd6 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013-2017 SendGrid, Inc. +Copyright (c) 2013-2018 SendGrid, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 9a9a906566f7641538587ad2d7cf8e1b45637eeb Mon Sep 17 00:00:00 2001 From: uppe-r <12294525+uppe-r@users.noreply.github.com> Date: Mon, 1 Oct 2018 18:42:24 +0100 Subject: [PATCH 020/112] Fixed tests --- test/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/__init__.py b/test/__init__.py index 241d00e..69abcfd 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -2,6 +2,7 @@ import json import os import unittest +import datetime from smtpapi import SMTPAPIHeader @@ -102,7 +103,7 @@ def setUp(self): './CHANGELOG.md', './CODE_OF_CONDUCT.md', './CONTRIBUTING.md', - ['./LICENSE.md', './License.txt'], + ['./LICENSE.md', './LICENSE.txt'], './README.md', './TROUBLESHOOTING.md', './USAGE.md', From 7b6fcfd143a47a2981245e3afebcbebd1bc62cbc Mon Sep 17 00:00:00 2001 From: StrikerRUS Date: Tue, 9 Oct 2018 15:08:07 +0300 Subject: [PATCH 021/112] fixed Travis, converted README and version as file --- .gitignore | 1 + .travis.yml | 8 +-- MANIFEST.in | 4 +- README.md | 111 -------------------------------- README.rst | 149 +++++++++++++++++++++++++++++++++++++++++++ VERSION.txt | 1 + setup.py | 24 ++++++- smtpapi/__init__.py | 9 ++- test/__init__.py | 4 +- test/test_project.py | 10 +-- 10 files changed, 194 insertions(+), 127 deletions(-) delete mode 100644 README.md create mode 100644 README.rst create mode 100644 VERSION.txt diff --git a/.gitignore b/.gitignore index e1b4fb6..40d319c 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ bin/ include/ lib/ .env +smtpapi/VERSION.txt diff --git a/.travis.yml b/.travis.yml index ad8f1b6..2d337f9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,9 @@ language: python python: -- '2.6' -- '2.7' -- '3.4' -- '3.5' + - '2.6' + - '2.7' + - '3.4' + - '3.5' install: - python setup.py install - pip install codecov diff --git a/MANIFEST.in b/MANIFEST.in index bb3ec5f..8d138aa 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1 +1,3 @@ -include README.md +include README.rst LICENSE.txt VERSION.txt +recursive-include smtpapi *.py *.txt +prune test diff --git a/README.md b/README.md deleted file mode 100644 index 7dfe5ab..0000000 --- a/README.md +++ /dev/null @@ -1,111 +0,0 @@ -![SendGrid Logo](https://uiux.s3.amazonaws.com/2016-logos/email-logo%402x.png) - -[![Travis Badge](https://travis-ci.org/sendgrid/smtpapi-python.svg?branch=master)](https://travis-ci.org/sendgrid/smtpapi-python) -[![Email Notifications Badge](https://dx.sendgrid.com/badge/python)](https://dx.sendgrid.com/newsletter/python) -[![Twitter Follow](https://img.shields.io/twitter/follow/sendgrid.svg?style=social&label=Follow)](https://twitter.com/sendgrid) -[![Codecov branch](https://img.shields.io/codecov/c/github/sendgrid/smtpapi-python/master.svg?style=flat-square&label=Codecov+Coverage)](https://codecov.io/gh/sendgrid/smtpapi-python) -[![GitHub contributors](https://img.shields.io/github/contributors/sendgrid/smtpapi-python.svg)](https://github.com/sendgrid/smtpapi-python/graphs/contributors) -[![MIT Licensed](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE.txt) - -**This module helps build SendGrid's SMTP API headers.** - -Learn more about the SMTP API at [SendGrid's documentation](https://sendgrid.com/docs/API_Reference/SMTP_API/index.html). - -# Announcements - -All updates to this module is documented in our [CHANGELOG](https://github.com/sendgrid/smtpapi-python/blob/master/CHANGELOG.md). - -# Table of Contents -- [Installation](#installation) -- [Quick Start](#quick-start) -- [Usage](#usage) -- [Roadmap](#roadmap) -- [How to Contribute](#contribute) -- [Local set up](#local_setup) -- [About](#about) -- [License](#license) - - -# Installation - -## Prerequisites - -- Python version 2.6, 2.7, 3.4 or 3.5 -- The SendGrid service, starting at the [free level](https://sendgrid.com/free?source=sendgrid-python) - -## Install Package - -```bash -pip install smtpapi -``` - -## Setup Environment Variables - -Update the development environment with your [SENDGRID_API_KEY](https://app.sendgrid.com/settings/api_keys), for example: - - -```bash -cp .env_sample .env -``` -In `.env` set `SENDGRID_API_KEY` to your own API key. - -You can add your environment variables to your environment by sourcing the file: - -```source .env``` - - - -# Quick Start - -```python -from smtpapi import SMTPAPIHeader -header = SMTPAPIHeader() -header.add_to('email@email.com') -print(header.json_string()) -``` - - -# Usage - -- [SendGrid Docs](https://sendgrid.com/docs/API_Reference/SMTP_API/index.html) -- [Example Code](https://github.com/sendgrid/smtpapi-python/tree/master/examples) - - -# Roadmap - -If you are interested in the future direction of this project, please take a look at our [milestones](https://github.com/sendgrid/smtpapi-python/milestones). We would love to hear your feedback. - - -# How to Contribute - -We encourage contribution to our projects, please see our [CONTRIBUTING](https://github.com/sendgrid/smtpapi-python/blob/master/CONTRIBUTING.md) guide for details. - -Quick links: - -- [Feature Request](https://github.com/sendgrid/smtpapi-python/blob/master/CONTRIBUTING.md#feature-request) -- [Bug Reports](https://github.com/sendgrid/smtpapi-python/blob/master/CONTRIBUTING.md#submit-a-bug-report) -- [Sign the CLA to Create a Pull Request](https://github.com/sendgrid/smtpapi-python/blob/master/CONTRIBUTING.md#cla) -- [Improvements to the Codebase](https://github.com/sendgrid/smtpapi-python/blob/master/CONTRIBUTING.md#improvements-to-the-codebase) - - - -# Local Setup of the project - -The simplest local development workflow is by using docker. - -> Steps - -1. Install Docker -2. Run `docker-compose build` (This builds the container) -3. Run `docker-compose up` (This runs tests by default) - - -# About - -smtpapi-python is guided and supported by the SendGrid [Developer Experience Team](mailto:dx@sendgrid.com). - -smtpapi-python is maintained and funded by SendGrid, Inc. The names and logos for smtpapi-python are trademarks of SendGrid, Inc. - - -# License -[The MIT License (MIT)](LICENSE.txt) diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..4d5df8d --- /dev/null +++ b/README.rst @@ -0,0 +1,149 @@ +.. image:: https://uiux.s3.amazonaws.com/2016-logos/email-logo%402x.png + :target: https://www.sendgrid.com + :alt: SendGrid Logo + +|Travis Badge| |Email Notifications Badge| |Twitter Follow| |Codecov branch| |Python Versions| |PyPI Version| |GitHub contributors| |MIT Licensed| + +**This module helps build SendGrid's SMTP API headers.** + +Learn more about the SMTP API at `SendGrid documentation`_. + +Announcements +============= + +All updates to this module is documented in our `CHANGELOG`_. + +Table of Contents +================= + +- `Installation <#installation>`__ +- `Quick Start <#quick-start>`__ +- `Usage <#usage>`__ +- `Roadmap <#roadmap>`__ +- `How to Contribute <#how-to-contribute>`__ +- `Local Setup of the Project <#local-setup-of-the-project>`__ +- `About <#about>`__ +- `License <#license>`__ + +Installation +============ + +Prerequisites +------------- + +- Python version 2.6, 2.7, 3.4 or 3.5 +- The SendGrid service, starting at the `free level`_ + +Install Package +--------------- + +.. code:: bash + + pip install smtpapi + +Setup Environment Variables +--------------------------- + +Update the development environment with your `SENDGRID_API_KEY`_, for example: + +.. code:: bash + + cp .env_sample .env + +In ``.env`` set ``SENDGRID_API_KEY`` to your own API key. + +You can add your environment variables to your environment by sourcing the file: + +.. code:: bash + + source .env + +Quick Start +=========== + +.. code:: python + + from smtpapi import SMTPAPIHeader + + header = SMTPAPIHeader() + header.add_to('email@email.com') + print(header.json_string()) + +Usage +===== + +- `SendGrid documentation`_ +- `Example Code`_ + +Roadmap +======= + +If you are interested in the future direction of this project, please take a look at our `milestones`_. +We would love to hear your feedback. + +How to Contribute +================= + +We encourage contribution to our projects, please see our `CONTRIBUTING`_ guide for details. + +Quick links: + +- `Feature Request`_ +- `Bug Reports`_ +- `Sign the CLA to Create a Pull Request`_ +- `Improvements to the Codebase`_ + +Local Setup of the Project +========================== + +The simplest local development workflow is by using docker. + +Steps: + +1. Install Docker +2. Run ``docker-compose build`` (this builds the container) +3. Run ``docker-compose up`` (this runs tests by default) + +About +===== + +**smtpapi-python** is guided and supported by the SendGrid `Developer Experience Team`_. + +**smtpapi-python** is maintained and funded by SendGrid, Inc. +The names and logos for **smtpapi-python** are trademarks of SendGrid, Inc. + +License +======= + +`The MIT License (MIT)`_ + +.. _SendGrid documentation: https://sendgrid.com/docs/API_Reference/SMTP_API/index.html +.. _CHANGELOG: https://github.com/sendgrid/smtpapi-python/blob/master/CHANGELOG.md +.. _free level: https://sendgrid.com/free?source=sendgrid-python +.. _SENDGRID_API_KEY: https://app.sendgrid.com/settings/api_keys +.. _Example Code: https://github.com/sendgrid/smtpapi-python/tree/master/examples +.. _milestones: https://github.com/sendgrid/smtpapi-python/milestones +.. _CONTRIBUTING: https://github.com/sendgrid/smtpapi-python/blob/master/CONTRIBUTING.md +.. _Feature Request: https://github.com/sendgrid/smtpapi-python/blob/master/CONTRIBUTING.md#feature-request +.. _Bug Reports: https://github.com/sendgrid/smtpapi-python/blob/master/CONTRIBUTING.md#submit-a-bug-report +.. _Sign the CLA to Create a Pull Request: https://github.com/sendgrid/smtpapi-python/blob/master/CONTRIBUTING.md#cla +.. _Improvements to the Codebase: https://github.com/sendgrid/smtpapi-python/blob/master/CONTRIBUTING.md#improvements-to-the-codebase +.. _Developer Experience Team: mailto:dx@sendgrid.com +.. _The MIT License (MIT): https://github.com/sendgrid/smtpapi-python/blob/master/LICENSE.txt + +.. |Travis Badge| image:: https://travis-ci.org/sendgrid/smtpapi-python.svg?branch=master + :target: https://travis-ci.org/sendgrid/smtpapi-python +.. |Email Notifications Badge| image:: https://dx.sendgrid.com/badge/python + :target: https://dx.sendgrid.com/newsletter/python +.. |Twitter Follow| image:: https://img.shields.io/twitter/follow/sendgrid.svg?style=social&label=Follow + :target: https://twitter.com/sendgrid +.. |Codecov branch| image:: https://img.shields.io/codecov/c/github/sendgrid/smtpapi-python/master.svg?style=flat-square&label=Codecov+Coverage + :target: https://codecov.io/gh/sendgrid/smtpapi-python +.. |Python Versions| image:: https://img.shields.io/pypi/pyversions/smtpapi.svg + :target: https://pypi.org/project/smtpapi/ +.. |PyPI Version| image:: https://img.shields.io/pypi/v/smtpapi.svg + :target: https://pypi.org/project/smtpapi/ +.. |GitHub contributors| image:: https://img.shields.io/github/contributors/sendgrid/smtpapi-python.svg + :target: https://github.com/sendgrid/smtpapi-python/graphs/contributors +.. |MIT Licensed| image:: https://img.shields.io/badge/license-MIT-blue.svg + :target: https://github.com/sendgrid/smtpapi-python/blob/master/LICENSE.txt diff --git a/VERSION.txt b/VERSION.txt new file mode 100644 index 0000000..9e11b32 --- /dev/null +++ b/VERSION.txt @@ -0,0 +1 @@ +0.3.1 diff --git a/setup.py b/setup.py index 81f015d..a6e11d0 100644 --- a/setup.py +++ b/setup.py @@ -1,12 +1,30 @@ +import io +import os +from distutils.file_util import copy_file from setuptools import setup, find_packages + +dir_path = os.path.abspath(os.path.dirname(__file__)) +readme = io.open(os.path.join(dir_path, 'README.rst'), encoding='utf-8').read() +version = io.open(os.path.join(dir_path, 'VERSION.txt'), encoding='utf-8').read().strip() +copy_file(os.path.join(dir_path, 'VERSION.txt'), + os.path.join(dir_path, 'smtpapi', 'VERSION.txt'), + verbose=0) setup( name='smtpapi', - version='0.3.1', + version=version, author='Yamil Asusta, Kane Kim', author_email='yamil@sendgrid.com, kane.isturm@sendgrid.com', - packages=find_packages(), + url='https://github.com/sendgrid/smtpapi-python/', + packages=find_packages(exclude=["test"]), + include_package_data=True, license='MIT License', description='Simple wrapper to use SendGrid SMTP API', - long_description='Simple wrapper to use SendGrid SMTP API', + long_description=readme, + classifiers=[ + 'Programming Language :: Python :: 2.6', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + ], ) diff --git a/smtpapi/__init__.py b/smtpapi/__init__.py index 43cbb59..5781d87 100644 --- a/smtpapi/__init__.py +++ b/smtpapi/__init__.py @@ -1,4 +1,11 @@ -import json, decimal +import decimal +import json +import os + + +dir_path = os.path.dirname(os.path.realpath(__file__)) +if os.path.isfile(os.path.join(dir_path, 'VERSION.txt')): + __version__ = open(os.path.join(dir_path, 'VERSION.txt')).read().strip() class _CustomJSONEncoder(json.JSONEncoder): diff --git a/test/__init__.py b/test/__init__.py index 69abcfd..83b29d8 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -104,10 +104,10 @@ def setUp(self): './CODE_OF_CONDUCT.md', './CONTRIBUTING.md', ['./LICENSE.md', './LICENSE.txt'], - './README.md', + './README.rst', './TROUBLESHOOTING.md', './USAGE.md', - './USE_CASES.md', + './VERSION.txt', ] self.file_not_found_message = 'File "{0}" does not exist in repo!' diff --git a/test/test_project.py b/test/test_project.py index 88da5a4..daf7d85 100644 --- a/test/test_project.py +++ b/test/test_project.py @@ -55,9 +55,9 @@ def test_license(self): def test_pr_template(self): self.assertEqual(True, os.path.isfile('./.github/PULL_REQUEST_TEMPLATE')) - # ./README.md + # ./README.rst def test_readme(self): - self.assertEqual(True, os.path.isfile('./README.md')) + self.assertEqual(True, os.path.isfile('./README.rst')) # ./TROUBLESHOOTING.md def test_troubleshooting(self): @@ -67,9 +67,9 @@ def test_troubleshooting(self): def test_usage(self): self.assertEqual(True, os.path.isfile('./USAGE.md')) - # ./USE_CASES.md + # ./VERSION.txt def test_use_cases(self): - self.assertEqual(True, os.path.isfile('./USE_CASES.md')) + self.assertEqual(True, os.path.isfile('./VERSION.txt')) if __name__ == '__main__': -unittest.main() + unittest.main() From 3ea7c4b33c83d470d3ee380c5aeaf047b6a1c89e Mon Sep 17 00:00:00 2001 From: Dmitry Danilov Date: Fri, 12 Oct 2018 00:10:10 +0300 Subject: [PATCH 022/112] add first-timers.md with guide for newcomers --- FIRST-TIMERS.md | 77 ++++++++++++++++++++++++++++++++++ static/img/github-fork.png | Bin 0 -> 16284 bytes static/img/github-sign-up.png | Bin 0 -> 77574 bytes 3 files changed, 77 insertions(+) create mode 100644 FIRST-TIMERS.md create mode 100644 static/img/github-fork.png create mode 100644 static/img/github-sign-up.png diff --git a/FIRST-TIMERS.md b/FIRST-TIMERS.md new file mode 100644 index 0000000..1b296cd --- /dev/null +++ b/FIRST-TIMERS.md @@ -0,0 +1,77 @@ +# How To Contribute to SendGrid Repositories via GitHub + Contributing to the SendGrid is easy! All you need to do is find an open issue (see the bottom of this page for a list of repositories containing open issues), fix it and submit a pull request. Once you have submitted your pull request, the team can easily review it before it is merged into the repository. + To make a pull request, follow these steps: + 1. Log into GitHub. If you do not already have a GitHub account, you will have to create one in order to submit a change. Click the Sign up link in the upper right-hand corner to create an account. Enter your username, password, and email address. If you are an employee of SendGrid, please use your full name with your GitHub account and enter SendGrid as your company so we can easily identify you. + + + + 2. __[Fork](https://help.github.com/fork-a-repo/)__ the [smtpapi-python](https://github.com/sendgrid/smtpapi-python) repository: + + + + 3. __Clone__ your fork via the following commands: + + ``` + # Clone your fork of the repo into the current directory + git clone https://github.com/your_username/smtpapi-python + # Navigate to the newly cloned directory + cd smtpapi-python + # Assign the original repo to a remote called "upstream" + git remote add upstream https://github.com/sendgrid/smtpapi-python + ``` + + > Don't forget to replace *your_username* in the URL by your real GitHub username. + + 4. __Create a new topic branch__ (off the main project development branch) to + contain your feature, change, or fix: + +``` + git checkout -b +``` + + 5. __Commit your changes__ in logical chunks. Please adhere to these [git commit + message guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) + or your code is unlikely be merged into the main project. Use Git's + [interactive rebase](https://help.github.com/articles/interactive-rebase) + feature to tidy up your commits before making them public. Probably you will also have to create tests (if needed) or create or update the example code that demonstrates the functionality of this change to the code. + 6. __Locally merge (or rebase)__ the upstream development branch into your topic branch: + + ``` + git pull [--rebase] upstream master + ``` + + 7. __Push__ your topic branch up to your fork: + ``` + git push origin + ``` + 8. __[Open a Pull Request](https://help.github.com/articles/creating-a-pull-request/#changing-the-branch-range-and-destination-repository/)__ + with a clear title and description against the `master` branch. All tests must be passing before we will review the PR. + + ### Important notice + Before creating a pull request, make sure that you respect the repository's constraints regarding contributions. You can find them in the [CONTRIBUTING.md](./CONTRIBUTING.md) file. + ## Repositories with Open, Easy, Help Wanted, Issue Filters + * [Python SDK](https://github.com/sendgrid/sendgrid-python/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) +* [PHP SDK](https://github.com/sendgrid/sendgrid-php/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) +* [C# SDK](https://github.com/sendgrid/sendgrid-csharp/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) +* [Ruby SDK](https://github.com/sendgrid/sendgrid-ruby/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) +* [Node.js SDK](https://github.com/sendgrid/sendgrid-nodejs/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) +* [Java SDK](https://github.com/sendgrid/sendgrid-java/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) +* [Go SDK](https://github.com/sendgrid/sendgrid-go/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) +* [Python STMPAPI Client](https://github.com/sendgrid/smtpapi-python/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) +* [PHP STMPAPI Client](https://github.com/sendgrid/smtpapi-php/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) +* [C# STMPAPI Client](https://github.com/sendgrid/smtpapi-csharp/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) +* [Ruby STMPAPI Client](https://github.com/sendgrid/smtpapi-ruby/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) +* [Node.js STMPAPI Client](https://github.com/sendgrid/smtpapi-nodejs/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) +* [Java STMPAPI Client](https://github.com/sendgrid/smtpapi-java/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) +* [Go STMPAPI Client](https://github.com/sendgrid/smtpapi-go/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) +* [Python HTTP Client](https://github.com/sendgrid/python-http-client/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) +* [PHP HTTP Client](https://github.com/sendgrid/php-http-client/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) +* [C# HTTP Client](https://github.com/sendgrid/csharp-http-client/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) +* [Java HTTP Client](https://github.com/sendgrid/java-http-client/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) +* [Ruby HTTP Client](https://github.com/sendgrid/ruby-http-client/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) +* [Go HTTP Client](https://github.com/sendgrid/rest/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) +* [Node.js HTTP Client](https://github.com/sendgrid/nodejs-http-client/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) +* [Open Source Data Collector](https://github.com/sendgrid/open-source-library-data-collector/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) +* [Open API Definition](https://github.com/sendgrid/sendgrid-oai/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) +* [DX Automator](https://github.com/sendgrid/dx-automator/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) +* [Documentation](https://github.com/sendgrid/docs/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) \ No newline at end of file diff --git a/static/img/github-fork.png b/static/img/github-fork.png new file mode 100644 index 0000000000000000000000000000000000000000..3c2335f8441595412e8686145909042e4d9547b4 GIT binary patch literal 16284 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

)jNi2FouR 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�%5Hr0Q_wuOEmTUIslHk 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%0Dw4#g9N9L{Z)Pd|3Nu@ zkyL?$gInH|-vD2JbQaTaR<<{Db~AJ|1(YpZoSjV_jRPmaZbS>$Jr`KiVD^&Y4#XVxib{5LOy7W0J944ka&7_U7po)sP* zo^xY05r&m>^+T#N3^pWwu!&?W}$%Vh2Iv~GGZFL{heP>5UP&^uE@TnrG>Dr zo`prI=yduDWoZd~je{^#&wbLeB+@=Fs$4igy{Gsh{K(@}5Z`prw#V&`jt`DihEL4oeYF*xI$lq}{14oNUR$rGew zkQ^Z&(T^qj?#-9@FEZTepE^&zRlU2eE@h6&$o6fS zHv z{uoNY8VZj{a~W09)-H`_yiUZh2=6|~j*iF2IXITTy({6_J?|u@dzX-T>Wnq+$HzMW zd8BGzLxGhqE5l6|+jKCNR-##BC2?t zjER|==eHKm3R{T0R~vW^jb^tVLtGOCngSWmn~kAl{C5{@(XxBquCW$*0wx7|NY&&^ zs?@ZdHxb9r^X1saClxy?zI(-oSeY`i3}%GmZJi_A)2o!Y@i|sp$4l`#9hsjAT#_<&lM251T|O_ ze0o8%iqYqayBys_sGe(A7Ta?=#L1Uq()e&?)?X4^>V8Vnl7mm@CrGDA)NPQ;BY$(Z z*p?|9srxN=jZ+j+&VI3o3WG~gL-1UJS`73@yoWp(ukg0Q8cFM0#aG-``$(20bt^uLxlSg)6HaA%i*Xkf!rHESAHGhOn?2dOJ= zI8+;e-YupajHY@rT_j1o(}K7z|DS@xN0E)_pxB@m1%SKZeg(azSquGkw#)G23` z**Q3#?+$&g=T5PXu?h!tTmLG7x<%zH7R?uB6X5JtC5nD_=X0lA-XgocdZMXsfvA}^ zxuVQ`8kU738p7n4ww(><-_GoQHX+Wgs&5W@KrhUxQIgm(rTj|vBWEl> z>O{nb{$_YzR4lT{B`0;{t3vQT@V5XlK3|6?IZz-|tAmw=g^O)=YD&pJr>TjX{Q4Z5 zN$cSu=-7?1*z(YW>Dwsnm$5$F%|ozq!c&f`k5Z8Ue>PY3n-*Wss0^YxDz1D)6qs?| zg(<|uRk-_(zoChB*Ed_N5W$Mml)?FvfRKhf$df*+P!CiY(2xE0vGMk)t{DqonSIbj z=r;|YUt}4NMp24I>RMg?S>HeqY)gYAI}WF@NK|^XU&64T^SzO?Mx-HUaN@v`Pm=u= ztMX&?nO^jw;A$)c(C-xW*^aQ+1ZC-=b0&fmC3q|lJ;jaut6HWcTPAV*@G?g_0F0OQ zq;PS`;I(dE>FVid=tBZOpJD7kvEP!CQii3uJL$edQ7>m)Q>{A ztFk-IhQSb17MjKY0Ba=-5StZ$D=+mwz2hvc9|j;PTNTL}r&y`vk8HA5)8E}`?2$gf z((mwNG1-{JR5V9ByCPccB&xM+lf6CSQZo%b&8zBha7)~5$7wI7y^55zM-RTeIe2b6 z&{R_;T+VK_yV~y7!Tpnr(dUQ3;d2qF3w~On)&0-u(aGDBe^Ni~iKw6O#DB~DN9w56 zM&H2lD-mRNm~NY$DcwZmlf56hwI_?^7Yx%cdF)eb#*@pcyGVF*%Bj8R-OJVf$XvI> z0W5zJLt(z^`Z;&j2+Z)u)g4nZ8Md~HT}YkOmsZb*Eb^eVdsN_*`dC zBzi`R@Y}!uz~_-lUNc7C+Not@nam7yuKamoWl@cv$UmYY{hTwCzR?<`2DLgmTYraw z5OP1+1dngVSPOg;;Z5H0Ngg0UMq2kg2NA?_p3tywkxfGrGVM65lde+*=q9SoDv3G<T120mCwMzF>^XxziiPht1HWA2XtJa(IT+2`#0E{={RuRiZ!vZOz3AP2z@uLaw zYAhKWRe3u<2!H(0lg!8IF6Za|jqFL6T%c?(1UlM;B4jLudB)gm623ZeJv3(XCvP)h z%t;sGz|ML4Vq@br@XojM{WBdU9u&Z?W!mkq8Cw5Zj5uPBLdav-pGud|GrTJOj20

WBj;|+^@H!~X7&VE;i{dVV3mUbe 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

  • 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 JEpHk6zX0Y}u`mDt literal 0 HcmV?d00001 From 55d3063d5ce2175c9b7c60a0b51749dae241b438 Mon Sep 17 00:00:00 2001 From: Ciaran Broderick Date: Mon, 15 Oct 2018 13:09:30 +0100 Subject: [PATCH 023/112] Started work on an automatic changelog updater --- changes.py | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 changes.py diff --git a/changes.py b/changes.py new file mode 100644 index 0000000..ea39388 --- /dev/null +++ b/changes.py @@ -0,0 +1,56 @@ +""" +Small python script that, when run, will update the CHANGELOG with information +about all merged pull requests since the previous release. + +This script must be run after tagging the latest version +It checks the log of commits since the previous tag and parses it +""" +import re +import subprocess +import sys + +RELEASE_MD_PATTERN = re.compile(r'## \[(\d+\.\d+\.\d+)\]') +MERGED_PR_PATTERN = re.compile( + r'[0-9a-f]{7} Merge pull request #(\d+) from (.+)/.+' +) + +# Get latest tag +command = 'git tag'.split(' ') +res = subprocess.run(command, capture_output=True, text=True) +if res.returncode != 0: + print('Error occurred when running git tag command:', str(res.stderr)) + sys.exit(1) +# Get the last line and get the tag number +latest_release = list(filter(None, res.stdout.split('\n')))[-1].split('v')[-1] +print('Generating CHANGELOG for', latest_release) + +# Read in the CHANGELOG file first +with open('CHANGELOG.md') as f: + # Read the text in as a list of lines + old_text = f.readlines() + # Get the latest release (top of the CHANGELOG) + for line in old_text: + match = RELEASE_MD_PATTERN.match(line) + if match: + prev_release = match[1] + break + +if latest_release == prev_release: + print( + 'The latest git tag matches the last release in the CHANGELOG. ' + 'Please tag the repository before running this script.' + ) + sys.exit(1) + +# Use git log to list all commits between that tag and HEAD +command = 'git log --oneline v{}..@'.format(prev_release).split(' ') +res = subprocess.run(command, capture_output=True, text=True) +if res.returncode != 0: + print('Error occurred when running git log command:', str(res.stderr)) + sys.exit(1) + +# Parse the output from the above command to find all commits for merged PRs +for line in res.stdout.split('\n'): + match = MERGED_PR_PATTERN.match(line) + if match: + print(match[1], match[2]) From cde22cded8c103a1cd80afc4244cc7344f441e8d Mon Sep 17 00:00:00 2001 From: Ciaran Broderick Date: Mon, 15 Oct 2018 14:09:36 +0100 Subject: [PATCH 024/112] Finished first draft of changelog updater script --- changes.py | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 98 insertions(+), 4 deletions(-) diff --git a/changes.py b/changes.py index ea39388..b78bd0b 100644 --- a/changes.py +++ b/changes.py @@ -8,20 +8,49 @@ import re import subprocess import sys +from datetime import datetime +# Regex patterns RELEASE_MD_PATTERN = re.compile(r'## \[(\d+\.\d+\.\d+)\]') MERGED_PR_PATTERN = re.compile( - r'[0-9a-f]{7} Merge pull request #(\d+) from (.+)/.+' + r'([0-9a-f]{7}) Merge pull request #(\d+) from (.+)/.+' ) +TAG_PATTERN = re.compile( + r'refs/tags/v(\d+\.\d+\.\d+) (\w{3} \w{3} \d{1,2} \d{2}:\d{2}:\d{2} \d{4})' +) + +# PR Type terms +FIX_TERMS = ['fix', 'change', 'update'] + +# Helper functions +def generate_pr_link(pr_num): + """ + Returns a markdown link to a PR in this repo given its number + """ + return ( + '[PR #{0}](https://github.com/sendgrid/smtpapi-python/pulls/{0})' + ).format(pr_num) + +def generate_user_link(user): + """ + Returns a markdown link to a user + """ + return '[@{0}](https://github.com/{0})'.format(user) # Get latest tag -command = 'git tag'.split(' ') +command = ['git', 'tag', '--format=%(refname) %(creatordate)'] res = subprocess.run(command, capture_output=True, text=True) if res.returncode != 0: print('Error occurred when running git tag command:', str(res.stderr)) sys.exit(1) # Get the last line and get the tag number -latest_release = list(filter(None, res.stdout.split('\n')))[-1].split('v')[-1] +latest_release_match = TAG_PATTERN.match( + list(filter(None, res.stdout.split('\n')))[-1], +) +latest_release = latest_release_match[1] +latest_release_date = datetime.strptime( + latest_release_match[2], '%a %b %d %H:%M:%S %Y', +) print('Generating CHANGELOG for', latest_release) # Read in the CHANGELOG file first @@ -50,7 +79,72 @@ sys.exit(1) # Parse the output from the above command to find all commits for merged PRs +merge_commits = [] for line in res.stdout.split('\n'): match = MERGED_PR_PATTERN.match(line) if match: - print(match[1], match[2]) + merge_commits.append(match) + +# Determine the type of PR from the commit message +added, fixes = [], [] +for commit in merge_commits: + # Get the hash of the commit and get the message of it + commit_sha = commit[1] + command = 'git show {} --format=format:%B'.format(commit_sha).split(' ') + res = subprocess.run(command, capture_output=True, text=True) + out = res.stdout.lower() + is_added = True + + # When storing we need the PR title, number and user + data = { + # 3rd line of the commit message is the PR title + 'title': out.split('\n')[2], + 'number': commit[2], + 'user': commit[3], + } + + for term in FIX_TERMS: + if term in out: + fixes.append(data) + is_added = False + break + if is_added: + added.append(data) + +# Now we need to write out the CHANGELOG again +with open('CHANGELOG.md', 'w') as f: + # Write out the header lines first + f.write('# Change Log\n') + f.write('All notable changes to this project will be documented in this file.\n') + f.write('\n') + + # Create and write out the new version information + latest_release_date_string = latest_release_date.strftime('%Y-%m-%d') + f.write('## [{}] - {} ##\n'.format( + latest_release, + latest_release_date_string, + )) + # Add the stuff that was added + f.write('### Added\n') + for commit in added: + f.write('- {}: {}{} Big thanks to {} for the PR!\n'.format( + generate_pr_link(commit['number']), + commit['title'], + '.' if commit['title'][-1] != '.' else '', + generate_user_link(commit['user']) + )) + f.write('\n') + # Add the fixes + f.write('### Fixes\n') + for commit in fixes: + f.write('- {}: {}{} Big thanks to {} for the PR!\n'.format( + generate_pr_link(commit['number']), + commit['title'], + '.' if commit['title'][-1] != '.' else '', + generate_user_link(commit['user']) + )) + f.write('\n') + + # Add the old stuff + for i in range(3, len(old_text)): + f.write(old_text[i]) From 46d539a79403751d8f9e0e56449d9fc68f03e66e Mon Sep 17 00:00:00 2001 From: Ciaran Broderick Date: Mon, 15 Oct 2018 14:15:05 +0100 Subject: [PATCH 025/112] Linting changes.py --- changes.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/changes.py b/changes.py index b78bd0b..561ca57 100644 --- a/changes.py +++ b/changes.py @@ -22,6 +22,7 @@ # PR Type terms FIX_TERMS = ['fix', 'change', 'update'] + # Helper functions def generate_pr_link(pr_num): """ @@ -31,12 +32,14 @@ def generate_pr_link(pr_num): '[PR #{0}](https://github.com/sendgrid/smtpapi-python/pulls/{0})' ).format(pr_num) + def generate_user_link(user): """ Returns a markdown link to a user """ return '[@{0}](https://github.com/{0})'.format(user) + # Get latest tag command = ['git', 'tag', '--format=%(refname) %(creatordate)'] res = subprocess.run(command, capture_output=True, text=True) @@ -114,9 +117,8 @@ def generate_user_link(user): # Now we need to write out the CHANGELOG again with open('CHANGELOG.md', 'w') as f: # Write out the header lines first - f.write('# Change Log\n') - f.write('All notable changes to this project will be documented in this file.\n') - f.write('\n') + for i in range(0, 3): + f.write(old_text[i]) # Create and write out the new version information latest_release_date_string = latest_release_date.strftime('%Y-%m-%d') From 09716c61ed396c422f1c71409088c9542854c6c3 Mon Sep 17 00:00:00 2001 From: vkmrishad Date: Sat, 20 Oct 2018 19:00:58 +0530 Subject: [PATCH 026/112] PEP-8 fix --- examples/example.py | 28 ++++++++++++++-------------- smtpapi/__init__.py | 9 +++++---- test/__init__.py | 2 ++ test/test_lisence.py | 2 ++ test/test_project.py | 8 +++++--- 5 files changed, 28 insertions(+), 21 deletions(-) diff --git a/examples/example.py b/examples/example.py index 965a1d0..73d1523 100644 --- a/examples/example.py +++ b/examples/example.py @@ -3,33 +3,33 @@ import time +from os import sys, path +from smtpapi import SMTPAPIHeader + if __name__ == '__main__' and __package__ is None: - from os import sys, path sys.path.append(path.dirname(path.dirname(path.abspath(__file__)))) - from smtpapi import SMTPAPIHeader -from smtpapi import SMTPAPIHeader header = SMTPAPIHeader() # [To](http://sendgrid.com/docs/API_Reference/SMTP_API/index.html) -#header.add_to('test@example.com') +# header.add_to('test@example.com') header.set_tos(['test1@example.com', 'test2@example.com']) # [Substitutions](http://sendgrid.com/docs/API_Reference/SMTP_API/substitution_tags.html) -#header.add_substitution('key', 'value') +# header.add_substitution('key', 'value') header.set_substitutions({'key': ['value1', 'value2']}) # [Unique Arguments](http://sendgrid.com/docs/API_Reference/SMTP_API/unique_arguments.html) -#header.add_unique_arg('key', 'value') -header.set_unique_args({'key':'value'}) +# header.add_unique_arg('key', 'value') +header.set_unique_args({'key': 'value'}) # [Categories](http://sendgrid.com/docs/API_Reference/SMTP_API/categories.html) -#header.add_category('category') +# header.add_category('category') header.set_categories(['category1', 'category2']) # [Sections](http://sendgrid.com/docs/API_Reference/SMTP_API/section_tags.html) -#header.add_section('key', 'section') -header.set_sections({'key1':'section1', 'key2':'section2'}) +# header.add_section('key', 'section') +header.set_sections({'key1': 'section1', 'key2': 'section2'}) # [Filters](http://sendgrid.com/docs/API_Reference/SMTP_API/apps.html) header.add_filter('filter', 'setting', 'value') @@ -41,8 +41,8 @@ header.set_ip_pool("testPool") # [Scheduling Parameters](https://sendgrid.com/docs/API_Reference/SMTP_API/scheduling_parameters.html) -#header.add_send_each_at(unix_timestamp) # must be a unix timestamp -#header.set_send_each_at([]) # must be a unix timestamp -header.set_send_at(int(time.time())) # must be a unix timestamp +# header.add_send_each_at(unix_timestamp) # must be a unix timestamp +# header.set_send_each_at([]) # must be a unix timestamp +header.set_send_at(int(time.time())) # must be a unix timestamp -print(header.json_string()) \ No newline at end of file +print(header.json_string()) diff --git a/smtpapi/__init__.py b/smtpapi/__init__.py index 5781d87..13306e6 100644 --- a/smtpapi/__init__.py +++ b/smtpapi/__init__.py @@ -2,11 +2,11 @@ import json import os - dir_path = os.path.dirname(os.path.realpath(__file__)) if os.path.isfile(os.path.join(dir_path, 'VERSION.txt')): __version__ = open(os.path.join(dir_path, 'VERSION.txt')).read().strip() + class _CustomJSONEncoder(json.JSONEncoder): def default(self, o): @@ -15,6 +15,7 @@ def default(self, o): # Provide a fallback to the default encoder if we haven't implemented special support for the object's class return super(_CustomJSONEncoder, self).default(o) + class SMTPAPIHeader(object): def __init__(self): @@ -67,14 +68,14 @@ def set_sections(self, value): def add_send_each_at(self, time): if 'send_each_at' not in self.data: - self.data['send_each_at'] = [] + self.data['send_each_at'] = [] self.data['send_each_at'].append(time) def set_send_each_at(self, time): - self.data['send_each_at'] = time + self.data['send_each_at'] = time def set_send_at(self, time): - self.data['send_at'] = time + self.data['send_at'] = time def add_filter(self, app, setting, val): if 'filters' not in self.data: diff --git a/test/__init__.py b/test/__init__.py index 83b29d8..3e700d8 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -87,6 +87,7 @@ def test_license_year(self): break self.assertEqual('Copyright (c) 2013-%s SendGrid, Inc.' % datetime.datetime.now().year, copyright_line) + class TestRepository(unittest.TestCase): def setUp(self): @@ -122,5 +123,6 @@ def test_repository_files_exists(self): else: self.assertTrue(os.path.exists(file_path), msg=self.file_not_found_message.format(file_path)) + if __name__ == '__main__': unittest.main() diff --git a/test/test_lisence.py b/test/test_lisence.py index d47c309..b3a7645 100644 --- a/test/test_lisence.py +++ b/test/test_lisence.py @@ -1,6 +1,7 @@ import sendgrid from sendgrid.helpers.mail import * from sendgrid.version import __version__ + try: import unittest2 as unittest except ImportError: @@ -13,6 +14,7 @@ host = "http://localhost:4010" + def test_license_year(self): LICENSE_FILE = 'license.txt' with open(LICENSE_FILE, 'r') as f: diff --git a/test/test_project.py b/test/test_project.py index daf7d85..3ea238a 100644 --- a/test/test_project.py +++ b/test/test_project.py @@ -5,15 +5,16 @@ except ImportError: import unittest + class ProjectTests(unittest.TestCase): # ./Docker or docker/Docker def test_docker_dir(self): - self.assertEqual(True, os.path.isdir("./Dockerfile") || os.path.isdir("./docker/Dockerfile")) + self.assertEqual(True, os.path.isdir("./Dockerfile") | | os.path.isdir("./docker/Dockerfile")) # ./docker-compose.yml or ./docker/docker-compose.yml def test_docker_compose(self): - self.assertEqual(True, os.path.isfile('./docker-compose.yml') || os.path.isfile('./docker/docker-compose.yml')) + self.assertEqual(True, os.path.isfile('./docker-compose.yml') | | os.path.isfile('./docker/docker-compose.yml')) # ./.env_sample def test_env(self): @@ -49,7 +50,7 @@ def test_issue_template(self): # ./LICENSE.md def test_license(self): - self.assertEqual(True, os.path.isfile('./LICENSE.md') || os.path.isfile('./LICENSE.txt')) + self.assertEqual(True, os.path.isfile('./LICENSE.md') | | os.path.isfile('./LICENSE.txt')) # ./.github/PULL_REQUEST_TEMPLATE def test_pr_template(self): @@ -71,5 +72,6 @@ def test_usage(self): def test_use_cases(self): self.assertEqual(True, os.path.isfile('./VERSION.txt')) + if __name__ == '__main__': unittest.main() From d2ccd2c3fde1a592f8847184d7872e07e0f6c307 Mon Sep 17 00:00:00 2001 From: Mohammed Rishad Date: Sat, 20 Oct 2018 19:05:45 +0530 Subject: [PATCH 027/112] Update test_project.py --- test/test_project.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test_project.py b/test/test_project.py index 3ea238a..41e440a 100644 --- a/test/test_project.py +++ b/test/test_project.py @@ -10,11 +10,11 @@ class ProjectTests(unittest.TestCase): # ./Docker or docker/Docker def test_docker_dir(self): - self.assertEqual(True, os.path.isdir("./Dockerfile") | | os.path.isdir("./docker/Dockerfile")) + self.assertEqual(True, os.path.isdir("./Dockerfile") || os.path.isdir("./docker/Dockerfile")) # ./docker-compose.yml or ./docker/docker-compose.yml def test_docker_compose(self): - self.assertEqual(True, os.path.isfile('./docker-compose.yml') | | os.path.isfile('./docker/docker-compose.yml')) + self.assertEqual(True, os.path.isfile('./docker-compose.yml') || os.path.isfile('./docker/docker-compose.yml')) # ./.env_sample def test_env(self): @@ -50,7 +50,7 @@ def test_issue_template(self): # ./LICENSE.md def test_license(self): - self.assertEqual(True, os.path.isfile('./LICENSE.md') | | os.path.isfile('./LICENSE.txt')) + self.assertEqual(True, os.path.isfile('./LICENSE.md') || os.path.isfile('./LICENSE.txt')) # ./.github/PULL_REQUEST_TEMPLATE def test_pr_template(self): From 56ccc025f7ccdfba1d9f0909a191ef5e617ed7e4 Mon Sep 17 00:00:00 2001 From: anatolyyyyyy Date: Sat, 13 Oct 2018 14:18:48 +0300 Subject: [PATCH 028/112] Update contribution to use Gitflow workflow --- .github/PULL_REQUEST_TEMPLATE | 2 +- CONTRIBUTING.md | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE b/.github/PULL_REQUEST_TEMPLATE index 7ad590b..75ee89b 100644 --- a/.github/PULL_REQUEST_TEMPLATE +++ b/.github/PULL_REQUEST_TEMPLATE @@ -12,7 +12,7 @@ Closes #2 ### Checklist - [ ] I have made a material change to the repo (functionality, testing, spelling, grammar) - [ ] I have read the [Contribution Guide] and my PR follows them. -- [ ] I updated my branch with the master branch. +- [ ] I updated my branch with the `development` branch. - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] I have added necessary documentation about the functionality in the appropriate .md file - [ ] I have added in line documentation to the code I modified diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8d41b42..55f5fad 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,4 +1,4 @@ -Hello! Thank you for choosing to help contribute to one of the SendGrid open source projects. There are many ways you can contribute and help is always welcome. We simply ask that you follow the following contribution policies. +Hello! Thank you for choosing to help contribute to one of the SendGrid open source projects. There are many ways you can contribute and help is always welcome. We simply ask that you follow the following contribution policies. - [CLAs and CCLAs](#cla) - [Roadmap & Milestones](#roadmap) @@ -58,6 +58,8 @@ In order to make the process easier, we've included a [sample bug report templat We welcome direct contributions to the smtpapi-python code base. Thank you! +Please note that we use the [Gitflow Workflow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow) for Git to help keep project development organized and consistent. + ### Development Environment ### #### Install and Run Locally #### @@ -140,7 +142,7 @@ Please run your code through: git pull upstream ``` -3. Create a new topic branch (off the main project development branch) to +3. Create a new topic branch off the `development` branch to contain your feature, change, or fix: ```bash @@ -157,10 +159,10 @@ Please run your code through: 4b. Create or update the example code that demonstrates the functionality of this change to the code. -5. Locally merge (or rebase) the upstream development branch into your topic branch: +5. Locally merge (or rebase) the upstream `development` branch into your topic branch: ```bash - git pull [--rebase] upstream master + git pull [--rebase] upstream development ``` 6. Push your topic branch up to your fork: @@ -170,6 +172,6 @@ Please run your code through: ``` 7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) - with a clear title and description against the `master` branch. All tests must be passing before we will review the PR. + with a clear title and description against the `development` branch. All tests must be passing before we will review the PR. If you have any additional questions, please feel free to [email](mailto:dx@sendgrid.com) us or create an issue in this repo. From 9ef713ba5f4d648b48e45f7b4f1885f8041e159c Mon Sep 17 00:00:00 2001 From: crnbrdrck Date: Wed, 24 Oct 2018 23:46:42 +0100 Subject: [PATCH 029/112] Adding shebang line to run the script from command line --- changes.py | 1 + 1 file changed, 1 insertion(+) diff --git a/changes.py b/changes.py index 561ca57..c8d1542 100644 --- a/changes.py +++ b/changes.py @@ -1,3 +1,4 @@ +#!/usr/bin/python """ Small python script that, when run, will update the CHANGELOG with information about all merged pull requests since the previous release. From 4b93e2254527bffe27cb695a71d3d837cb02be20 Mon Sep 17 00:00:00 2001 From: crnbrdrck Date: Wed, 24 Oct 2018 23:47:44 +0100 Subject: [PATCH 030/112] Changing PR attribution style as requested --- changes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/changes.py b/changes.py index c8d1542..79448d5 100644 --- a/changes.py +++ b/changes.py @@ -130,7 +130,7 @@ def generate_user_link(user): # Add the stuff that was added f.write('### Added\n') for commit in added: - f.write('- {}: {}{} Big thanks to {} for the PR!\n'.format( + f.write('- {}: {}{} (via {})\n'.format( generate_pr_link(commit['number']), commit['title'], '.' if commit['title'][-1] != '.' else '', @@ -140,7 +140,7 @@ def generate_user_link(user): # Add the fixes f.write('### Fixes\n') for commit in fixes: - f.write('- {}: {}{} Big thanks to {} for the PR!\n'.format( + f.write('- {}: {}{} (via {})\n'.format( generate_pr_link(commit['number']), commit['title'], '.' if commit['title'][-1] != '.' else '', From 98d054b72e517bf766675838a98a7fc99a1b18e0 Mon Sep 17 00:00:00 2001 From: Elise Shanholtz Date: Wed, 15 Jan 2020 10:53:09 -0800 Subject: [PATCH 031/112] chore: prep the repo for automated releasing (#101) --- .travis.yml | 37 +++++++++++++++++++------------------ CHANGELOG.md | 6 ++++-- LICENSE.txt | 2 +- Makefile | 22 ++++++++++++++++++++++ README.rst | 2 +- test/__init__.py | 2 +- test/requirements.txt | 2 ++ test/test_lisence.py | 22 ---------------------- test/test_project.py | 10 +++++----- 9 files changed, 55 insertions(+), 50 deletions(-) create mode 100644 Makefile create mode 100644 test/requirements.txt delete mode 100644 test/test_lisence.py diff --git a/.travis.yml b/.travis.yml index 2d337f9..58fb87f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,23 +1,24 @@ language: python python: - - '2.6' - - '2.7' - - '3.4' - - '3.5' + - '2.7' + - '3.4' + - '3.5' + - '3.6' install: - - python setup.py install - - pip install codecov + - make install + - make test-install + - pip install codecov script: - - python test/__init__.py - - coverage run test/__init__.py + - make test + - . venv/bin/activate; coverage run test/__init__.py after_success: - - codecov -notifications: - hipchat: - rooms: - secure: XbJIz0PtZo+/G6UCnCxLgYDPk7OS8fpyiQwpnfGBr2xW1Z5vhWS+jrR6GndAFJfW9mmgcvq9dJL4bSThITebcZJJtztfuWnGUnONKbfSsFcuEr6o3uGPNmfVwZ9JAL78BUU861A/ykcWe/6lkovlUphkDLa2/l1r7t7TGD75f5k= - template: - - '%{repository} - Build %{build_number} on branch %{branch} by %{author}: %{message} - View on GitHub' - format: html + - codecov +deploy: + provider: pypi + user: __token__ + password: + secure: $PYPI_TOKEN + on: + branch: master + condition: "$TRAVIS_TEST_RESULT = 0" + tags: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 68cdfe9..2316538 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Change Log All notable changes to this project will be documented in this file. -## [0.3.1] - 2015-10-01 +[2015-10-01] Version 0.3.1 +--------------------------- + ### Added -- Added in support for `Decimal` objects in SMTP API JSON messages (via @jstol) \ No newline at end of file +- Added in support for `Decimal` objects in SMTP API JSON messages (via @jstol) diff --git a/LICENSE.txt b/LICENSE.txt index 7756fd6..d55059a 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013-2018 SendGrid, Inc. +Copyright (c) 2013-2020 Twilio SendGrid, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..783f8ea --- /dev/null +++ b/Makefile @@ -0,0 +1,22 @@ +.PHONY: venv install test-install test clean nopyc + +venv: + @python --version || (echo "Python is not installed, please install Python 2 or Python 3"; exit 1); + virtualenv --python=python venv + +install: venv + . venv/bin/activate; python setup.py install + . venv/bin/activate; pip install . + +test-install: + . venv/bin/activate; pip install -r test/requirements.txt + +test: + . venv/bin/activate; python -m unittest discover -v + . venv/bin/activate; python test/__init__.py + +clean: nopyc + rm -rf venv + +nopyc: + find . -name \*.pyc -delete diff --git a/README.rst b/README.rst index 4d5df8d..83f14ca 100644 --- a/README.rst +++ b/README.rst @@ -31,7 +31,7 @@ Installation Prerequisites ------------- -- Python version 2.6, 2.7, 3.4 or 3.5 +- Python version 2.7, 3.4, 3.5, or 3.6 - The SendGrid service, starting at the `free level`_ Install Package diff --git a/test/__init__.py b/test/__init__.py index 3e700d8..012bbc4 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -85,7 +85,7 @@ def test_license_year(self): if line.startswith('Copyright'): copyright_line = line.strip() break - self.assertEqual('Copyright (c) 2013-%s SendGrid, Inc.' % datetime.datetime.now().year, copyright_line) + self.assertEqual('Copyright (c) 2013-%s Twilio SendGrid, Inc.' % datetime.datetime.now().year, copyright_line) class TestRepository(unittest.TestCase): diff --git a/test/requirements.txt b/test/requirements.txt new file mode 100644 index 0000000..5b3644a --- /dev/null +++ b/test/requirements.txt @@ -0,0 +1,2 @@ +sendgrid +coverage diff --git a/test/test_lisence.py b/test/test_lisence.py deleted file mode 100644 index b3a7645..0000000 --- a/test/test_lisence.py +++ /dev/null @@ -1,22 +0,0 @@ -import sendgrid -from sendgrid.helpers.mail import * -from sendgrid.version import __version__ - -try: - import unittest2 as unittest -except ImportError: - import unittest -import os -import subprocess -import sys -import time -import datetime - -host = "http://localhost:4010" - - -def test_license_year(self): - LICENSE_FILE = 'license.txt' - with open(LICENSE_FILE, 'r') as f: - copyright_line = f.readline().rstrip() - self.assertEqual('Copyright (c) 2012-%s SendGrid, Inc.' % datetime.datetime.now().year, copyright_line) diff --git a/test/test_project.py b/test/test_project.py index 41e440a..fdead3c 100644 --- a/test/test_project.py +++ b/test/test_project.py @@ -9,16 +9,16 @@ class ProjectTests(unittest.TestCase): # ./Docker or docker/Docker - def test_docker_dir(self): - self.assertEqual(True, os.path.isdir("./Dockerfile") || os.path.isdir("./docker/Dockerfile")) + def test_dockerfile(self): + self.assertEqual(True, os.path.isfile("./Dockerfile") or os.path.isfile("./docker/Dockerfile")) # ./docker-compose.yml or ./docker/docker-compose.yml def test_docker_compose(self): - self.assertEqual(True, os.path.isfile('./docker-compose.yml') || os.path.isfile('./docker/docker-compose.yml')) + self.assertEqual(True, os.path.isfile('./docker-compose.yml') or os.path.isfile('./docker/docker-compose.yml')) # ./.env_sample def test_env(self): - self.assertEqual(True, os.path.isfile('./env_sample')) + self.assertEqual(True, os.path.isfile('./.env_sample')) # ./.gitignore def test_gitignore(self): @@ -50,7 +50,7 @@ def test_issue_template(self): # ./LICENSE.md def test_license(self): - self.assertEqual(True, os.path.isfile('./LICENSE.md') || os.path.isfile('./LICENSE.txt')) + self.assertEqual(True, os.path.isfile('./LICENSE.md') or os.path.isfile('./LICENSE.txt')) # ./.github/PULL_REQUEST_TEMPLATE def test_pr_template(self): From f577f0d06b4fc44f2a73bcd836ba69687657bf94 Mon Sep 17 00:00:00 2001 From: childish-sambino Date: Fri, 17 Jan 2020 16:14:33 -0600 Subject: [PATCH 032/112] docs: baseline all the templated markdown docs (#102) --- .github/ISSUE_TEMPLATE | 17 -------- .github/PULL_REQUEST_TEMPLATE | 24 ---------- CODE_OF_CONDUCT.md | 82 ++++++++++++++++++++++++----------- CONTRIBUTING.md | 2 +- ISSUE_TEMPLATE.md | 26 +++++++++++ LICENSE.txt => LICENSE.md | 16 +++---- MANIFEST.in | 2 +- PULL_REQUEST_TEMPLATE.md | 31 +++++++++++++ README.rst | 4 +- test/__init__.py | 8 ++-- test/test_project.py | 8 ++-- 11 files changed, 134 insertions(+), 86 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE delete mode 100644 .github/PULL_REQUEST_TEMPLATE create mode 100644 ISSUE_TEMPLATE.md rename LICENSE.txt => LICENSE.md (59%) create mode 100644 PULL_REQUEST_TEMPLATE.md diff --git a/.github/ISSUE_TEMPLATE b/.github/ISSUE_TEMPLATE deleted file mode 100644 index 373d0e5..0000000 --- a/.github/ISSUE_TEMPLATE +++ /dev/null @@ -1,17 +0,0 @@ -#### Issue Summary - -A summary of the issue and the environment in which it occurs. If suitable, include the steps required to reproduce the bug. Please feel free to include screenshots, screencasts, code examples. - - -#### Steps to Reproduce - -1. This is the first step -2. This is the second step -3. Further steps, etc. - -Any other information you want to share that is relevant to the issue being reported. Especially, why do you consider this to be a bug? What do you expect to happen instead? - -#### Technical details: - -* smtpapi-pythonn Version: master (latest commit: [commit number]) -* Python Version: X.X diff --git a/.github/PULL_REQUEST_TEMPLATE b/.github/PULL_REQUEST_TEMPLATE deleted file mode 100644 index 75ee89b..0000000 --- a/.github/PULL_REQUEST_TEMPLATE +++ /dev/null @@ -1,24 +0,0 @@ - -# Fixes # - -### Checklist -- [ ] I have made a material change to the repo (functionality, testing, spelling, grammar) -- [ ] I have read the [Contribution Guide] and my PR follows them. -- [ ] I updated my branch with the `development` branch. -- [ ] I have added tests that prove my fix is effective or that my feature works -- [ ] I have added necessary documentation about the functionality in the appropriate .md file -- [ ] I have added in line documentation to the code I modified - -### Short description of what this PR does: -- -- - -If you have questions, please send an email to [Sendgrid](mailto:dx@sendgrid.com), or file a Github Issue in this repository. diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index a0482c5..2f0727e 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,41 +1,73 @@ -# SendGrid Community Code of Conduct +# Contributor Covenant Code of Conduct -The SendGrid open source community is made up of members from around the globe with a diverse set of skills, personalities, and experiences. It is through these differences that our community experiences successes and continued growth. When you're working with members of the community, we encourage you to follow these guidelines, which help steer our interactions and strive to maintain a positive, successful and growing community. +## Our Pledge -### Be Open -Members of the community are open to collaboration, whether it's on pull requests, code reviews, approvals, issues or otherwise. We're receptive to constructive comments and criticism, as the experiences and skill sets of all members contribute to the whole of our efforts. We're accepting of all who wish to take part in our activities, fostering an environment where anyone can participate, and everyone can make a difference. +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. -### Be Considerate -Members of the community are considerate of their peers, which include other contributors and users of SendGrid. We're thoughtful when addressing the efforts of others, keeping in mind that often the labor was completed with the intent of the good of the community. We're attentive in our communications, whether in person or online, and we're tactful when approaching differing views. +## Our Standards -### Be Respectful -Members of the community are respectful. We're respectful of others, their positions, their skills, their commitments and their efforts. We're respectful of the volunteer efforts that permeate the SendGrid community. We're respectful of the processes outlined in the community, and we work within them. When we disagree, we are courteous in raising our issues. Overall, we're good to each other. We contribute to this community not because we have to, but because we want to. If we remember that, these guidelines will come naturally. +Examples of behavior that contributes to creating a positive environment +include: -## Additional Guidance +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members -### Disclose Potential Conflicts of Interest -Community discussions often involve interested parties. We expect participants to be aware when they are conflicted due to employment or other projects they are involved in and disclose those interests to other project members. When in doubt, over-disclose. Perceived conflicts of interest are important to address so that the community’s decisions are credible even when unpopular, difficult or favorable to the interests of one group over another. +Examples of unacceptable behavior by participants include: -### Interpretation -This Code is not exhaustive or complete. It is not a rulebook; it serves to distill our common understanding of a collaborative, shared environment and goals. We expect it to be followed in spirit as much as in the letter. When in doubt, try to abide by [SendGrid’s cultural values](https://sendgrid.com/blog/employee-engagement-the-4h-way) defined by our “4H’s”: Happy, Hungry, Humble and Honest. +- The use of sexualized language or imagery and unwelcome sexual attention or + advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic + address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting -### Enforcement -Most members of the SendGrid community always comply with this Code, not because of the existence of this Code, but because they have long experience participating in open source communities where the conduct described above is normal and expected. However, failure to observe this Code may be grounds for suspension, reporting the user for abuse or changing permissions for outside contributors. +## Our Responsibilities -## If you have concerns about someone’s conduct -**Initiate Direct Contact** - It is always appropriate to email a community member (if contact information is available), mention that you think their behavior was out of line, and (if necessary) point them to this Code. +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. -**Discuss Publicly** - Discussing publicly is always acceptable. Note, though, that approaching the person directly may be better, as it tends to make them less defensive, and it respects the time of other community members, so you probably want to try direct contact first. +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. -**Contact the Moderators** - You can reach the SendGrid moderators by emailing dx@sendgrid.com. +## Scope -## Submission to SendGrid Repositories -Finally, just a reminder, changes to the SendGrid repositories will only be accepted upon completion of the [SendGrid Contributor Agreement](https://cla.sendgrid.com). +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at open-source@twilio.com. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. ## Attribution -SendGrid thanks the following, on which it draws for content and inspiration: +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html -* [Python Community Code of Conduct](https://www.python.org/psf/codeofconduct/) -* [Open Source Initiative General Code of Conduct](https://opensource.org/codeofconduct) -* [Apache Code of Conduct](https://www.apache.org/foundation/policies/conduct.html) +[homepage]: https://www.contributor-covenant.org diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 55f5fad..7f975f7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -51,7 +51,7 @@ Before you decide to create a new issue, please try the following: ### Please use our Bug Report Template -In order to make the process easier, we've included a [sample bug report template](https://github.com/sendgrid/smtpapi-python/.github/ISSUE_TEMPLATE) (borrowed from [Ghost](https://github.com/TryGhost/Ghost/)). The template uses [GitHub flavored markdown](https://help.github.com/articles/github-flavored-markdown/) for formatting. +In order to make the process easier, we've included a [sample bug report template](https://github.com/sendgrid/smtpapi-python/ISSUE_TEMPLATE.md) (borrowed from [Ghost](https://github.com/TryGhost/Ghost/)). The template uses [GitHub flavored markdown](https://help.github.com/articles/github-flavored-markdown/) for formatting. ## Improvements to the Codebase diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..56dbe14 --- /dev/null +++ b/ISSUE_TEMPLATE.md @@ -0,0 +1,26 @@ + + +### Issue Summary +A summary of the issue and the environment in which it occurs. If suitable, include the steps required to reproduce the bug. Please feel free to include screenshots, screencasts, or code examples. + +### Steps to Reproduce +1. This is the first step +2. This is the second step +3. Further steps, etc. + +### Code Snippet +```python +# paste code here +``` + +### Exception/Log +``` +# paste exception/log here +``` + +### Technical details: +* smtpapi-python version: +* python version: + diff --git a/LICENSE.txt b/LICENSE.md similarity index 59% rename from LICENSE.txt rename to LICENSE.md index d55059a..29aba59 100644 --- a/LICENSE.txt +++ b/LICENSE.md @@ -1,13 +1,13 @@ -The MIT License (MIT) +MIT License -Copyright (c) 2013-2020 Twilio SendGrid, Inc. +Copyright (C) 2020, Twilio SendGrid, Inc. -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. diff --git a/MANIFEST.in b/MANIFEST.in index 8d138aa..9feef94 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,3 @@ -include README.rst LICENSE.txt VERSION.txt +include README.rst LICENSE.md VERSION.txt recursive-include smtpapi *.py *.txt prune test diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..215059a --- /dev/null +++ b/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,31 @@ + + +# Fixes # + +A short description of what this PR does. + +### Checklist +- [ ] I acknowledge that all my contributions will be made under the project's license +- [ ] I have made a material change to the repo (functionality, testing, spelling, grammar) +- [ ] I have read the [Contribution Guidelines](CONTRIBUTING.md) and my PR follows them +- [ ] I have titled the PR appropriately +- [ ] I have updated my branch with the master branch +- [ ] I have added tests that prove my fix is effective or that my feature works +- [ ] I have added necessary documentation about the functionality in the appropriate .md file +- [ ] I have added inline documentation to the code I modified + +If you have questions, please file a [support ticket](https://twilio.com/help/contact), or create a GitHub Issue in this repository. diff --git a/README.rst b/README.rst index 83f14ca..3cdfe41 100644 --- a/README.rst +++ b/README.rst @@ -129,7 +129,7 @@ License .. _Sign the CLA to Create a Pull Request: https://github.com/sendgrid/smtpapi-python/blob/master/CONTRIBUTING.md#cla .. _Improvements to the Codebase: https://github.com/sendgrid/smtpapi-python/blob/master/CONTRIBUTING.md#improvements-to-the-codebase .. _Developer Experience Team: mailto:dx@sendgrid.com -.. _The MIT License (MIT): https://github.com/sendgrid/smtpapi-python/blob/master/LICENSE.txt +.. _The MIT License (MIT): https://github.com/sendgrid/smtpapi-python/blob/master/LICENSE.md .. |Travis Badge| image:: https://travis-ci.org/sendgrid/smtpapi-python.svg?branch=master :target: https://travis-ci.org/sendgrid/smtpapi-python @@ -146,4 +146,4 @@ License .. |GitHub contributors| image:: https://img.shields.io/github/contributors/sendgrid/smtpapi-python.svg :target: https://github.com/sendgrid/smtpapi-python/graphs/contributors .. |MIT Licensed| image:: https://img.shields.io/badge/license-MIT-blue.svg - :target: https://github.com/sendgrid/smtpapi-python/blob/master/LICENSE.txt + :target: https://github.com/sendgrid/smtpapi-python/blob/master/LICENSE.md diff --git a/test/__init__.py b/test/__init__.py index 012bbc4..d75dfb3 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -78,14 +78,14 @@ def test_drop_empty(self): self.assertEqual(self.dropsHeader, json.loads(header.json_string())) def test_license_year(self): - LICENSE_FILE = 'LICENSE.txt' + LICENSE_FILE = 'LICENSE.md' copyright_line = '' with open(LICENSE_FILE, 'r') as f: for line in f: if line.startswith('Copyright'): copyright_line = line.strip() break - self.assertEqual('Copyright (c) 2013-%s Twilio SendGrid, Inc.' % datetime.datetime.now().year, copyright_line) + self.assertEqual('Copyright (C) %s, Twilio SendGrid, Inc. ' % datetime.datetime.now().year, copyright_line) class TestRepository(unittest.TestCase): @@ -97,8 +97,8 @@ def setUp(self): ['./docker-compose.yml', './docker/docker-compose.yml'], './.codeclimate.yml', './.env_sample', - './.github/ISSUE_TEMPLATE', - './.github/PULL_REQUEST_TEMPLATE', + './ISSUE_TEMPLATE.md', + './PULL_REQUEST_TEMPLATE.md', './.gitignore', './.travis.yml', './CHANGELOG.md', diff --git a/test/test_project.py b/test/test_project.py index fdead3c..85feda5 100644 --- a/test/test_project.py +++ b/test/test_project.py @@ -44,17 +44,17 @@ def test_code_of_conduct(self): def test_contributing(self): self.assertEqual(True, os.path.isfile('./CONTRIBUTING.md')) - # ./.github/ISSUE_TEMPLATE + # ./ISSUE_TEMPLATE.md def test_issue_template(self): - self.assertEqual(True, os.path.isfile('./.github/ISSUE_TEMPLATE')) + self.assertEqual(True, os.path.isfile('./ISSUE_TEMPLATE.md')) # ./LICENSE.md def test_license(self): self.assertEqual(True, os.path.isfile('./LICENSE.md') or os.path.isfile('./LICENSE.txt')) - # ./.github/PULL_REQUEST_TEMPLATE + # ./PULL_REQUEST_TEMPLATE.md def test_pr_template(self): - self.assertEqual(True, os.path.isfile('./.github/PULL_REQUEST_TEMPLATE')) + self.assertEqual(True, os.path.isfile('./PULL_REQUEST_TEMPLATE.md')) # ./README.rst def test_readme(self): From 5f5c792cb144fa9677b58c81d9b3278381bd546e Mon Sep 17 00:00:00 2001 From: Elise Shanholtz Date: Thu, 23 Jan 2020 10:15:32 -0800 Subject: [PATCH 033/112] fix: travis deploy on python 3.6 --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 58fb87f..490e7e9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,3 +22,4 @@ deploy: branch: master condition: "$TRAVIS_TEST_RESULT = 0" tags: true + python: "3.6" From 0577fc920e5a25a7fab662fce88b929344fcc441 Mon Sep 17 00:00:00 2001 From: Twilio Date: Fri, 24 Jan 2020 08:03:39 +0000 Subject: [PATCH 034/112] [Librarian] Version Bump --- CHANGELOG.md | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2316538..36bea10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,48 @@ # Change Log All notable changes to this project will be documented in this file. +[2020-01-24] Version 0.4.0 +-------------------------- +**Library - Docs** +- [PR #102](https://github.com/sendgrid/smtpapi-python/pull/102): baseline all the templated markdown docs. Thanks to [@childish-sambino](https://github.com/childish-sambino)! +- [PR #77](https://github.com/sendgrid/smtpapi-python/pull/77): add first-timers.md with guide for newcomers. Thanks to [@daniloff200](https://github.com/daniloff200)! +- [PR #79](https://github.com/sendgrid/smtpapi-python/pull/79): Update contribution to use Gitflow workflow. Thanks to [@anatolyyyyyy](https://github.com/anatolyyyyyy)! +- [PR #93](https://github.com/sendgrid/smtpapi-python/pull/93): Added Announcement. Thanks to [@krischoi07](https://github.com/krischoi07)! +- [PR #34](https://github.com/sendgrid/smtpapi-python/pull/34): Add USAGE.md. Thanks to [@geomars](https://github.com/geomars)! +- [PR #27](https://github.com/sendgrid/smtpapi-python/pull/27): update contributing.md - fix typo. Thanks to [@pushkyn](https://github.com/pushkyn)! +- [PR #26](https://github.com/sendgrid/smtpapi-python/pull/26): update README.md. Thanks to [@thepriefy](https://github.com/thepriefy)! +- [PR #23](https://github.com/sendgrid/smtpapi-python/pull/23): ADD ISSUE_TEMPLATE. Thanks to [@prashant0598](https://github.com/prashant0598)! +- [PR #21](https://github.com/sendgrid/smtpapi-python/pull/21): add table of contents in README.md. Thanks to [@thepriefy](https://github.com/thepriefy)! +- [PR #19](https://github.com/sendgrid/smtpapi-python/pull/19): Update README. Thanks to [@micahduron](https://github.com/micahduron)! +- [PR #12](https://github.com/sendgrid/smtpapi-python/pull/12): Update README.md. Thanks to [@ciceropablo](https://github.com/ciceropablo)! +- [PR #20](https://github.com/sendgrid/smtpapi-python/pull/20): Demonstrate how to review the request body for troubleshooting. Thanks to [@mptap](https://github.com/mptap)! + +**Library - Feature** +- [PR #35](https://github.com/sendgrid/smtpapi-python/pull/35): Add docker files and update README. Thanks to [@NdagiStanley](https://github.com/NdagiStanley)! +- [PR #80](https://github.com/sendgrid/smtpapi-python/pull/80): Adding CHANGELOG auto generation script. Thanks to [@freyamade](https://github.com/freyamade)! + +**Library - Chore** +- [PR #37](https://github.com/sendgrid/smtpapi-python/pull/37): Created Code Climate YML file. Thanks to [@prashuchaudhary](https://github.com/prashuchaudhary)! +- [PR #41](https://github.com/sendgrid/smtpapi-python/pull/41): update LICENSE - fix year. Thanks to [@pushkyn](https://github.com/pushkyn)! +- [PR #65](https://github.com/sendgrid/smtpapi-python/pull/65): Fix "Complexity" issue in examples/example.py. Thanks to [@thepriefy](https://github.com/thepriefy)! +- [PR #66](https://github.com/sendgrid/smtpapi-python/pull/66): Update LICENSE.txt. Thanks to [@nocategory](https://github.com/nocategory)! +- [PR #87](https://github.com/sendgrid/smtpapi-python/pull/87): PEP8 fix. Thanks to [@vkmrishad](https://github.com/vkmrishad)! +- [PR #33](https://github.com/sendgrid/smtpapi-python/pull/33): Add .env_sample. Thanks to [@CorneliusIV](https://github.com/CorneliusIV)! +- [PR #29](https://github.com/sendgrid/smtpapi-python/pull/29): Create PULL_REQUEST_TEMPLATE.md. Thanks to [@random-hacktoberfest-participant-2017](https://github.com/random-hacktoberfest-participant-2017)! +- [PR #25](https://github.com/sendgrid/smtpapi-python/pull/25): Added CodeCov Badge. Thanks to [@gr8shivam](https://github.com/gr8shivam)! + +**Library - Test** +- [PR #42](https://github.com/sendgrid/smtpapi-python/pull/42): Issue#40 unittest to check for specific repo files. Thanks to [@bertuss](https://github.com/bertuss)! +- [PR #43](https://github.com/sendgrid/smtpapi-python/pull/43): added unittest to check for specific repo files. Thanks to [@riyasyash](https://github.com/riyasyash)! +- [PR #44](https://github.com/sendgrid/smtpapi-python/pull/44): added test_project.py for testing files in dir. Thanks to [@garuna-m6](https://github.com/garuna-m6)! +- [PR #45](https://github.com/sendgrid/smtpapi-python/pull/45): Add unit test for license year. Thanks to [@pushkyn](https://github.com/pushkyn)! +- [PR #48](https://github.com/sendgrid/smtpapi-python/pull/48): Test added for checking license year. Thanks to [@parth-p](https://github.com/parth-p)! + +**Library - Fix** +- [PR #52](https://github.com/sendgrid/smtpapi-python/pull/52): Update travis - add codecov. Thanks to [@pushkyn](https://github.com/pushkyn)! +- [PR #75](https://github.com/sendgrid/smtpapi-python/pull/75): fixed Travis, converted README and version as file. Thanks to [@StrikerRUS](https://github.com/StrikerRUS)! + + [2015-10-01] Version 0.3.1 --------------------------- From 03dcb0a8a1f461624676553515e8d4a15bc009a6 Mon Sep 17 00:00:00 2001 From: Twilio Date: Fri, 24 Jan 2020 08:04:51 +0000 Subject: [PATCH 035/112] Release 0.4.0 --- VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION.txt b/VERSION.txt index 9e11b32..1d0ba9e 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -0.3.1 +0.4.0 From 150820b0f751123858c3c7e724cdc39677a3fb5f Mon Sep 17 00:00:00 2001 From: Elmer Thomas Date: Fri, 24 Jan 2020 09:20:59 -0800 Subject: [PATCH 036/112] fix: travis update for autodeploy (#103) --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 490e7e9..5cb941c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,6 +18,8 @@ deploy: user: __token__ password: secure: $PYPI_TOKEN + edge: true + distributions: sdist bdist_wheel on: branch: master condition: "$TRAVIS_TEST_RESULT = 0" From c0b1948d59991b48db18f5457e2d5b5dbef75f76 Mon Sep 17 00:00:00 2001 From: Twilio Date: Fri, 24 Jan 2020 17:25:22 +0000 Subject: [PATCH 037/112] [Librarian] Version Bump --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36bea10..7e605b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Change Log All notable changes to this project will be documented in this file. +[2020-01-24] Version 0.4.1 +-------------------------- +**Library - Fix** +- [PR #103](https://github.com/sendgrid/smtpapi-python/pull/103): travis update for autodeploy. Thanks to [@thinkingserious](https://github.com/thinkingserious)! + + [2020-01-24] Version 0.4.0 -------------------------- **Library - Docs** From 8070ca4413674725ee7ef88d706bd760544f1458 Mon Sep 17 00:00:00 2001 From: Twilio Date: Fri, 24 Jan 2020 17:26:45 +0000 Subject: [PATCH 038/112] Release 0.4.1 --- VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION.txt b/VERSION.txt index 1d0ba9e..267577d 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -0.4.0 +0.4.1 From fa698574dd88312d6c8f5a962a0d44a0af4ba2da Mon Sep 17 00:00:00 2001 From: Vinayak <32881538+vinayak42@users.noreply.github.com> Date: Wed, 19 Feb 2020 19:56:15 +0530 Subject: [PATCH 039/112] docs: Fix typos and grammatical errors (#88) --- USAGE.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/USAGE.md b/USAGE.md index 871c292..a2060fc 100644 --- a/USAGE.md +++ b/USAGE.md @@ -36,9 +36,9 @@ print(header.json_string()) * [Using the SMTP API](#use-smtp-api) * [Settings](#settings) * [Categories](#categories) -* [Schedulling Parameters](#schedulling-parameters) +* [Scheduling Parameters](#scheduling-parameters) * [Section Tags](#section-tags) -* [Subtitution Tags](#subtitution-tags) +* [Substitution Tags](#substitution-tags) * [Suppression Groups](#suppression-groups) * [Unique Arguments](#unique-arguments) @@ -123,7 +123,7 @@ Sends a BCC copy of the email created in this transaction to the address specifi # Categories **This endpoint allows you to add categories to the X-SMTPAPI header of the emails you send via SendGrid** -By adding categories to the X-SMTPAPI header of the emails that you send via SendGrid you can to track emails based on your own categorization system. +By adding categories to the X-SMTPAPI header of the emails that you send via SendGrid you can to track emails based on your categorization system. Categories must be in 7bit encoding using the US-ASCII character set, and should be used to group messages together by broad topic. If you need to attach unique data or identifiers to a message, use [Unique Arguments](https://sendgrid.com/docs/API_Reference/SMTP_API/unique_arguments.html) instead. @@ -151,8 +151,8 @@ You can assign up to 10 categories per message: } ``` - -# Schedulling Parameters + +# Scheduling Parameters **This endpoint allows you to send large volumes of email in queued batches or target individual recipients by specifying a custom UNIX timestamp parameter.** This parameter allows SendGrid to begin processing a customer’s email requests before sending. SendGrid will then queue those messages and release them when the timestamp is exceeded. This technique allows for a more efficient way to distribute large email requests and can improve overall mail delivery time performance. @@ -168,7 +168,7 @@ Using the parameters defined below, you can queue batches of emails targeting in **Note: Using both send_at and send_each_at is not valid and will cause your request to be dropped.** ### Send At -To schedule a send request for a large batch of emails use the send_at parameter which will send all emails at approximately the same time. send_at is a UNIX timestamp. +To schedule a send request for a large batch of emails, use the send_at parameter which will send all emails at approximately the same time. send_at is a UNIX timestamp. Example of **`send_at`** email header @@ -212,8 +212,8 @@ The format of the SMTP API section tag has the form: } ``` - -# Subtitution Tags + +# Substitution Tags **This endpoint allows you to easily generate dynamic content for each recipient on your list.** @@ -387,4 +387,4 @@ To apply different unique arguments to individual emails, you may use substituti "customerAccountNumber": "-account_number-" } } -``` \ No newline at end of file +``` From de4c5af12b8ff91a8a1fb889519f78f89ce4016c Mon Sep 17 00:00:00 2001 From: Andre Dantas Date: Wed, 19 Feb 2020 14:27:17 +0000 Subject: [PATCH 040/112] Fix similar-code issue in smtpapi/__init__.py (#53) --- LICENSE.md | 14 +++++++------- smtpapi/__init__.py | 36 +++++++++++++++++------------------- 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/LICENSE.md b/LICENSE.md index 29aba59..35244b0 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,13 +1,13 @@ -MIT License +The MIT License (MIT) Copyright (C) 2020, Twilio SendGrid, Inc. -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. diff --git a/smtpapi/__init__.py b/smtpapi/__init__.py index 13306e6..1ed55a7 100644 --- a/smtpapi/__init__.py +++ b/smtpapi/__init__.py @@ -1,10 +1,5 @@ -import decimal import json -import os - -dir_path = os.path.dirname(os.path.realpath(__file__)) -if os.path.isfile(os.path.join(dir_path, 'VERSION.txt')): - __version__ = open(os.path.join(dir_path, 'VERSION.txt')).read().strip() +import decimal class _CustomJSONEncoder(json.JSONEncoder): @@ -12,7 +7,8 @@ class _CustomJSONEncoder(json.JSONEncoder): def default(self, o): if isinstance(o, decimal.Decimal): return float(o) - # Provide a fallback to the default encoder if we haven't implemented special support for the object's class + # Provide a fallback to the default encoder if we haven't implemented + # special support for the object's class return super(_CustomJSONEncoder, self).default(o) @@ -42,34 +38,36 @@ def add_substitution(self, key, value): def set_substitutions(self, subs): self.data['sub'] = subs + def _add_key_value(self, index, key, value): + if index not in self.data: + self.data[index] = {} + self.data[index][key] = value + + def _add_key(self, index, key): + if index not in self.data: + self.data[index] = [] + self.data[index].append(key) + def add_unique_arg(self, key, value): - if 'unique_args' not in self.data: - self.data['unique_args'] = {} - self.data['unique_args'][key] = value + self._add_key_value('unique_args', key, value) def set_unique_args(self, value): self.data['unique_args'] = value def add_category(self, category): - if 'category' not in self.data: - self.data['category'] = [] - self.data['category'].append(category) + self._add_key('category', category) def set_categories(self, category): self.data['category'] = category def add_section(self, key, section): - if 'section' not in self.data: - self.data['section'] = {} - self.data['section'][key] = section + self._add_key_value('section', key, section) def set_sections(self, value): self.data['section'] = value def add_send_each_at(self, time): - if 'send_each_at' not in self.data: - self.data['send_each_at'] = [] - self.data['send_each_at'].append(time) + self._add_key('send_each_at', time) def set_send_each_at(self, time): self.data['send_each_at'] = time From dbf715ecae001220ae44bae88b420da99d1cacb6 Mon Sep 17 00:00:00 2001 From: Twilio Date: Wed, 19 Feb 2020 23:15:54 +0000 Subject: [PATCH 041/112] [Librarian] Version Bump --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e605b7..853b555 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,15 @@ # Change Log All notable changes to this project will be documented in this file. +[2020-02-19] Version 0.4.2 +-------------------------- +**Library - Fix** +- [PR #53](https://github.com/sendgrid/smtpapi-python/pull/53): "similar-code" issue in smtpapi/__init__.py. Thanks to [@andre8359](https://github.com/andre8359)! + +**Library - Docs** +- [PR #88](https://github.com/sendgrid/smtpapi-python/pull/88): Fix typos and grammatical errors. Thanks to [@vinayak42](https://github.com/vinayak42)! + + [2020-01-24] Version 0.4.1 -------------------------- **Library - Fix** From 966c12d33ec34c91a2d2f9be16d33355224003b5 Mon Sep 17 00:00:00 2001 From: Twilio Date: Wed, 19 Feb 2020 23:17:09 +0000 Subject: [PATCH 042/112] Release 0.4.2 --- VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION.txt b/VERSION.txt index 267577d..2b7c5ae 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -0.4.1 +0.4.2 From bd151a886e8a65c46ef4d82ddf246792e6177e40 Mon Sep 17 00:00:00 2001 From: childish-sambino Date: Fri, 21 Feb 2020 11:55:15 -0600 Subject: [PATCH 043/112] chore: add Python 3.8 to Travis (#104) --- .travis.yml | 5 ++++- README.rst | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5cb941c..c1283bb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,12 @@ +dist: xenial # required for Python >= 3.7 language: python python: - '2.7' - '3.4' - '3.5' - '3.6' + - '3.7' + - '3.8' install: - make install - make test-install @@ -24,4 +27,4 @@ deploy: branch: master condition: "$TRAVIS_TEST_RESULT = 0" tags: true - python: "3.6" + python: '3.6' diff --git a/README.rst b/README.rst index 3cdfe41..ab7fb56 100644 --- a/README.rst +++ b/README.rst @@ -31,7 +31,7 @@ Installation Prerequisites ------------- -- Python version 2.7, 3.4, 3.5, or 3.6 +- Python version 2.7 or 3.4+ - The SendGrid service, starting at the `free level`_ Install Package From 0bc1ef0b12bac2a5d43967bbffc31782d410e1c1 Mon Sep 17 00:00:00 2001 From: Sam Harrison Date: Wed, 4 Mar 2020 14:23:13 -0600 Subject: [PATCH 044/112] fix: drop the unnecessary python install step --- Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile b/Makefile index 783f8ea..7cff157 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,6 @@ venv: virtualenv --python=python venv install: venv - . venv/bin/activate; python setup.py install . venv/bin/activate; pip install . test-install: From ee690ffde22da3de6a8c5ca1ba8c45542ed1c1f0 Mon Sep 17 00:00:00 2001 From: Elise Shanholtz Date: Thu, 5 Mar 2020 10:38:38 -0800 Subject: [PATCH 045/112] fix: update travis autodeploy --- .travis.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index c1283bb..19d3b70 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,10 +18,9 @@ after_success: - codecov deploy: provider: pypi - user: __token__ - password: - secure: $PYPI_TOKEN - edge: true + user: "__token__" + password: $PYPI_TOKEN + skip_cleanup: true distributions: sdist bdist_wheel on: branch: master From 61600972065bc6142fb3ac7c428cbf0a75a23476 Mon Sep 17 00:00:00 2001 From: Twilio Date: Wed, 1 Apr 2020 22:24:48 +0000 Subject: [PATCH 046/112] [Librarian] Version Bump --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 853b555..855987d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Change Log All notable changes to this project will be documented in this file. +[2020-04-01] Version 0.4.3 +-------------------------- +**Library - Chore** +- [PR #104](https://github.com/sendgrid/smtpapi-python/pull/104): add Python 3.8 to Travis. Thanks to [@childish-sambino](https://github.com/childish-sambino)! + + [2020-02-19] Version 0.4.2 -------------------------- **Library - Fix** From 2cf3d7cff2c22fea148a55cc8fcb4e5e89072137 Mon Sep 17 00:00:00 2001 From: Twilio Date: Wed, 1 Apr 2020 22:26:43 +0000 Subject: [PATCH 047/112] Release 0.4.3 --- VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION.txt b/VERSION.txt index 2b7c5ae..17b2ccd 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -0.4.2 +0.4.3 From 3b03806b863745f4fb14fb04099dc0e9b19d0bc7 Mon Sep 17 00:00:00 2001 From: Sam Harrison Date: Fri, 3 Apr 2020 15:29:52 -0500 Subject: [PATCH 048/112] chore: update Travis CI Slack notifications --- .gitignore | 1 + .travis.yml | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/.gitignore b/.gitignore index 40d319c..e6f4e3e 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ include/ lib/ .env smtpapi/VERSION.txt +venv/ diff --git a/.travis.yml b/.travis.yml index 19d3b70..3e0133b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,3 +27,11 @@ deploy: condition: "$TRAVIS_TEST_RESULT = 0" tags: true python: '3.6' + +notifications: + slack: + if: branch = master + on_success: never + on_failure: change + rooms: + - secure: GBYjICnJwGDgb3CM8STuWXESuR2hUZHkl1oCQC8Vd9WmId281AeMflMw3GIo9Ay+uY0+TXUIUihxS61SuX9T/LP4lV7b47dH9BzQ7IbVVfCaOtgq7KmkD4dCeaA8X5zvTktrpMcS1b2WNKKaExCkuetj80dJRSX5vw1s+zl3o5U= From 8473ee3d6eca3146507912f9a3f44c7a7eaa1df3 Mon Sep 17 00:00:00 2001 From: childish-sambino Date: Mon, 6 Apr 2020 11:09:07 -0500 Subject: [PATCH 049/112] Update .travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 3e0133b..caa97ac 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,6 +31,7 @@ deploy: notifications: slack: if: branch = master + on_pull_requests: false on_success: never on_failure: change rooms: From f81ca422c179d98c5ee7548c1385c2b637d0e1b4 Mon Sep 17 00:00:00 2001 From: Sam Harrison Date: Wed, 8 Apr 2020 16:21:26 -0500 Subject: [PATCH 050/112] docs: cleanup support/help/contact information --- CONTRIBUTING.md | 2 -- README.rst | 7 ++----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7f975f7..9231c90 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -173,5 +173,3 @@ Please run your code through: 7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) with a clear title and description against the `development` branch. All tests must be passing before we will review the PR. - -If you have any additional questions, please feel free to [email](mailto:dx@sendgrid.com) us or create an issue in this repo. diff --git a/README.rst b/README.rst index ab7fb56..75a36ff 100644 --- a/README.rst +++ b/README.rst @@ -107,10 +107,8 @@ Steps: About ===== -**smtpapi-python** is guided and supported by the SendGrid `Developer Experience Team`_. - -**smtpapi-python** is maintained and funded by SendGrid, Inc. -The names and logos for **smtpapi-python** are trademarks of SendGrid, Inc. +**smtpapi-python** is maintained and funded by Twilio SendGrid, Inc. +The names and logos for **smtpapi-python** are trademarks of Twilio SendGrid, Inc. License ======= @@ -128,7 +126,6 @@ License .. _Bug Reports: https://github.com/sendgrid/smtpapi-python/blob/master/CONTRIBUTING.md#submit-a-bug-report .. _Sign the CLA to Create a Pull Request: https://github.com/sendgrid/smtpapi-python/blob/master/CONTRIBUTING.md#cla .. _Improvements to the Codebase: https://github.com/sendgrid/smtpapi-python/blob/master/CONTRIBUTING.md#improvements-to-the-codebase -.. _Developer Experience Team: mailto:dx@sendgrid.com .. _The MIT License (MIT): https://github.com/sendgrid/smtpapi-python/blob/master/LICENSE.md .. |Travis Badge| image:: https://travis-ci.org/sendgrid/smtpapi-python.svg?branch=master From df1cae2074a7265266073c3701a7aa5195d4ee92 Mon Sep 17 00:00:00 2001 From: Sam Harrison Date: Fri, 29 May 2020 10:04:38 -0500 Subject: [PATCH 051/112] docs: shorten and correct the issue template link --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9231c90..b0d7109 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -51,7 +51,7 @@ Before you decide to create a new issue, please try the following: ### Please use our Bug Report Template -In order to make the process easier, we've included a [sample bug report template](https://github.com/sendgrid/smtpapi-python/ISSUE_TEMPLATE.md) (borrowed from [Ghost](https://github.com/TryGhost/Ghost/)). The template uses [GitHub flavored markdown](https://help.github.com/articles/github-flavored-markdown/) for formatting. +In order to make the process easier, we've included a [sample bug report template](ISSUE_TEMPLATE.md). ## Improvements to the Codebase From 3244b1aff3e861912375589a6b9c5fff4afb68ba Mon Sep 17 00:00:00 2001 From: Mary Troiani Date: Tue, 30 Jun 2020 12:36:46 -0700 Subject: [PATCH 052/112] docs: add use cases directory and README.md file for use cases (#99) --- use_cases/README.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 use_cases/README.md diff --git a/use_cases/README.md b/use_cases/README.md new file mode 100644 index 0000000..4d00af9 --- /dev/null +++ b/use_cases/README.md @@ -0,0 +1,3 @@ +This directory provides examples for specific use cases. Please [open an issue](https://github.com/sendgrid/smtpapi-python/issues) or make a pull request for any use cases you would like to see here. Thank you! + +# Table of Contents From b3e29d5b5cf918b5281dc6b8c91bbe2d3ca73209 Mon Sep 17 00:00:00 2001 From: childish-sambino Date: Wed, 1 Jul 2020 12:59:16 -0500 Subject: [PATCH 053/112] fix: update supported Python versions in setup file --- setup.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index a6e11d0..da73644 100644 --- a/setup.py +++ b/setup.py @@ -22,9 +22,11 @@ description='Simple wrapper to use SendGrid SMTP API', long_description=readme, classifiers=[ - 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', ], ) From 3666d43257b3c4d06fee1f19408774cce4621607 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Wed, 1 Jul 2020 23:12:44 +0300 Subject: [PATCH 054/112] fix: Fix and add flake8 to CI (#86) --- .flake8 | 2 ++ .gitignore | 13 +++++------ .travis.yml | 1 + examples/example.py | 22 +++++++++++-------- setup.py | 5 ++++- test/__init__.py | 25 +++++++++++++++++----- test/requirements.txt | 1 + test/test_project.py | 50 ++++++++++++++++++++++++------------------- 8 files changed, 76 insertions(+), 43 deletions(-) create mode 100644 .flake8 diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..47be0b2 --- /dev/null +++ b/.flake8 @@ -0,0 +1,2 @@ +[flake8] +exclude = build,venv,.svn,CVS,.bzr,.hg,.git,__pycache__,.tox,.eggs,*.egg diff --git a/.gitignore b/.gitignore index e6f4e3e..301d0e8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,15 @@ -*.pyc *.egg *.egg-info -dist -eggs -build -sdist +*.pyc +.coverage +.env .Python bin/ +build +dist +eggs include/ lib/ -.env +sdist smtpapi/VERSION.txt venv/ diff --git a/.travis.yml b/.travis.yml index caa97ac..3f53f34 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,6 +14,7 @@ install: script: - make test - . venv/bin/activate; coverage run test/__init__.py + - . venv/bin/activate; flake8 --statistics --count after_success: - codecov deploy: diff --git a/examples/example.py b/examples/example.py index 719eb17..07c3b15 100644 --- a/examples/example.py +++ b/examples/example.py @@ -3,12 +3,10 @@ from smtpapi import SMTPAPIHeader import time +from os import path, sys if __name__ == '__main__' and __package__ is None: - from os import sys, path - sys.path.append(path.dirname(path.dirname(path.abspath(__file__)))) - from smtpapi import SMTPAPIHeader header = SMTPAPIHeader() @@ -16,11 +14,13 @@ # header.add_to('test@example.com') header.set_tos(['test1@example.com', 'test2@example.com']) -# [Substitutions](http://sendgrid.com/docs/API_Reference/SMTP_API/substitution_tags.html) +# [Substitutions] +# (http://sendgrid.com/docs/API_Reference/SMTP_API/substitution_tags.html) # header.add_substitution('key', 'value') header.set_substitutions({'key': ['value1', 'value2']}) -# [Unique Arguments](http://sendgrid.com/docs/API_Reference/SMTP_API/unique_arguments.html) +# [Unique Arguments] +# (http://sendgrid.com/docs/API_Reference/SMTP_API/unique_arguments.html) # header.add_unique_arg('key', 'value') header.set_unique_args({'key': 'value'}) @@ -32,16 +32,20 @@ # header.add_section('key', 'section') header.set_sections({'key1': 'section1', 'key2': 'section2'}) -# [Filters](http://sendgrid.com/docs/API_Reference/SMTP_API/apps.html) +# [Filters] +# (http://sendgrid.com/docs/API_Reference/SMTP_API/apps.html) header.add_filter('filter', 'setting', 'value') -# [ASM Group ID](https://sendgrid.com/docs/User_Guide/advanced_suppression_manager.html) +# [ASM Group ID] +# (https://sendgrid.com/docs/User_Guide/advanced_suppression_manager.html) header.set_asm_group_id('value') -# [IP Pools](https://sendgrid.com/docs/API_Reference/Web_API_v3/IP_Management/ip_pools.html) +# [IP Pools] +# (https://sendgrid.com/docs/API_Reference/Web_API_v3/IP_Management/ip_pools.html) header.set_ip_pool("testPool") -# [Scheduling Parameters](https://sendgrid.com/docs/API_Reference/SMTP_API/scheduling_parameters.html) +# [Scheduling Parameters] +# (https://sendgrid.com/docs/API_Reference/SMTP_API/scheduling_parameters.html) # header.add_send_each_at(unix_timestamp) # must be a unix timestamp # header.set_send_each_at([]) # must be a unix timestamp header.set_send_at(int(time.time())) # must be a unix timestamp diff --git a/setup.py b/setup.py index da73644..50b5a32 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,10 @@ dir_path = os.path.abspath(os.path.dirname(__file__)) readme = io.open(os.path.join(dir_path, 'README.rst'), encoding='utf-8').read() -version = io.open(os.path.join(dir_path, 'VERSION.txt'), encoding='utf-8').read().strip() +version = io.open( + os.path.join(dir_path, 'VERSION.txt'), + encoding='utf-8', +).read().strip() copy_file(os.path.join(dir_path, 'VERSION.txt'), os.path.join(dir_path, 'smtpapi', 'VERSION.txt'), verbose=0) diff --git a/test/__init__.py b/test/__init__.py index d75dfb3..149d225 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -46,7 +46,11 @@ def test_add(self): def test_set(self): header = SMTPAPIHeader() - header.set_tos(["test@email.com", "test2@email.com", "test3@email.com"]) + header.set_tos([ + "test@email.com", + "test2@email.com", + "test3@email.com", + ]) header.set_substitutions({ "subKey": ["subValue"], "decimalKey": [decimal.Decimal("1.23456789")] @@ -85,7 +89,11 @@ def test_license_year(self): if line.startswith('Copyright'): copyright_line = line.strip() break - self.assertEqual('Copyright (C) %s, Twilio SendGrid, Inc. ' % datetime.datetime.now().year, copyright_line) + self.assertEqual( + 'Copyright (C) %s, Twilio SendGrid, Inc. ' + % datetime.datetime.now().year, + copyright_line + ) class TestRepository(unittest.TestCase): @@ -118,10 +126,17 @@ def test_repository_files_exists(self): for file_path in self.required_files: if isinstance(file_path, list): # multiple file paths: assert that any one of the files exists - self.assertTrue(any(os.path.exists(f) for f in file_path), - msg=self.file_not_found_message.format('" or "'.join(file_path))) + self.assertTrue( + any(os.path.exists(f) for f in file_path), + msg=self.file_not_found_message.format( + '" or "'.join(file_path) + ), + ) else: - self.assertTrue(os.path.exists(file_path), msg=self.file_not_found_message.format(file_path)) + self.assertTrue( + os.path.exists(file_path), + msg=self.file_not_found_message.format(file_path), + ) if __name__ == '__main__': diff --git a/test/requirements.txt b/test/requirements.txt index 5b3644a..89035cf 100644 --- a/test/requirements.txt +++ b/test/requirements.txt @@ -1,2 +1,3 @@ sendgrid coverage +flake8 diff --git a/test/test_project.py b/test/test_project.py index 85feda5..fdd3684 100644 --- a/test/test_project.py +++ b/test/test_project.py @@ -1,76 +1,82 @@ import os - -try: - import unittest2 as unittest -except ImportError: - import unittest +import unittest class ProjectTests(unittest.TestCase): # ./Docker or docker/Docker - def test_dockerfile(self): - self.assertEqual(True, os.path.isfile("./Dockerfile") or os.path.isfile("./docker/Dockerfile")) + def test_docker_dir(self): + self.assertTrue( + os.path.isfile("./Dockerfile") + or os.path.isdir("./docker/Dockerfile") + ) # ./docker-compose.yml or ./docker/docker-compose.yml def test_docker_compose(self): - self.assertEqual(True, os.path.isfile('./docker-compose.yml') or os.path.isfile('./docker/docker-compose.yml')) + self.assertTrue( + os.path.isfile('./docker-compose.yml') + or os.path.isfile('./docker/docker-compose.yml') + ) # ./.env_sample def test_env(self): - self.assertEqual(True, os.path.isfile('./.env_sample')) + self.assertTrue(os.path.isfile('./.env_sample')) # ./.gitignore def test_gitignore(self): - self.assertEqual(True, os.path.isfile('./.gitignore')) + self.assertTrue(os.path.isfile('./.gitignore')) # ./.travis.yml def test_travis(self): - self.assertEqual(True, os.path.isfile('./.travis.yml')) + self.assertTrue(os.path.isfile('./.travis.yml')) # ./.codeclimate.yml def test_codeclimate(self): - self.assertEqual(True, os.path.isfile('./.codeclimate.yml')) + self.assertTrue(os.path.isfile('./.codeclimate.yml')) # ./CHANGELOG.md def test_changelog(self): - self.assertEqual(True, os.path.isfile('./CHANGELOG.md')) + self.assertTrue(os.path.isfile('./CHANGELOG.md')) # ./CODE_OF_CONDUCT.md def test_code_of_conduct(self): - self.assertEqual(True, os.path.isfile('./CODE_OF_CONDUCT.md')) + self.assertTrue(os.path.isfile('./CODE_OF_CONDUCT.md')) # ./CONTRIBUTING.md def test_contributing(self): - self.assertEqual(True, os.path.isfile('./CONTRIBUTING.md')) + self.assertTrue(os.path.isfile('./CONTRIBUTING.md')) # ./ISSUE_TEMPLATE.md def test_issue_template(self): - self.assertEqual(True, os.path.isfile('./ISSUE_TEMPLATE.md')) + self.assertTrue(os.path.isfile('./ISSUE_TEMPLATE.md')) # ./LICENSE.md def test_license(self): - self.assertEqual(True, os.path.isfile('./LICENSE.md') or os.path.isfile('./LICENSE.txt')) + self.assertTrue( + os.path.isfile('./LICENSE.md') or os.path.isfile('./LICENSE.txt') + ) # ./PULL_REQUEST_TEMPLATE.md def test_pr_template(self): - self.assertEqual(True, os.path.isfile('./PULL_REQUEST_TEMPLATE.md')) + self.assertTrue( + os.path.isfile('./PULL_REQUEST_TEMPLATE.md') + ) # ./README.rst def test_readme(self): - self.assertEqual(True, os.path.isfile('./README.rst')) + self.assertTrue(os.path.isfile('./README.rst')) # ./TROUBLESHOOTING.md def test_troubleshooting(self): - self.assertEqual(True, os.path.isfile('./TROUBLESHOOTING.md')) + self.assertTrue(os.path.isfile('./TROUBLESHOOTING.md')) # ./USAGE.md def test_usage(self): - self.assertEqual(True, os.path.isfile('./USAGE.md')) + self.assertTrue(os.path.isfile('./USAGE.md')) # ./VERSION.txt def test_use_cases(self): - self.assertEqual(True, os.path.isfile('./VERSION.txt')) + self.assertTrue(os.path.isfile('./VERSION.txt')) if __name__ == '__main__': From 68ef8eb1132b8c38ff79488d0314b1083ee80d8c Mon Sep 17 00:00:00 2001 From: Twilio Date: Wed, 8 Jul 2020 18:32:19 +0000 Subject: [PATCH 055/112] [Librarian] Version Bump --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 855987d..1713e79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,15 @@ # Change Log All notable changes to this project will be documented in this file. +[2020-07-08] Version 0.4.4 +-------------------------- +**Library - Fix** +- [PR #86](https://github.com/sendgrid/smtpapi-python/pull/86): Fix and add flake8 to CI. Thanks to [@hugovk](https://github.com/hugovk)! + +**Library - Docs** +- [PR #99](https://github.com/sendgrid/smtpapi-python/pull/99): add use cases directory and README.md file for use cases. Thanks to [@mtroiani](https://github.com/mtroiani)! + + [2020-04-01] Version 0.4.3 -------------------------- **Library - Chore** From 185c227e82bf604b5d239a635e3e2a1c752854ee Mon Sep 17 00:00:00 2001 From: Twilio Date: Wed, 8 Jul 2020 18:34:16 +0000 Subject: [PATCH 056/112] Release 0.4.4 --- VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION.txt b/VERSION.txt index 17b2ccd..6f2743d 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -0.4.3 +0.4.4 From e2663c1a0cb5b6e11db7407152d2c96f603d84e7 Mon Sep 17 00:00:00 2001 From: Sam Harrison Date: Mon, 13 Jul 2020 10:24:47 -0500 Subject: [PATCH 057/112] chore: drop the CLA links --- CONTRIBUTING.md | 16 ---------------- README.rst | 2 -- 2 files changed, 18 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b0d7109..67b759a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,7 +1,5 @@ Hello! Thank you for choosing to help contribute to one of the SendGrid open source projects. There are many ways you can contribute and help is always welcome. We simply ask that you follow the following contribution policies. -- [CLAs and CCLAs](#cla) -- [Roadmap & Milestones](#roadmap) - [Feature Request](#feature-request) - [Submit a Bug Report](#submit-a-bug-report) - [Improvements to the Codebase](#improvements-to-the-codebase) @@ -10,22 +8,8 @@ Hello! Thank you for choosing to help contribute to one of the SendGrid open sou - [Style Guidelines & Naming Conventions](#style-guidelines-and-naming-conventions) - [Creating a Pull Request](#creating-a-pull-request) - We use [Milestones](https://github.com/sendgrid/smtpapi-python/milestones) to help define current roadmaps, please feel free to grab an issue from the current milestone. Please indicate that you have begun work on it to avoid collisions. Once a PR is made, community review, comments, suggestions and additional PRs are welcomed and encouraged. - -## CLAs and CCLAs - -Before you get started, SendGrid requires that a SendGrid Contributor License Agreement (CLA) be filled out by every contributor to a SendGrid open source project. - -Our goal with the CLA is to clarify the rights of our contributors and reduce other risks arising from inappropriate contributions. The CLA also clarifies the rights SendGrid holds in each contribution and helps to avoid misunderstandings over what rights each contributor is required to grant to SendGrid when making a contribution. In this way the CLA encourages broad participation by our open source community and helps us build strong open source projects, free from any individual contributor withholding or revoking rights to any contribution. - -SendGrid does not merge a pull request made against a SendGrid open source project until that pull request is associated with a signed CLA. Copies of the CLA are available [here](https://gist.github.com/SendGridDX/98b42c0a5d500058357b80278fde3be8#file-sendgrid_cla). - -When you create a Pull Request, after a few seconds, a comment will appear with a link to the CLA. Click the link and fill out the brief form and then click the "I agree" button and you are all set. You will not be asked to re-sign the CLA unless we make a change. - -There are a few ways to contribute, which we'll enumerate below: - ## Feature Request diff --git a/README.rst b/README.rst index 75a36ff..638c6b6 100644 --- a/README.rst +++ b/README.rst @@ -90,7 +90,6 @@ Quick links: - `Feature Request`_ - `Bug Reports`_ -- `Sign the CLA to Create a Pull Request`_ - `Improvements to the Codebase`_ Local Setup of the Project @@ -124,7 +123,6 @@ License .. _CONTRIBUTING: https://github.com/sendgrid/smtpapi-python/blob/master/CONTRIBUTING.md .. _Feature Request: https://github.com/sendgrid/smtpapi-python/blob/master/CONTRIBUTING.md#feature-request .. _Bug Reports: https://github.com/sendgrid/smtpapi-python/blob/master/CONTRIBUTING.md#submit-a-bug-report -.. _Sign the CLA to Create a Pull Request: https://github.com/sendgrid/smtpapi-python/blob/master/CONTRIBUTING.md#cla .. _Improvements to the Codebase: https://github.com/sendgrid/smtpapi-python/blob/master/CONTRIBUTING.md#improvements-to-the-codebase .. _The MIT License (MIT): https://github.com/sendgrid/smtpapi-python/blob/master/LICENSE.md From 33860a3b2dede8b886f73141f52b0d58bff1c22d Mon Sep 17 00:00:00 2001 From: Sam Harrison Date: Mon, 27 Jul 2020 17:11:48 -0500 Subject: [PATCH 058/112] chore: update README to reflect default branch rename --- README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rst b/README.rst index 638c6b6..9f4cc20 100644 --- a/README.rst +++ b/README.rst @@ -10,6 +10,7 @@ Learn more about the SMTP API at `SendGrid documentation`_. Announcements ============= +**The default branch name for this repository has been changed to `main` as of 07/27/2020.** All updates to this module is documented in our `CHANGELOG`_. From fdd86bfb64d68f69578fb7553292891fd929db8a Mon Sep 17 00:00:00 2001 From: Sam Harrison Date: Tue, 28 Jul 2020 09:56:36 -0500 Subject: [PATCH 059/112] chore: update CI config to use new default branch name --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3f53f34..7f2cc66 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,14 +24,14 @@ deploy: skip_cleanup: true distributions: sdist bdist_wheel on: - branch: master + branch: main condition: "$TRAVIS_TEST_RESULT = 0" tags: true python: '3.6' notifications: slack: - if: branch = master + if: branch = main on_pull_requests: false on_success: never on_failure: change From f310f8fe18f60571b9eb4390efeaef5ffc270404 Mon Sep 17 00:00:00 2001 From: Twilio Date: Mon, 3 Aug 2020 22:32:20 +0000 Subject: [PATCH 060/112] docs: Update templated markdown docs to use new default branch name --- ISSUE_TEMPLATE.md | 6 +++++- LICENSE.md | 14 +++++++------- PULL_REQUEST_TEMPLATE.md | 2 +- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md index 56dbe14..8c043fd 100644 --- a/ISSUE_TEMPLATE.md +++ b/ISSUE_TEMPLATE.md @@ -1,5 +1,9 @@ ### Issue Summary @@ -21,6 +25,6 @@ A summary of the issue and the environment in which it occurs. If suitable, incl ``` ### Technical details: -* smtpapi-python version: +* smtpapi-python version: * python version: diff --git a/LICENSE.md b/LICENSE.md index 35244b0..29aba59 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,13 +1,13 @@ -The MIT License (MIT) +MIT License Copyright (C) 2020, Twilio SendGrid, Inc. -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md index 215059a..a868180 100644 --- a/PULL_REQUEST_TEMPLATE.md +++ b/PULL_REQUEST_TEMPLATE.md @@ -23,7 +23,7 @@ A short description of what this PR does. - [ ] I have made a material change to the repo (functionality, testing, spelling, grammar) - [ ] I have read the [Contribution Guidelines](CONTRIBUTING.md) and my PR follows them - [ ] I have titled the PR appropriately -- [ ] I have updated my branch with the master branch +- [ ] I have updated my branch with the main branch - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] I have added necessary documentation about the functionality in the appropriate .md file - [ ] I have added inline documentation to the code I modified From 07ca62c7829afd836bfa429c444ecc56e45ace8d Mon Sep 17 00:00:00 2001 From: Elmer Thomas Date: Mon, 10 Aug 2020 10:16:50 -0700 Subject: [PATCH 061/112] chore: update GitHub branch references to use HEAD (#105) --- CONTRIBUTING.md | 6 +++--- Dockerfile | 4 ++-- FIRST-TIMERS.md | 4 ++-- README.rst | 20 ++++++++++---------- twilio_sendgrid_logo.png | Bin 0 -> 14596 bytes 5 files changed, 17 insertions(+), 17 deletions(-) create mode 100644 twilio_sendgrid_logo.png diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 67b759a..72c76f5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -61,7 +61,7 @@ cd smtpapi-python ##### Execute: ##### -See the [examples folder](https://github.com/sendgrid/smtpapi-python/tree/master/examples) to get started quickly. +See the [examples folder](examples) to get started quickly. ## Understanding the Code Base @@ -83,9 +83,9 @@ Builds the SMTPAPI header. All PRs require passing tests before the PR will be reviewed. -All test files are in the [`test`](https://github.com/sendgrid/smtpapi-python/tree/master/test) directory. +All test files are in the [`test`](test) directory. -For the purposes of contributing to this repo, please update the [`__init__.py`](https://github.com/sendgrid/smtpapi-python/blob/master/test/__init__.py) file with unit tests as you modify the code. +For the purposes of contributing to this repo, please update the [`__init__.py`](test/__init__.py) file with unit tests as you modify the code. ```bash python setup.py install diff --git a/Dockerfile b/Dockerfile index 8f5a44f..527ece2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM ubuntu:xenial ENV PYTHON_VERSIONS='python2.6 python2.7 python3.4 python3.5 python3.6' \ - OAI_SPEC_URL="https://raw.githubusercontent.com/sendgrid/sendgrid-oai/master/oai_stoplight.json" + OAI_SPEC_URL="https://raw.githubusercontent.com/sendgrid/sendgrid-oai/HEAD/oai_stoplight.json" # install testing versions of python, including old versions, from deadsnakes RUN set -x \ @@ -17,7 +17,7 @@ RUN set -x \ WORKDIR /root # install Prism -ADD https://raw.githubusercontent.com/stoplightio/prism/master/install.sh install.sh +ADD https://raw.githubusercontent.com/stoplightio/prism/HEAD/install.sh install.sh RUN chmod +x ./install.sh && \ ./install.sh && \ rm ./install.sh diff --git a/FIRST-TIMERS.md b/FIRST-TIMERS.md index 1b296cd..1c5e8d8 100644 --- a/FIRST-TIMERS.md +++ b/FIRST-TIMERS.md @@ -37,7 +37,7 @@ 6. __Locally merge (or rebase)__ the upstream development branch into your topic branch: ``` - git pull [--rebase] upstream master + git pull [--rebase] upstream main ``` 7. __Push__ your topic branch up to your fork: @@ -45,7 +45,7 @@ git push origin ``` 8. __[Open a Pull Request](https://help.github.com/articles/creating-a-pull-request/#changing-the-branch-range-and-destination-repository/)__ - with a clear title and description against the `master` branch. All tests must be passing before we will review the PR. + with a clear title and description against the `main` branch. All tests must be passing before we will review the PR. ### Important notice Before creating a pull request, make sure that you respect the repository's constraints regarding contributions. You can find them in the [CONTRIBUTING.md](./CONTRIBUTING.md) file. diff --git a/README.rst b/README.rst index 9f4cc20..5157f89 100644 --- a/README.rst +++ b/README.rst @@ -116,24 +116,24 @@ License `The MIT License (MIT)`_ .. _SendGrid documentation: https://sendgrid.com/docs/API_Reference/SMTP_API/index.html -.. _CHANGELOG: https://github.com/sendgrid/smtpapi-python/blob/master/CHANGELOG.md +.. _CHANGELOG: https://github.com/sendgrid/smtpapi-python/blob/HEAD/CHANGELOG.md .. _free level: https://sendgrid.com/free?source=sendgrid-python .. _SENDGRID_API_KEY: https://app.sendgrid.com/settings/api_keys -.. _Example Code: https://github.com/sendgrid/smtpapi-python/tree/master/examples +.. _Example Code: https://github.com/sendgrid/smtpapi-python/tree/HEAD/examples .. _milestones: https://github.com/sendgrid/smtpapi-python/milestones -.. _CONTRIBUTING: https://github.com/sendgrid/smtpapi-python/blob/master/CONTRIBUTING.md -.. _Feature Request: https://github.com/sendgrid/smtpapi-python/blob/master/CONTRIBUTING.md#feature-request -.. _Bug Reports: https://github.com/sendgrid/smtpapi-python/blob/master/CONTRIBUTING.md#submit-a-bug-report -.. _Improvements to the Codebase: https://github.com/sendgrid/smtpapi-python/blob/master/CONTRIBUTING.md#improvements-to-the-codebase -.. _The MIT License (MIT): https://github.com/sendgrid/smtpapi-python/blob/master/LICENSE.md +.. _CONTRIBUTING: https://github.com/sendgrid/smtpapi-python/blob/HEAD/CONTRIBUTING.md +.. _Feature Request: https://github.com/sendgrid/smtpapi-python/blob/HEAD/CONTRIBUTING.md#feature-request +.. _Bug Reports: https://github.com/sendgrid/smtpapi-python/blob/HEAD/CONTRIBUTING.md#submit-a-bug-report +.. _Improvements to the Codebase: https://github.com/sendgrid/smtpapi-python/blob/HEAD/CONTRIBUTING.md#improvements-to-the-codebase +.. _The MIT License (MIT): https://github.com/sendgrid/smtpapi-python/blob/HEAD/LICENSE.md -.. |Travis Badge| image:: https://travis-ci.org/sendgrid/smtpapi-python.svg?branch=master +.. |Travis Badge| image:: https://travis-ci.org/sendgrid/smtpapi-python.svg?branch=main :target: https://travis-ci.org/sendgrid/smtpapi-python .. |Email Notifications Badge| image:: https://dx.sendgrid.com/badge/python :target: https://dx.sendgrid.com/newsletter/python .. |Twitter Follow| image:: https://img.shields.io/twitter/follow/sendgrid.svg?style=social&label=Follow :target: https://twitter.com/sendgrid -.. |Codecov branch| image:: https://img.shields.io/codecov/c/github/sendgrid/smtpapi-python/master.svg?style=flat-square&label=Codecov+Coverage +.. |Codecov branch| image:: https://img.shields.io/codecov/c/github/sendgrid/smtpapi-python/main.svg?style=flat-square&label=Codecov+Coverage :target: https://codecov.io/gh/sendgrid/smtpapi-python .. |Python Versions| image:: https://img.shields.io/pypi/pyversions/smtpapi.svg :target: https://pypi.org/project/smtpapi/ @@ -142,4 +142,4 @@ License .. |GitHub contributors| image:: https://img.shields.io/github/contributors/sendgrid/smtpapi-python.svg :target: https://github.com/sendgrid/smtpapi-python/graphs/contributors .. |MIT Licensed| image:: https://img.shields.io/badge/license-MIT-blue.svg - :target: https://github.com/sendgrid/smtpapi-python/blob/master/LICENSE.md + :target: https://github.com/sendgrid/smtpapi-python/blob/HEAD/LICENSE.md diff --git a/twilio_sendgrid_logo.png b/twilio_sendgrid_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..a4c22239ac0cc70e10a51f828390d713edc8a29b GIT binary patch literal 14596 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 literal 0 HcmV?d00001 From e4e3400c1be910403db561b962acf279c41115a0 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 13 Aug 2020 18:13:13 +0200 Subject: [PATCH 062/112] docs: Correct *.md files using Grammarly (#70) --- CONTRIBUTING.md | 7 ++++--- README.rst | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 72c76f5..7fbea69 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,7 +8,8 @@ Hello! Thank you for choosing to help contribute to one of the SendGrid open sou - [Style Guidelines & Naming Conventions](#style-guidelines-and-naming-conventions) - [Creating a Pull Request](#creating-a-pull-request) -We use [Milestones](https://github.com/sendgrid/smtpapi-python/milestones) to help define current roadmaps, please feel free to grab an issue from the current milestone. Please indicate that you have begun work on it to avoid collisions. Once a PR is made, community review, comments, suggestions and additional PRs are welcomed and encouraged. + +We use [Milestones](https://github.com/sendgrid/smtpapi-python/milestones) to help define current roadmaps, please feel free to grab an issue from the current milestone. Please indicate that you have begun work on it to avoid collisions. Once a PR is made, community review, comments, suggestions, and additional PRs are welcomed and encouraged. ## Feature Request @@ -30,7 +31,7 @@ A software bug is a demonstrable issue in the code base. In order for us to diag Before you decide to create a new issue, please try the following: 1. Check the Github issues tab if the identified issue has already been reported, if so, please add a +1 to the existing post. -2. Update to the latest version of this code and check if issue has already been fixed +2. Update to the latest version of this code and check if the issue has already been fixed 3. Copy and fill in the Bug Report Template we have provided below ### Please use our Bug Report Template @@ -135,7 +136,7 @@ Please run your code through: 4. Commit your changes in logical chunks. Please adhere to these [git commit message guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) - or your code is unlikely be merged into the main project. Use Git's + or your code is unlikely to be merged into the main project. Use Git's [interactive rebase](https://help.github.com/articles/interactive-rebase) feature to tidy up your commits before making them public. diff --git a/README.rst b/README.rst index 5157f89..c3de41f 100644 --- a/README.rst +++ b/README.rst @@ -96,11 +96,11 @@ Quick links: Local Setup of the Project ========================== -The simplest local development workflow is by using docker. +The simplest local development workflow is by using Docker. Steps: -1. Install Docker +1. Install [Docker](https://www.docker.com/) 2. Run ``docker-compose build`` (this builds the container) 3. Run ``docker-compose up`` (this runs tests by default) From 999dd10550c94e8c81897d96f7a1b7d232d33340 Mon Sep 17 00:00:00 2001 From: Siddhant Sharma Date: Thu, 13 Aug 2020 21:54:24 +0530 Subject: [PATCH 063/112] docs: Fix .md with Grammar.ly (#72) --- CHANGELOG.md | 2 +- CONTRIBUTING.md | 14 +++++++------- README.rst | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1713e79..857c353 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ # Change Log -All notable changes to this project will be documented in this file. +All the notable changes to this project will be documented in this file. [2020-07-08] Version 0.4.4 -------------------------- diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7fbea69..156c05d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,4 +1,4 @@ -Hello! Thank you for choosing to help contribute to one of the SendGrid open source projects. There are many ways you can contribute and help is always welcome. We simply ask that you follow the following contribution policies. +Hello! Thank you for choosing to help contribute to one of the Twilio SendGrid open source projects. There are many ways you can contribute and help is always welcome. We simply ask that you follow the following contribution policies. - [Feature Request](#feature-request) - [Submit a Bug Report](#submit-a-bug-report) @@ -18,21 +18,21 @@ If you'd like to make a feature request, please read this section. The GitHub issue tracker is the preferred channel for library feature requests, but please respect the following restrictions: -- Please **search for existing issues** in order to ensure we don't have duplicate bugs/feature requests. -- Please be respectful and considerate of others when commenting on issues +- Please **search for existing issues** to ensure we don't have duplicate bugs/feature requests. +- Please be respectful and considerate of others when commenting on issues. ## Submit a Bug Report Note: DO NOT include your credentials in ANY code examples, descriptions, or media you make public. -A software bug is a demonstrable issue in the code base. In order for us to diagnose the issue and respond as quickly as possible, please add as much detail as possible into your bug report. +A software bug is a demonstrable issue in the code base. For us to diagnose the issue and respond as quickly as possible, please add as much detail as possible into your bug report. Before you decide to create a new issue, please try the following: 1. Check the Github issues tab if the identified issue has already been reported, if so, please add a +1 to the existing post. -2. Update to the latest version of this code and check if the issue has already been fixed -3. Copy and fill in the Bug Report Template we have provided below +2. Update to the latest version of this code and check if the issue has already been fixed. +3. Copy and fill in the Bug Report Template we have provided below. ### Please use our Bug Report Template @@ -84,7 +84,7 @@ Builds the SMTPAPI header. All PRs require passing tests before the PR will be reviewed. -All test files are in the [`test`](test) directory. +All the test files are in the [`test`](test) directory. For the purposes of contributing to this repo, please update the [`__init__.py`](test/__init__.py) file with unit tests as you modify the code. diff --git a/README.rst b/README.rst index c3de41f..7b6f15f 100644 --- a/README.rst +++ b/README.rst @@ -12,7 +12,7 @@ Announcements ============= **The default branch name for this repository has been changed to `main` as of 07/27/2020.** -All updates to this module is documented in our `CHANGELOG`_. +All the updates to this module are documented in our `CHANGELOG`_. Table of Contents ================= @@ -85,7 +85,7 @@ We would love to hear your feedback. How to Contribute ================= -We encourage contribution to our projects, please see our `CONTRIBUTING`_ guide for details. +We encourage contribution to our projects, please see our `CONTRIBUTING`_ guide for more details. Quick links: From f429f6ec8187b0f0bb6daaa848cf7e1d5146450d Mon Sep 17 00:00:00 2001 From: Sam Harrison Date: Tue, 18 Aug 2020 10:11:13 -0500 Subject: [PATCH 064/112] docs: clean up and reconcile first timers documentation --- FIRST-TIMERS.md => FIRST_TIMERS.md | 108 +++++++++++++++-------------- 1 file changed, 55 insertions(+), 53 deletions(-) rename FIRST-TIMERS.md => FIRST_TIMERS.md (50%) diff --git a/FIRST-TIMERS.md b/FIRST_TIMERS.md similarity index 50% rename from FIRST-TIMERS.md rename to FIRST_TIMERS.md index 1c5e8d8..174f5d0 100644 --- a/FIRST-TIMERS.md +++ b/FIRST_TIMERS.md @@ -1,56 +1,60 @@ -# How To Contribute to SendGrid Repositories via GitHub - Contributing to the SendGrid is easy! All you need to do is find an open issue (see the bottom of this page for a list of repositories containing open issues), fix it and submit a pull request. Once you have submitted your pull request, the team can easily review it before it is merged into the repository. - To make a pull request, follow these steps: - 1. Log into GitHub. If you do not already have a GitHub account, you will have to create one in order to submit a change. Click the Sign up link in the upper right-hand corner to create an account. Enter your username, password, and email address. If you are an employee of SendGrid, please use your full name with your GitHub account and enter SendGrid as your company so we can easily identify you. +# How To Contribute to Twilio SendGrid Repositories via GitHub +Contributing to the Twilio SendGrid repositories is easy! All you need to do is find an open issue (see the bottom of this page for a list of repositories containing open issues), fix it and submit a pull request. Once you have submitted your pull request, the team can easily review it before it is merged into the repository. + +To make a pull request, follow these steps: + +1. Log into GitHub. If you do not already have a GitHub account, you will have to create one in order to submit a change. Click the Sign up link in the upper right-hand corner to create an account. Enter your username, password, and email address. If you are an employee of Twilio SendGrid, please use your full name with your GitHub account and enter Twilio SendGrid as your company so we can easily identify you. - 2. __[Fork](https://help.github.com/fork-a-repo/)__ the [smtpapi-python](https://github.com/sendgrid/smtpapi-python) repository: - - - - 3. __Clone__ your fork via the following commands: - - ``` - # Clone your fork of the repo into the current directory - git clone https://github.com/your_username/smtpapi-python - # Navigate to the newly cloned directory - cd smtpapi-python - # Assign the original repo to a remote called "upstream" - git remote add upstream https://github.com/sendgrid/smtpapi-python - ``` - - > Don't forget to replace *your_username* in the URL by your real GitHub username. - - 4. __Create a new topic branch__ (off the main project development branch) to - contain your feature, change, or fix: - -``` - git checkout -b -``` - - 5. __Commit your changes__ in logical chunks. Please adhere to these [git commit - message guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) - or your code is unlikely be merged into the main project. Use Git's - [interactive rebase](https://help.github.com/articles/interactive-rebase) - feature to tidy up your commits before making them public. Probably you will also have to create tests (if needed) or create or update the example code that demonstrates the functionality of this change to the code. - 6. __Locally merge (or rebase)__ the upstream development branch into your topic branch: - - ``` - git pull [--rebase] upstream main - ``` - - 7. __Push__ your topic branch up to your fork: - ``` - git push origin - ``` - 8. __[Open a Pull Request](https://help.github.com/articles/creating-a-pull-request/#changing-the-branch-range-and-destination-repository/)__ - with a clear title and description against the `main` branch. All tests must be passing before we will review the PR. - - ### Important notice - Before creating a pull request, make sure that you respect the repository's constraints regarding contributions. You can find them in the [CONTRIBUTING.md](./CONTRIBUTING.md) file. - ## Repositories with Open, Easy, Help Wanted, Issue Filters - * [Python SDK](https://github.com/sendgrid/sendgrid-python/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) +2. __[Fork](https://help.github.com/fork-a-repo/)__ the [smtpapi-python](https://github.com/sendgrid/smtpapi-python) repository: + + + +3. __Clone__ your fork via the following commands: + +```bash +# Clone your fork of the repo into the current directory +git clone https://github.com/your_username/smtpapi-python +# Navigate to the newly cloned directory +cd smtpapi-python +# Assign the original repo to a remote called "upstream" +git remote add upstream https://github.com/sendgrid/smtpapi-python +``` + +> Don't forget to replace *your_username* in the URL by your real GitHub username. + +4. __Create a new topic branch__ (off the main project development branch) to contain your feature, change, or fix: + +```bash +git checkout -b +``` + +5. __Commit your changes__ in logical chunks. + +Please adhere to these [git commit message guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) or your code is unlikely be merged into the main project. Use Git's [interactive rebase](https://help.github.com/articles/interactive-rebase) feature to tidy up your commits before making them public. Probably you will also have to create tests (if needed) or create or update the example code that demonstrates the functionality of this change to the code. + +6. __Locally merge (or rebase)__ the upstream development branch into your topic branch: + +```bash +git pull [--rebase] upstream main +``` + +7. __Push__ your topic branch up to your fork: + +```bash +git push origin +``` + +8. __[Open a Pull Request](https://help.github.com/articles/creating-a-pull-request/#changing-the-branch-range-and-destination-repository/)__ with a clear title and description against the `main` branch. All tests must be passing before we will review the PR. + +## Important notice + +Before creating a pull request, make sure that you respect the repository's constraints regarding contributions. You can find them in the [CONTRIBUTING.md](CONTRIBUTING.md) file. + +## Repositories with Open, Easy, Help Wanted, Issue Filters + +* [Python SDK](https://github.com/sendgrid/sendgrid-python/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) * [PHP SDK](https://github.com/sendgrid/sendgrid-php/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) * [C# SDK](https://github.com/sendgrid/sendgrid-csharp/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) * [Ruby SDK](https://github.com/sendgrid/sendgrid-ruby/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) @@ -70,8 +74,6 @@ * [Java HTTP Client](https://github.com/sendgrid/java-http-client/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) * [Ruby HTTP Client](https://github.com/sendgrid/ruby-http-client/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) * [Go HTTP Client](https://github.com/sendgrid/rest/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) -* [Node.js HTTP Client](https://github.com/sendgrid/nodejs-http-client/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) -* [Open Source Data Collector](https://github.com/sendgrid/open-source-library-data-collector/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) * [Open API Definition](https://github.com/sendgrid/sendgrid-oai/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) * [DX Automator](https://github.com/sendgrid/dx-automator/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) -* [Documentation](https://github.com/sendgrid/docs/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) \ No newline at end of file +* [Documentation](https://github.com/sendgrid/docs/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) From b74956441cedfe18580a87a7ad916e4dffa7e244 Mon Sep 17 00:00:00 2001 From: Twilio Date: Wed, 19 Aug 2020 18:54:14 +0000 Subject: [PATCH 065/112] [Librarian] Version Bump --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 857c353..43d3983 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,16 @@ # Change Log All the notable changes to this project will be documented in this file. +[2020-08-19] Version 0.4.5 +-------------------------- +**Library - Docs** +- [PR #72](https://github.com/sendgrid/smtpapi-python/pull/72): Fix .md with Grammar.ly. Thanks to [@ssiddhantsharma](https://github.com/ssiddhantsharma)! +- [PR #70](https://github.com/sendgrid/smtpapi-python/pull/70): Correct *.md files using Grammarly. Thanks to [@myzeprog](https://github.com/myzeprog)! + +**Library - Chore** +- [PR #105](https://github.com/sendgrid/smtpapi-python/pull/105): update GitHub branch references to use HEAD. Thanks to [@thinkingserious](https://github.com/thinkingserious)! + + [2020-07-08] Version 0.4.4 -------------------------- **Library - Fix** From f4e5c7733c153d6beffd626491d6257c6b8c92c7 Mon Sep 17 00:00:00 2001 From: Twilio Date: Wed, 19 Aug 2020 19:03:47 +0000 Subject: [PATCH 066/112] Release 0.4.5 --- VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION.txt b/VERSION.txt index 6f2743d..0bfccb0 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -0.4.4 +0.4.5 From a9335e47fbd1199c2efc0c6da45e6c0f225279c4 Mon Sep 17 00:00:00 2001 From: Sam Harrison Date: Mon, 24 Aug 2020 09:57:48 -0500 Subject: [PATCH 067/112] docs: remove roadmap/milestone sections for CONTRIBUTING and README --- CONTRIBUTING.md | 3 --- README.rst | 8 -------- 2 files changed, 11 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 156c05d..afcc51e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,9 +8,6 @@ Hello! Thank you for choosing to help contribute to one of the Twilio SendGrid o - [Style Guidelines & Naming Conventions](#style-guidelines-and-naming-conventions) - [Creating a Pull Request](#creating-a-pull-request) - -We use [Milestones](https://github.com/sendgrid/smtpapi-python/milestones) to help define current roadmaps, please feel free to grab an issue from the current milestone. Please indicate that you have begun work on it to avoid collisions. Once a PR is made, community review, comments, suggestions, and additional PRs are welcomed and encouraged. - ## Feature Request diff --git a/README.rst b/README.rst index 7b6f15f..bc07001 100644 --- a/README.rst +++ b/README.rst @@ -20,7 +20,6 @@ Table of Contents - `Installation <#installation>`__ - `Quick Start <#quick-start>`__ - `Usage <#usage>`__ -- `Roadmap <#roadmap>`__ - `How to Contribute <#how-to-contribute>`__ - `Local Setup of the Project <#local-setup-of-the-project>`__ - `About <#about>`__ @@ -76,12 +75,6 @@ Usage - `SendGrid documentation`_ - `Example Code`_ -Roadmap -======= - -If you are interested in the future direction of this project, please take a look at our `milestones`_. -We would love to hear your feedback. - How to Contribute ================= @@ -120,7 +113,6 @@ License .. _free level: https://sendgrid.com/free?source=sendgrid-python .. _SENDGRID_API_KEY: https://app.sendgrid.com/settings/api_keys .. _Example Code: https://github.com/sendgrid/smtpapi-python/tree/HEAD/examples -.. _milestones: https://github.com/sendgrid/smtpapi-python/milestones .. _CONTRIBUTING: https://github.com/sendgrid/smtpapi-python/blob/HEAD/CONTRIBUTING.md .. _Feature Request: https://github.com/sendgrid/smtpapi-python/blob/HEAD/CONTRIBUTING.md#feature-request .. _Bug Reports: https://github.com/sendgrid/smtpapi-python/blob/HEAD/CONTRIBUTING.md#submit-a-bug-report From fdd00fb8f8401fc7cca610701d6c6d19382445bf Mon Sep 17 00:00:00 2001 From: Elise Shanholtz Date: Fri, 28 Aug 2020 15:31:23 -0700 Subject: [PATCH 068/112] chore: move encrypted tokens to environment variables --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7f2cc66..4b8029e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,5 +35,4 @@ notifications: on_pull_requests: false on_success: never on_failure: change - rooms: - - secure: GBYjICnJwGDgb3CM8STuWXESuR2hUZHkl1oCQC8Vd9WmId281AeMflMw3GIo9Ay+uY0+TXUIUihxS61SuX9T/LP4lV7b47dH9BzQ7IbVVfCaOtgq7KmkD4dCeaA8X5zvTktrpMcS1b2WNKKaExCkuetj80dJRSX5vw1s+zl3o5U= + rooms: $SLACK_TOKEN From aa9236f5e0fbb3622b60a30abb04ee6121afe37b Mon Sep 17 00:00:00 2001 From: Elise Shanholtz Date: Tue, 1 Sep 2020 13:23:44 -0700 Subject: [PATCH 069/112] Revert "chore: move encrypted tokens to environment variables" This reverts commit fdd00fb8 --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4b8029e..7f2cc66 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,4 +35,5 @@ notifications: on_pull_requests: false on_success: never on_failure: change - rooms: $SLACK_TOKEN + rooms: + - secure: GBYjICnJwGDgb3CM8STuWXESuR2hUZHkl1oCQC8Vd9WmId281AeMflMw3GIo9Ay+uY0+TXUIUihxS61SuX9T/LP4lV7b47dH9BzQ7IbVVfCaOtgq7KmkD4dCeaA8X5zvTktrpMcS1b2WNKKaExCkuetj80dJRSX5vw1s+zl3o5U= From 8dfb657132f9d9eec204a6cff866503f138c1a47 Mon Sep 17 00:00:00 2001 From: Yudhik Agrawal Date: Tue, 22 Sep 2020 03:37:39 +0530 Subject: [PATCH 070/112] docs: Few typos and grammatical mistake corrected (#57) --- USAGE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/USAGE.md b/USAGE.md index a2060fc..737d565 100644 --- a/USAGE.md +++ b/USAGE.md @@ -90,7 +90,7 @@ You can add as many of the SMTP API methods as you want to a single large JSON s The above example is formatted for readability. Headers must be wrapped to keep the line length under 72. By RFC 821 no line can be longer than 1,000, so if you are going to generate this string yourself it is a good idea to make sure that you wrap it. ## Requirements and Limitations -While there is a hard limit of 10,000 addresses that can be sent to in a multiple recipient e-mail, it is best to split up large jobs to around 1,000 recipients, to better allow for the processing load to be distributed. Furthermore, if you have a large number of additional substitutions or sections in the headers, it is best to split the send into even smaller groups. +While there is a hard limit of 10,000 addresses that can be sent to in a multiple recipient e-mail, it is best to split up large jobs to around 1,000 recipients, to better allow for the processing load to be distributed. Furthermore, if you have numerous additional substitutions or sections in the headers, it is best to split the group into even smaller groups. # Settings (Filters) @@ -332,7 +332,7 @@ You can specify up to 25 groups to display. ``` ## Groups -You can find your group IDs by looking at the Group ID column in the Unsubscribe Groups UI, or by calling the [GET method](https://sendgrid.com/docs/API_Reference/Web_API_v3/Suppression_Management/groups.html#-GET) of the groups resource. +You can find your group IDs by looking at the Group ID column in the Unsubscribe Groups UI, or by calling the [GET method](https://sendgrid.com/docs/API_Reference/Web_API_v3/Suppression_Management/groups.html#-GET) of the group's resource. # Unique Arguments From d067a27966e013e0b10685238a73a2ee219f9b0d Mon Sep 17 00:00:00 2001 From: Ian Shorrock Date: Mon, 21 Sep 2020 16:19:54 -0600 Subject: [PATCH 071/112] docs: Add pull request info to CONTRIBUTING and README (#61) --- CONTRIBUTING.md | 7 +++++++ README.rst | 2 ++ 2 files changed, 9 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index afcc51e..64bbd95 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,6 +7,7 @@ Hello! Thank you for choosing to help contribute to one of the Twilio SendGrid o - [Testing](#testing) - [Style Guidelines & Naming Conventions](#style-guidelines-and-naming-conventions) - [Creating a Pull Request](#creating-a-pull-request) +- [Code Reviews](#code-reviews) ## Feature Request @@ -155,3 +156,9 @@ Please run your code through: 7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) with a clear title and description against the `development` branch. All tests must be passing before we will review the PR. + +## Code Reviews +If you can, please look at open PRs and review them. +Give feedback and help us merge these PRs much faster! +If you don't know how, GitHub has some great +[information on how to review a Pull Request](https://help.github.com/articles/about-pull-request-reviews/). diff --git a/README.rst b/README.rst index bc07001..515f954 100644 --- a/README.rst +++ b/README.rst @@ -85,6 +85,7 @@ Quick links: - `Feature Request`_ - `Bug Reports`_ - `Improvements to the Codebase`_ +- `Review Pull Requests`_ Local Setup of the Project ========================== @@ -117,6 +118,7 @@ License .. _Feature Request: https://github.com/sendgrid/smtpapi-python/blob/HEAD/CONTRIBUTING.md#feature-request .. _Bug Reports: https://github.com/sendgrid/smtpapi-python/blob/HEAD/CONTRIBUTING.md#submit-a-bug-report .. _Improvements to the Codebase: https://github.com/sendgrid/smtpapi-python/blob/HEAD/CONTRIBUTING.md#improvements-to-the-codebase +.. _Review Pull Requests: https://github.com/sendgrid/smtpapi-python/blob/HEAD/CONTRIBUTING.md#code-reviews) .. _The MIT License (MIT): https://github.com/sendgrid/smtpapi-python/blob/HEAD/LICENSE.md .. |Travis Badge| image:: https://travis-ci.org/sendgrid/smtpapi-python.svg?branch=main From 0e1bfe48ed5ac64baf463fd3eb8777a621b780ea Mon Sep 17 00:00:00 2001 From: Twilio Date: Mon, 28 Sep 2020 20:12:43 +0000 Subject: [PATCH 072/112] [Librarian] Version Bump --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43d3983..bc79638 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ # Change Log All the notable changes to this project will be documented in this file. +[2020-09-28] Version 0.4.6 +-------------------------- +**Library - Docs** +- [PR #57](https://github.com/sendgrid/smtpapi-python/pull/57): Few typos and grammatical mistake corrected. Thanks to [@yudhik11](https://github.com/yudhik11)! +- [PR #61](https://github.com/sendgrid/smtpapi-python/pull/61): Add pull request info to CONTRIBUTING and README. Thanks to [@shorrock](https://github.com/shorrock)! + + [2020-08-19] Version 0.4.5 -------------------------- **Library - Docs** From 041411b7861874543b874bff92d9025fbea69a58 Mon Sep 17 00:00:00 2001 From: Twilio Date: Mon, 28 Sep 2020 20:15:04 +0000 Subject: [PATCH 073/112] Release 0.4.6 --- VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION.txt b/VERSION.txt index 0bfccb0..ef52a64 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -0.4.5 +0.4.6 From a013aea1f154bb9677971ff9b54ef243a18a9408 Mon Sep 17 00:00:00 2001 From: Sam Harrison Date: Wed, 14 Oct 2020 15:53:28 -0500 Subject: [PATCH 074/112] chore: fix spelling typos --- FIRST_TIMERS.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/FIRST_TIMERS.md b/FIRST_TIMERS.md index 174f5d0..d977112 100644 --- a/FIRST_TIMERS.md +++ b/FIRST_TIMERS.md @@ -61,13 +61,13 @@ Before creating a pull request, make sure that you respect the repository's cons * [Node.js SDK](https://github.com/sendgrid/sendgrid-nodejs/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) * [Java SDK](https://github.com/sendgrid/sendgrid-java/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) * [Go SDK](https://github.com/sendgrid/sendgrid-go/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) -* [Python STMPAPI Client](https://github.com/sendgrid/smtpapi-python/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) -* [PHP STMPAPI Client](https://github.com/sendgrid/smtpapi-php/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) -* [C# STMPAPI Client](https://github.com/sendgrid/smtpapi-csharp/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) -* [Ruby STMPAPI Client](https://github.com/sendgrid/smtpapi-ruby/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) -* [Node.js STMPAPI Client](https://github.com/sendgrid/smtpapi-nodejs/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) -* [Java STMPAPI Client](https://github.com/sendgrid/smtpapi-java/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) -* [Go STMPAPI Client](https://github.com/sendgrid/smtpapi-go/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) +* [Python SMTPAPI Client](https://github.com/sendgrid/smtpapi-python/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) +* [PHP SMTPAPI Client](https://github.com/sendgrid/smtpapi-php/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) +* [C# SMTPAPI Client](https://github.com/sendgrid/smtpapi-csharp/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) +* [Ruby SMTPAPI Client](https://github.com/sendgrid/smtpapi-ruby/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) +* [Node.js SMTPAPI Client](https://github.com/sendgrid/smtpapi-nodejs/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) +* [Java SMTPAPI Client](https://github.com/sendgrid/smtpapi-java/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) +* [Go SMTPAPI Client](https://github.com/sendgrid/smtpapi-go/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) * [Python HTTP Client](https://github.com/sendgrid/python-http-client/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) * [PHP HTTP Client](https://github.com/sendgrid/php-http-client/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) * [C# HTTP Client](https://github.com/sendgrid/csharp-http-client/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) From 443fd0cc04b2decacf2ea12245dff0cddb24c009 Mon Sep 17 00:00:00 2001 From: Twilio Date: Thu, 15 Oct 2020 16:25:44 +0000 Subject: [PATCH 075/112] chore: update template files --- PULL_REQUEST_TEMPLATE.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md index a868180..89cac7f 100644 --- a/PULL_REQUEST_TEMPLATE.md +++ b/PULL_REQUEST_TEMPLATE.md @@ -19,13 +19,13 @@ Closes #2 A short description of what this PR does. ### Checklist -- [ ] I acknowledge that all my contributions will be made under the project's license +- [x] I acknowledge that all my contributions will be made under the project's license - [ ] I have made a material change to the repo (functionality, testing, spelling, grammar) -- [ ] I have read the [Contribution Guidelines](CONTRIBUTING.md) and my PR follows them +- [ ] I have read the [Contribution Guidelines](https://github.com/sendgrid/smtpapi-python/blob/main/CONTRIBUTING.md) and my PR follows them - [ ] I have titled the PR appropriately - [ ] I have updated my branch with the main branch - [ ] I have added tests that prove my fix is effective or that my feature works -- [ ] I have added necessary documentation about the functionality in the appropriate .md file +- [ ] I have added the necessary documentation about the functionality in the appropriate .md file - [ ] I have added inline documentation to the code I modified If you have questions, please file a [support ticket](https://twilio.com/help/contact), or create a GitHub Issue in this repository. From 783d411717740a7f49f757122f7b928a45266519 Mon Sep 17 00:00:00 2001 From: Twilio Date: Thu, 15 Oct 2020 16:35:34 +0000 Subject: [PATCH 076/112] chore: update template files --- PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md index 89cac7f..47ddaa8 100644 --- a/PULL_REQUEST_TEMPLATE.md +++ b/PULL_REQUEST_TEMPLATE.md @@ -28,4 +28,4 @@ A short description of what this PR does. - [ ] I have added the necessary documentation about the functionality in the appropriate .md file - [ ] I have added inline documentation to the code I modified -If you have questions, please file a [support ticket](https://twilio.com/help/contact), or create a GitHub Issue in this repository. +If you have questions, please file a [support ticket](https://support.sendgrid.com/hc/en-us), or create a GitHub Issue in this repository. From e7ea7b383a3cc68b6628016f36b9b0578e05ea67 Mon Sep 17 00:00:00 2001 From: Twilio Date: Thu, 15 Oct 2020 21:28:59 +0000 Subject: [PATCH 077/112] chore: update template files --- PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md index 47ddaa8..10cc132 100644 --- a/PULL_REQUEST_TEMPLATE.md +++ b/PULL_REQUEST_TEMPLATE.md @@ -28,4 +28,4 @@ A short description of what this PR does. - [ ] I have added the necessary documentation about the functionality in the appropriate .md file - [ ] I have added inline documentation to the code I modified -If you have questions, please file a [support ticket](https://support.sendgrid.com/hc/en-us), or create a GitHub Issue in this repository. +If you have questions, please file a [support ticket](https://support.sendgrid.com), or create a GitHub Issue in this repository. From c5d0a43130a2d16b04edb501d8192461c608e7f0 Mon Sep 17 00:00:00 2001 From: Twilio Date: Tue, 27 Oct 2020 21:34:48 +0000 Subject: [PATCH 078/112] chore: update template files --- LICENSE.md => LICENSE | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename LICENSE.md => LICENSE (100%) diff --git a/LICENSE.md b/LICENSE similarity index 100% rename from LICENSE.md rename to LICENSE From 8c97f01e072d59bfa2728fa9a18613e87a6f2411 Mon Sep 17 00:00:00 2001 From: Sam Harrison Date: Tue, 27 Oct 2020 16:42:34 -0500 Subject: [PATCH 079/112] chore: update license references --- MANIFEST.in | 2 +- README.rst | 4 ++-- test/__init__.py | 4 ++-- test/test_project.py | 6 ++---- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/MANIFEST.in b/MANIFEST.in index 9feef94..20d9d81 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,3 @@ -include README.rst LICENSE.md VERSION.txt +include README.rst LICENSE VERSION.txt recursive-include smtpapi *.py *.txt prune test diff --git a/README.rst b/README.rst index 515f954..81602ac 100644 --- a/README.rst +++ b/README.rst @@ -119,7 +119,7 @@ License .. _Bug Reports: https://github.com/sendgrid/smtpapi-python/blob/HEAD/CONTRIBUTING.md#submit-a-bug-report .. _Improvements to the Codebase: https://github.com/sendgrid/smtpapi-python/blob/HEAD/CONTRIBUTING.md#improvements-to-the-codebase .. _Review Pull Requests: https://github.com/sendgrid/smtpapi-python/blob/HEAD/CONTRIBUTING.md#code-reviews) -.. _The MIT License (MIT): https://github.com/sendgrid/smtpapi-python/blob/HEAD/LICENSE.md +.. _The MIT License (MIT): https://github.com/sendgrid/smtpapi-python/blob/HEAD/LICENSE .. |Travis Badge| image:: https://travis-ci.org/sendgrid/smtpapi-python.svg?branch=main :target: https://travis-ci.org/sendgrid/smtpapi-python @@ -136,4 +136,4 @@ License .. |GitHub contributors| image:: https://img.shields.io/github/contributors/sendgrid/smtpapi-python.svg :target: https://github.com/sendgrid/smtpapi-python/graphs/contributors .. |MIT Licensed| image:: https://img.shields.io/badge/license-MIT-blue.svg - :target: https://github.com/sendgrid/smtpapi-python/blob/HEAD/LICENSE.md + :target: https://github.com/sendgrid/smtpapi-python/blob/HEAD/LICENSE diff --git a/test/__init__.py b/test/__init__.py index 149d225..4f7a4c8 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -82,7 +82,7 @@ def test_drop_empty(self): self.assertEqual(self.dropsHeader, json.loads(header.json_string())) def test_license_year(self): - LICENSE_FILE = 'LICENSE.md' + LICENSE_FILE = 'LICENSE' copyright_line = '' with open(LICENSE_FILE, 'r') as f: for line in f: @@ -112,7 +112,7 @@ def setUp(self): './CHANGELOG.md', './CODE_OF_CONDUCT.md', './CONTRIBUTING.md', - ['./LICENSE.md', './LICENSE.txt'], + './LICENSE', './README.rst', './TROUBLESHOOTING.md', './USAGE.md', diff --git a/test/test_project.py b/test/test_project.py index fdd3684..5da99fa 100644 --- a/test/test_project.py +++ b/test/test_project.py @@ -50,11 +50,9 @@ def test_contributing(self): def test_issue_template(self): self.assertTrue(os.path.isfile('./ISSUE_TEMPLATE.md')) - # ./LICENSE.md + # ./LICENSE def test_license(self): - self.assertTrue( - os.path.isfile('./LICENSE.md') or os.path.isfile('./LICENSE.txt') - ) + self.assertTrue(os.path.isfile('./LICENSE')) # ./PULL_REQUEST_TEMPLATE.md def test_pr_template(self): From 38483cf5238c532fe2524b678b2bb055c370c7d8 Mon Sep 17 00:00:00 2001 From: Elmer Thomas Date: Fri, 30 Oct 2020 14:17:13 -0700 Subject: [PATCH 080/112] chore: update badge --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 81602ac..ce83fb2 100644 --- a/README.rst +++ b/README.rst @@ -121,8 +121,8 @@ License .. _Review Pull Requests: https://github.com/sendgrid/smtpapi-python/blob/HEAD/CONTRIBUTING.md#code-reviews) .. _The MIT License (MIT): https://github.com/sendgrid/smtpapi-python/blob/HEAD/LICENSE -.. |Travis Badge| image:: https://travis-ci.org/sendgrid/smtpapi-python.svg?branch=main - :target: https://travis-ci.org/sendgrid/smtpapi-python +.. |Travis Badge| image:: https://travis-ci.com/sendgrid/smtpapi-python.svg?branch=main + :target: https://travis-ci.com/sendgrid/smtpapi-python .. |Email Notifications Badge| image:: https://dx.sendgrid.com/badge/python :target: https://dx.sendgrid.com/newsletter/python .. |Twitter Follow| image:: https://img.shields.io/twitter/follow/sendgrid.svg?style=social&label=Follow From 588431cf0269e129a21ea2eaae39bf1254231319 Mon Sep 17 00:00:00 2001 From: Georgia Martha Sari Date: Fri, 20 Nov 2020 04:49:45 +0700 Subject: [PATCH 081/112] chore: Add .codeclimate.yml and update test/__init__.py (#63) --- .codeclimate.yml | 25 +++++++++++++++++-------- test/__init__.py | 9 ++++++--- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/.codeclimate.yml b/.codeclimate.yml index 3d89c6a..1d04a03 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -1,4 +1,5 @@ -engines: +# Python Engines +engines: duplication: enabled: true config: @@ -6,14 +7,22 @@ engines: - python fixme: enabled: true - markdownlint: - enabled: true pep8: + enabled: true + radon: enabled: true - radon: - enabled: true + markdownlint: + enabled: true + +# Ratings ratings: paths: - - "**.inc" - - "**.module" - - "**.py" \ No newline at end of file + - "**.py" # default for enable Radon analysis + - "**.md" + - "**.inc" + - "**.module" + +# List the files or directories excluded from analysis. +exclude_paths: +- dist/** +- build/** diff --git a/test/__init__.py b/test/__init__.py index 4f7a4c8..00ff8b8 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -1,11 +1,15 @@ import decimal import json import os -import unittest import datetime from smtpapi import SMTPAPIHeader +try: + import unittest2 as unittest +except ImportError: + import unittest + class TestSMTPAPI(unittest.TestCase): @@ -101,8 +105,7 @@ class TestRepository(unittest.TestCase): def setUp(self): self.required_files = [ - ['./Dockerfile', './docker/Dockerfile'], - ['./docker-compose.yml', './docker/docker-compose.yml'], + './Dockerfile', './.codeclimate.yml', './.env_sample', './ISSUE_TEMPLATE.md', From aff9341b97fbd3afb66dcb51dc59d348b750d215 Mon Sep 17 00:00:00 2001 From: Twilio Date: Wed, 2 Dec 2020 19:54:52 +0000 Subject: [PATCH 082/112] [Librarian] Version Bump --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc79638..140adf9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Change Log All the notable changes to this project will be documented in this file. +[2020-12-02] Version 0.4.7 +-------------------------- +**Library - Chore** +- [PR #63](https://github.com/sendgrid/smtpapi-python/pull/63): Add .codeclimate.yml and update test/__init__.py. Thanks to [@geomars](https://github.com/geomars)! + + [2020-09-28] Version 0.4.6 -------------------------- **Library - Docs** From 036c8ad65236797aa034bd19bdb62aac9bc58d79 Mon Sep 17 00:00:00 2001 From: Twilio Date: Wed, 2 Dec 2020 19:56:18 +0000 Subject: [PATCH 083/112] Release 0.4.7 --- VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION.txt b/VERSION.txt index ef52a64..f905682 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -0.4.6 +0.4.7 From ecc3b52b72b9051430e790a178fa1b4d0d92ba12 Mon Sep 17 00:00:00 2001 From: Twilio Date: Wed, 6 Jan 2021 18:18:56 +0000 Subject: [PATCH 084/112] chore: update template files --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 29aba59..e5439a9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (C) 2020, Twilio SendGrid, Inc. +Copyright (C) 2021, Twilio SendGrid, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in From 47e455a60bd2efd6f71a1b42313f8190e1f40bd7 Mon Sep 17 00:00:00 2001 From: Twilio Date: Fri, 12 Mar 2021 20:35:59 +0000 Subject: [PATCH 085/112] chore: update template files --- .github/ISSUE_TEMPLATE/config.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/config.yml diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..e94b1ca --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,10 @@ +contact_links: + - name: Twilio SendGrid Support + url: https://support.sendgrid.com + about: Get Support + - name: Stack Overflow + url: https://stackoverflow.com/questions/tagged/smtpapi-python+or+sendgrid+python + about: Ask questions on Stack Overflow + - name: Documentation + url: https://sendgrid.com/docs/for-developers/ + about: View Reference Documentation From a208e69a251b90c11d34586618b398547dee8757 Mon Sep 17 00:00:00 2001 From: Elise Shanholtz Date: Fri, 23 Apr 2021 11:12:50 -0700 Subject: [PATCH 086/112] chore: rotate key --- .travis.yml | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7f2cc66..4658527 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,26 +1,26 @@ -dist: xenial # required for Python >= 3.7 +dist: xenial language: python python: - - '2.7' - - '3.4' - - '3.5' - - '3.6' - - '3.7' - - '3.8' +- '2.7' +- '3.4' +- '3.5' +- '3.6' +- '3.7' +- '3.8' install: - - make install - - make test-install - - pip install codecov +- make install +- make test-install +- pip install codecov script: - - make test - - . venv/bin/activate; coverage run test/__init__.py - - . venv/bin/activate; flake8 --statistics --count +- make test +- ". venv/bin/activate; coverage run test/__init__.py" +- ". venv/bin/activate; flake8 --statistics --count" after_success: - - codecov +- codecov deploy: provider: pypi - user: "__token__" - password: $PYPI_TOKEN + user: __token__ + password: "$PYPI_TOKEN" skip_cleanup: true distributions: sdist bdist_wheel on: @@ -28,7 +28,6 @@ deploy: condition: "$TRAVIS_TEST_RESULT = 0" tags: true python: '3.6' - notifications: slack: if: branch = main @@ -36,4 +35,4 @@ notifications: on_success: never on_failure: change rooms: - - secure: GBYjICnJwGDgb3CM8STuWXESuR2hUZHkl1oCQC8Vd9WmId281AeMflMw3GIo9Ay+uY0+TXUIUihxS61SuX9T/LP4lV7b47dH9BzQ7IbVVfCaOtgq7KmkD4dCeaA8X5zvTktrpMcS1b2WNKKaExCkuetj80dJRSX5vw1s+zl3o5U= + secure: jdCNaDBFGJTicPHjoCzfGifivx0O5qO32wRTJKfi6UAFFADa58txxQCG1Zj762neJUb7G7mZXmWVtg11y9oInxrRQkqpTi5zCNAFSBbkMVRPnl/f9oRS2R50XCMj+ONxy52de9315WPUSDPmU+qDtWdwz5UCiOQKmyl8FcXDw68= From b7c38406eaeee1e146b408175b93d6b30ef42754 Mon Sep 17 00:00:00 2001 From: Elmer Thomas Date: Wed, 16 Jun 2021 16:40:02 -0700 Subject: [PATCH 087/112] update slack token --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4658527..d367065 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,4 +35,4 @@ notifications: on_success: never on_failure: change rooms: - secure: jdCNaDBFGJTicPHjoCzfGifivx0O5qO32wRTJKfi6UAFFADa58txxQCG1Zj762neJUb7G7mZXmWVtg11y9oInxrRQkqpTi5zCNAFSBbkMVRPnl/f9oRS2R50XCMj+ONxy52de9315WPUSDPmU+qDtWdwz5UCiOQKmyl8FcXDw68= + secure: btNfACha/8fuIMDdeUyMywSryI/XGm5ZE+cUEKo6l1Z6CX4VcnMCjNPGbj9GEL6jk0PDxBbdyEslci3dzt5ApOBMFg7OWTcPxDKoKNLHnUvEe2VPblZN0O1N/RAM3OPkhpbToo/uyZmnHIqTmOT51RfA1mkUYtu5YgPF+bwjhv0= From c422b5c9d003f3f89ab36b16a62b7488d467a2fe Mon Sep 17 00:00:00 2001 From: Elmer Thomas Date: Wed, 21 Jul 2021 15:31:24 -0700 Subject: [PATCH 088/112] Remove newsletter badge --- README.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.rst b/README.rst index ce83fb2..f8c4769 100644 --- a/README.rst +++ b/README.rst @@ -2,7 +2,7 @@ :target: https://www.sendgrid.com :alt: SendGrid Logo -|Travis Badge| |Email Notifications Badge| |Twitter Follow| |Codecov branch| |Python Versions| |PyPI Version| |GitHub contributors| |MIT Licensed| +|Travis Badge| |Twitter Follow| |Codecov branch| |Python Versions| |PyPI Version| |GitHub contributors| |MIT Licensed| **This module helps build SendGrid's SMTP API headers.** @@ -123,8 +123,6 @@ License .. |Travis Badge| image:: https://travis-ci.com/sendgrid/smtpapi-python.svg?branch=main :target: https://travis-ci.com/sendgrid/smtpapi-python -.. |Email Notifications Badge| image:: https://dx.sendgrid.com/badge/python - :target: https://dx.sendgrid.com/newsletter/python .. |Twitter Follow| image:: https://img.shields.io/twitter/follow/sendgrid.svg?style=social&label=Follow :target: https://twitter.com/sendgrid .. |Codecov branch| image:: https://img.shields.io/codecov/c/github/sendgrid/smtpapi-python/main.svg?style=flat-square&label=Codecov+Coverage From 779f6baa8d5ccc6ea524a2b8a8e9b170d288d1e8 Mon Sep 17 00:00:00 2001 From: Shwetha Radhakrishna Date: Thu, 9 Sep 2021 13:42:11 -0500 Subject: [PATCH 089/112] chore: test againt python v3.9 (#106) --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index d367065..c100c79 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,7 @@ python: - '3.6' - '3.7' - '3.8' +- '3.9' install: - make install - make test-install From dce3ff14a99769aa1386b117c0687351337711dd Mon Sep 17 00:00:00 2001 From: Twilio Date: Wed, 22 Sep 2021 18:42:38 +0000 Subject: [PATCH 090/112] [Librarian] Version Bump --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 140adf9..a7785f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Change Log All the notable changes to this project will be documented in this file. +[2021-09-22] Version 0.4.8 +-------------------------- +**Library - Chore** +- [PR #106](https://github.com/sendgrid/smtpapi-python/pull/106): test against python v3.9. Thanks to [@shwetha-manvinkurke](https://github.com/shwetha-manvinkurke)! + + [2020-12-02] Version 0.4.7 -------------------------- **Library - Chore** From 4339c9a4d39b18e9c7b8e561027b3577416d2199 Mon Sep 17 00:00:00 2001 From: Twilio Date: Wed, 22 Sep 2021 18:44:09 +0000 Subject: [PATCH 091/112] Release 0.4.8 --- VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION.txt b/VERSION.txt index f905682..cb498ab 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -0.4.7 +0.4.8 From cad19b93eb79be3bb4031bea3b9421ccebb5bb64 Mon Sep 17 00:00:00 2001 From: Jennifer Mah <42650198+JenniferMah@users.noreply.github.com> Date: Wed, 1 Dec 2021 11:45:07 -0800 Subject: [PATCH 092/112] chore: migrate to GitHub Actions (#107) --- .codeclimate.yml | 28 -------------------- .github/workflows/release.yml | 50 +++++++++++++++++++++++++++++++++++ .github/workflows/tests.yml | 50 +++++++++++++++++++++++++++++++++++ .travis.yml | 39 --------------------------- Makefile | 3 +++ README.rst | 6 ++--- test/__init__.py | 2 -- test/test_project.py | 8 ------ 8 files changed, 106 insertions(+), 80 deletions(-) delete mode 100644 .codeclimate.yml create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/tests.yml delete mode 100644 .travis.yml diff --git a/.codeclimate.yml b/.codeclimate.yml deleted file mode 100644 index 1d04a03..0000000 --- a/.codeclimate.yml +++ /dev/null @@ -1,28 +0,0 @@ -# Python Engines -engines: - duplication: - enabled: true - config: - languages: - - python - fixme: - enabled: true - pep8: - enabled: true - radon: - enabled: true - markdownlint: - enabled: true - -# Ratings -ratings: - paths: - - "**.py" # default for enable Radon analysis - - "**.md" - - "**.inc" - - "**.module" - -# List the files or directories excluded from analysis. -exclude_paths: -- dist/** -- build/** diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..6ac5355 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,50 @@ +name: Publish Python distributions +on: + push: + tags: + - '*' + workflow_dispatch: + +jobs: + release: + name: Release + runs-on: ubuntu-latest + steps: + - name: Checkout sendgrid-python-smtpapi + uses: actions/checkout@v2 + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.6' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install build + pip install wheel + python setup.py sdist bdist_wheel + + - name: Publish package to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + user: __token__ + password: ${{ secrets.PYPI_TOKEN }} + + notify-on-failure: + name: Slack notify on failure + if: ${{ failure() }} + needs: [ release ] + runs-on: ubuntu-latest + steps: + - uses: rtCamp/action-slack-notify@v2 + env: + SLACK_COLOR: 'danger' + SLACK_ICON_EMOJI: ':github:' + SLACK_MESSAGE: ${{ format('Failed to release {1}{3} {0}/{1}/actions/runs/{2}', github.server_url, github.repository, github.run_id, ':') }} + SLACK_TITLE: Release Failure + SLACK_USERNAME: GitHub Actions + SLACK_MSG_AUTHOR: twilio-dx + SLACK_FOOTER: Posted automatically using GitHub Actions + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} + MSG_MINIMAL: true diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..2c558f1 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,50 @@ +name: Run Tests +on: + push: + branches: [ '*' ] + pull_request: + branches: [ main ] + schedule: + # Run automatically at 8AM PST Monday-Friday + - cron: '0 15 * * 1-5' + workflow_dispatch: + +jobs: + tests: + name: Run Tests + runs-on: ubuntu-latest + timeout-minutes: 20 + strategy: + matrix: + python-version: [ '2.7', '3.5', '3.6', '3.7', '3.8', '3.9' ] + steps: + - name: Checkout sendgrid-python-smtpapi + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + + - name: Build & Test + run: make install test-install test + + notify-on-failure: + name: Slack notify on failure + if: ${{ failure() && github.ref == 'refs/heads/main' && github.event_name != 'pull_request' }} + needs: [ tests ] + runs-on: ubuntu-latest + steps: + - uses: rtCamp/action-slack-notify@v2 + env: + SLACK_COLOR: 'danger' + SLACK_ICON_EMOJI: ':github:' + SLACK_MESSAGE: ${{ format('Failed running build on {1}{3} {0}/{1}/actions/runs/{2}', github.server_url, github.repository, github.run_id, ':') }} + SLACK_TITLE: Build Failure + SLACK_USERNAME: GitHub Actions + SLACK_MSG_AUTHOR: twilio-dx + SLACK_FOOTER: Posted automatically using GitHub Actions + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} + MSG_MINIMAL: true diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index c100c79..0000000 --- a/.travis.yml +++ /dev/null @@ -1,39 +0,0 @@ -dist: xenial -language: python -python: -- '2.7' -- '3.4' -- '3.5' -- '3.6' -- '3.7' -- '3.8' -- '3.9' -install: -- make install -- make test-install -- pip install codecov -script: -- make test -- ". venv/bin/activate; coverage run test/__init__.py" -- ". venv/bin/activate; flake8 --statistics --count" -after_success: -- codecov -deploy: - provider: pypi - user: __token__ - password: "$PYPI_TOKEN" - skip_cleanup: true - distributions: sdist bdist_wheel - on: - branch: main - condition: "$TRAVIS_TEST_RESULT = 0" - tags: true - python: '3.6' -notifications: - slack: - if: branch = main - on_pull_requests: false - on_success: never - on_failure: change - rooms: - secure: btNfACha/8fuIMDdeUyMywSryI/XGm5ZE+cUEKo6l1Z6CX4VcnMCjNPGbj9GEL6jk0PDxBbdyEslci3dzt5ApOBMFg7OWTcPxDKoKNLHnUvEe2VPblZN0O1N/RAM3OPkhpbToo/uyZmnHIqTmOT51RfA1mkUYtu5YgPF+bwjhv0= diff --git a/Makefile b/Makefile index 7cff157..3e3bb1a 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ venv: @python --version || (echo "Python is not installed, please install Python 2 or Python 3"; exit 1); + pip install virtualenv virtualenv --python=python venv install: venv @@ -13,6 +14,8 @@ test-install: test: . venv/bin/activate; python -m unittest discover -v . venv/bin/activate; python test/__init__.py + . venv/bin/activate; flake8 --statistics --count + . venv/bin/activate; coverage run test/__init__.py clean: nopyc rm -rf venv diff --git a/README.rst b/README.rst index f8c4769..d1fd087 100644 --- a/README.rst +++ b/README.rst @@ -2,7 +2,7 @@ :target: https://www.sendgrid.com :alt: SendGrid Logo -|Travis Badge| |Twitter Follow| |Codecov branch| |Python Versions| |PyPI Version| |GitHub contributors| |MIT Licensed| +|Tests Badge| |Twitter Follow| |Codecov branch| |Python Versions| |PyPI Version| |GitHub contributors| |MIT Licensed| **This module helps build SendGrid's SMTP API headers.** @@ -121,8 +121,8 @@ License .. _Review Pull Requests: https://github.com/sendgrid/smtpapi-python/blob/HEAD/CONTRIBUTING.md#code-reviews) .. _The MIT License (MIT): https://github.com/sendgrid/smtpapi-python/blob/HEAD/LICENSE -.. |Travis Badge| image:: https://travis-ci.com/sendgrid/smtpapi-python.svg?branch=main - :target: https://travis-ci.com/sendgrid/smtpapi-python +.. |Tests Badge| image:: https://github.com/sendgrid/smtpapi-python/actions/workflows/tests.yml/badge.svg + :target: https://github.com/sendgrid/smtpapi-python/actions/workflows/tests.yml .. |Twitter Follow| image:: https://img.shields.io/twitter/follow/sendgrid.svg?style=social&label=Follow :target: https://twitter.com/sendgrid .. |Codecov branch| image:: https://img.shields.io/codecov/c/github/sendgrid/smtpapi-python/main.svg?style=flat-square&label=Codecov+Coverage diff --git a/test/__init__.py b/test/__init__.py index 00ff8b8..d195960 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -106,12 +106,10 @@ def setUp(self): self.required_files = [ './Dockerfile', - './.codeclimate.yml', './.env_sample', './ISSUE_TEMPLATE.md', './PULL_REQUEST_TEMPLATE.md', './.gitignore', - './.travis.yml', './CHANGELOG.md', './CODE_OF_CONDUCT.md', './CONTRIBUTING.md', diff --git a/test/test_project.py b/test/test_project.py index 5da99fa..5de7ec9 100644 --- a/test/test_project.py +++ b/test/test_project.py @@ -26,14 +26,6 @@ def test_env(self): def test_gitignore(self): self.assertTrue(os.path.isfile('./.gitignore')) - # ./.travis.yml - def test_travis(self): - self.assertTrue(os.path.isfile('./.travis.yml')) - - # ./.codeclimate.yml - def test_codeclimate(self): - self.assertTrue(os.path.isfile('./.codeclimate.yml')) - # ./CHANGELOG.md def test_changelog(self): self.assertTrue(os.path.isfile('./CHANGELOG.md')) From c504defafab9481f2b920fba6e1b2da51cb6b21f Mon Sep 17 00:00:00 2001 From: Twilio Date: Wed, 1 Dec 2021 21:10:21 +0000 Subject: [PATCH 093/112] [Librarian] Version Bump --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a7785f0..4dd5d62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Change Log All the notable changes to this project will be documented in this file. +[2021-12-01] Version 0.4.9 +-------------------------- +**Library - Chore** +- [PR #107](https://github.com/sendgrid/smtpapi-python/pull/107): migrate to GitHub Actions. Thanks to [@JenniferMah](https://github.com/JenniferMah)! + + [2021-09-22] Version 0.4.8 -------------------------- **Library - Chore** From 68658246f7818b48547d8ed141b1519a4e532b0b Mon Sep 17 00:00:00 2001 From: Twilio Date: Wed, 1 Dec 2021 21:11:12 +0000 Subject: [PATCH 094/112] Release 0.4.9 --- VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION.txt b/VERSION.txt index cb498ab..76914dd 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -0.4.8 +0.4.9 From b3997ad258d0af90ddb15c1fec25f8ebd1e56260 Mon Sep 17 00:00:00 2001 From: Jennifer Mah <42650198+JenniferMah@users.noreply.github.com> Date: Tue, 4 Jan 2022 15:07:14 -0700 Subject: [PATCH 095/112] chore: update license year (#108) --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index e5439a9..5db04ff 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (C) 2021, Twilio SendGrid, Inc. +Copyright (C) 2022, Twilio SendGrid, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in From 30567a435631d437cac7a83a620044cfda3abc96 Mon Sep 17 00:00:00 2001 From: Twilio Date: Wed, 12 Jan 2022 19:20:19 +0000 Subject: [PATCH 096/112] [Librarian] Version Bump --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4dd5d62..cb69be0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Change Log All the notable changes to this project will be documented in this file. +[2022-01-12] Version 0.4.10 +--------------------------- +**Library - Chore** +- [PR #108](https://github.com/sendgrid/smtpapi-python/pull/108): update license year. Thanks to [@JenniferMah](https://github.com/JenniferMah)! + + [2021-12-01] Version 0.4.9 -------------------------- **Library - Chore** From 2cdc080d2e8a102a8e8f7a19bb40e9993848f54e Mon Sep 17 00:00:00 2001 From: Twilio Date: Wed, 12 Jan 2022 19:21:16 +0000 Subject: [PATCH 097/112] Release 0.4.10 --- VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION.txt b/VERSION.txt index 76914dd..e8423da 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -0.4.9 +0.4.10 From 5049dc156254e5c29960128ebe468794095b990a Mon Sep 17 00:00:00 2001 From: Hunga1 Date: Thu, 3 Feb 2022 13:25:48 -0700 Subject: [PATCH 098/112] chore: merge test and deploy gh action workflows (#109) --- .github/workflows/release.yml | 50 ------------------ .github/workflows/test-and-deploy.yml | 76 +++++++++++++++++++++++++++ .github/workflows/tests.yml | 50 ------------------ README.rst | 6 +-- 4 files changed, 79 insertions(+), 103 deletions(-) delete mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/test-and-deploy.yml delete mode 100644 .github/workflows/tests.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 6ac5355..0000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: Publish Python distributions -on: - push: - tags: - - '*' - workflow_dispatch: - -jobs: - release: - name: Release - runs-on: ubuntu-latest - steps: - - name: Checkout sendgrid-python-smtpapi - uses: actions/checkout@v2 - - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: '3.6' - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install build - pip install wheel - python setup.py sdist bdist_wheel - - - name: Publish package to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 - with: - user: __token__ - password: ${{ secrets.PYPI_TOKEN }} - - notify-on-failure: - name: Slack notify on failure - if: ${{ failure() }} - needs: [ release ] - runs-on: ubuntu-latest - steps: - - uses: rtCamp/action-slack-notify@v2 - env: - SLACK_COLOR: 'danger' - SLACK_ICON_EMOJI: ':github:' - SLACK_MESSAGE: ${{ format('Failed to release {1}{3} {0}/{1}/actions/runs/{2}', github.server_url, github.repository, github.run_id, ':') }} - SLACK_TITLE: Release Failure - SLACK_USERNAME: GitHub Actions - SLACK_MSG_AUTHOR: twilio-dx - SLACK_FOOTER: Posted automatically using GitHub Actions - SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} - MSG_MINIMAL: true diff --git a/.github/workflows/test-and-deploy.yml b/.github/workflows/test-and-deploy.yml new file mode 100644 index 0000000..236dce3 --- /dev/null +++ b/.github/workflows/test-and-deploy.yml @@ -0,0 +1,76 @@ +name: Test and Deploy +on: + push: + branches: [ '*' ] + tags: [ '*' ] + pull_request: + branches: [ main ] + schedule: + # Run automatically at 8AM PST Monday-Friday + - cron: '0 15 * * 1-5' + workflow_dispatch: + +jobs: + test: + name: Test + runs-on: ubuntu-latest + timeout-minutes: 20 + strategy: + matrix: + python-version: [ '2.7', '3.5', '3.6', '3.7', '3.8', '3.9' ] + steps: + - name: Checkout sendgrid-python-smtpapi + uses: actions/checkout@v2 + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + + - name: Build & Test + run: make install test-install test + + deploy: + name: Deploy + if: success() && github.ref_type == 'tag' + needs: [ test ] + runs-on: ubuntu-latest + steps: + - name: Checkout sendgrid-python-smtpapi + uses: actions/checkout@v2 + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.6' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install build + pip install wheel + python setup.py sdist bdist_wheel + + - name: Publish package to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + user: __token__ + password: ${{ secrets.PYPI_TOKEN }} + + notify-on-failure: + name: Slack notify on failure + if: failure() && github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || github.ref_type == 'tag') + needs: [ test, deploy ] + runs-on: ubuntu-latest + steps: + - uses: rtCamp/action-slack-notify@v2 + env: + SLACK_COLOR: failure + SLACK_ICON_EMOJI: ':github:' + SLACK_MESSAGE: ${{ format('Test *{0}*, Deploy *{1}*, {2}/{3}/actions/runs/{4}', needs.test.result, needs.deploy.result, github.server_url, github.repository, github.run_id) }} + SLACK_TITLE: Action Failure - ${{ github.repository }} + SLACK_USERNAME: GitHub Actions + SLACK_MSG_AUTHOR: twilio-dx + SLACK_FOOTER: Posted automatically using GitHub Actions + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} + MSG_MINIMAL: true diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml deleted file mode 100644 index 2c558f1..0000000 --- a/.github/workflows/tests.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: Run Tests -on: - push: - branches: [ '*' ] - pull_request: - branches: [ main ] - schedule: - # Run automatically at 8AM PST Monday-Friday - - cron: '0 15 * * 1-5' - workflow_dispatch: - -jobs: - tests: - name: Run Tests - runs-on: ubuntu-latest - timeout-minutes: 20 - strategy: - matrix: - python-version: [ '2.7', '3.5', '3.6', '3.7', '3.8', '3.9' ] - steps: - - name: Checkout sendgrid-python-smtpapi - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - - name: Build & Test - run: make install test-install test - - notify-on-failure: - name: Slack notify on failure - if: ${{ failure() && github.ref == 'refs/heads/main' && github.event_name != 'pull_request' }} - needs: [ tests ] - runs-on: ubuntu-latest - steps: - - uses: rtCamp/action-slack-notify@v2 - env: - SLACK_COLOR: 'danger' - SLACK_ICON_EMOJI: ':github:' - SLACK_MESSAGE: ${{ format('Failed running build on {1}{3} {0}/{1}/actions/runs/{2}', github.server_url, github.repository, github.run_id, ':') }} - SLACK_TITLE: Build Failure - SLACK_USERNAME: GitHub Actions - SLACK_MSG_AUTHOR: twilio-dx - SLACK_FOOTER: Posted automatically using GitHub Actions - SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} - MSG_MINIMAL: true diff --git a/README.rst b/README.rst index d1fd087..10d386b 100644 --- a/README.rst +++ b/README.rst @@ -2,7 +2,7 @@ :target: https://www.sendgrid.com :alt: SendGrid Logo -|Tests Badge| |Twitter Follow| |Codecov branch| |Python Versions| |PyPI Version| |GitHub contributors| |MIT Licensed| +|Test and Deploy Badge| |Twitter Follow| |Codecov branch| |Python Versions| |PyPI Version| |GitHub contributors| |MIT Licensed| **This module helps build SendGrid's SMTP API headers.** @@ -121,8 +121,8 @@ License .. _Review Pull Requests: https://github.com/sendgrid/smtpapi-python/blob/HEAD/CONTRIBUTING.md#code-reviews) .. _The MIT License (MIT): https://github.com/sendgrid/smtpapi-python/blob/HEAD/LICENSE -.. |Tests Badge| image:: https://github.com/sendgrid/smtpapi-python/actions/workflows/tests.yml/badge.svg - :target: https://github.com/sendgrid/smtpapi-python/actions/workflows/tests.yml +.. |Test and Deploy Badge| image:: https://github.com/sendgrid/smtpapi-python/actions/workflows/test-and-deploy.yml/badge.svg + :target: https://github.com/sendgrid/smtpapi-python/actions/workflows/test-and-deploy.yml .. |Twitter Follow| image:: https://img.shields.io/twitter/follow/sendgrid.svg?style=social&label=Follow :target: https://twitter.com/sendgrid .. |Codecov branch| image:: https://img.shields.io/codecov/c/github/sendgrid/smtpapi-python/main.svg?style=flat-square&label=Codecov+Coverage From 369194c1c281ba6302bd9571c8b102db501b0501 Mon Sep 17 00:00:00 2001 From: Shwetha Radhakrishna Date: Thu, 3 Feb 2022 17:06:31 -0600 Subject: [PATCH 099/112] chore: add gh release to workflow (#110) --- .github/workflows/test-and-deploy.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-and-deploy.yml b/.github/workflows/test-and-deploy.yml index 236dce3..74df983 100644 --- a/.github/workflows/test-and-deploy.yml +++ b/.github/workflows/test-and-deploy.yml @@ -29,7 +29,7 @@ jobs: - name: Build & Test run: make install test-install test - + deploy: name: Deploy if: success() && github.ref_type == 'tag' @@ -51,12 +51,19 @@ jobs: pip install wheel python setup.py sdist bdist_wheel + - name: Create GitHub Release + uses: sendgrid/dx-automator/actions/release@main + with: + footer: '**[pypi](https://pypi.org/project/smtpapi/${version})**' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Publish package to PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: user: __token__ password: ${{ secrets.PYPI_TOKEN }} - + notify-on-failure: name: Slack notify on failure if: failure() && github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || github.ref_type == 'tag') From febae3a85640a0c4a7ebd7f324d9fa6648aa3afd Mon Sep 17 00:00:00 2001 From: childish-sambino Date: Tue, 8 Feb 2022 09:14:16 -0600 Subject: [PATCH 100/112] chore: upgrade supported language versions (#111) --- .github/workflows/test-and-deploy.yml | 4 ++-- setup.py | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-and-deploy.yml b/.github/workflows/test-and-deploy.yml index 74df983..a73e81b 100644 --- a/.github/workflows/test-and-deploy.yml +++ b/.github/workflows/test-and-deploy.yml @@ -17,7 +17,7 @@ jobs: timeout-minutes: 20 strategy: matrix: - python-version: [ '2.7', '3.5', '3.6', '3.7', '3.8', '3.9' ] + python-version: [ '2.7', '3.5', '3.6', '3.7', '3.8', '3.9', '3.10' ] steps: - name: Checkout sendgrid-python-smtpapi uses: actions/checkout@v2 @@ -42,7 +42,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v2 with: - python-version: '3.6' + python-version: '3.10' - name: Install dependencies run: | diff --git a/setup.py b/setup.py index 50b5a32..1777899 100644 --- a/setup.py +++ b/setup.py @@ -31,5 +31,7 @@ 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', ], ) From 5cc396040a8d65fab5ba07a81d73f57ee757af26 Mon Sep 17 00:00:00 2001 From: Twilio Date: Wed, 9 Feb 2022 14:49:26 -0800 Subject: [PATCH 101/112] [Librarian] Version Bump --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cb69be0..3e0f4d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,14 @@ # Change Log All the notable changes to this project will be documented in this file. +[2022-02-09] Version 0.4.11 +--------------------------- +**Library - Chore** +- [PR #111](https://github.com/sendgrid/smtpapi-python/pull/111): upgrade supported language versions. Thanks to [@childish-sambino](https://github.com/childish-sambino)! +- [PR #110](https://github.com/sendgrid/smtpapi-python/pull/110): add gh release to workflow. Thanks to [@shwetha-manvinkurke](https://github.com/shwetha-manvinkurke)! +- [PR #109](https://github.com/sendgrid/smtpapi-python/pull/109): merge test and deploy gh action workflows. Thanks to [@Hunga1](https://github.com/Hunga1)! + + [2022-01-12] Version 0.4.10 --------------------------- **Library - Chore** From fb379c7270de9abcba76c761f7c9f201b9afbf32 Mon Sep 17 00:00:00 2001 From: Twilio Date: Wed, 9 Feb 2022 14:49:27 -0800 Subject: [PATCH 102/112] Release 0.4.11 --- VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION.txt b/VERSION.txt index e8423da..5f749c1 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -0.4.10 +0.4.11 From 641cbeea02976b294092107175ae1af377d45249 Mon Sep 17 00:00:00 2001 From: Elise Shanholtz Date: Mon, 28 Feb 2022 12:54:11 -0800 Subject: [PATCH 103/112] chore: push Datadog Release Metric upon deploy success (#112) --- .github/workflows/test-and-deploy.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/test-and-deploy.yml b/.github/workflows/test-and-deploy.yml index a73e81b..9638a03 100644 --- a/.github/workflows/test-and-deploy.yml +++ b/.github/workflows/test-and-deploy.yml @@ -64,6 +64,11 @@ jobs: user: __token__ password: ${{ secrets.PYPI_TOKEN }} + - name: Submit metric to Datadog + uses: sendgrid/dx-automator/actions/datadog-release-metric@main + env: + DD_API_KEY: ${{ secrets.DATADOG_API_KEY }} + notify-on-failure: name: Slack notify on failure if: failure() && github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || github.ref_type == 'tag') From 22fd9a9f05fc5abc6bdd705f9340f2facb724eb7 Mon Sep 17 00:00:00 2001 From: Twilio Date: Wed, 9 Mar 2022 12:21:53 -0800 Subject: [PATCH 104/112] [Librarian] Version Bump --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e0f4d9..6d884e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Change Log All the notable changes to this project will be documented in this file. +[2022-03-09] Version 0.4.12 +--------------------------- +**Library - Chore** +- [PR #112](https://github.com/sendgrid/smtpapi-python/pull/112): push Datadog Release Metric upon deploy success. Thanks to [@eshanholtz](https://github.com/eshanholtz)! + + [2022-02-09] Version 0.4.11 --------------------------- **Library - Chore** From 289130cf884f6f27ae7778564c901f1f887f1a6a Mon Sep 17 00:00:00 2001 From: Twilio Date: Wed, 9 Mar 2022 12:21:54 -0800 Subject: [PATCH 105/112] Release 0.4.12 --- VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION.txt b/VERSION.txt index 5f749c1..75274d8 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -0.4.11 +0.4.12 From 9c89dfa7cebf6701ffab2dde32978953e6cc170a Mon Sep 17 00:00:00 2001 From: Sam Harrison Date: Thu, 24 Mar 2022 10:48:11 -0500 Subject: [PATCH 106/112] chore: remove outdated announcements --- README.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.rst b/README.rst index 10d386b..21716ff 100644 --- a/README.rst +++ b/README.rst @@ -10,8 +10,6 @@ Learn more about the SMTP API at `SendGrid documentation`_. Announcements ============= -**The default branch name for this repository has been changed to `main` as of 07/27/2020.** - All the updates to this module are documented in our `CHANGELOG`_. Table of Contents From 1e4e71cfff7318c57d2fabe0db219fff10bc07a9 Mon Sep 17 00:00:00 2001 From: Sam Harrison Date: Fri, 25 Mar 2022 13:39:50 -0500 Subject: [PATCH 107/112] feat: add PR title validation --- .github/workflows/pr-lint.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .github/workflows/pr-lint.yml diff --git a/.github/workflows/pr-lint.yml b/.github/workflows/pr-lint.yml new file mode 100644 index 0000000..8388f21 --- /dev/null +++ b/.github/workflows/pr-lint.yml @@ -0,0 +1,15 @@ +name: Lint PR +on: + pull_request_target: + types: [ opened, edited, reopened ] + +jobs: + validate: + name: Validate title + runs-on: ubuntu-latest + steps: + - uses: amannn/action-semantic-pull-request@v4 + with: + types: chore docs fix feat test + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 1f3ff7bc95ad23af1d6fdf862932adcb6c0ce977 Mon Sep 17 00:00:00 2001 From: Sam Harrison Date: Thu, 21 Apr 2022 14:44:34 -0500 Subject: [PATCH 108/112] test: lint PRs on synchronize events Since synchronize events clears the status checks, it needs to be re-run. --- .github/workflows/pr-lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-lint.yml b/.github/workflows/pr-lint.yml index 8388f21..dc7af3d 100644 --- a/.github/workflows/pr-lint.yml +++ b/.github/workflows/pr-lint.yml @@ -1,7 +1,7 @@ name: Lint PR on: pull_request_target: - types: [ opened, edited, reopened ] + types: [ opened, edited, synchronize, reopened ] jobs: validate: From b6cc0cb53a9e8cbbf9e8a592050cc0adde3ec64e Mon Sep 17 00:00:00 2001 From: Sam Harrison Date: Thu, 12 May 2022 10:28:27 -0500 Subject: [PATCH 109/112] chore: drop the issue links from FIRST_TIMERS doc --- FIRST_TIMERS.md | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/FIRST_TIMERS.md b/FIRST_TIMERS.md index d977112..ade7912 100644 --- a/FIRST_TIMERS.md +++ b/FIRST_TIMERS.md @@ -51,29 +51,3 @@ git push origin ## Important notice Before creating a pull request, make sure that you respect the repository's constraints regarding contributions. You can find them in the [CONTRIBUTING.md](CONTRIBUTING.md) file. - -## Repositories with Open, Easy, Help Wanted, Issue Filters - -* [Python SDK](https://github.com/sendgrid/sendgrid-python/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) -* [PHP SDK](https://github.com/sendgrid/sendgrid-php/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) -* [C# SDK](https://github.com/sendgrid/sendgrid-csharp/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) -* [Ruby SDK](https://github.com/sendgrid/sendgrid-ruby/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) -* [Node.js SDK](https://github.com/sendgrid/sendgrid-nodejs/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) -* [Java SDK](https://github.com/sendgrid/sendgrid-java/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) -* [Go SDK](https://github.com/sendgrid/sendgrid-go/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) -* [Python SMTPAPI Client](https://github.com/sendgrid/smtpapi-python/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) -* [PHP SMTPAPI Client](https://github.com/sendgrid/smtpapi-php/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) -* [C# SMTPAPI Client](https://github.com/sendgrid/smtpapi-csharp/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) -* [Ruby SMTPAPI Client](https://github.com/sendgrid/smtpapi-ruby/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) -* [Node.js SMTPAPI Client](https://github.com/sendgrid/smtpapi-nodejs/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) -* [Java SMTPAPI Client](https://github.com/sendgrid/smtpapi-java/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) -* [Go SMTPAPI Client](https://github.com/sendgrid/smtpapi-go/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) -* [Python HTTP Client](https://github.com/sendgrid/python-http-client/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) -* [PHP HTTP Client](https://github.com/sendgrid/php-http-client/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) -* [C# HTTP Client](https://github.com/sendgrid/csharp-http-client/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) -* [Java HTTP Client](https://github.com/sendgrid/java-http-client/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) -* [Ruby HTTP Client](https://github.com/sendgrid/ruby-http-client/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) -* [Go HTTP Client](https://github.com/sendgrid/rest/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) -* [Open API Definition](https://github.com/sendgrid/sendgrid-oai/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) -* [DX Automator](https://github.com/sendgrid/dx-automator/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) -* [Documentation](https://github.com/sendgrid/docs/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3A%22difficulty%3A+easy%22+label%3A%22status%3A+help+wanted%22) From cb137a74d01ce9e53129b7f081b05484643bd200 Mon Sep 17 00:00:00 2001 From: "Gareth Paul Jones (GPJ)" Date: Thu, 12 May 2022 11:38:24 -0700 Subject: [PATCH 110/112] docs: Update README to align with SendGrid Support (#113) --- .github/ISSUE_TEMPLATE/config.yml | 10 ---------- CONTRIBUTING.md | 29 ----------------------------- ISSUE_TEMPLATE.md | 30 ------------------------------ PULL_REQUEST_TEMPLATE.md | 2 +- README.rst | 4 ---- TROUBLESHOOTING.md | 2 -- test/__init__.py | 1 - test/test_project.py | 4 ---- 8 files changed, 1 insertion(+), 81 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/config.yml delete mode 100644 ISSUE_TEMPLATE.md diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index e94b1ca..0000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,10 +0,0 @@ -contact_links: - - name: Twilio SendGrid Support - url: https://support.sendgrid.com - about: Get Support - - name: Stack Overflow - url: https://stackoverflow.com/questions/tagged/smtpapi-python+or+sendgrid+python - about: Ask questions on Stack Overflow - - name: Documentation - url: https://sendgrid.com/docs/for-developers/ - about: View Reference Documentation diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 64bbd95..53bcd2a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,7 +1,5 @@ Hello! Thank you for choosing to help contribute to one of the Twilio SendGrid open source projects. There are many ways you can contribute and help is always welcome. We simply ask that you follow the following contribution policies. -- [Feature Request](#feature-request) -- [Submit a Bug Report](#submit-a-bug-report) - [Improvements to the Codebase](#improvements-to-the-codebase) - [Understanding the Code Base](#understanding-the-codebase) - [Testing](#testing) @@ -9,33 +7,6 @@ Hello! Thank you for choosing to help contribute to one of the Twilio SendGrid o - [Creating a Pull Request](#creating-a-pull-request) - [Code Reviews](#code-reviews) - -## Feature Request - -If you'd like to make a feature request, please read this section. - -The GitHub issue tracker is the preferred channel for library feature requests, but please respect the following restrictions: - -- Please **search for existing issues** to ensure we don't have duplicate bugs/feature requests. -- Please be respectful and considerate of others when commenting on issues. - - -## Submit a Bug Report - -Note: DO NOT include your credentials in ANY code examples, descriptions, or media you make public. - -A software bug is a demonstrable issue in the code base. For us to diagnose the issue and respond as quickly as possible, please add as much detail as possible into your bug report. - -Before you decide to create a new issue, please try the following: - -1. Check the Github issues tab if the identified issue has already been reported, if so, please add a +1 to the existing post. -2. Update to the latest version of this code and check if the issue has already been fixed. -3. Copy and fill in the Bug Report Template we have provided below. - -### Please use our Bug Report Template - -In order to make the process easier, we've included a [sample bug report template](ISSUE_TEMPLATE.md). - ## Improvements to the Codebase diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md deleted file mode 100644 index 8c043fd..0000000 --- a/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,30 +0,0 @@ - - -### Issue Summary -A summary of the issue and the environment in which it occurs. If suitable, include the steps required to reproduce the bug. Please feel free to include screenshots, screencasts, or code examples. - -### Steps to Reproduce -1. This is the first step -2. This is the second step -3. Further steps, etc. - -### Code Snippet -```python -# paste code here -``` - -### Exception/Log -``` -# paste exception/log here -``` - -### Technical details: -* smtpapi-python version: -* python version: - diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md index 10cc132..02d2736 100644 --- a/PULL_REQUEST_TEMPLATE.md +++ b/PULL_REQUEST_TEMPLATE.md @@ -28,4 +28,4 @@ A short description of what this PR does. - [ ] I have added the necessary documentation about the functionality in the appropriate .md file - [ ] I have added inline documentation to the code I modified -If you have questions, please file a [support ticket](https://support.sendgrid.com), or create a GitHub Issue in this repository. +If you have questions, please file a [support ticket](https://support.sendgrid.com). diff --git a/README.rst b/README.rst index 21716ff..4b6041f 100644 --- a/README.rst +++ b/README.rst @@ -80,8 +80,6 @@ We encourage contribution to our projects, please see our `CONTRIBUTING`_ guide Quick links: -- `Feature Request`_ -- `Bug Reports`_ - `Improvements to the Codebase`_ - `Review Pull Requests`_ @@ -113,8 +111,6 @@ License .. _SENDGRID_API_KEY: https://app.sendgrid.com/settings/api_keys .. _Example Code: https://github.com/sendgrid/smtpapi-python/tree/HEAD/examples .. _CONTRIBUTING: https://github.com/sendgrid/smtpapi-python/blob/HEAD/CONTRIBUTING.md -.. _Feature Request: https://github.com/sendgrid/smtpapi-python/blob/HEAD/CONTRIBUTING.md#feature-request -.. _Bug Reports: https://github.com/sendgrid/smtpapi-python/blob/HEAD/CONTRIBUTING.md#submit-a-bug-report .. _Improvements to the Codebase: https://github.com/sendgrid/smtpapi-python/blob/HEAD/CONTRIBUTING.md#improvements-to-the-codebase .. _Review Pull Requests: https://github.com/sendgrid/smtpapi-python/blob/HEAD/CONTRIBUTING.md#code-reviews) .. _The MIT License (MIT): https://github.com/sendgrid/smtpapi-python/blob/HEAD/LICENSE diff --git a/TROUBLESHOOTING.md b/TROUBLESHOOTING.md index af15ede..717dcfa 100644 --- a/TROUBLESHOOTING.md +++ b/TROUBLESHOOTING.md @@ -1,7 +1,5 @@ If you have a non-library SendGrid issue, please contact our [support team](https://support.sendgrid.com). -If you can't find a solution below, please open an [issue](https://github.com/sendgrid/smtpapi-python/issues). - ## Table of Contents * [Viewing the Request Body](#request-body) diff --git a/test/__init__.py b/test/__init__.py index d195960..417fadc 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -107,7 +107,6 @@ def setUp(self): self.required_files = [ './Dockerfile', './.env_sample', - './ISSUE_TEMPLATE.md', './PULL_REQUEST_TEMPLATE.md', './.gitignore', './CHANGELOG.md', diff --git a/test/test_project.py b/test/test_project.py index 5de7ec9..888cc41 100644 --- a/test/test_project.py +++ b/test/test_project.py @@ -38,10 +38,6 @@ def test_code_of_conduct(self): def test_contributing(self): self.assertTrue(os.path.isfile('./CONTRIBUTING.md')) - # ./ISSUE_TEMPLATE.md - def test_issue_template(self): - self.assertTrue(os.path.isfile('./ISSUE_TEMPLATE.md')) - # ./LICENSE def test_license(self): self.assertTrue(os.path.isfile('./LICENSE')) From b9c04e355435489df44094b1f5651934c5900bf5 Mon Sep 17 00:00:00 2001 From: Raghav Katyal Date: Wed, 6 Jul 2022 16:15:34 -0700 Subject: [PATCH 111/112] Adding misc as PR type (#114) --- .github/workflows/pr-lint.yml | 2 +- PULL_REQUEST_TEMPLATE.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pr-lint.yml b/.github/workflows/pr-lint.yml index dc7af3d..2f5232b 100644 --- a/.github/workflows/pr-lint.yml +++ b/.github/workflows/pr-lint.yml @@ -10,6 +10,6 @@ jobs: steps: - uses: amannn/action-semantic-pull-request@v4 with: - types: chore docs fix feat test + types: chore docs fix feat test misc env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md index 02d2736..8a966bb 100644 --- a/PULL_REQUEST_TEMPLATE.md +++ b/PULL_REQUEST_TEMPLATE.md @@ -3,7 +3,7 @@ We appreciate the effort for this pull request but before that please make sure Please format the PR title appropriately based on the type of change: [!]: -Where is one of: docs, chore, feat, fix, test. +Where is one of: docs, chore, feat, fix, test, misc. Add a '!' after the type for breaking changes (e.g. feat!: new breaking feature). **All third-party contributors acknowledge that any contributions they provide will be made under the same open-source license that the open-source project is provided under.** From e89ee24d62cfc57608369836b0f8fc9a1daddeb3 Mon Sep 17 00:00:00 2001 From: Sam Harrison Date: Tue, 3 Jan 2023 09:09:32 -0600 Subject: [PATCH 112/112] docs: updated the year in the license --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 5db04ff..3154774 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (C) 2022, Twilio SendGrid, Inc. +Copyright (C) 2023, Twilio SendGrid, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in