|
@@ -1,110 +1,6 @@
|
|
"""
|
|
"""
|
|
-Frank can be configured using the following yaml::
|
|
|
|
- .frank.yml
|
|
|
|
-
|
|
|
|
- commads:
|
|
|
|
- - test
|
|
|
|
- - deploy
|
|
|
|
- - publish
|
|
|
|
-
|
|
|
|
- newtag:
|
|
|
|
- - python:
|
|
|
|
- - frank.actions:detect_new_tag
|
|
|
|
-
|
|
|
|
- deploy:
|
|
|
|
- - cmd
|
|
|
|
- - runif
|
|
|
|
- - test
|
|
|
|
- - newtag
|
|
|
|
-
|
|
|
|
- publish:
|
|
|
|
- - shell:
|
|
|
|
- - cd docs; make html
|
|
|
|
- - python:
|
|
|
|
- - frank.actions:recursive_copy
|
|
|
|
-
|
|
|
|
-The sections commands is a simple list of command you would
|
|
|
|
-like to define.
|
|
|
|
-This section is optional. It's main purpose is for you to decalre
|
|
|
|
-which commands frank should execute upon recieving a load.
|
|
|
|
-
|
|
|
|
-Each command is a dictionary with the following possible keys::
|
|
|
|
-
|
|
|
|
- cmd_name:
|
|
|
|
- - cmd # not mandatory if you include it in the list of commands
|
|
|
|
- - runif # a conditional to determine whether to run or skip the command
|
|
|
|
- # it can contain multiple directives which can be python
|
|
|
|
- # code to execute
|
|
|
|
- # or shell code
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-For example, let's say you would like to build the sphinx documentation
|
|
|
|
-of your project after every push. You start by defining a command
|
|
|
|
-build_docs in the following way::
|
|
|
|
-
|
|
|
|
- build_docs:
|
|
|
|
- - cmd
|
|
|
|
- - shell:
|
|
|
|
- - cd docs
|
|
|
|
- - make html
|
|
|
|
-
|
|
|
|
-You could also specify::
|
|
|
|
-
|
|
|
|
- build_docs:
|
|
|
|
- - cmd
|
|
|
|
- - shell: cd docs; make html
|
|
|
|
-
|
|
|
|
-or::
|
|
|
|
-
|
|
|
|
- build_docs:
|
|
|
|
- - shell:
|
|
|
|
- - cwd: docs
|
|
|
|
- - cmd: make html
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-This tells that `build_docs` is a command that executes after every push.
|
|
|
|
-It will execute a shell and will run the shell commands
|
|
|
|
-`cd docs; make html`. Pretty straight forward!
|
|
|
|
-
|
|
|
|
-Now, let's refine. Suppose we want to build the docs only if the docs changed,
|
|
|
|
-thus ignoring completely, changes in the embeded docs strings*::
|
|
|
|
-
|
|
|
|
- build_docs:
|
|
|
|
- - cmd
|
|
|
|
- - runif:
|
|
|
|
- - shell:
|
|
|
|
- - git --no-pager diff --name-status HEAD~1 | grep -v docs
|
|
|
|
- - shell: cd docs; make html
|
|
|
|
-
|
|
|
|
-Now, the command will run if the latest git commit have changed the docs
|
|
|
|
-directory. Since the grep command will return exit with 1.
|
|
|
|
-Alternatively, the conditional to run can be some python code that returns
|
|
|
|
-True or False. Here is how to specify this:
|
|
|
|
-
|
|
|
|
- build_docs:
|
|
|
|
- - cmd
|
|
|
|
- - runif:
|
|
|
|
- - python: frank.githubparsers:detect_changes_in_docs
|
|
|
|
- - shell: cd docs; make html
|
|
|
|
-
|
|
|
|
-This, will invoke the method ``detect_changes_in_docs`` which is
|
|
|
|
-found in the module `frank.githubparsers`.
|
|
|
|
-If this function will return True the shell command will execute.
|
|
|
|
-If the methods takes some arguments, they could also be given.
|
|
|
|
-Suppose the function is called `detect_changes_in` and this function
|
|
|
|
-takes a single paramter called path we can configure the
|
|
|
|
-build_docs command in the following way:
|
|
|
|
-
|
|
|
|
- build_docs:
|
|
|
|
- - cmd
|
|
|
|
- - runif:
|
|
|
|
- - python:
|
|
|
|
- - function: frank.githubparsers:detect_changes_in
|
|
|
|
- - args:
|
|
|
|
- - path: docs
|
|
|
|
-
|
|
|
|
-* This is probably a lame idea, but it's good for demonstration.
|
|
|
|
-So, do write doc-strings, and do build your docs often.
|
|
|
|
|
|
+Frank-ci - A simple CI for Pythonistas, based on Flask + Huey.
|
|
|
|
+For more information see the docs/frank.rst
|
|
"""
|
|
"""
|
|
|
|
|
|
import hmac
|
|
import hmac
|
|
@@ -286,7 +182,42 @@ def clone(clone_url, branch, depth=1):
|
|
@taskq.task()
|
|
@taskq.task()
|
|
def count_beans():
|
|
def count_beans():
|
|
print "count_12"
|
|
print "count_12"
|
|
- return "count_12"
|
|
|
|
|
|
+ return "count_12"
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+@taskq.task()
|
|
|
|
+def build_task(request_json):
|
|
|
|
+ """
|
|
|
|
+ . clone the latest commit (--depth 1)
|
|
|
|
+ . parse yaml config
|
|
|
|
+ . for each command in the config
|
|
|
|
+ . run command
|
|
|
|
+ . report success or failure
|
|
|
|
+ """
|
|
|
|
+ request_as_json = request.get_json()
|
|
|
|
+ clone_dest = parse_branch_gh(request_as_json)
|
|
|
|
+ repo_name = request_as_json["repository"]['name']
|
|
|
|
+ try:
|
|
|
|
+ o, e = clone(request_as_json['repository']['ssh_url'], clone_dest)
|
|
|
|
+ except Exception as E:
|
|
|
|
+ print E, E.message
|
|
|
|
+ # parse yaml is still very crude ...
|
|
|
|
+ # it could yield selfect with a run method
|
|
|
|
+ # thus:
|
|
|
|
+ # for action in parse_yaml(clone_dest):
|
|
|
|
+ # action.run()
|
|
|
|
+ #
|
|
|
|
+ # this should also handle dependencies,
|
|
|
|
+ # the following implementation is very crud
|
|
|
|
+ failed = None
|
|
|
|
+ for action in parse_yaml(clone_dest):
|
|
|
|
+ # if config says we use huey, we should modiy run_action
|
|
|
|
+ results = run_action(action)
|
|
|
|
+
|
|
|
|
+ if any([result.code for result in results]):
|
|
|
|
+ report_failure(results)
|
|
|
|
+ else:
|
|
|
|
+ report_success(results)
|
|
|
|
|
|
|
|
|
|
@app.route('/beans')
|
|
@app.route('/beans')
|
|
@@ -308,44 +239,19 @@ def start():
|
|
"""
|
|
"""
|
|
main logic:
|
|
main logic:
|
|
1. listen to post
|
|
1. listen to post
|
|
- 2a if authenticated post do:
|
|
|
|
- 3. clone the latest commit (--depth 1)
|
|
|
|
- 4. parse yaml config
|
|
|
|
- 5. for each command in the config
|
|
|
|
- 7. run command
|
|
|
|
- 8. report success or failure
|
|
|
|
- """
|
|
|
|
|
|
+ 2. if authenticated post do:
|
|
|
|
+ enqueue task to build or test the code
|
|
# This is authentication for github only
|
|
# This is authentication for github only
|
|
# We could\should check for other hostings
|
|
# We could\should check for other hostings
|
|
|
|
+ """
|
|
ans = hmac.new(app.config['POST_KEY'], request.data,
|
|
ans = hmac.new(app.config['POST_KEY'], request.data,
|
|
hashlib.sha1).hexdigest()
|
|
hashlib.sha1).hexdigest()
|
|
secret = request.headers['X-Hub-Signature'].split('=')[-1]
|
|
secret = request.headers['X-Hub-Signature'].split('=')[-1]
|
|
if ans != secret:
|
|
if ans != secret:
|
|
return abort(500)
|
|
return abort(500)
|
|
request_as_json = request.get_json()
|
|
request_as_json = request.get_json()
|
|
- clone_dest = parse_branch_gh(request_as_json)
|
|
|
|
- repo_name = request_as_json["repository"]['name']
|
|
|
|
- try:
|
|
|
|
- o, e = clone(request_as_json['repository']['ssh_url'], clone_dest)
|
|
|
|
- except Exception as E:
|
|
|
|
- print E, E.message
|
|
|
|
- # parse yaml is still very crude ...
|
|
|
|
- # it could yield selfect with a run method
|
|
|
|
- # thus:
|
|
|
|
- # for action in parse_yaml(clone_dest):
|
|
|
|
- # action.run()
|
|
|
|
- #
|
|
|
|
- # this should also handle dependencies,
|
|
|
|
- # the following implementation is very crud
|
|
|
|
- failed = None
|
|
|
|
- for action in parse_yaml(clone_dest):
|
|
|
|
- # if config says we use huey, we should modiy run_action
|
|
|
|
- results = run_action(action)
|
|
|
|
-
|
|
|
|
- if any([result.code for result in results]):
|
|
|
|
- report_failure(results)
|
|
|
|
- else:
|
|
|
|
- report_success(results)
|
|
|
|
|
|
+ build_task(request_as_json)
|
|
|
|
+ return "OK"
|
|
|
|
|
|
|
|
|
|
@click.group()
|
|
@click.group()
|