gerrit code review: how to script a plugin with scala and groovy

34
Luca Milanesio GerritForge Luca@ gerritforge.com http :// www.gerritforge.com Twitter: @gitenterprise How to script a Plugin

Upload: luca-milanesio

Post on 29-Nov-2014

967 views

Category:

Education


2 download

DESCRIPTION

How to extend Gerrit Code Review using Scala and Groovy scripting plugins

TRANSCRIPT

Page 1: Gerrit Code Review: how to script a plugin with Scala and Groovy

Luca MilanesioGerritForge

[email protected]://www.gerritforge.comTwitter: @gitenterprise

How to script a Plugin

Page 2: Gerrit Code Review: how to script a plugin with Scala and Groovy

2

About Luca

Luca MilanesioCo-founder of GerritForge

over 20 years of experience in Agile Development SCM, CI and ALM worldwide

Contributor to Jenkins since 2007 (and previously Hudson)

Git SCM mentor for the Enterprise since 2009

Contributor to Gerrit Code Review community since 2011

Page 3: Gerrit Code Review: how to script a plugin with Scala and Groovy

3

About GerritForge

Founded in 2009 in London UKMission: Agile EnterpriseProducts:

Page 4: Gerrit Code Review: how to script a plugin with Scala and Groovy

4

Agenda Where we come from ? 2 years ago: Gerrit plugins We want more plugins Create a plugin in 60 seconds What, how and when are coming? Plugins showcase

Page 5: Gerrit Code Review: how to script a plugin with Scala and Groovy

5

WHO REMEMBERS THIS ?

GitTogether 2011Gerrit 2.2.x

Page 6: Gerrit Code Review: how to script a plugin with Scala and Groovy

6

Why don’t we introduce plugins ?

They have been so successful with

Jenkins

Page 7: Gerrit Code Review: how to script a plugin with Scala and Groovy

7

Gerrit Hackathon7th of May 2012

The first “helloworld”plugin was born

Page 8: Gerrit Code Review: how to script a plugin with Scala and Groovy

8

WHO REMEMBERS THIS ?

Gerrit Summit 2012Ver. 2.5.x

Page 9: Gerrit Code Review: how to script a plugin with Scala and Groovy

9

Gerrit Plugins Growth

in 2 years

50

Page 10: Gerrit Code Review: how to script a plugin with Scala and Groovy

10

Can we do more ? Let's ask Jenkins

Page 11: Gerrit Code Review: how to script a plugin with Scala and Groovy

11

PLUGINS SUCCESS =

COMMUNITY ENGAGEMENT

Page 12: Gerrit Code Review: how to script a plugin with Scala and Groovy

12

COMMUNITY =

BRIDGINGDIFFERENCES

Page 13: Gerrit Code Review: how to script a plugin with Scala and Groovy

13

That would be very useful for Gerrit Administrators to be able to write quick automation scripts for their daily tasks. I would prioritize groovy plugin more for the popularity of groovy scripting.

I think adding a "scripting language plugin" to support plugins written in scripting languages is a very good idea

Hi all, I was thinking about extending

Gerrit capabilities to load plugins / extensions by

providing "wrapper" for other JVM languages.

So … we asked the Community

I would prefer scala, because I've already written my plugins

with it. imho the builld process is the main impediment.

Page 14: Gerrit Code Review: how to script a plugin with Scala and Groovy

14

CHALLENGEfor building a Gerrit Plugin

Page 15: Gerrit Code Review: how to script a plugin with Scala and Groovy

15

NO STEPS, NO BUILD … just do it !

$ cat - > ~/gerrit/plugins/hello-1.0.groovy

import com.google.gerrit.sshd.*import com.google.gerrit.extensions.annotations.*

@Export("groovy")class GroovyCommand extends SshCommand { public void run() { stdout.println "Hi from Groovy" }}^D

This sample has 190 chars: you need to type at least 3.2 chars/sec to complete the sample in only one minute

https://gist.github.com/lucamilanesio/9687053

Page 16: Gerrit Code Review: how to script a plugin with Scala and Groovy

16

IS THAT TRUE ? Let’s check on Gerrit

$ ssh –p 29418 user@localhost gerrit plugin ls

Name Version Status File----------------------------------------------------------------------hello 1.0 ENABLED hello-1.0.groovy

