gerrit code review: how to script a plugin with scala and groovy
Post on 29-Nov-2014
967 Views
Preview:
DESCRIPTION
TRANSCRIPT
Luca MilanesioGerritForge
Luca@gerritforge.comhttp://www.gerritforge.comTwitter: @gitenterprise
How to script a Plugin
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
3
About GerritForge
Founded in 2009 in London UKMission: Agile EnterpriseProducts:
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
5
WHO REMEMBERS THIS ?
GitTogether 2011Gerrit 2.2.x
6
Why don’t we introduce plugins ?
They have been so successful with
Jenkins
7
Gerrit Hackathon7th of May 2012
The first “helloworld”plugin was born
8
WHO REMEMBERS THIS ?
Gerrit Summit 2012Ver. 2.5.x
9
Gerrit Plugins Growth
in 2 years
50
10
Can we do more ? Let's ask Jenkins
11
PLUGINS SUCCESS =
COMMUNITY ENGAGEMENT
12
COMMUNITY =
BRIDGINGDIFFERENCES
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.
14
CHALLENGEfor building a Gerrit Plugin
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
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.
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.
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
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!
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
?
21
WHAT can scripting plugins do now ?
1. Define new SSH commands
2. Define new REST APIs
3. Listen to Gerrit events
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
23
Scripting plugins showcase
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
25
Script classes get Plugins Guice
Injections
(but cannot add Guice Modules)
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
27
Scala is COMPACT + FUNCTIONAL
NOTE: for Guice injection@Inject() before constructor vals
28
FUNCTIONAL IS PERFECT
FOR …
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
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
31
And there is more …
audit eventsdownload commands
project and group eventsmessage of the dayProlog predicates
auth backendsavatars
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 (?)
33
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
top related