Skip to content
This repository was archived by the owner on Mar 23, 2021. It is now read-only.

Conform to ConfigInitializable #9

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 35 additions & 7 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,29 +28,48 @@ You can see which version of Bob is currently running by typing `version`
<br>The script to run for each target is specified when the command is instantiated.
<br>For example:<br>
```swift
let config = try Config()
let buildTargets = [
TravisTarget(name: "staging", script: Script("fastlane ios distribute_staging")),
TravisTarget(name: "testflight", script: Script("fastlane ios distribute_testflight")),
]
let buildCommand = TravisScriptCommand(name: "build", config: travisConfig, targets: buildTargets, defaultBranch: "Develop")
let travisCI = try TravisCI(config: config)
let buildCommand = TravisScriptCommand(name: "build", travis: travisCI, targets: buildTargets, defaultBranch: BranchName("develop"))
try bob.register(buildCommand)
```
would register a command with the name `build`. Typing `build staging` would start the lane `distribute_staging` on Travis.

would register a command with the name `build`. Typing `build staging` would start the lane `distribute_staging` on Travis.
Your `bob.json` file should look like this (replace your token & urls)
```json
{
"travis-repo-url": "<# Url of the repo. Along the lines of https://api.travis-ci.com/repo/{owner%2Frepo} #>",
"travis-token": <# Travis CI access token #>
<# other configurations #>
}
```
### Align Version
iOS specific command used to change the `CFBundleShortVersionString` and `CFBundleVersion` values in specified `.plist` files.
<br>For example:<br>
```swift
let config = try Config()
let plistPaths: [String] = [
"App/Info.plist",
"siriKit/Info.plist",
"siriKitUI/Info.plist"
]
let alignCommand = AlignVersionCommand(config: gitHubConfig, defaultBranch: "Develop", plistPaths: plistPaths, author: author)
let gitHub = try GitHub(config: config)
let alignCommand = AlignVersionCommand(gitHub: gitHub, defaultBranch: BranchName("develop"), plistPaths: plistPaths, author: Author(name: "bob", email: "[email protected]"))
try bob.register(alignCommand)
```
would register a command that can be invoked by typing `align 3.0 4`. Bob would then create a commit on GitHub by changing the 3 specified files.

Your `bob.json` file should look like this (replace your token & urls)
```json
{
"github-username": <# Username of authenticated Github user #>,
"github-access-token": <# Persoanl access token for the authenticated user #>,
"github-repo-url": <# Url of the repo. Alogn the lines of https://api.github.com/repos/{owner}/{repo} #>,
<# other configurations #>
}
```
## Getting started

### Creating a bot on Slack
Expand Down Expand Up @@ -85,6 +104,15 @@ You can delete the unused template files by running:
rm -rf Sources/App/Controllers
rm -rf Sources/App/Models
```

All of your configured tokens will reside in `bob.json` file in the `Config` folder. It should look like this (replace your token), and you can add this file to your `.gitignore`.
```json
{
"slack-token": <# Slack bot token #>,
<# other configurations #>
}
```

All of your custom code will reside in the `Sources/App` folder.<br>
Create an Xcode project by running
```bash
Expand All @@ -94,9 +122,9 @@ Change the `Sources/App/main.swift` file to:
```swift
import Bob

let config = Bob.Configuration(slackToken: "your-slack-token")
let config = try Config()
let bob = Bob(config: config)

<# register commands #>
try bob.start()
```
and you're good to go. Select the `App` scheme and run it. You can now send messages to `Bob` via Slack, and it will respond.
Expand Down
34 changes: 29 additions & 5 deletions Sources/Bob/APIs/GitHub/GitHub.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public struct Commit {
}