Gerrit auto-detects the new Groovy file under $GERRIT_SITE/plugins, invoke the interpreter and auto-wrap the class into a self-contained Gerrit plugin.

Groovy class is compiled into byte-code BUT is slower than native Java plugin.

Page 17: Gerrit Code Review: how to script a plugin with Scala and Groovy

17

DOES IT REALLY WORK ?

$ ssh –p 29418 user@localhost hello groovy

Hi from Groovy

No magic … IT IS ALL REAL !

Plugin name (hello) comes from the script filename.

A new SSH command (groovy) has been defined in Gerrit associated to the Groovy script loaded.

Page 18: Gerrit Code Review: how to script a plugin with Scala and Groovy

18

What about Scala ? Just do it again !

$ cat - > ~/gerrit/plugins/hi-1.0.scala

import com.google.gerrit.sshd._import com.google.gerrit.extensions.annotations._

@Export("scala")class ScalaCommand extends SshCommand { override def run = stdout println "Hi from Scala"}^D

Scala is more concise with just 178 chars : you can take it easy with 2.9 chars/sec to type it a minute

https://gist.github.com/lucamilanesio/9687092

Page 19: Gerrit Code Review: how to script a plugin with Scala and Groovy

19

You have now two plugins loaded

$ ssh –p 29418 user@localhost gerrit plugin ls

Name Version Status File----------------------------------------------------------------------hello 1.0 ENABLED hello-1.0.groovyhi 1.0 ENABLED hi-1.0.scala

There are no differences for Gerrit between Java, Groovy or Scala plugins: they have the same dignity and power.

Scala compiler takes longer but byte-code runs at the same speed as a native Java plugin!

Page 20: Gerrit Code Review: how to script a plugin with Scala and Groovy

20

Reactions from the Gerrit mailing list …So i checked it out and tried it, and what should i say ...

Wow, it rocks! ;-)

Combined with new and shiny Plugin API the code is really short. So i started new repoon gh [1] and created two working plugins [2], [3], and sure would add more, so to say,cookbook-groovy-plugin:

$>ssh gerrit review approve I59302cbb$>Approve change: I59302cbb.

What do YOU think

?

Page 21: Gerrit Code Review: how to script a plugin with Scala and Groovy

21

WHAT can scripting plugins do now ?

1. Define new SSH commands

2. Define new REST APIs

3. Listen to Gerrit events

Page 22: Gerrit Code Review: how to script a plugin with Scala and Groovy

22

HOW can I patch Gerrit for scripting plugins ?

Install the “scripting-plugins” patches:https://gerrit-review.googlesource.com/#/q/status:open+project:gerrit+branch:master+topic:scripting-plugins,n,z

$ git clone https://gerrit.googlesource.com/gerrit && cd gerrit

$ git pull origin refs/changes/47/54247/11

$ buck build gerrit

You may want to increase the JVM PermGen on gerrit.config when loading/unloading scripting plugins

[container]javaOptions = -XX:MaxPermSize=1024m

Page 23: Gerrit Code Review: how to script a plugin with Scala and Groovy

23

Scripting plugins showcase

Page 24: Gerrit Code Review: how to script a plugin with Scala and Groovy

24

Create a branch through Gerrit API$ cat - > ~/gerrit/plugins/branch-1.0.groovyimport com.google.gerrit.sshd.*import com.google.gerrit.extensions.annotations.*import com.google.gerrit.extensions.api.*import com.google.gerrit.extensions.api.projects.*import com.google.inject.*import org.kohsuke.args4j.*

@Export("create")@CommandMetaData(name = "create-branch", description = "Create branch")class CreateBranch extends SshCommand { @Inject GerritApi api @Argument(index = 0, usage = "Project name", metaVar = "PROJECT") String projectName @Argument(index = 1, usage = "Branch name", metaVar = "BRANCH") String branchName @Argument(index = 2, usage = "Branch point sha1", metaVar = "SHA1") String sha1

void run() { BranchInput branch = new BranchInput() branch.revision = sha1 api.projects().name(projectName).branch(branchName).create(branch) stdout.println("Branch created: " + branchName) }}^D

https://gist.github.com/lucamilanesio/9687118

