{"action":"created","comment":{"url":"https://api.github.com/repos/txels/ep/pulls/comments/26892439","id":26892439,"diff_hunk":"@@ -1,3 +1,117 @@\n # ep\n \n A tool to support an explicit contract between application and plaftorm.\n+\n+Inspired by Heroku's post about [an explicit contract between application and\n+platform](https://blog.heroku.com/archives/2011/6/28/the_new_heroku_4_erosion_resistance_explicit_contracts),\n+`ep` aims to provide a reusable mechanism to cover that contract.\n+\n+As a summary, Heroku's contract is based on:\n+\n+- Dependency management: declared as part of the codebase\n+- Procfile: as a mechanism to specify what should be run\n+- Web process binds to $PORT (an externally provided environment variable\n+- stdout for logs\n+- Resource handles in the environment: environment variables for configuration,\n+  in particular for connecting to external resources\n+\n+\n+## What defines a contract in `ep`\n+\n+An `ep`-based contract tries to cover these areas:\n+\n+- A defined way to specify your dependencies\n+- A defined way to run your project\n+- Configured purely via environment variables\n+\n+The particulars of the contract are specified via a configuration file that\n+lives on the root of your application's repository. This configuration file\n+is in YAML format and is called `ep.yml` by default.\n+\n+\n+### A defined way to specify dependencies\n+\n+Dependencies can be of various types. `ep` aims to cover at least the\n+following:\n+\n+ - `python`: via pip install of a requirements file. Defaults to\n+   `requirements.txt` at the root folder\n+ - `node`: via npm install of a package file. Defaults to `package.json` at\n+   the root\n+\n+> The root here refers to the directory where `ep.yml` lives.\n+\n+> Future extensions may cover ruby gems, bower packages, and even os-level\n+> packages on some OSes\n+\n+There are two types of dependencies from the PoV of `ep`:\n+ - Those that the tool will be able to install\n+ - Those that it will only verify, but not attempt to install. These include\n+   e.g. the version of Python in your system\n+\n+Some of these dependencies will have their defaults.\n+This could be a partial example of a `ep.yml`.\n+\n+```yaml\n+ep: 1.0.0\n+dependencies:\n+  - python\n+      version: 2.7\n+      file: requirements/runtime.txt\n+  - npm\n+```\n+\n+The command to install dependencies via ep is:\n+\n+    ep setup\n+\n+`ep` will always install dependencies in an isolated environment. This means\n+e.g. a virtual environment in Python, local npm install etc. `ep` will manage\n+the creation of this isolated environment for you.\n+\n+\n+### A defined way to run your project\n+\n+`ep` doesn't force you to use `Procfile`, but lets you define your run\n+command:\n+\n+```yaml\n+run: gunicorn myapp.wsgi\n+```\n+\n+Defaults to running a `Procfile` in your root.\n+\n+Run your project using:\n+\n+    ep run\n+\n+\n+### Configuration via environment variables\n+\n+Your app should be configurable via environment variables. Your `ep.yml` file\n+provides an explicit definition of what those variables are, and optional\n+default values and help.\n+\n+```yaml\n+run:\n+  environment:\n+    PORT:\n+      default: 8000\n+      help: The port the web application will run on\n+    SOME_EXTERNAL_SERVICE_URL:\n+      default: http://localhost:9000\n+```\n+\n+`ep run` will complain if variables that do not have a default value are not\n+privided, and refuse to run.\n+\n+\n+## Additional features\n+\n+Besides the basic explicit contract defined above, `ep` helps you with extra\n+things.\n+\n+### Extra setup steps\n+\n+TODO: define a mechanism to have additional setup steps such as running\n+migrations on a django project, etc...","path":"README.md","position":117,"original_position":117,"commit_id":"10ac2d91d5f2aa3df1a156d01a5ad94e873612a9","original_commit_id":"10ac2d91d5f2aa3df1a156d01a5ad94e873612a9","user":{"login":"txels","id":874958,"avatar_url":"https://avatars.githubusercontent.com/u/874958?v=3","gravatar_id":"","url":"https://api.github.com/users/txels","html_url":"https://github.com/txels","followers_url":"https://api.github.com/users/txels/followers","following_url":"https://api.github.com/users/txels/following{/other_user}","gists_url":"https://api.github.com/users/txels/gists{/gist_id}","starred_url":"https://api.github.com/users/txels/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/txels/subscriptions","organizations_url":"https://api.github.com/users/txels/orgs","repos_url":"https://api.github.com/users/txels/repos","events_url":"https://api.github.com/users/txels/events{/privacy}","received_events_url":"https://api.github.com/users/txels/received_events","type":"User","site_admin":false},"body":"Something that might be worth adding here is something like \"packaging for deploy\"? `ep package`\r\n\r\nConfiguration options might include package as tarball, or as a docker image... Packaging would take care of including a proper `ep.yml` file in the deployed image so that when unpackaging `ep` could be able to run the service in the remote host as well.\r\n\r\nI'm still fuzzy-thinking about this.","created_at":"2015-03-21T14:46:00Z","updated_at":"2015-03-21T14:46:00Z","html_url":"https://github.com/txels/ep/pull/1#discussion_r26892439","pull_request_url":"https://api.github.com/repos/txels/ep/pulls/1","_links":{"self":{"href":"https://api.github.com/repos/txels/ep/pulls/comments/26892439"},"html":{"href":"https://github.com/txels/ep/pull/1#discussion_r26892439"},"pull_request":{"href":"https://api.github.com/repos/txels/ep/pulls/1"}}},"pull_request":{"url":"https://api.github.com/repos/txels/ep/pulls/1","id":31652462,"html_url":"https://github.com/txels/ep/pull/1","diff_url":"https://github.com/txels/ep/pull/1.diff","patch_url":"https://github.com/txels/ep/pull/1.patch","issue_url":"https://api.github.com/repos/txels/ep/issues/1","number":1,"state":"open","locked":false,"title":"Readme-driven-development: initial spec for ep","user":{"login":"txels","id":874958,"avatar_url":"https://avatars.githubusercontent.com/u/874958?v=3","gravatar_id":"","url":"https://api.github.com/users/txels","html_url":"https://github.com/txels","followers_url":"https://api.github.com/users/txels/followers","following_url":"https://api.github.com/users/txels/following{/other_user}","gists_url":"https://api.github.com/users/txels/gists{/gist_id}","starred_url":"https://api.github.com/users/txels/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/txels/subscriptions","organizations_url":"https://api.github.com/users/txels/orgs","repos_url":"https://api.github.com/users/txels/repos","events_url":"https://api.github.com/users/txels/events{/privacy}","received_events_url":"https://api.github.com/users/txels/received_events","type":"User","site_admin":false},"body":"An initial spec or statement of intent for `ep`.","created_at":"2015-03-20T21:14:00Z","updated_at":"2015-03-21T14:46:00Z","closed_at":null,"merged_at":null,"merge_commit_sha":"0f48518f3c119031b60787163f9b4d72459f26cd","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/txels/ep/pulls/1/commits","review_comments_url":"https://api.github.com/repos/txels/ep/pulls/1/comments","review_comment_url":"https://api.github.com/repos/txels/ep/pulls/comments{/number}","comments_url":"https://api.github.com/repos/txels/ep/issues/1/comments","statuses_url":"https://api.github.com/repos/txels/ep/statuses/10ac2d91d5f2aa3df1a156d01a5ad94e873612a9","head":{"label":"txels:carles/readme-driven-development","ref":"carles/readme-driven-development","sha":"10ac2d91d5f2aa3df1a156d01a5ad94e873612a9","user":{"login":"txels","id":874958,"avatar_url":"https://avatars.githubusercontent.com/u/874958?v=3","gravatar_id":"","url":"https://api.github.com/users/txels","html_url":"https://github.com/txels","followers_url":"https://api.github.com/users/txels/followers","following_url":"https://api.github.com/users/txels/following{/other_user}","gists_url":"https://api.github.com/users/txels/gists{/gist_id}","starred_url":"https://api.github.com/users/txels/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/txels/subscriptions","organizations_url":"https://api.github.com/users/txels/orgs","repos_url":"https://api.github.com/users/txels/repos","events_url":"https://api.github.com/users/txels/events{/privacy}","received_events_url":"https://api.github.com/users/txels/received_events","type":"User","site_admin":false},"repo":{"id":32605078,"name":"ep","full_name":"txels/ep","owner":{"login":"txels","id":874958,"avatar_url":"https://avatars.githubusercontent.com/u/874958?v=3","gravatar_id":"","url":"https://api.github.com/users/txels","html_url":"https://github.com/txels","followers_url":"https://api.github.com/users/txels/followers","following_url":"https://api.github.com/users/txels/following{/other_user}","gists_url":"https://api.github.com/users/txels/gists{/gist_id}","starred_url":"https://api.github.com/users/txels/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/txels/subscriptions","organizations_url":"https://api.github.com/users/txels/orgs","repos_url":"https://api.github.com/users/txels/repos","events_url":"https://api.github.com/users/txels/events{/privacy}","received_events_url":"https://api.github.com/users/txels/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/txels/ep","description":"Toolset to make it easy to build an explicit contract between application and platform","fork":false,"url":"https://api.github.com/repos/txels/ep","forks_url":"https://api.github.com/repos/txels/ep/forks","keys_url":"https://api.github.com/repos/txels/ep/keys{/key_id}","collaborators_url":"https://api.github.com/repos/txels/ep/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/txels/ep/teams","hooks_url":"https://api.github.com/repos/txels/ep/hooks","issue_events_url":"https://api.github.com/repos/txels/ep/issues/events{/number}","events_url":"https://api.github.com/repos/txels/ep/events","assignees_url":"https://api.github.com/repos/txels/ep/assignees{/user}","branches_url":"https://api.github.com/repos/txels/ep/branches{/branch}","tags_url":"https://api.github.com/repos/txels/ep/tags","blobs_url":"https://api.github.com/repos/txels/ep/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/txels/ep/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/txels/ep/git/refs{/sha}","trees_url":"https://api.github.com/repos/txels/ep/git/trees{/sha}","statuses_url":"https://api.github.com/repos/txels/ep/statuses/{sha}","languages_url":"https://api.github.com/repos/txels/ep/languages","stargazers_url":"https://api.github.com/repos/txels/ep/stargazers","contributors_url":"https://api.github.com/repos/txels/ep/contributors","subscribers_url":"https://api.github.com/repos/txels/ep/subscribers","subscription_url":"https://api.github.com/repos/txels/ep/subscription","commits_url":"https://api.github.com/repos/txels/ep/commits{/sha}","git_commits_url":"https://api.github.com/repos/txels/ep/git/commits{/sha}","comments_url":"https://api.github.com/repos/txels/ep/comments{/number}","issue_comment_url":"https://api.github.com/repos/txels/ep/issues/comments{/number}","contents_url":"https://api.github.com/repos/txels/ep/contents/{+path}","compare_url":"https://api.github.com/repos/txels/ep/compare/{base}...{head}","merges_url":"https://api.github.com/repos/txels/ep/merges","archive_url":"https://api.github.com/repos/txels/ep/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/txels/ep/downloads","issues_url":"https://api.github.com/repos/txels/ep/issues{/number}","pulls_url":"https://api.github.com/repos/txels/ep/pulls{/number}","milestones_url":"https://api.github.com/repos/txels/ep/milestones{/number}","notifications_url":"https://api.github.com/repos/txels/ep/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/txels/ep/labels{/name}","releases_url":"https://api.github.com/repos/txels/ep/releases{/id}","created_at":"2015-03-20T20:22:39Z","updated_at":"2015-03-20T20:22:39Z","pushed_at":"2015-03-20T21:21:17Z","git_url":"git://github.com/txels/ep.git","ssh_url":"git@github.com:txels/ep.git","clone_url":"https://github.com/txels/ep.git","svn_url":"https://github.com/txels/ep","homepage":null,"size":0,"stargazers_count":0,"watchers_count":0,"language":null,"has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"master"}},"base":{"label":"txels:master","ref":"master","sha":"3b0e5ace360561df6543526812e9031432073a12","user":{"login":"txels","id":874958,"avatar_url":"https://avatars.githubusercontent.com/u/874958?v=3","gravatar_id":"","url":"https://api.github.com/users/txels","html_url":"https://github.com/txels","followers_url":"https://api.github.com/users/txels/followers","following_url":"https://api.github.com/users/txels/following{/other_user}","gists_url":"https://api.github.com/users/txels/gists{/gist_id}","starred_url":"https://api.github.com/users/txels/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/txels/subscriptions","organizations_url":"https://api.github.com/users/txels/orgs","repos_url":"https://api.github.com/users/txels/repos","events_url":"https://api.github.com/users/txels/events{/privacy}","received_events_url":"https://api.github.com/users/txels/received_events","type":"User","site_admin":false},"repo":{"id":32605078,"name":"ep","full_name":"txels/ep","owner":{"login":"txels","id":874958,"avatar_url":"https://avatars.githubusercontent.com/u/874958?v=3","gravatar_id":"","url":"https://api.github.com/users/txels","html_url":"https://github.com/txels","followers_url":"https://api.github.com/users/txels/followers","following_url":"https://api.github.com/users/txels/following{/other_user}","gists_url":"https://api.github.com/users/txels/gists{/gist_id}","starred_url":"https://api.github.com/users/txels/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/txels/subscriptions","organizations_url":"https://api.github.com/users/txels/orgs","repos_url":"https://api.github.com/users/txels/repos","events_url":"https://api.github.com/users/txels/events{/privacy}","received_events_url":"https://api.github.com/users/txels/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/txels/ep","description":"Toolset to make it easy to build an explicit contract between application and platform","fork":false,"url":"https://api.github.com/repos/txels/ep","forks_url":"https://api.github.com/repos/txels/ep/forks","keys_url":"https://api.github.com/repos/txels/ep/keys{/key_id}","collaborators_url":"https://api.github.com/repos/txels/ep/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/txels/ep/teams","hooks_url":"https://api.github.com/repos/txels/ep/hooks","issue_events_url":"https://api.github.com/repos/txels/ep/issues/events{/number}","events_url":"https://api.github.com/repos/txels/ep/events","assignees_url":"https://api.github.com/repos/txels/ep/assignees{/user}","branches_url":"https://api.github.com/repos/txels/ep/branches{/branch}","tags_url":"https://api.github.com/repos/txels/ep/tags","blobs_url":"https://api.github.com/repos/txels/ep/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/txels/ep/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/txels/ep/git/refs{/sha}","trees_url":"https://api.github.com/repos/txels/ep/git/trees{/sha}","statuses_url":"https://api.github.com/repos/txels/ep/statuses/{sha}","languages_url":"https://api.github.com/repos/txels/ep/languages","stargazers_url":"https://api.github.com/repos/txels/ep/stargazers","contributors_url":"https://api.github.com/repos/txels/ep/contributors","subscribers_url":"https://api.github.com/repos/txels/ep/subscribers","subscription_url":"https://api.github.com/repos/txels/ep/subscription","commits_url":"https://api.github.com/repos/txels/ep/commits{/sha}","git_commits_url":"https://api.github.com/repos/txels/ep/git/commits{/sha}","comments_url":"https://api.github.com/repos/txels/ep/comments{/number}","issue_comment_url":"https://api.github.com/repos/txels/ep/issues/comments{/number}","contents_url":"https://api.github.com/repos/txels/ep/contents/{+path}","compare_url":"https://api.github.com/repos/txels/ep/compare/{base}...{head}","merges_url":"https://api.github.com/repos/txels/ep/merges","archive_url":"https://api.github.com/repos/txels/ep/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/txels/ep/downloads","issues_url":"https://api.github.com/repos/txels/ep/issues{/number}","pulls_url":"https://api.github.com/repos/txels/ep/pulls{/number}","milestones_url":"https://api.github.com/repos/txels/ep/milestones{/number}","notifications_url":"https://api.github.com/repos/txels/ep/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/txels/ep/labels{/name}","releases_url":"https://api.github.com/repos/txels/ep/releases{/id}","created_at":"2015-03-20T20:22:39Z","updated_at":"2015-03-20T20:22:39Z","pushed_at":"2015-03-20T21:21:17Z","git_url":"git://github.com/txels/ep.git","ssh_url":"git@github.com:txels/ep.git","clone_url":"https://github.com/txels/ep.git","svn_url":"https://github.com/txels/ep","homepage":null,"size":0,"stargazers_count":0,"watchers_count":0,"language":null,"has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/txels/ep/pulls/1"},"html":{"href":"https://github.com/txels/ep/pull/1"},"issue":{"href":"https://api.github.com/repos/txels/ep/issues/1"},"comments":{"href":"https://api.github.com/repos/txels/ep/issues/1/comments"},"review_comments":{"href":"https://api.github.com/repos/txels/ep/pulls/1/comments"},"review_comment":{"href":"https://api.github.com/repos/txels/ep/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/txels/ep/pulls/1/commits"},"statuses":{"href":"https://api.github.com/repos/txels/ep/statuses/10ac2d91d5f2aa3df1a156d01a5ad94e873612a9"}}}}