diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index 92203b6..5557bcb 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -34,7 +34,7 @@ jobs:
 
     # Initializes the CodeQL tools for scanning.
     - name: Initialize CodeQL
-      uses: github/codeql-action/init@v1
+      uses: github/codeql-action/init@v2
       with:
         languages: ${{ matrix.language }}
         # If you wish to specify custom queries, you can do so here or in a config file.
@@ -45,7 +45,7 @@ jobs:
     # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).
     # If this step fails, then you should remove it and run the build manually (see below)
     - name: Autobuild
-      uses: github/codeql-action/autobuild@v1
+      uses: github/codeql-action/autobuild@v2
 
     # ℹ️ Command-line programs to run using the OS shell.
     # 📚 https://git.io/JvXDl
@@ -59,4 +59,4 @@ jobs:
     #   make release
 
     - name: Perform CodeQL Analysis
-      uses: github/codeql-action/analyze@v1
+      uses: github/codeql-action/analyze@v2
diff --git a/.github/workflows/pythonapp.yml b/.github/workflows/pythonapp.yml
index 33c8473..a5bd13d 100644
--- a/.github/workflows/pythonapp.yml
+++ b/.github/workflows/pythonapp.yml
@@ -6,8 +6,11 @@ jobs:
   build:
     strategy:
       matrix:
-        runs-on: [ubuntu-20.04, macOS-latest]
-        python-version: [ '3.6', '3.8', '3.9']
+        runs-on: [ubuntu-20.04, ubuntu-latest, macOS-latest]
+        python-version: [ '3.6', '3.8', '3.9', '3.11']
+        exclude:
+          - runs-on: ubuntu-latest
+            python-version: '3.6'
       fail-fast: false
 
     runs-on: ${{ matrix.runs-on }}
@@ -37,8 +40,11 @@ jobs:
       #         flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
       #         # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
       #         flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
+      - name: Check with pycodestyle
+        run: |
+          pycodestyle -v awscurl
       - name: Test with pytest
         run: |
-          pytest -v --cov=awscurl --cov-fail-under=77 --cov-report html --cov-report annotate
+          pytest -v --cov=awscurl --cov-fail-under=77 --cov-report html
       - name: Test with tox
         run: tox -vv
diff --git a/.travis.yml b/.travis.yml
index d9438ae..8fc67bd 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,5 @@
 language: python
 python:
-  - "2.7"
   - "3.6"
   - "3.7"
   - "3.8"
@@ -16,4 +15,4 @@ env:
 # command to run tests
 script:
   - pycodestyle -v awscurl