Page 25: Gerrit Code Review: how to script a plugin with Scala and Groovy

25

Script classes get Plugins Guice

Injections

(but cannot add Guice Modules)

Page 26: Gerrit Code Review: how to script a plugin with Scala and Groovy

26

List projects via REST API$ cat - > ~/gerrit/plugins/projects-1.0.scala

import com.google.inject._import com.google.gerrit.extensions.annotations._import com.google.gerrit.server.project._import javax.servlet.http._import scala.collection.JavaConversions._

@Singleton @Export("/")class Projects @Inject() (val pc: ProjectCache) extends HttpServlet { override def doGet(req: HttpServletRequest, resp: HttpServletResponse) = resp.getWriter print "[" + (pc.all map ( "\"" + _.get + "\"" ) mkString ",") + "]"}^D

https://gist.github.com/lucamilanesio/9687133

Page 27: Gerrit Code Review: how to script a plugin with Scala and Groovy

27

Scala is COMPACT + FUNCTIONAL

NOTE: for Guice injection@Inject() before constructor vals

Page 28: Gerrit Code Review: how to script a plugin with Scala and Groovy

28

FUNCTIONAL IS PERFECT

FOR …

Page 29: Gerrit Code Review: how to script a plugin with Scala and Groovy

29

Scalable in-process hooks$ cat - > ~/gerrit/plugins/inprochook-1.0.scalaimport org.slf4j.LoggerFactory._import com.google.inject._import com.google.gerrit.common._import com.google.gerrit.server.events._import com.google.gerrit.extensions.registration.DynamicSet

@Singletonclass ListenToChanges extends ChangeListener { val log = getLogger(classOf[ListenToChanges])

override def onChangeEvent(e: ChangeEvent) = e match { case comm: CommentAddedEvent => log info s"${comm.author.name} said '${comm.comment}' " + s"on ${comm.change.project}/${comm.change.number}'" case _ => }}

class HooksModule extends AbstractModule { override def configure = DynamicSet bind(binder, classOf[ChangeListener]) to classOf[ListenToChanges]}^D

Less CPU overhead (no exec/fork) faster and scalable

Works on behalf of user thread identity Access Gerrit injected objects (Cache, ReviewDb, JGit)

https://gist.github.com/lucamilanesio/9687154

Page 30: Gerrit Code Review: how to script a plugin with Scala and Groovy

30

Commit message validation$ cat - > ~/gerrit/plugins/commitheadline-1.0.scala

import scala.collection.JavaConversions._import com.google.inject._import com.google.gerrit.extensions.annotations._import com.google.gerrit.server.git.validators._import com.google.gerrit.server.events._

@Singleton@Listenclass HasIssueInCommitHeadline extends CommitValidationListener { override def onCommitReceived(e: CommitReceivedEvent) = "[A-Z]+-[0-9]+".r findFirstIn e.commit.getShortMessage map { issue => Seq(new CommitValidationMessage(s"Issue: $issue", false)) } getOrElse { throw new CommitValidationException("Missing JIRA-ID in commit headline") }}^D

Native pattern-matching support Java regex available out-of-the box Support for Optional values (map/getOrElse)

https://gist.github.com/lucamilanesio/9687174

Page 31: Gerrit Code Review: how to script a plugin with Scala and Groovy

31

And there is more …

audit eventsdownload commands

project and group eventsmessage of the dayProlog predicates

auth backendsavatars

Page 32: Gerrit Code Review: how to script a plugin with Scala and Groovy

32

WHEN scripting plugins will be included in Gerrit ? Hackathon #6

24-26th March we will keep on hacking on

Gerrit

MISSION: improve, stabilise and

merge scripting plugins into Gerrit master !

TARGET VERSION: Gerrit Ver. 2.10 (?)

Page 33: Gerrit Code Review: how to script a plugin with Scala and Groovy

33

Page 34: Gerrit Code Review: how to script a plugin with Scala and Groovy

Try it on-line (with scripting): http://gerrithub.io/login

Read the Gerrit book: http://gerrithub.io/book

Keep in touch: http://gitenterprise.me

Learn more about Gerrit with

20% OFF Book discount for Gerrit User Summit 2014

Book PROMO-CODE: LGCRB20 eBook PROMO-CODE: LGCReB20