laughedelic / scalajs-probot   12609435

Mozilla Public License 2.0 Website GitHub

🤖Scala.js facades for the Probot framework

Scala versions: 2.12
Scala.js versions: 0.6

Scala.js facades for the Probot framework 🤖

This project contains Scala.js facades for the Probot framework used to build GitHub Apps on Node.js.

🚧 WORK IN PROGRESS 🚧

This project is in active development, there are no published releases yet. Things may break without a warning, so don't rely on it.

If you want to experiment with it and write a GitHub bot in Scala.js, don't hesitate to write to the Gitter chat and ask any questions. And if you're looking for ideas, check out the dedicated probot/ideas repo.

Usage

First of all you should head to the Probot docs and read at least the Getting Started part. It explains the basics very well and gives you a general understanding of how this framework functions.

For interacting with the GitHub API this library depends on the Scala.js facades for the Octokit library: scalajs-octokit.

For the usage example refer to the scalafmt-probot project. The project setup will be simplified in the future.

Installation

🛠 Check installation instructions later, when there is a published release...
  1. Add Probot dependency to your project. It's important that the version of the underlying JS library matches the one this facade is built for.

    • If it's a Node.js project where you manage dependencies with npm, run

      npm install probot@next --save
    • If it's a Scala.js project use [scalajs-bundler] and add to your build.sbt:

      Compile/npmDependencies += "probot" -> "next"

    These facades are based on the TypeScript version of Probot which is not released yet, but is available under the next version tag.

  2. Add facades dependency to your build.sbt:

    resolvers += Resolver.jcenterRepo
    libraryDependencies += "laughedelic" %%% "scalajs-probot" % "<version>"

    (see the latest release version on the badge above)

  3. To turn the project into a runnable application add to your build.sbt:

    scalaJSUseMainModuleInitializer := true

    Then in the code implement a Probot.Plugin (which is a function Application => Unit) and define a main method:

    import laughedelic.probot._
    
    object ProbotApp {
    
      def plugin(app: Application): Unit = ???
    
      def main(args: Array[String]): Unit = ProbotApp.run(plugin)
    }

    See the example below.

  4. (Optionally) for local testing you may want to add a dependency on the smee-client

    Compile/npmDependencies += "smee-client" -> "1.0.1"

    Then you can run the application with sbt run it should work the same as the npm start (=probot run ./lib/index.js) from the Probot docs. The only difference is that it ignores any command line args, so I have to set environment variables. You can set them in the .env file.

Example

Here's a translation of the Hello World example from the Probot docs to Scala:

import laughedelic.probot._
import scala.scalajs.concurrent.JSExecutionContext.Implicits.queue

object HelloWorld {

  def plugin(app: Application): Unit = {

    app.on("issues.opened") { context =>
      // Post a comment on every new issue
      context.github.issues.createComment(
        owner  = context.issue().owner,
        repo   = context.issue().repo,
        number = context.issue().number,
        body   = "Hello World! 👋"
      )
    }
  }

  def main(args: Array[String]): Unit = Probot.run(plugin)
}

The translation from JavaScript is pretty straightforward. A couple of things to notice:

  • In JS all GitHub API parameters are just objects, so it's possible to reuse context.issue and write
    context.github.issues.createComment(
      // context.issue appends given object to { owner: ..., repo: ..., number: ... }
      context.issue({body: 'Hello World!'})
    )
    In Scala createComment method has typed arguments, so we have to pass those values from the context explicitly. I don't think it's too verbose, but if anybody has an idea how to improve it, let me know.
  • { context => ... } callback returns a Future which is converted to a js.Promise, this is why the execution context import is needed.

For a more complex example and the general project setup refer to the scalafmt-probot project.