Jose Diaz-Gonzalez
Committed by GitHub

Merge pull request #66 from josegonzalez/packaging

Packaging Improvements
...@@ -4,8 +4,8 @@ python: ...@@ -4,8 +4,8 @@ python:
4 - "3.3" 4 - "3.3"
5 - "3.4" 5 - "3.4"
6 - "3.5" 6 - "3.5"
7 +cache: pip
7 install: 8 install:
8 - - pip install -r requirements.txt 9 + - pip install -r requirements-dev.txt
9 - - pip install coverage python-coveralls
10 script: nosetests tests/unit --cover-erase --with-coverage --cover-package kappa 10 script: nosetests tests/unit --cover-erase --with-coverage --cover-package kappa
11 after_success: coveralls 11 after_success: coveralls
......
1 include README.md 1 include README.md
2 include LICENSE 2 include LICENSE
3 include requirements.txt 3 include requirements.txt
4 -include kappa/_version
5 recursive-include samples *.js *.py *.yml *.cf *.json *.txt 4 recursive-include samples *.js *.py *.yml *.cf *.json *.txt
......
1 +=====
1 kappa 2 kappa
2 ===== 3 =====
3 4
4 -[![Build Status](https://travis-ci.org/garnaat/kappa.svg?branch=develop)](https://travis-ci.org/garnaat/kappa) 5 +.. image:: https://travis-ci.org/garnaat/kappa.svg?branch=develop
6 + :target: https://travis-ci.org/garnaat/kappa
5 7
6 -[![Code Health](https://landscape.io/github/garnaat/kappa/develop/landscape.svg)](https://landscape.io/github/garnaat/kappa/develop) 8 +.. image:: https://landscape.io/github/garnaat/kappa/develop/landscape.svg
9 + :target: https://landscape.io/github/garnaat/kappa/develop
7 10
8 **Kappa** is a command line tool that (hopefully) makes it easier to 11 **Kappa** is a command line tool that (hopefully) makes it easier to
9 deploy, update, and test functions for AWS Lambda. 12 deploy, update, and test functions for AWS Lambda.
...@@ -12,10 +15,8 @@ There are quite a few steps involved in developing a Lambda function. ...@@ -12,10 +15,8 @@ There are quite a few steps involved in developing a Lambda function.
12 You have to: 15 You have to:
13 16
14 * Write the function itself 17 * Write the function itself
15 -* Create the IAM role required by the Lambda function itself (the executing 18 +* Create the IAM role required by the Lambda function itself (the executing role) to allow it access to any resources it needs to do its job
16 -role) to allow it access to any resources it needs to do its job 19 +* Add additional permissions to the Lambda function if it is going to be used in a Push model (e.g. S3, SNS) rather than a Pull model.
17 -* Add additional permissions to the Lambda function if it is going to be used
18 -in a Push model (e.g. S3, SNS) rather than a Pull model.
19 * Zip the function and any dependencies and upload it to AWS Lambda 20 * Zip the function and any dependencies and upload it to AWS Lambda
20 * Test the function with mock data 21 * Test the function with mock data
21 * Retrieve the output of the function from CloudWatch Logs 22 * Retrieve the output of the function from CloudWatch Logs
...@@ -34,19 +35,19 @@ If you need to make changes, kappa will allow you to easily update your Lambda ...@@ -34,19 +35,19 @@ If you need to make changes, kappa will allow you to easily update your Lambda
34 function with new code or update your event sources as needed. 35 function with new code or update your event sources as needed.
35 36
36 Installation 37 Installation
37 ------------- 38 +============
38 39
39 -The quickest way to get kappa is to install the latest stable version via pip: 40 +The quickest way to get kappa is to install the latest stable version via pip::
40 41
41 pip install kappa 42 pip install kappa
42 43
43 -Or for the development version: 44 +Or for the development version::
44 45
45 pip install git+https://github.com/garnaat/kappa.git 46 pip install git+https://github.com/garnaat/kappa.git
46 47
47 48
48 Quick Start 49 Quick Start
49 ------------ 50 +===========
50 51
51 To get a feel for how kappa works, let's take a look at a very simple example 52 To get a feel for how kappa works, let's take a look at a very simple example
52 contained in the ``samples/simple`` directory of the kappa distribution. This 53 contained in the ``samples/simple`` directory of the kappa distribution. This
...@@ -54,38 +55,39 @@ example is so simple, in fact, that it doesn't really do anything. It's just a ...@@ -54,38 +55,39 @@ example is so simple, in fact, that it doesn't really do anything. It's just a
54 small Lambda function (written in Python) that accepts some JSON input, logs 55 small Lambda function (written in Python) that accepts some JSON input, logs
55 that input to CloudWatch logs, and returns a JSON document back. 56 that input to CloudWatch logs, and returns a JSON document back.
56 57
57 -The structure of the directory is: 58 +The structure of the directory is::
58 59
59 -``` 60 + simple/
60 -simple/ 61 + ├── _src
61 -├── _src 62 + │   ├── README.md
62 -│   ├── README.md 63 + │   ├── requirements.txt
63 -│   ├── requirements.txt 64 + │   ├── setup.cfg
64 -│   ├── setup.cfg 65 + │   └── simple.py
65 -│   └── simple.py 66 + ├── _tests
66 -├── _tests 67 + │   └── test_one.json
67 -│   └── test_one.json 68 + └── kappa.yml.sample
68 -└── kappa.yml.sample
69 -```
70 69
71 Within the directory we see: 70 Within the directory we see:
72 71
73 -* `kappa.yml.sample` which is a sample YAML configuration file for the project 72 +* ``kappa.yml.sample`` which is a sample YAML configuration file for the project
74 -* `_src` which is a directory containing the source code for the Lambda function 73 +* ``_src`` which is a directory containing the source code for the Lambda function
75 -* `_test` which is a directory containing some test data 74 +* ``_test`` which is a directory containing some test data
76 75
77 The first step is to make a copy of the sample configuration file: 76 The first step is to make a copy of the sample configuration file:
78 77
79 - $ cd simple 78 +.. code-block:: bash
80 - $ cp kappa.yml.sample kappa.yml 79 +
80 + cd simple
81 + cp kappa.yml.sample kappa.yml
81 82
82 Now you will need to edit ``kappa.yml`` slightly for your use. The file looks 83 Now you will need to edit ``kappa.yml`` slightly for your use. The file looks
83 like this: 84 like this:
84 85
85 -``` 86 +.. code-block:: yaml
86 ---- 87 +
87 -name: kappa-simple 88 + ---
88 -environments: 89 + name: kappa-simple
90 + environments:
89 dev: 91 dev:
90 profile: <your profile here> 92 profile: <your profile here>
91 region: <your region here> 93 region: <your region here>
...@@ -102,13 +104,12 @@ environments: ...@@ -102,13 +104,12 @@ environments:
102 - arn: arn:aws:logs:*:*:* 104 - arn: arn:aws:logs:*:*:*
103 actions: 105 actions:
104 - "*" 106 - "*"
105 -lambda: 107 + lambda:
106 description: A very simple Kappa example 108 description: A very simple Kappa example
107 handler: simple.handler 109 handler: simple.handler
108 runtime: python2.7 110 runtime: python2.7
109 memory_size: 128 111 memory_size: 128
110 timeout: 3 112 timeout: 3
111 -```
112 113
113 The ``name`` at the top is just a name used for this Lambda function and other 114 The ``name`` at the top is just a name used for this Lambda function and other
114 things we create that are related to this Lambda function (e.g. roles, 115 things we create that are related to this Lambda function (e.g. roles,
...@@ -123,12 +124,14 @@ section also includes a ``policy`` section. This is where we tell kappa about ...@@ -123,12 +124,14 @@ section also includes a ``policy`` section. This is where we tell kappa about
123 AWS resources that our Lambda function needs access to and what kind of access 124 AWS resources that our Lambda function needs access to and what kind of access
124 it requires. For example, your Lambda function may need to read from an SNS 125 it requires. For example, your Lambda function may need to read from an SNS
125 topic or write to a DynamoDB table and this is where you would provide the ARN 126 topic or write to a DynamoDB table and this is where you would provide the ARN
126 -([Amazon Resource Name](http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html)) 127 +(`Amazon Resource Name`_)
127 that identify those resources. Since this is a very simple example, the only 128 that identify those resources. Since this is a very simple example, the only
128 resource listed here is for CloudWatch logs so that our Lambda function is able 129 resource listed here is for CloudWatch logs so that our Lambda function is able
129 to write to the CloudWatch log group that will be created for it automatically 130 to write to the CloudWatch log group that will be created for it automatically
130 by AWS Lambda. 131 by AWS Lambda.
131 132
133 +.. _`Amazon Resource Name`: http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html
134 +
132 The ``lambda`` section contains the configuration information about our Lambda 135 The ``lambda`` section contains the configuration information about our Lambda
133 function. These values are passed to Lambda when we create the function and 136 function. These values are passed to Lambda when we create the function and
134 can be updated at any time after. 137 can be updated at any time after.
...@@ -142,28 +145,27 @@ typing. ...@@ -142,28 +145,27 @@ typing.
142 Once you have made the necessary modifications, you should be ready to deploy 145 Once you have made the necessary modifications, you should be ready to deploy
143 your Lambda function to the AWS Lambda service. To do so, just do this: 146 your Lambda function to the AWS Lambda service. To do so, just do this:
144 147
145 -``` 148 +.. code-block:: bash
146 -$ kappa deploy 149 +
147 -``` 150 + kappa deploy
148 151
149 This assumes you want to deploy the default environment called ``dev`` and that 152 This assumes you want to deploy the default environment called ``dev`` and that
150 you have named your config file ``kappa.yml``. If, instead, you called your 153 you have named your config file ``kappa.yml``. If, instead, you called your
151 environment ``test`` and named your config file foo.yml, you would do this: 154 environment ``test`` and named your config file foo.yml, you would do this:
152 155
153 -``` 156 +.. code-block:: bash
154 -$ kappa --env test --config foo.yml deploy 157 +
155 -``` 158 + kappa --env test --config foo.yml deploy
156 159
157 In either case, you should see output that looks something like this: 160 In either case, you should see output that looks something like this:
158 161
159 -``` 162 +.. code-block:: bash
160 -$ kappa deploy 163 +
161 -deploying 164 + kappa deploy
162 -...deploying policy kappa-simple-dev 165 + # deploying
163 -...creating function kappa-simple-dev 166 + # ...deploying policy kappa-simple-dev
164 -done 167 + # ...creating function kappa-simple-dev
165 -$ 168 + # done
166 -```
167 169
168 So, what kappa has done is it has created a new Managed Policy called 170 So, what kappa has done is it has created a new Managed Policy called
169 ``kappa-simple-dev`` that grants access to the CloudWatch Logs service. It has 171 ``kappa-simple-dev`` that grants access to the CloudWatch Logs service. It has
...@@ -173,19 +175,18 @@ Lambda called kappa-simple-dev. ...@@ -173,19 +175,18 @@ Lambda called kappa-simple-dev.
173 175
174 To test this out, try this: 176 To test this out, try this:
175 177
176 -``` 178 +.. code-block:: bash
177 -$ kappa invoke _tests/test_one.json
178 -invoking
179 -START RequestId: 0f2f9ecf-9df7-11e5-ae87-858fbfb8e85f Version: $LATEST
180 -[DEBUG] 2015-12-08T22:00:15.363Z 0f2f9ecf-9df7-11e5-ae87-858fbfb8e85f {u'foo': u'bar', u'fie': u'baz'}
181 -END RequestId: 0f2f9ecf-9df7-11e5-ae87-858fbfb8e85f
182 -REPORT RequestId: 0f2f9ecf-9df7-11e5-ae87-858fbfb8e85f Duration: 0.40 ms Billed Duration: 100 ms Memory Size: 256 MB Max Memory Used: 23 MB
183 179
184 -Response: 180 + kappa invoke _tests/test_one.json
185 -{"status": "success"} 181 + # invoking
186 -done 182 + # START RequestId: 0f2f9ecf-9df7-11e5-ae87-858fbfb8e85f Version: $LATEST
187 -$ 183 + # [DEBUG] 2015-12-08T22:00:15.363Z 0f2f9ecf-9df7-11e5-ae87-858fbfb8e85f {u'foo': u'bar', u'fie': u'baz'}
188 -``` 184 + # END RequestId: 0f2f9ecf-9df7-11e5-ae87-858fbfb8e85f
185 + # REPORT RequestId: 0f2f9ecf-9df7-11e5-ae87-858fbfb8e85f Duration: 0.40 ms Billed Duration: 100 ms Memory Size: 256 MB Max Memory Used: 23 MB
186 + #
187 + # Response:
188 + # {"status": "success"}
189 + # done
189 190
190 We have just called our Lambda function, passing in the contents of the file 191 We have just called our Lambda function, passing in the contents of the file
191 ``_tests/test_one.json`` as input to our function. We can see the output of 192 ``_tests/test_one.json`` as input to our function. We can see the output of
...@@ -198,7 +199,9 @@ Need to make a change in your function, your list of resources, or your ...@@ -198,7 +199,9 @@ Need to make a change in your function, your list of resources, or your
198 function configuration? Just go ahead and make the change and then re-run the 199 function configuration? Just go ahead and make the change and then re-run the
199 ``deploy`` command: 200 ``deploy`` command:
200 201
201 - $ kappa deploy 202 +.. code-block:: bash
203 +
204 + kappa deploy
202 205
203 Kappa will figure out what has changed and make the necessary updates for you. 206 Kappa will figure out what has changed and make the necessary updates for you.
204 207
...@@ -206,34 +209,34 @@ That gives you a quick overview of kappa. To learn more about it, I recommend ...@@ -206,34 +209,34 @@ That gives you a quick overview of kappa. To learn more about it, I recommend
206 you check out the tutorial. 209 you check out the tutorial.
207 210
208 Policies 211 Policies
209 --------- 212 +========
210 213
211 Hands up who loves writing IAM policies. Yeah, that's what I thought. With 214 Hands up who loves writing IAM policies. Yeah, that's what I thought. With
212 Kappa, there is a simplified way of writing policies and granting your Lambda 215 Kappa, there is a simplified way of writing policies and granting your Lambda
213 function the permissions it needs. 216 function the permissions it needs.
214 217
215 -The simplified version allows you to specify, in your `kappa.yml` file, the 218 +The simplified version allows you to specify, in your ``kappa.yml`` file, the
216 ARN of the resource you want to access, and then a list of the API methods you 219 ARN of the resource you want to access, and then a list of the API methods you
217 want to allow. For example: 220 want to allow. For example:
218 221
219 -``` 222 +.. code-block:: yaml
220 -policy: 223 +
224 + policy:
221 resources: 225 resources:
222 - arn: arn:aws:logs:*:*:* 226 - arn: arn:aws:logs:*:*:*
223 actions: 227 actions:
224 - "*" 228 - "*"
225 -```
226 229
227 To express this using the official IAM policy format, you can instead use a 230 To express this using the official IAM policy format, you can instead use a
228 statement: 231 statement:
229 232
230 -``` 233 +.. code-block:: yaml
231 -policy: 234 +
235 + policy:
232 statements: 236 statements:
233 - Effect: Allow 237 - Effect: Allow
234 Resource: "*" 238 Resource: "*"
235 Action: 239 Action:
236 - "logs:*" 240 - "logs:*"
237 -```
238 241
239 Both of these do the same thing. 242 Both of these do the same thing.
......
...@@ -12,19 +12,23 @@ ...@@ -12,19 +12,23 @@
12 # All configuration values have a default; values that are commented out 12 # All configuration values have a default; values that are commented out
13 # serve to show the default. 13 # serve to show the default.
14 14
15 -import sys
16 import os 15 import os
17 import shlex 16 import shlex
17 +import sys
18 +
19 +assert os
20 +assert shlex
21 +assert sys
18 22
19 # If extensions (or modules to document with autodoc) are in another directory, 23 # If extensions (or modules to document with autodoc) are in another directory,
20 # add these directories to sys.path here. If the directory is relative to the 24 # add these directories to sys.path here. If the directory is relative to the
21 # documentation root, use os.path.abspath to make it absolute, like shown here. 25 # documentation root, use os.path.abspath to make it absolute, like shown here.
22 -#sys.path.insert(0, os.path.abspath('.')) 26 +# sys.path.insert(0, os.path.abspath('.'))
23 27
24 # -- General configuration ------------------------------------------------ 28 # -- General configuration ------------------------------------------------
25 29
26 # If your documentation needs a minimal Sphinx version, state it here. 30 # If your documentation needs a minimal Sphinx version, state it here.
27 -#needs_sphinx = '1.0' 31 +# needs_sphinx = '1.0'
28 32
29 # Add any Sphinx extension module names here, as strings. They can be 33 # Add any Sphinx extension module names here, as strings. They can be
30 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 34 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
...@@ -42,7 +46,7 @@ templates_path = ['_templates'] ...@@ -42,7 +46,7 @@ templates_path = ['_templates']
42 source_suffix = '.rst' 46 source_suffix = '.rst'
43 47
44 # The encoding of source files. 48 # The encoding of source files.
45 -#source_encoding = 'utf-8-sig' 49 +# source_encoding = 'utf-8-sig'
46 50
47 # The master toctree document. 51 # The master toctree document.
48 master_doc = 'index' 52 master_doc = 'index'
...@@ -70,9 +74,9 @@ language = None ...@@ -70,9 +74,9 @@ language = None
70 74
71 # There are two options for replacing |today|: either, you set today to some 75 # There are two options for replacing |today|: either, you set today to some
72 # non-false value, then it is used: 76 # non-false value, then it is used:
73 -#today = '' 77 +# today = ''
74 # Else, today_fmt is used as the format for a strftime call. 78 # Else, today_fmt is used as the format for a strftime call.
75 -#today_fmt = '%B %d, %Y' 79 +# today_fmt = '%B %d, %Y'
76 80
77 # List of patterns, relative to source directory, that match files and 81 # List of patterns, relative to source directory, that match files and
78 # directories to ignore when looking for source files. 82 # directories to ignore when looking for source files.
...@@ -80,27 +84,27 @@ exclude_patterns = ['_build'] ...@@ -80,27 +84,27 @@ exclude_patterns = ['_build']
80 84
81 # The reST default role (used for this markup: `text`) to use for all 85 # The reST default role (used for this markup: `text`) to use for all
82 # documents. 86 # documents.
83 -#default_role = None 87 +# default_role = None
84 88
85 # If true, '()' will be appended to :func: etc. cross-reference text. 89 # If true, '()' will be appended to :func: etc. cross-reference text.
86 -#add_function_parentheses = True 90 +# add_function_parentheses = True
87 91
88 # If true, the current module name will be prepended to all description 92 # If true, the current module name will be prepended to all description
89 # unit titles (such as .. function::). 93 # unit titles (such as .. function::).
90 -#add_module_names = True 94 +# add_module_names = True
91 95
92 # If true, sectionauthor and moduleauthor directives will be shown in the 96 # If true, sectionauthor and moduleauthor directives will be shown in the
93 # output. They are ignored by default. 97 # output. They are ignored by default.
94 -#show_authors = False 98 +# show_authors = False
95 99
96 # The name of the Pygments (syntax highlighting) style to use. 100 # The name of the Pygments (syntax highlighting) style to use.
97 pygments_style = 'sphinx' 101 pygments_style = 'sphinx'
98 102
99 # A list of ignored prefixes for module index sorting. 103 # A list of ignored prefixes for module index sorting.
100 -#modindex_common_prefix = [] 104 +# modindex_common_prefix = []
101 105
102 # If true, keep warnings as "system message" paragraphs in the built documents. 106 # If true, keep warnings as "system message" paragraphs in the built documents.
103 -#keep_warnings = False 107 +# keep_warnings = False
104 108
105 # If true, `todo` and `todoList` produce output, else they produce nothing. 109 # If true, `todo` and `todoList` produce output, else they produce nothing.
106 todo_include_todos = False 110 todo_include_todos = False
...@@ -115,26 +119,26 @@ html_theme = 'alabaster' ...@@ -115,26 +119,26 @@ html_theme = 'alabaster'
115 # Theme options are theme-specific and customize the look and feel of a theme 119 # Theme options are theme-specific and customize the look and feel of a theme
116 # further. For a list of options available for each theme, see the 120 # further. For a list of options available for each theme, see the
117 # documentation. 121 # documentation.
118 -#html_theme_options = {} 122 +# html_theme_options = {}
119 123
120 # Add any paths that contain custom themes here, relative to this directory. 124 # Add any paths that contain custom themes here, relative to this directory.
121 -#html_theme_path = [] 125 +# html_theme_path = []
122 126
123 # The name for this set of Sphinx documents. If None, it defaults to 127 # The name for this set of Sphinx documents. If None, it defaults to
124 # "<project> v<release> documentation". 128 # "<project> v<release> documentation".
125 -#html_title = None 129 +# html_title = None
126 130
127 # A shorter title for the navigation bar. Default is the same as html_title. 131 # A shorter title for the navigation bar. Default is the same as html_title.
128 -#html_short_title = None 132 +# html_short_title = None
129 133
130 # The name of an image file (relative to this directory) to place at the top 134 # The name of an image file (relative to this directory) to place at the top
131 # of the sidebar. 135 # of the sidebar.
132 -#html_logo = None 136 +# html_logo = None
133 137
134 # The name of an image file (within the static path) to use as favicon of the 138 # The name of an image file (within the static path) to use as favicon of the
135 # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 139 # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
136 # pixels large. 140 # pixels large.
137 -#html_favicon = None 141 +# html_favicon = None
138 142
139 # Add any paths that contain custom static files (such as style sheets) here, 143 # Add any paths that contain custom static files (such as style sheets) here,
140 # relative to this directory. They are copied after the builtin static files, 144 # relative to this directory. They are copied after the builtin static files,
...@@ -144,62 +148,62 @@ html_static_path = ['_static'] ...@@ -144,62 +148,62 @@ html_static_path = ['_static']
144 # Add any extra paths that contain custom files (such as robots.txt or 148 # Add any extra paths that contain custom files (such as robots.txt or
145 # .htaccess) here, relative to this directory. These files are copied 149 # .htaccess) here, relative to this directory. These files are copied
146 # directly to the root of the documentation. 150 # directly to the root of the documentation.
147 -#html_extra_path = [] 151 +# html_extra_path = []
148 152
149 # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 153 # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
150 # using the given strftime format. 154 # using the given strftime format.
151 -#html_last_updated_fmt = '%b %d, %Y' 155 +# html_last_updated_fmt = '%b %d, %Y'
152 156
153 # If true, SmartyPants will be used to convert quotes and dashes to 157 # If true, SmartyPants will be used to convert quotes and dashes to
154 # typographically correct entities. 158 # typographically correct entities.
155 -#html_use_smartypants = True 159 +# html_use_smartypants = True
156 160
157 # Custom sidebar templates, maps document names to template names. 161 # Custom sidebar templates, maps document names to template names.
158 -#html_sidebars = {} 162 +# html_sidebars = {}
159 163
160 # Additional templates that should be rendered to pages, maps page names to 164 # Additional templates that should be rendered to pages, maps page names to
161 # template names. 165 # template names.
162 -#html_additional_pages = {} 166 +# html_additional_pages = {}
163 167
164 # If false, no module index is generated. 168 # If false, no module index is generated.
165 -#html_domain_indices = True 169 +# html_domain_indices = True
166 170
167 # If false, no index is generated. 171 # If false, no index is generated.
168 -#html_use_index = True 172 +# html_use_index = True
169 173
170 # If true, the index is split into individual pages for each letter. 174 # If true, the index is split into individual pages for each letter.
171 -#html_split_index = False 175 +# html_split_index = False
172 176
173 # If true, links to the reST sources are added to the pages. 177 # If true, links to the reST sources are added to the pages.
174 -#html_show_sourcelink = True 178 +# html_show_sourcelink = True
175 179
176 # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 180 # If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
177 -#html_show_sphinx = True 181 +# html_show_sphinx = True
178 182
179 # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 183 # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
180 -#html_show_copyright = True 184 +# html_show_copyright = True
181 185
182 # If true, an OpenSearch description file will be output, and all pages will 186 # If true, an OpenSearch description file will be output, and all pages will
183 # contain a <link> tag referring to it. The value of this option must be the 187 # contain a <link> tag referring to it. The value of this option must be the
184 # base URL from which the finished HTML is served. 188 # base URL from which the finished HTML is served.
185 -#html_use_opensearch = '' 189 +# html_use_opensearch = ''
186 190
187 # This is the file name suffix for HTML files (e.g. ".xhtml"). 191 # This is the file name suffix for HTML files (e.g. ".xhtml").
188 -#html_file_suffix = None 192 +# html_file_suffix = None
189 193
190 # Language to be used for generating the HTML full-text search index. 194 # Language to be used for generating the HTML full-text search index.
191 # Sphinx supports the following languages: 195 # Sphinx supports the following languages:
192 # 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' 196 # 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
193 # 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' 197 # 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
194 -#html_search_language = 'en' 198 +# html_search_language = 'en'
195 199
196 # A dictionary with options for the search language support, empty by default. 200 # A dictionary with options for the search language support, empty by default.
197 # Now only 'ja' uses this config value 201 # Now only 'ja' uses this config value
198 -#html_search_options = {'type': 'default'} 202 +# html_search_options = {'type': 'default'}
199 203
200 # The name of a javascript file (relative to the configuration directory) that 204 # The name of a javascript file (relative to the configuration directory) that
201 # implements a search results scorer. If empty, the default will be used. 205 # implements a search results scorer. If empty, the default will be used.
202 -#html_search_scorer = 'scorer.js' 206 +# html_search_scorer = 'scorer.js'
203 207
204 # Output file base name for HTML help builder. 208 # Output file base name for HTML help builder.
205 htmlhelp_basename = 'kappadoc' 209 htmlhelp_basename = 'kappadoc'
...@@ -207,17 +211,17 @@ htmlhelp_basename = 'kappadoc' ...@@ -207,17 +211,17 @@ htmlhelp_basename = 'kappadoc'
207 # -- Options for LaTeX output --------------------------------------------- 211 # -- Options for LaTeX output ---------------------------------------------
208 212
209 latex_elements = { 213 latex_elements = {
210 -# The paper size ('letterpaper' or 'a4paper'). 214 + # The paper size ('letterpaper' or 'a4paper').
211 -#'papersize': 'letterpaper', 215 + # 'papersize': 'letterpaper',
212 216
213 -# The font size ('10pt', '11pt' or '12pt'). 217 + # The font size ('10pt', '11pt' or '12pt').
214 -#'pointsize': '10pt', 218 + # 'pointsize': '10pt',
215 219
216 -# Additional stuff for the LaTeX preamble. 220 + # Additional stuff for the LaTeX preamble.
217 -#'preamble': '', 221 + # 'preamble': '',
218 222
219 -# Latex figure (float) alignment 223 + # Latex figure (float) alignment
220 -#'figure_align': 'htbp', 224 + # 'figure_align': 'htbp',
221 } 225 }
222 226
223 # Grouping the document tree into LaTeX files. List of tuples 227 # Grouping the document tree into LaTeX files. List of tuples
...@@ -230,23 +234,23 @@ latex_documents = [ ...@@ -230,23 +234,23 @@ latex_documents = [
230 234
231 # The name of an image file (relative to this directory) to place at the top of 235 # The name of an image file (relative to this directory) to place at the top of
232 # the title page. 236 # the title page.
233 -#latex_logo = None 237 +# latex_logo = None
234 238
235 # For "manual" documents, if this is true, then toplevel headings are parts, 239 # For "manual" documents, if this is true, then toplevel headings are parts,
236 # not chapters. 240 # not chapters.
237 -#latex_use_parts = False 241 +# latex_use_parts = False
238 242
239 # If true, show page references after internal links. 243 # If true, show page references after internal links.
240 -#latex_show_pagerefs = False 244 +# latex_show_pagerefs = False
241 245
242 # If true, show URL addresses after external links. 246 # If true, show URL addresses after external links.
243 -#latex_show_urls = False 247 +# latex_show_urls = False
244 248
245 # Documents to append as an appendix to all manuals. 249 # Documents to append as an appendix to all manuals.
246 -#latex_appendices = [] 250 +# latex_appendices = []
247 251
248 # If false, no module index is generated. 252 # If false, no module index is generated.
249 -#latex_domain_indices = True 253 +# latex_domain_indices = True
250 254
251 255
252 # -- Options for manual page output --------------------------------------- 256 # -- Options for manual page output ---------------------------------------
...@@ -259,7 +263,7 @@ man_pages = [ ...@@ -259,7 +263,7 @@ man_pages = [
259 ] 263 ]
260 264
261 # If true, show URL addresses after external links. 265 # If true, show URL addresses after external links.
262 -#man_show_urls = False 266 +# man_show_urls = False
263 267
264 268
265 # -- Options for Texinfo output ------------------------------------------- 269 # -- Options for Texinfo output -------------------------------------------
...@@ -274,13 +278,13 @@ texinfo_documents = [ ...@@ -274,13 +278,13 @@ texinfo_documents = [
274 ] 278 ]
275 279
276 # Documents to append as an appendix to all manuals. 280 # Documents to append as an appendix to all manuals.
277 -#texinfo_appendices = [] 281 +# texinfo_appendices = []
278 282
279 # If false, no module index is generated. 283 # If false, no module index is generated.
280 -#texinfo_domain_indices = True 284 +# texinfo_domain_indices = True
281 285
282 # How to display URL addresses: 'footnote', 'no', or 'inline'. 286 # How to display URL addresses: 'footnote', 'no', or 'inline'.
283 -#texinfo_show_urls = 'footnote' 287 +# texinfo_show_urls = 'footnote'
284 288
285 # If true, do not generate a @detailmenu in the "Top" node's menu. 289 # If true, do not generate a @detailmenu in the "Top" node's menu.
286 -#texinfo_no_detailmenu = False 290 +# texinfo_no_detailmenu = False
......
...@@ -12,6 +12,4 @@ ...@@ -12,6 +12,4 @@
12 # See the License for the specific language governing permissions and 12 # See the License for the specific language governing permissions and
13 # limitations under the License. 13 # limitations under the License.
14 14
15 -import os 15 +__version__ = '0.3.1'
16 -
17 -__version__ = open(os.path.join(os.path.dirname(__file__), '_version')).read()
......
1 -0.3.1
...\ No newline at end of file ...\ No newline at end of file
...@@ -190,10 +190,12 @@ class Context(object): ...@@ -190,10 +190,12 @@ class Context(object):
190 def list_event_sources(self): 190 def list_event_sources(self):
191 event_sources = [] 191 event_sources = []
192 for event_source in self.event_sources: 192 for event_source in self.event_sources:
193 - event_sources.append({'arn': event_source.arn, 193 + event_sources.append({
194 + 'arn': event_source.arn,
194 'starting_position': event_source.starting_position, 195 'starting_position': event_source.starting_position,
195 'batch_size': event_source.batch_size, 196 'batch_size': event_source.batch_size,
196 - 'enabled': event_source.enabled}) 197 + 'enabled': event_source.enabled
198 + })
197 return event_sources 199 return event_sources
198 200
199 def enable_event_sources(self): 201 def enable_event_sources(self):
......
...@@ -227,7 +227,9 @@ class Function(object): ...@@ -227,7 +227,9 @@ class Function(object):
227 227
228 try: 228 try:
229 dir_path = os.path.relpath(root, relroot) 229 dir_path = os.path.relpath(root, relroot)
230 - dir_path = os.path.normpath(os.path.splitdrive(dir_path)[1]) 230 + dir_path = os.path.normpath(
231 + os.path.splitdrive(dir_path)[1]
232 + )
231 while dir_path[0] in (os.sep, os.altsep): 233 while dir_path[0] in (os.sep, os.altsep):
232 dir_path = dir_path[1:] 234 dir_path = dir_path[1:]
233 dir_path += '/' 235 dir_path += '/'
......
...@@ -53,17 +53,17 @@ class Log(object): ...@@ -53,17 +53,17 @@ class Log(object):
53 LOG.info( 53 LOG.info(
54 'log group %s has not been created yet', self.log_group_name) 54 'log group %s has not been created yet', self.log_group_name)
55 return [] 55 return []
56 - latest_stream = None 56 + latest = None
57 streams = self.streams() 57 streams = self.streams()
58 for stream in streams: 58 for stream in streams:
59 - if not latest_stream: 59 + if not latest:
60 - latest_stream = stream 60 + latest = stream
61 - elif stream['lastEventTimestamp'] > latest_stream['lastEventTimestamp']: 61 + elif stream['lastEventTimestamp'] > latest['lastEventTimestamp']:
62 - latest_stream = stream 62 + latest = stream
63 response = self._log_client.call( 63 response = self._log_client.call(
64 'get_log_events', 64 'get_log_events',
65 logGroupName=self.log_group_name, 65 logGroupName=self.log_group_name,
66 - logStreamName=latest_stream['logStreamName']) 66 + logStreamName=latest['logStreamName'])
67 LOG.debug(response) 67 LOG.debug(response)
68 return response['events'] 68 return response['events']
69 69
......
...@@ -88,7 +88,7 @@ def tail(ctx): ...@@ -88,7 +88,7 @@ def tail(ctx):
88 """Show the last 10 lines of the log file""" 88 """Show the last 10 lines of the log file"""
89 click.echo('tailing logs') 89 click.echo('tailing logs')
90 for e in ctx.tail()[-10:]: 90 for e in ctx.tail()[-10:]:
91 - ts = datetime.utcfromtimestamp(e['timestamp']//1000).isoformat() 91 + ts = datetime.utcfromtimestamp(e['timestamp'] // 1000).isoformat()
92 click.echo("{}: {}".format(ts, e['message'])) 92 click.echo("{}: {}".format(ts, e['message']))
93 click.echo('done') 93 click.echo('done')
94 94
......
1 +#!/usr/bin/env bash
2 +set -eo pipefail; [[ $RELEASE_TRACE ]] && set -x
3 +
4 +PACKAGE_NAME='kappa'
5 +INIT_PACKAGE_NAME='kappa'
6 +PUBLIC="true"
7 +
8 +# Colors
9 +COLOR_OFF="\033[0m" # unsets color to term fg color
10 +RED="\033[0;31m" # red
11 +GREEN="\033[0;32m" # green
12 +YELLOW="\033[0;33m" # yellow
13 +MAGENTA="\033[0;35m" # magenta
14 +CYAN="\033[0;36m" # cyan
15 +
16 +# ensure wheel is available
17 +pip install wheel > /dev/null
18 +
19 +# ensure Pygment is available
20 +pip install Pygments > /dev/null
21 +
22 +command -v gitchangelog >/dev/null 2>&1 || {
23 + echo -e "${RED}WARNING: Missing gitchangelog binary, please run: pip install gitchangelog==2.2.0${COLOR_OFF}\n"
24 + exit 1
25 +}
26 +
27 +command -v rst-lint > /dev/null || {
28 + echo -e "${RED}WARNING: Missing rst-lint binary, please run: pip install restructuredtext_lint${COLOR_OFF}\n"
29 + exit 1
30 +}
31 +
32 +if [[ "$@" != "major" ]] && [[ "$@" != "minor" ]] && [[ "$@" != "patch" ]]; then
33 + echo -e "${RED}WARNING: Invalid release type, must specify 'major', 'minor', or 'patch'${COLOR_OFF}\n"
34 + exit 1
35 +fi
36 +
37 +echo -e "\n${GREEN}STARTING RELEASE PROCESS${COLOR_OFF}\n"
38 +
39 +set +e;
40 +git status | grep "working directory clean" &> /dev/null
41 +if [ ! $? -eq 0 ]; then # working directory is NOT clean
42 + echo -e "${RED}WARNING: You have uncomitted changes, you may have forgotten something${COLOR_OFF}\n"
43 + exit 1
44 +fi
45 +set -e;
46 +
47 +echo -e "${YELLOW}--->${COLOR_OFF} Updating local copy"
48 +git pull -q origin master
49 +git fetch --tags > /dev/null
50 +
51 +echo -e "${YELLOW}--->${COLOR_OFF} Retrieving release versions"
52 +
53 +current_version=$(cat ${INIT_PACKAGE_NAME}/__init__.py |grep '__version__ ='|sed 's/[^0-9.]//g')
54 +major=$(echo $current_version | awk '{split($0,a,"."); print a[1]}')
55 +minor=$(echo $current_version | awk '{split($0,a,"."); print a[2]}')
56 +patch=$(echo $current_version | awk '{split($0,a,"."); print a[3]}')
57 +
58 +if [[ "$@" == "major" ]]; then
59 + major=$(($major + 1));
60 + minor="0"
61 + patch="0"
62 +elif [[ "$@" == "minor" ]]; then
63 + minor=$(($minor + 1));
64 + patch="0"
65 +elif [[ "$@" == "patch" ]]; then
66 + patch=$(($patch + 1));
67 +fi
68 +
69 +next_version="${major}.${minor}.${patch}"
70 +
71 +echo -e "${YELLOW} >${COLOR_OFF} ${MAGENTA}${current_version}${COLOR_OFF} -> ${MAGENTA}${next_version}${COLOR_OFF}"
72 +
73 +echo -e "${YELLOW}--->${COLOR_OFF} Ensuring readme passes lint checks (if this fails, run rst-lint)"
74 +rst-lint README.rst > /dev/null
75 +
76 +echo -e "${YELLOW}--->${COLOR_OFF} Creating necessary temp file"
77 +tempfoo=$(basename $0)
78 +TMPFILE=$(mktemp /tmp/${tempfoo}.XXXXXX) || {
79 + echo -e "${RED}WARNING: Cannot create temp file using mktemp in /tmp dir ${COLOR_OFF}\n"
80 + exit 1
81 +}
82 +
83 +find_this="__version__ = '$current_version'"
84 +replace_with="__version__ = '$next_version'"
85 +
86 +echo -e "${YELLOW}--->${COLOR_OFF} Updating ${INIT_PACKAGE_NAME}/__init__.py"
87 +sed "s/$find_this/$replace_with/" ${INIT_PACKAGE_NAME}/__init__.py > $TMPFILE && mv $TMPFILE ${INIT_PACKAGE_NAME}/__init__.py
88 +
89 +echo -e "${YELLOW}--->${COLOR_OFF} Updating README.rst"
90 +find_this="${PACKAGE_NAME}.git@$current_version"
91 +replace_with="${PACKAGE_NAME}.git@$next_version"
92 +sed "s/$find_this/$replace_with/" README.rst > $TMPFILE && mv $TMPFILE README.rst
93 +find_this="${PACKAGE_NAME}==$current_version"
94 +replace_with="${PACKAGE_NAME}==$next_version"
95 +sed "s/$find_this/$replace_with/" README.rst > $TMPFILE && mv $TMPFILE README.rst
96 +
97 +if [ -f docs/conf.py ]; then
98 + echo -e "${YELLOW}--->${COLOR_OFF} Updating docs"
99 + find_this="version = '${current_version}'"
100 + replace_with="version = '${next_version}'"
101 + sed "s/$find_this/$replace_with/" docs/conf.py > $TMPFILE && mv $TMPFILE docs/conf.py
102 +
103 + find_this="release = '${current_version}'"
104 + replace_with="release = '${next_version}'"
105 + sed "s/$find_this/$replace_with/" docs/conf.py > $TMPFILE && mv $TMPFILE docs/conf.py
106 +fi
107 +
108 +echo -e "${YELLOW}--->${COLOR_OFF} Updating CHANGES.rst for new release"
109 +version_header="$next_version ($(date +%F))"
110 +set +e; dashes=$(yes '-'|head -n ${#version_header}|tr -d '\n') ; set -e
111 +gitchangelog |sed "4s/.*/$version_header/"|sed "5s/.*/$dashes/" > $TMPFILE && mv $TMPFILE CHANGES.rst
112 +
113 +echo -e "${YELLOW}--->${COLOR_OFF} Adding changed files to git"
114 +git add CHANGES.rst README.rst ${INIT_PACKAGE_NAME}/__init__.py
115 +if [ -f docs/conf.py ]; then git add docs/conf.py; fi
116 +
117 +echo -e "${YELLOW}--->${COLOR_OFF} Creating release"
118 +git commit -q -m "Release version $next_version"
119 +
120 +echo -e "${YELLOW}--->${COLOR_OFF} Tagging release"
121 +git tag -a $next_version -m "Release version $next_version"
122 +
123 +echo -e "${YELLOW}--->${COLOR_OFF} Pushing release and tags to github"
124 +git push -q origin master && git push -q --tags
125 +
126 +if [[ "$PUBLIC" == "true" ]]; then
127 + echo -e "${YELLOW}--->${COLOR_OFF} Creating python release"
128 + cp README.rst README
129 + python setup.py sdist bdist_wheel upload > /dev/null
130 + rm README
131 +else
132 + echo -e "${YELLOW}--->${COLOR_OFF} Creating local python dist and wheel for manual release"
133 + python setup.py sdist bdist_wheel > /dev/null
134 +fi
135 +
136 +echo -e "\n${CYAN}RELEASED VERSION ${next_version}${COLOR_OFF}\n"
1 +-r requirements.txt
2 +coverage==4.1
3 +mock>=1.0.1
4 +nose==1.3.1
5 +python-coveralls==2.7.0
6 +requests==2.10.0
7 +sh==1.11
8 +tox==1.7.1
1 +PyYAML>=3.11
1 boto3>=1.2.3 2 boto3>=1.2.3
3 +click>=5.1
2 placebo>=0.8.1 4 placebo>=0.8.1
3 -click==5.1
4 -PyYAML>=3.11
5 -mock>=1.0.1
6 -nose==1.3.1
7 -tox==1.7.1
......
...@@ -21,6 +21,7 @@ def foobar(): ...@@ -21,6 +21,7 @@ def foobar():
21 21
22 22
23 def _get(event, context): 23 def _get(event, context):
24 + assert context
24 customer_id = event.get('id') 25 customer_id = event.get('id')
25 if customer_id is None: 26 if customer_id is None:
26 raise Exception('No id provided for GET operation') 27 raise Exception('No id provided for GET operation')
...@@ -32,6 +33,7 @@ def _get(event, context): ...@@ -32,6 +33,7 @@ def _get(event, context):
32 33
33 34
34 def _post(event, context): 35 def _post(event, context):
36 + assert context
35 item = event['json_body'] 37 item = event['json_body']
36 if item is None: 38 if item is None:
37 raise Exception('No json_body found in event') 39 raise Exception('No json_body found in event')
...@@ -41,6 +43,7 @@ def _post(event, context): ...@@ -41,6 +43,7 @@ def _post(event, context):
41 43
42 44
43 def _put(event, context): 45 def _put(event, context):
46 + assert context
44 data = _get(event, context) 47 data = _get(event, context)
45 id_ = data.get('id') 48 id_ = data.get('id')
46 data.update(event['json_body']) 49 data.update(event['json_body'])
...@@ -51,6 +54,7 @@ def _put(event, context): ...@@ -51,6 +54,7 @@ def _put(event, context):
51 54
52 55
53 def handler(event, context): 56 def handler(event, context):
57 + assert context
54 LOG.info(event) 58 LOG.info(event)
55 http_method = event.get('http_method') 59 http_method = event.get('http_method')
56 if not http_method: 60 if not http_method:
......
...@@ -5,5 +5,6 @@ LOG.setLevel(logging.DEBUG) ...@@ -5,5 +5,6 @@ LOG.setLevel(logging.DEBUG)
5 5
6 6
7 def handler(event, context): 7 def handler(event, context):
8 + assert context
8 LOG.debug(event) 9 LOG.debug(event)
9 return {'status': 'success'} 10 return {'status': 'success'}
......
...@@ -6,6 +6,7 @@ LOG.setLevel(logging.INFO) ...@@ -6,6 +6,7 @@ LOG.setLevel(logging.INFO)
6 6
7 7
8 def handler(event, context): 8 def handler(event, context):
9 + assert context
9 for record in event['Records']: 10 for record in event['Records']:
10 start_time = record['Sns']['Timestamp'] 11 start_time = record['Sns']['Timestamp']
11 LOG.info('start_time: %s', start_time) 12 LOG.info('start_time: %s', start_time)
......
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 2
3 -from setuptools import setup, find_packages 3 +from kappa import __version__
4 -
5 import os 4 import os
6 5
7 -requires = [ 6 +try:
8 - 'boto3>=1.2.2', 7 + from setuptools import setup
9 - 'placebo>=0.4.1', 8 +except ImportError:
10 - 'click>=5.0', 9 + from distutils.core import setup
11 - 'PyYAML>=3.11' 10 +
12 -] 11 +
12 +def open_file(fname):
13 + return open(os.path.join(os.path.dirname(__file__), fname))
13 14
14 15
15 -setup( 16 +def run_setup():
17 + setup(
16 name='kappa', 18 name='kappa',
17 - version=open(os.path.join('kappa', '_version')).read().strip(), 19 + version=__version__,
18 description='A CLI tool for AWS Lambda developers', 20 description='A CLI tool for AWS Lambda developers',
19 - long_description=open('README.md').read(), 21 + long_description=open_file('README.rst').read(),
22 + url='https://github.com/garnaat/kappa',
20 author='Mitch Garnaat', 23 author='Mitch Garnaat',
21 author_email='mitch@garnaat.com', 24 author_email='mitch@garnaat.com',
22 - url='https://github.com/garnaat/kappa', 25 + license='Apache License 2.0',
23 - packages=find_packages(exclude=['tests*']), 26 + packages=['kappa', 'kappa.scripts'],
24 package_data={'kappa': ['_version']}, 27 package_data={'kappa': ['_version']},
25 package_dir={'kappa': 'kappa'}, 28 package_dir={'kappa': 'kappa'},
26 entry_points=""" 29 entry_points="""
27 [console_scripts] 30 [console_scripts]
28 kappa=kappa.scripts.cli:cli 31 kappa=kappa.scripts.cli:cli
29 """, 32 """,
30 - install_requires=requires, 33 + install_requires=open_file('requirements.txt').readlines(),
31 - license=open("LICENSE").read(), 34 + test_suite='tests',
35 + include_package_data=True,
36 + zip_safe=True,
32 classifiers=( 37 classifiers=(
33 'Development Status :: 3 - Alpha', 38 'Development Status :: 3 - Alpha',
34 'Intended Audience :: Developers', 39 'Intended Audience :: Developers',
...@@ -42,4 +47,7 @@ setup( ...@@ -42,4 +47,7 @@ setup(
42 'Programming Language :: Python :: 3.4', 47 'Programming Language :: Python :: 3.4',
43 'Programming Language :: Python :: 3.5' 48 'Programming Language :: Python :: 3.5'
44 ), 49 ),
45 -) 50 + )
51 +
52 +if __name__ == '__main__':
53 + run_setup()
......