{"id":13878814,"url":"https://github.com/skroutz/cogy","last_synced_at":"2025-04-27T03:30:55.307Z","repository":{"id":12722024,"uuid":"72629378","full_name":"skroutz/cogy","owner":"skroutz","description":"Cog commands from your Rails app","archived":false,"fork":false,"pushed_at":"2023-01-30T13:20:21.000Z","size":836,"stargazers_count":21,"open_issues_count":15,"forks_count":1,"subscribers_count":14,"default_branch":"master","last_synced_at":"2024-10-31T13:53:15.218Z","etag":null,"topics":["chat","chat-bot","chatbot","chatbots","chatops","cog","rails"],"latest_commit_sha":null,"homepage":"https://github.com/operable/cog","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/skroutz.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-11-02T10:32:19.000Z","updated_at":"2024-04-26T06:36:39.000Z","dependencies_parsed_at":"2023-02-17T23:10:13.676Z","dependency_job_id":null,"html_url":"https://github.com/skroutz/cogy","commit_stats":null,"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skroutz%2Fcogy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skroutz%2Fcogy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skroutz%2Fcogy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skroutz%2Fcogy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/skroutz","download_url":"https://codeload.github.com/skroutz/cogy/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224056571,"owners_count":17248329,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chat","chat-bot","chatbot","chatbots","chatops","cog","rails"],"created_at":"2024-08-06T08:02:00.918Z","updated_at":"2024-11-11T06:11:13.089Z","avatar_url":"https://github.com/skroutz.png","language":"Ruby","funding_links":[],"categories":["Ruby"],"sub_categories":[],"readme":"# Cogy\n\n[![Build Status](https://api.travis-ci.org/skroutz/cogy.svg?branch=master)](https://travis-ci.org/skroutz/cogy)\n[![Gem Version](https://badge.fury.io/rb/cogy.svg)](https://badge.fury.io/rb/cogy)\n[![Documentation](http://img.shields.io/badge/yard-docs-blue.svg)](http://www.rubydoc.info/github/skroutz/cogy)\n\nCogy integrates [Cog](https://operable.io/) with Rails\nin a way that writing \u0026 deploying commands from your application is a breeze.\n\nSee the API documentation [here](http://www.rubydoc.info/github/skroutz/cogy).\n\nRefer to the [Changelog](CHANGELOG.md) to see what's changed between releases.\n\n## Features\n\n- Define commands from your Rails app (see [_Usage_](#usage))\n- Bundle config is generated automatically\n- Commands are installed _automatically_ when you deploy (see [_Deployment_](#deployment))\n- Supports JSON responses and Cog Templates (see [_Returning JSON to COG_](#returning-json-to-cog))\n- Customizable error template (see [_Error template_](#error-template))\n\n...and [more on the way](https://github.com/skroutz/cogy/issues?q=is%3Aopen+is%3Aissue+label%3Afeature)!\n\n## Why\n\nCreating ChatOps commands that talk with a Rails app typically involves writing\na route, maybe a controller, an action and code to handle the command arguments\nand options.\n\nThis is a tedious and repetitive task and involves a lot of boilerplate\ncode each time someone wants to add a new command.\n\nCogy is an opinionated library that provides a way to get rid of all the\nboilerplate stuff so you can focus on just the actual commands.\n\nDeploying a new command is as simple as writing:\n\n```ruby\n# in cogy/my_commands.rb\n\non \"foo\", desc: \"Echo a foo bar back at you!\" do\n  \"@#{handle}: foo bar\"\nend\n```\n\n...and deploying!\n\n## How it works\n\nCogy is essentially three things:\n\n1. An opinionated way to write, manage \u0026 ship commands: All Cogy commands are\n   defined in your Rails app and end up invoking a single executable within the\n   Relay (see below). Cogy also provides bundle versioning and dynamically generates the\n   installable bundle config, which is also served by your Rails application\n   and consumed by the [`cogy:install`](https://github.com/skroutz/cogy-bundle)\n   command that installs the new Cogy-generated bundle when you deploy your\n   application.\n2. A library that provides the API for defining the commands. This library\n   is integrated in your application via a Rails Engine that routes the incoming\n   requests to their respective handlers. It also creates the `/inventory`\n   endpoint, which serves the installable bundle configuration in YAML and can be\n   consumed directly by the [`cogy:install`](https://github.com/skroutz/cogy-bundle) command.\n3. A [Cog bundle](https://github.com/skroutz/cogy-bundle) that contains the\n   [executable](https://github.com/skroutz/cogy-bundle/blob/master/commands/cogy)\n   that all the commands end up invoking.\n   It is placed inside the Relays and performs the requests to your application\n   when a user invokes a command in the chat. It then posts the result back\n   to the user. It also contains the `cogy:install` command for automating\n   the task of installing the new bundle when a command is added/modified.\n\nTake a look at the relevant [diagrams](diagrams/) for a detailed illustration.\n\n## Requirements\n\n* Cog 1.0.0.beta2 or later\n* [cogy bundle](https://github.com/skroutz/cogy-bundle) 0.4.0 or later\n* Ruby 2.1 or later\n* Rails 4.2 or later\n\n## Status\n\nCogy is still in public alpha.\n\nWhile we use it in production, it's still under heavy development.\nThis means that there are a few rough edges and things change fast.\n\nHowever we'd love any [feedback, suggestions or ideas](https://github.com/skroutz/cogy/issues/new).\n\n## Install\n\nAdd it to your Gemfile:\n\n```ruby\ngem \"cogy\"\n```\n\nThen run `bundle install`\n\nNext, run the generator:\n\n```shell\n$ bin/rails g cogy:install\n```\n\nThis will create a sample command, mount the engine and add a sample\nconfiguration initializer in your application.\n\n## Usage\n\nDefining a new command:\n\n```ruby\n# in cogy/my_commands.rb\n\non \"foo\", desc: \"Echo a bar\" do\n  \"bar\"\nend\n```\n\nThis will print \"bar\" back to the user who calls `!foo` in Slack.\n\nLet's define a command that simply adds the numbers passed as arguments:\n\n```ruby\n# in cogy/calculations.rb\n\non \"add\", args: [:a, :b], desc: \"Add two numbers\" do\n  a.to_i + b.to_i\nend\n```\n\nInside the block there are the following helpers available:\n\n* `args`: an array containing the arguments passed to the command\n  * arguments can also be accessed by their names as local variables\n* `opts`: a hash containing the options passed to the command\n* `handle`: the chat handle of the user who called the command\n* `env`: a hash containing the Relay environment as available in the cogy\n  bundle\n\nFor instructions on defining your own helpers, see [Helpers](#helpers).\n\nA more complete example:\n\n```ruby\n# in cogy/commands.rb\non \"calc\",\n  args: [:a, :b],\n  opts: { op: { type: \"string\", required: true } },\n  desc: \"Performs a calculation between numbers \u003ca\u003e and \u003cb\u003e\",\n  examples: [\"myapp:calc sum 1 2\", \"myapp:calc sum -1 -2\"] do\n  op = opts[:op].to_sym\n  result = args.map(\u0026:to_i).inject(\u0026op)\n  \"Hello @#{user}, the result is: #{result}\"\nend\n```\n\nFor more examples see the [test commands](https://github.com/skroutz/cogy/tree/master/test/dummies/cogy).\n\n### Returning JSON to Cog\n\nYou can return JSON to Cog by just returning a `Hash`:\n\n```ruby\non \"foo\", desc: \"Just a JSON\" do\n  { a: 3 }\nend\n```\n\nThe hash is automatically converted to JSON. The above command would return\nthe following response to Cog:\n\n```\nCOG_TEMPLATE: foo\nJSON\n{\"a\":3}\n```\n\nTo customize the Cog [template](#Templates) to be used, use the `template`\noption:\n\n```ruby\non \"foo\", desc: \"Just a JSON\", template: \"bar\" do\n  { a: 3 }\nend\n```\n\nInfo on how Cog handles JSON can be found in the [official documentation](https://cog-book.operable.io/#_returning_data_from_cog).\n\n### Templates\n\n[Templates](https://cog-book.operable.io/#_templates) are defined in their own files under `templates/` inside any of\nthe [command load paths](#Configuration). For example:\n\n```\n$ tree\n.\n├── README.rdoc\n├── \u003c..\u003e\n├── cogy\n│   ├── some_commands.rb\n│   └── templates\n│       └── foo # \u003c--- a template named 'foo'\n|── \u003c...\u003e\n```\n\nGiven the following template:\n\n```\n# in cogy/templates/foo\n~ hello world ~\n```\n\nthe resulting bundle config would look like this:\n\n```yaml\n---\ncog_bundle_version: 4\nname: foo\ndescription: The bundle you really need\nversion: 0.0.1\ncommands:\n  \u003c...\u003e\ntemplates:\n  foo:\n    body: |-\n      ~ hello world ~\n```\n\nRefer to the [Cog book](https://cog-book.operable.io/#_templates) for more on\ntemplates.\n\n## Configuration\n\nThe configuration options provided are the following:\n\n```ruby\n# in config/initializers/cogy.rb\n\nCogy.configure do |config|\n  # Configuration related to the generated Cog bundle. Will be used when\n  # generating the bundle config YAML to be installed.\n  config.bundle = {\n    # The bundle name.\n    #\n    # Default: \"myapp\"\n    name: \"myapp\",\n\n    # The bundle description\n    #\n    # Default: \"Cog commands generated from Cogy\"\n    description: \"myapp-generated commands from Cogy\",\n\n    # The bundle version.\n    #\n    # Can be either a string or an object that responds to `#call` and returns\n    # a string.\n    #\n    # Default: \"0.0.1\"\n    version: \"0.0.1\",\n\n    # If you used a callable object, it will be evaluated each time the inventory\n    # is called. This can be useful if you want the version to change\n    # automatically.\n    #\n    # For example, this will change the version only when a command is\n    # added or is modified (uses the 'grit' gem).\n    version: -\u003e {\n      repo = Grit::Repo.new(Rails.root.to_s)\n      repo.log(\"HEAD\", \"cogy/\", max_count: 1).first.date.strftime(\"%y%m%d.%H%M%S\")\n    },\n\n    # The path in the Relay where the cogy command executable is located.\n    cogy_executable: \"/cogcmd/cogy\"\n\n    # The endpoint where Cogy is reachable at. This depends on where you've\n    # mounted the Cogy engine at.\n    cogy_endpoint: \"http://www.example.com/cogy\"\n  }\n\n  # Paths in your application where the files that define the commands live in.\n  # For example the default value will search for all `*.rb` files in the `cogy/`\n  # directory relative to the root of your application.\n  #\n  # Default: [\"cogy\"]\n  config.command_load_paths = \"cogy\"\nend\n\n```\n\nYou can use the generator to quickly create a config initializer in your app:\n\n```shell\n$ bin/rails g cogy:config\n```\n\n### Helpers\n\nIt is possible to define helpers that can be used throughout commands. This is\nuseful for DRYing repetitive code.\n\nThey are defined during configuration and may also accept arguments.\n\nLet's define a helper that fetches the `address` of a `Shop` record:\ncommand:\n\n```ruby\nCogy.configure do |c|\n  c.helper(:shop_address) { Shop.find_by(owner: handle).address }\nend\n```\n\n*(Note that custom helpers also have access to the default helpers like\n`handle`, `args` etc.)*\n\nThen we could have a command that makes use of the helper:\n\n```ruby\non \"shop_address\", desc: \"Returns the user's Shop address\" do\n  \"@#{handle}: Your shop's address is #{shop_address}\"\nend\n```\n\nHelpers may also accept arguments:\n\n```ruby\nCogy.configure do |c|\n  c.helper(:format) { |answer| answer.titleize }\nend\n```\n\nThis helper could be called like so:\n\n```ruby\non \"foo\", desc: \"Nothing special\" do\n  format \"hello there, how are you today?\"\nend\n```\n\nRails URL helpers (ie. `foo_url`) are also available inside the commands.\n\n## Error template\n\nWhen a command throws an error the\n[default error template](https://github.com/skroutz/cogy/blob/master/app/views/cogy/error.text.erb) is rendered, which\nis the following:\n\n    @\u003c%= @user %\u003e: Command '\u003c%= @cmd %\u003e' returned an error.\n\n    ```\n    \u003c%= @exception.class %\u003e:\u003c%= @exception.message %\u003e\n    ```\n\nIt can be overriden in the application by creating a view in\n`app/views/cogy/error.text.erb`.\n\n## Testing commands\n\nWe don't yet provide means to write tests for the commands, but you can easily\ntest them by executing a request to your development server. For example,\nif you mounted the engine like so:\n\n```ruby\nmount Cogy::Engine, at: \"cogy\"\n```\n\nyou can test a `foo` command like this:\n\n```shell\n$ curl -XPOST --data \"COG_ARGV_0=foo\" http://localhost:3000/cogy/cmd/foo\n```\n\nIn the request body you may pass the complete or any part of the\n[Cog environment](https://cog-book.operable.io/#_command_environment_variables) you need.\n\nThis is essentially what the [cogy executable](https://github.com/skroutz/cogy-bundle)\nalso does.\n\n## Deployment\n\nCogy provides integration with Capistrano 2 \u0026 3.\n\nThere is just one task, `cogy:notify_cog`, which executes the\n[installation Trigger](#installation-trigger).\n\nThe task should run\n*after* the application server is restarted, so that the new commands\nare picked up and served by the Inventory endpoint. In Capistrano 2 for\nexample, it should run after the built-in `deploy:restart` task.\n\nThe following options need to be set:\n\n* `cogy_release_trigger_url`: This is the URL of the Cog Trigger that will\n  install the newly deployed bundle (ie. `!cogy:install`)\n* `cogy_endpoint`: Where the Cogy Engine is mounted at.\n  For example `http://myapp.com/cogy`.\n\nYou can also configure the timeout value for the request to the Trigger by\nsetting the `cogy_trigger_timeout` option (default: 7).\n\nThe code of the task can be found [here](https://github.com/skroutz/cogy/blob/master/lib/cogy/capistrano/cogy.rake).\n\n### Capistrano 2\n\nAdd the following in `config/deploy.rb`:\n\n```ruby\n# in config/deploy.rb\nrequire \"cogy/capistrano\"\n\nset :cogy_release_trigger_url, \"\u003cTRIGGER-INVOCATION-URL\u003e\"\nset :cogy_endpoint, \"\u003cCOGY-MOUNT-POINT\u003e\"\n\nafter \"deploy:restart\", \"cogy:notify_cog\"\n```\n\n### Capistrano 3\n\nAdd the following in your Capfile:\n\n```ruby\nrequire \"cogy/capistrano\"\n```\n\nThen configure the task and hook it:\n\n```ruby\n# in config/deploy.rb\n\nset :cogy_release_trigger_url, \"\u003cTRIGGER-INVOCATION-URL\u003e\"\nset :cogy_endpoint, \"\u003cCOGY-MOUNT-POINT\u003e\"\n\nafter \"\u003capp-restart-task\u003e\", \"cogy:notify_cog\"\n```\n\n### Installation Trigger\n\nIn order to automate the process of installing the new bundle versions\n(eg. after a new command is added), you must create a [Cog Trigger](https://cog-book.operable.io/#_developing_a_trigger)\nthat will perform the installation, which will be called when you deploy your\napp.\n\nThe trigger will look this:\n\n```shell\n$ cogctl triggers\nName               ID                                    Enabled  Pipeline\nReleaseUrlTrigger  d10df83b-a737-4fc4-8d9b-bf9627412d0a  true     cogy:install --url $body.url \u003e chat://#general\n```\n\nIt essentially uses the [cogy bundle](https://github.com/skroutz/cogy-bundle)\nand installs the bundle config which is served by your application\n(ie. http://your-app.com/cogy/inventory).\n\nSee [_Deployment_](#deployment) on information about how this trigger is\ninvoked.\n\n## Development\n\nRunning the tests and RuboCop for the latest Rails version:\n\n```shell\n$ rake\n```\n\nRunning just the tests:\n\n```shell\n$ rake test\n```\n\nRunning RuboCop:\n\n```shell\n$ rake rubocop\n```\n\nGenerating documentation:\n\n```shell\n$ rake yard\n```\n\nRunning the tests for all the supported Rails versions:\n\n\n```shell\n$ appraisal rake\n```\n\nOr for a specific version:\n\n```shell\n$ appraisal 4.2 rake test\n```\n\n## Authors\n\n* [Agis Anastasopoulos](https://github.com/agis-)\n* [Mpampis Kostas](https://github.com/charkost)\n\n## License\n\nCogy is licensed under MIT. See [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskroutz%2Fcogy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fskroutz%2Fcogy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskroutz%2Fcogy/lists"}