{"id":18925229,"url":"https://github.com/babylonhealth/stevenson","last_synced_at":"2025-04-15T12:33:19.193Z","repository":{"id":45235561,"uuid":"173131879","full_name":"babylonhealth/Stevenson","owner":"babylonhealth","description":"Stevenson is a Vapor framework designed to build integrations between Slack apps, GitHub, JIRA and CI services (CircleCI).","archived":false,"fork":false,"pushed_at":"2024-02-09T00:33:57.000Z","size":305,"stargazers_count":60,"open_issues_count":1,"forks_count":2,"subscribers_count":16,"default_branch":"master","last_synced_at":"2025-03-28T21:35:19.959Z","etag":null,"topics":["bot","circle-ci","fastlane","ios","server-side-swift","slack","vapor"],"latest_commit_sha":null,"homepage":"","language":"Swift","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/babylonhealth.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null}},"created_at":"2019-02-28T14:58:38.000Z","updated_at":"2024-11-25T15:50:11.000Z","dependencies_parsed_at":"2022-08-04T13:00:23.613Z","dependency_job_id":null,"html_url":"https://github.com/babylonhealth/Stevenson","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/babylonhealth%2FStevenson","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/babylonhealth%2FStevenson/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/babylonhealth%2FStevenson/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/babylonhealth%2FStevenson/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/babylonhealth","download_url":"https://codeload.github.com/babylonhealth/Stevenson/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249072609,"owners_count":21208214,"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":["bot","circle-ci","fastlane","ios","server-side-swift","slack","vapor"],"created_at":"2024-11-08T11:10:07.389Z","updated_at":"2025-04-15T12:33:18.864Z","avatar_url":"https://github.com/babylonhealth.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🤖 Stevenson Bot\n\n\u003cp\u003e\n    \u003ca href=\"https://vapor.codes\"\u003e\n        \u003cimg src=\"https://img.shields.io/badge/Vapor-3-orange.svg\" alt=\"Version 3\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://swift.org\"\u003e\n        \u003cimg src=\"https://img.shields.io/badge/swift-5.1-brightgreen.svg\" alt=\"Swift 5.1\"\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\n`Stevenson` is a Vapor framework designed to build integrations between Slack apps, GitHub, JIRA and CI services (CircleCI).\nThis project also contains implementation of the Slack app used by Babylon iOS team (if you want to know more about how our team works, check our [playbook](https://github.com/babylonhealth/ios-playbook))\n\n## 🚀 Usage\n\nTo use `Stevenson` in your app add it as a dependency to your `Package.swift`:\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/babylonhealth/Stevenson.git\", .branch(\"master\")),\n]\n```\n\nand then import it to your project:\n\n```swift\nimport Stevenson\n```\n\n### Supported services\n\n`Stevenson` comes with implementation of Slack [slash commands](https://api.slack.com/slash-commands), GitHub, JIRA and CircleCI APIs. At the moment it does not implement complete set of these APIs but only provides bare minimum required for the functionality of the app.\n\nTo create these services, use corresponding type constructors providing required values. It's advised but not required to store these values in the environment variables:\n\n```swift\nlet slack = SlackService(\n    token: Environment.get(\"SLACK_TOKEN\")\n)\n\nlet ci = CircleCIService(\n    token: Environment.get(\"CIRCLECI_TOKEN\")\n)\n\nlet jira = JiraService(\n    baseURL: Environment.get(\"JIRA_BASE_URL\").flatMap(URL.init(string:)),\n    username: Environment.get(\"JIRA_USERNAME\"),\n    password: Environment.get(\"JIRA_TOKEN\")\n)\n\nlet github = GitHubService(\n    username: Environment.get(\"GITHUB_USERNAME\"),\n    token: Environment.get(\"GITHUB_TOKEN\")\n)\n```\n\n### Creating a Slack command\n\nTo create a Slack [slash command](https://api.slack.com/slash-commands) start with registering it in your Slack app following Slack documentation. \n\n_Note: instead of using your own Slack app you may use Slack Slash Commands app. In this case you will register your slash commands in this app but the process will be pretty much the same._\n\nThen use the `SlackCommand` type to implement it:\n\n```swift\nlet myAmazingCommand = SlackCommand(\n    // This name should be the same name that you used to register a command in your Slack app\n    name: \"myAmazingCommand\",\n    // This message will be sent back to Slack when you call your command with `/myAmazingCommand help`\n    help: \"Some command usage instructions\", \n    // This closure is where the command is actually implemented\n    run: { metadata, request in\n        /**\n        Parse `metadata` here, do something useful, \n        i.e. invoke a CI job, and send a response back to Slack\n        */\n    }\n)\n```\n \n Then register a route in your app with a path that matches the command name (usually Slack sends commands as `POST` requests):\n \n```swift\nrouter.post(myAmazingCommand.name) { request -\u003e Future\u003cResponse\u003e in\n    try slack.handle(command: myAmazingCommand, on: request)\n}\n```\n\nFor more details check the commands implemented in the app.\n\n## 💻 Development\n\nTo develop locally on this repo:\n\n* [Install Vapor locally](http://docs.vapor.codes/3.0/install/macos/)\n* Run `vapor xcode` to create the Xcode project\n* Open the Xcode project and work in it\n* You'll need to define some environment variables in your scheme (Edit Scheme \u003e \"Run\" Action \u003e \"Arguments\" tab) if you want to try to run the [Babylon Stevenson app](BabylonCommands.md) locally. Typically declare [the same env variables](BabylonCommands.md#environment-variables) that are defined in the hosting environment (like Heroku or AWS on the server side). \n* Hit Cmd-R to run the Vapor server locally. It will listen at `http://localhost:8080`\n* Try it out by sending fake Slack payloads mimicking a Slack slash command\n\nFor example to simulate `/fastlane somelane someargs`, use this (adapt the `\u0026text=` value and the `/fastlane` endpoint to your needs)\n\n```bash\ncurl --request POST \\\n  --url http://localhost:8080/fastlane \\\n  --header 'content-type: application/x-www-form-urlencoded' \\\n  --data 'token=__SLACK_TOKEN__\u0026channel_name=__SOME_SLACK_CHANNEL__\u0026text=somelane%20someargs'\n```\n\n## 🕹 Adding a new Slack command to the app\n\nIf you need to create a new Slack command:\n\n 1. Go to the Slack Commands config page for your team's Slack app: `https://api.slack.com/apps/\u003cYourSlackAppID\u003e/slash-commands`\n 2. Click on \"Create New Command\"\n   * Fill in the slash command (e.g. `/foo`)\n   * Enter the URL this command will trigger – e.g. if your instance will be hosted on Heroku it will look like `https://\u003cappname\u003e.herokuapp.com/\u003ccommand\u003e`, replacing `\u003cappname\u003e` with the name of your Heroku app instance (e.g. `stevenson-bot`) and `\u003ccommand\u003e` by the command name (e.g. `foo`)\n   * Fill in the short description and the hint for the command\n   * Hit \"Save\"\n 3. Open the project in Xcode and add a new handler for the Slack command:\n   * Implement your command as a static function/constant in a `extension SlackCommand` (see `MainCommand.swift` or `SlackCommand+Fastlane` as examples):\n   \n   ```swift\nextension SlackCommand {\n   static func \u003ccommand\u003e(/* optional params if needed */) { \n        SlackCommand(\n            name: \"\u003ccommand\u003e\", \n            help: \"...\",\n            allowedChannels: [...],\n            run: { ... }\n        ) \n    }\n}\n   ```\n   \n   * Open `configure.swift` and add that newly-created command to the list of handled commands\n\n   ```swift\n   routes(router: router, slack: slack, commands: [\n       .fastlane(ci), \n       ..., \n       .\u003ccommand\u003e()\n   ])\n```\n\n## 🚢 Deployment on Heroku\n\nThere are just example instructions if you plan to host the app on [Heroku](https://dashboard.heroku.com/apps).\n\n_You can skip step 1 and 2 if you have already set it up locally._\n\n1. Install the Heroku CLI.\n   ```bash\n   brew install heroku/brew/heroku\n   heroku login\n   ```\n   \n2. Navigate to the local repo, and configure the Heroku remote using the CLI.\n   ```bash\n   heroku git:remote -a \u003cheroku-app-name\u003e\n   ```\n   \n3. Push the `master` branch to deploy.\n   ```bash\n   git checkout master\n   git push heroku master\n   ```\n\nAlternatively, you can deploy a specific branch manually by going to the deploy page on Heroku dashboard and using the \"Manual Deploy\" section at the very bottom.\n\nOnce the app is deployed, if you need to debug things, you can see the logs using `heroku logs -a \u003cheroku-app-name\u003e`.\n\nTo set the aforementioned environment variables with the real values on Heroku:\n\n* Go to your Heroku dashboard\n* Navigate to Settings\n* set the environment variables like `SLACK_TOKEN` etc\n\n## 📖 Documentation\n\n* Learn more about the Stevenson's instance we use at Babylon and the commands that we implemented using this framework to support our processes [here](BabylonCommands.md)\n* For instructions on how to use Vapor, visit the Vapor web framework's [documentation](http://docs.vapor.codes).\n\n## ✨ Take a look at our other OSS projects!\n\n* [Bento](https://github.com/babylonhealth/Bento): Swift library for building component-based interfaces on top of UITableView and UICollectionView 🍱\n* [DrawerKit](https://github.com/babylonhealth/DrawerKit): DrawerKit lets an UIViewController modally present another UIViewController in a manner similar to the way Apple's Maps app works.\n* [ReactiveFeedback](https://github.com/babylonhealth/ReactiveFeedback): Unidirectional reactive architecture\n* 🚧 [Wall-E](https://github.com/babylonhealth/Wall-E): A bot that monitors and manages your pull requests by ensuring they are merged when they're ready and don't stack up in your repository 🤓\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbabylonhealth%2Fstevenson","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbabylonhealth%2Fstevenson","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbabylonhealth%2Fstevenson/lists"}