/// Used for communicating with the GitHub api
public class GitHub {
public final class GitHub {

/// Configuration needed for authentication with the api
public struct Configuration {
Expand All @@ -104,12 +104,12 @@ public class GitHub {

private let base64LoginData: String
private let repoUrl: String
private let drop: Droplet
public init(config: Configuration, droplet: Droplet) {
private let client: ClientFactoryProtocol
public init(config: Configuration, client: ClientFactoryProtocol) {
let authString = config.username + ":" + config.personalAccessToken
self.base64LoginData = authString.data(using: .utf8)!.base64EncodedString()
self.repoUrl = config.repoUrl
self.drop = droplet
self.client = client
}

private func uri(at path: String) -> String {
Expand All @@ -118,7 +118,7 @@ public class GitHub {

private func perform(_ request: Request) throws -> JSON {
request.headers[HeaderKey("Authorization")] = "Basic " + self.base64LoginData
let response = try self.drop.client.respond(to: request)
let response = try self.client.respond(to: request)
if response.status.isSuccessfulRequest {
if let json = response.json {
return json
Expand Down Expand Up @@ -288,3 +288,27 @@ public class GitHub {
}

}

extension Config {
/// Resolves configured GitHub configuration
func resolveGitHubConfiguration() throws -> GitHub.Configuration {
guard let user = self[Bob.configFile, "github-username"]?.string else {
throw "Unable to find GitHub username. It should be found in \" Configs/bob.json\" under the key \"github-username\"."
}
guard let token = self[Bob.configFile, "github-access-token"]?.string else {
throw "Unable to find GitHub personal access token. It should be found in \" Configs/bob.json\" under the key \"github-access-token\"."
}
guard let repoURL = self[Bob.configFile, "github-repo-url"]?.string else {
throw "Unable to find GitHub repository URL. It should be found in \" Configs/bob.json\" under the key \"github-repo-url\"."
}
return GitHub.Configuration(username: user, personalAccessToken: token, repoUrl: repoURL)
}
}

extension GitHub: ConfigInitializable {
public convenience init(config: Config) throws {
let configuration = try config.resolveGitHubConfiguration()
let client = try config.resolveClient()
self.init(config: configuration, client: client)
}
}
35 changes: 29 additions & 6 deletions Sources/Bob/APIs/TravisCI/TravisCI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ extension Dictionary where Key: ExpressibleByStringLiteral, Value: Any {
}

/// Used for communication with TravisCI api
public class TravisCI {
public final class TravisCI {


/// Configuration needed for authentication with the api
Expand All @@ -70,13 +70,14 @@ public class TravisCI {
}

private let config: Configuration
private let drop: Droplet
private let client: ClientFactoryProtocol
/// Initializes the object with provided configuration
///
/// - Parameter config: Configuration to use
public init(config: Configuration, droplet: Droplet) {
/// - Parameter client: HTTP Client factory to use
public init(config: Configuration, client: ClientFactoryProtocol) {
self.config = config
self.drop = droplet
self.client = client
}


Expand All @@ -102,10 +103,32 @@ public class TravisCI {
request.headers[HeaderKey("Travis-API-Version")] = "3"
request.headers[HeaderKey("Content-Type")] = "application/json"

let response = try self.drop.client.respond(to: request)
let response = try self.client.respond(to: request)
if !response.status.isSuccessfulRequest {
throw "Error: `" + request.uri.description + "` - " + response.status.reasonPhrase
}
}

}


extension Config {
/// Resolves configured Travis CI configuration
func resolveTravisConfiguration() throws -> TravisCI.Configuration {
guard let url = self[Bob.configFile, "travis-repo-url"]?.string else {
throw "Unable to find Travis CI repo URL. It should be found in \" Configs/bob.json\" under the key \"travis-repo-url\"."
}

guard let token = self[Bob.configFile, "travis-token"]?.string else {
throw "Unable to find Travis CI access token. It should be found in \" Configs/bob.json\" under the key \"travis-token\"."
}
return TravisCI.Configuration(repoUrl: url, token: token)
}
}

extension TravisCI: ConfigInitializable {
public convenience init(config: Config) throws {
let configuration = try config.resolveTravisConfiguration()
let client = try config.resolveClient()
self.init(config: configuration, client: client)
}
}
29 changes: 24 additions & 5 deletions Sources/Bob/Core/Bob.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@
import Foundation
import Vapor

public class Bob {
public final class Bob {

static let version: String = "1.0.2"

static let configFile: String = "bob"

/// Struct containing all properties needed for Bob to function
public struct Configuration {
public let slackToken: String
Expand All @@ -44,9 +45,9 @@ public class Bob {
/// Initializer
///
/// - Parameter configuration: Configuration for setup
/// - Parameter droplet: Droplet
public init(config: Configuration, droplet: Droplet) {
self.slackClient = SlackClient(token: config.slackToken, droplet: droplet)
/// - Parameter client: HTTP Client to use
public init(config: Configuration, client: ClientFactoryProtocol) {
self.slackClient = SlackClient(token: config.slackToken, client: client)
self.factory = CommandFactory(commands: [HelloCommand(), VersionCommand()])
self.processor = CommandProcessor(factory: self.factory)
self.executor = CommandExecutor()
Expand Down Expand Up @@ -102,3 +103,21 @@ fileprivate extension CommandFactory {
}

}

extension Config {
/// Resolves configured Bob configuration
func resolveBobConfiguration() throws -> Bob.Configuration {
guard let token = self[Bob.configFile, "slack-token"]?.string else {
throw "Unable to find Slack access token. It should be found in \" Configs/bob.json\" under the key \"slack-token\"."
}
return Bob.Configuration(slackToken: token)
}
}

extension Bob: ConfigInitializable {
public convenience init(config: Config) throws {
let configuration = try config.resolveBobConfiguration()
let client = try config.resolveClient()
self.init(config: configuration, client: client)
}
}
8 changes: 4 additions & 4 deletions Sources/Bob/Core/Slack/SlackClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@ extension ClientFactoryProtocol {
class SlackClient {

private let token: String
private let droplet: Droplet
init(token: String, droplet: Droplet) {
private let client: ClientFactoryProtocol
init(token: String, client: ClientFactoryProtocol) {
self.token = token
self.droplet = droplet
self.client = client
}

func connect(onMessage: @escaping (_ message: String, _ sender: MessageSender) -> Void) throws {

let rtmResponse = try self.droplet.client.loadRealtimeApi(token: self.token)
let rtmResponse = try self.client.loadRealtimeApi(token: self.token)
guard let webSocketURL = rtmResponse.json?["url"]?.string else { throw "Unable to retrieve `url` from slack. Reason \(rtmResponse.status.reasonPhrase). Raw response \(rtmResponse.data)" }

try WebSocketFactory.shared.connect(to: webSocketURL) { (socket) in
Expand Down