Skip to content

Commit

Permalink
Merge pull request #2 from hawry/add-ignore-and-cleanup
Browse files Browse the repository at this point in the history
add ignore feature and refactor code
  • Loading branch information
hawry authored Oct 13, 2019
2 parents aaba4a6 + 81a9320 commit 7c801c5
Show file tree
Hide file tree
Showing 12 changed files with 383 additions and 238 deletions.
94 changes: 94 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ Options:
contains more than one ApiGateway resource)
-f, --format [yaml|json] output format [default: yaml]
-i, --indent INTEGER if output format is json, specify indentation
-d, --debug if enabled, show debug logs
--no-ignore if set, deforest will export paths marked as
ignored
--version Show the version and exit.
--help Show this message and exit.
```
Expand All @@ -33,6 +36,97 @@ Options:

Version 0.1.1 and later supports CloudFormation templates as input. If more than one API Gateway is part of the template, the `--outfile` flag will be ignored.

## Hide paths

Version 0.2.0 introduced support for deforest to ignore certain paths. If you specify `x-deforest-ignore: true` anywhere in your specification, deforest will not extract its _parent_ node to the end results. Example:

```yaml
paths:
"/validation":
post:
responses:
"200":
schema:
type: array
items:
"$ref": "#/definitions/Error"
headers:
test-method-response-header:
type: string
get:
x-deforest-ignore: true
parameters:
- name: q1
in: query
required: true
responses:
"200":
schema:
type: array
items:
"$ref": "#/definitions/Error"
headers:
test-method-response-header:
type: string
```
will result in
```yaml
paths:
/validation:
post:
responses:
"200":
headers:
test-method-response-header:
type: string
schema:
items:
$ref: "#/definitions/Error"
type: array
```
If we'd written this:
```yaml
paths:
"/validation":
x-deforest-ignore: true
post:
responses:
"200":
schema:
type: array
items:
"$ref": "#/definitions/Error"
headers:
test-method-response-header:
type: string
get:
parameters:
- name: q1
in: query
required: true
responses:
"200":
schema:
type: array
items:
"$ref": "#/definitions/Error"
headers:
test-method-response-header:
type: string
```
we'd get an empty result since the _parent_ node is removed:
```yaml
paths: {}
```
If `x-deforest-ignore: false`, or missing, the node will be extracted as usual. If the runtime flag `--no-ignore` is set, the nodes will be extracted as usual as well.

# Limitations

The output file looses its order of the keys in the file, which shouldn't affect you if you're using a converter to create a graphical documentation/specification - but can be confusing if you have a specific internal order you wish to keep.
Expand Down
2 changes: 2 additions & 0 deletions deforest/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
VERSION = "0.1.1"
LOGGER = "deforest"
97 changes: 0 additions & 97 deletions deforest/cfcleaner.py

This file was deleted.

66 changes: 0 additions & 66 deletions deforest/cleaner.py

This file was deleted.

90 changes: 90 additions & 0 deletions deforest/cleaners.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import logging


class CloudFormationCleaner:
KEY_CF_FIELD = "AWSTemplateFormatVersion"
KEY_CF_RESOURCES = "Resources"
KEY_CF_BODY = "Body"
KEY_CF_TYPE = "Type"
KEY_CF_PROPERTIES = "Properties"
CF_APIGW_TYPE = "AWS::ApiGateway::RestApi"

def __init__(self, caller):
logging.debug("created {}".format(self))
self.caller = caller

def clean(self):
logging.debug("{} clean".format(self))
logging.debug("checking {}".format(self.caller.result))
if not CloudFormationCleaner.KEY_CF_FIELD in self.caller.result:
self.caller.result = [self.caller.result]
return
rval = []
copy = self.caller.result
res = copy[CloudFormationCleaner.KEY_CF_RESOURCES]
for k in res:
if isinstance(res[k], dict):
if self._is_apigw(res[k]) and self._has_body(res[k]):
logging.info(
"identified resource '{}' as an API Gateway".format(k))
rval.append(
res[k][CloudFormationCleaner.KEY_CF_PROPERTIES][CloudFormationCleaner.KEY_CF_BODY])
self.caller.result = rval

def _is_apigw(self, node):
if CloudFormationCleaner.KEY_CF_TYPE in node:
return node[CloudFormationCleaner.KEY_CF_TYPE] == CloudFormationCleaner.CF_APIGW_TYPE
return False

def _has_body(self, node):
return CloudFormationCleaner.KEY_CF_PROPERTIES in node and CloudFormationCleaner.KEY_CF_BODY in node[CloudFormationCleaner.KEY_CF_PROPERTIES]


class DefaultCleaner:
keys = ["x-amazon"]
copy = None

def __init__(self, caller):
logging.debug("created {}".format(self))
self.caller = caller

def clean(self):
logging.debug("{} clean".format(self))
logging.debug("checking {}".format(self.caller.result))
self.copy = self.caller.result
for i in self.copy:
self._clean(i)
self.caller.result = self.copy

def _clean(self, v):
for k in v.keys():
if any(m in k for m in self.keys):
del v[k]
else:
if isinstance(v[k], dict):
self._clean(v[k])


class IgnoreCleaner:
DEFOREST_IGNORE_KEY = "x-deforest-ignore"
copy = None

def __init__(self, caller):
logging.debug("created {}".format(self))
self.caller = caller

def clean(self):
self.copy = self.caller.result
for i in self.copy:
self._clean(i)
self.caller.result = self.copy

def _clean(self, v):
for k in v.keys():
if isinstance(v[k], dict):
if IgnoreCleaner.DEFOREST_IGNORE_KEY in v[k]:
if v[k][IgnoreCleaner.DEFOREST_IGNORE_KEY] is True:
logging.debug("removing {}".format(v[k]))
del v[k]
else:
self._clean(v[k])
4 changes: 3 additions & 1 deletion deforest/constant.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
VERSION = "0.1.1"
VERSION = "0.2.0"
LOGGER = "deforest"
EXIT_NOTFOUND = 1
EXIT_PARSEERR = 2
Loading

0 comments on commit 7c801c5

Please sign in to comment.