-  - pytest -v --cov=awscurl --cov-fail-under=77 --cov-report html --cov-report annotate
+  - pytest -v --cov=awscurl --cov-fail-under=77 --cov-report html
diff --git a/README.md b/README.md
index 929539c..bcbe579 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
 # awscurl [![Donate](https://img.shields.io/badge/donate-github-orange.svg?style=flat-square)](https://github.com/sponsors/okigan) [![Donate](https://img.shields.io/badge/donate-paypal-orange.svg?style=flat-square)](https://www.paypal.com/donate/?business=UDN4FL55J34QC&amount=25) [![Donate](https://img.shields.io/badge/donate-buy_me_a_coffee-orange.svg?style=flat-square)](https://www.buymeacoffee.com/okigan)
 
 [![PyPI](https://img.shields.io/pypi/v/awscurl.svg)](https://pypi.python.org/pypi/awscurl)
-[![Build Status](https://travis-ci.org/okigan/awscurl.svg?branch=master)](https://travis-ci.org/okigan/awscurl)
+[![Build Status](https://github.com/okigan/awscurl/actions/workflows/pythonapp.yml/badge.svg)](https://github.com/okigan/awscurl)
 [![Docker Hub](https://img.shields.io/docker/pulls/okigan/awscurl.svg)](https://hub.docker.com/r/okigan/awscurl)
 ![CI badge](https://github.com/okigan/awscurl/workflows/CI/badge.svg?branch=master)
 
diff --git a/awscurl/awscurl.py b/awscurl/awscurl.py
index c437d7a..0f1cebc 100755
--- a/awscurl/awscurl.py
+++ b/awscurl/awscurl.py
@@ -145,7 +145,7 @@ def make_request(method,
 
 
 def remove_default_port(parsed_url):
-    default_ports = { 'http': 80, 'https': 443 }
+    default_ports = {'http': 80, 'https': 443}
     if any(parsed_url.scheme == scheme and parsed_url.port == port
            for scheme, port in default_ports.items()):
         host = parsed_url.hostname
@@ -359,7 +359,7 @@ def __send_request(uri, data, headers, method, verify, allow_redirects):
     __log('\nBEGIN REQUEST++++++++++++++++++++++++++++++++++++')
     __log('Request URL = ' + uri)
 
-    if (verify == False):
+    if (verify is False):
         import urllib3
         urllib3.disable_warnings()
 
@@ -469,7 +469,7 @@ def inner_main(argv):
     # https://github.com/boto/botocore/blob/c76553d3158b083d818f88c898d8f6d7918478fd/botocore/credentials.py#L260-262
     parser.add_argument('--security_token', env_var='AWS_SECURITY_TOKEN')
     parser.add_argument('--session_token', env_var='AWS_SESSION_TOKEN')
-    parser.add_argument('-L', '--location', action='store_true', default=False, 
+    parser.add_argument('-L', '--location', action='store_true', default=False,
                         help="Follow redirects")
 
     parser.add_argument('uri')
@@ -531,12 +531,12 @@ def inner_main(argv):
     elif IS_VERBOSE:
         pprint.PrettyPrinter(stream=sys.stderr).pprint(response.headers)
         pprint.PrettyPrinter(stream=sys.stderr).pprint('')
-        
+
     print(response.text)
 
-    response.raise_for_status()
+    exit_code = 0 if response.ok else 1
 
-    return 0
+    return exit_code
 
 
 def main():

diff --git a/tests/integration_test.py b/tests/integration_test.py
index d1aac31..092c2e6 100644
--- a/tests/integration_test.py
+++ b/tests/integration_test.py
@@ -21,7 +21,6 @@ print(f'sys.path2={sys.path}')
 
 import pytest
 from mock import patch
-from requests import HTTPError
 
 from awscurl.awscurl import make_request, inner_main
 
@@ -123,5 +122,8 @@ class TestMakeRequestWithTokenAndNonEnglishData(TestCase):
 class TestInnerMainMethod(TestCase):
     maxDiff = None
 
-    with pytest.raises(HTTPError):
-        inner_main(['--verbose', '--service', 's3', 'https://awscurl-sample-bucket.s3.amazonaws.com'])
\ No newline at end of file
+    def test_exit_code(self, *args, **kwargs):
+        self.assertEqual(
+            inner_main(['--verbose', '--service', 's3', 'https://awscurl-sample-bucket.s3.amazonaws.com']),
+            1
+        )

raise_for_request should not be used for non-successful response
Hi there,

I'm wondering why you elected to use `response.raise_for_status()` after receiving the response - https://github.com/okigan/awscurl/blob/184d7735b57d5c71f75f52a85cc8c8909226b6d5/awscurl/awscurl.py#L537

Would it not make more sense to return an exit code that is either 0 for a successful request or non-zero for a non-successful request?

This would mean tools such as jq etc could still parse the response without the Python traceback interfering where a non-successful status code may still be anticipated.

Happy to open a PR if it makes sense.
tests/integration_test.py::TestInnerMainMethod::test_exit_code
tests/integration_test.py::TestMakeRequestWithToken::test_make_request tests/integration_test.py::TestMakeRequestWithTokenAndNonEnglishData::test_make_request tests/integration_test.py::TestMakeRequestWithTokenAndEnglishData::test_make_request tests/integration_test.py::TestMakeRequestWithTokenAndBinaryData::test_make_request