Take Control. Write a Plugin. Part II

47
Jenkins User Conference San Francisco, Sept 30 2012 #jenkinsconf Take Control. Write a Plugin. Part II Baruch Sadogursky JFrog www.jfrog.com

description

Take Control. Write a Plugin. Part II. Baruch Sadogursky JFrog www.jfrog.com. About me. Developer Advocate @JFrog Job definition: Write code Talk about it github.com/ jbaruch @ jbaruch. JFrog & Jenkins. With Jenkins from day 1 Jenkins Artifactory Plugin Hosted JUC Israel - PowerPoint PPT Presentation

Transcript of Take Control. Write a Plugin. Part II

Page 1: Take Control. Write a Plugin. Part II

Jenkins User Conference San Francisco, Sept 30 2012 #jenkinsconf

Take Control. Write a Plugin.Part II

Baruch SadogurskyJFrog

www.jfrog.com

Page 2: Take Control. Write a Plugin. Part II

About me

Developer Advocate @JFrogJob definition:

Write code Talk about it

github.com/jbaruch@jbaruch

Page 3: Take Control. Write a Plugin. Part II

With Jenkins from day 1Jenkins Artifactory PluginHosted JUC Israelrepo.jenkins-ci.orgJavaOne DEMOzone

JFrog & Jenkins

Page 4: Take Control. Write a Plugin. Part II

Vote and guessingWorking with remote agentsWorking in multiple operation systemsCreating UI using GroovyWriting custom Jelly(?) tagsMaintaining backwards compatibility

Agenda

Page 5: Take Control. Write a Plugin. Part II

Vote and guessingWorking with remote agentsWorking in multiple operation systemsCreating UI using GroovyWriting custom Jelly(?) tagsMaintaining backwards compatibility

Agenda

Page 6: Take Control. Write a Plugin. Part II

Who saw “Take Control. Write a Plugin” session on YouTube?Let me guess…

one or two hands…

First, let’s vote

Page 7: Take Control. Write a Plugin. Part II

PREVIOUSLY IN “TAKE CONTROL. WRITE A PLUGIN”…

“Hello, my name is Noam Tenne”

Page 8: Take Control. Write a Plugin. Part II

What you can do with pluginsWhat you can’t do with pluginsPlugins statistics

Overview – Why plugins

Page 9: Take Control. Write a Plugin. Part II

UISCMBuild ProcessesSlave managementTooling ... Many, many, more

You can even create new extension points!

What can I extend?

Page 10: Take Control. Write a Plugin. Part II

IDEAll majors have good supportWe love IntelliJ IDEA

Build toolCan be Maven or Gradle

Environment

Page 11: Take Control. Write a Plugin. Part II

Target: Rewarding failing builds with insulting mockeryGlobal configuration: Motivation phraseProject configuration: Is motivator enabledOutcome: Message appears in log after failure

The “Motivation” Plugin

Page 12: Take Control. Write a Plugin. Part II

BACK TO OUR AGENDANowdays…

Page 13: Take Control. Write a Plugin. Part II

Vote and guessingWorking with remote agentsWorking in multiple operation systemsCreating UI using GroovyWriting custom Jelly(?) tagsMaintaining backwards compatibility

Agenda

Page 14: Take Control. Write a Plugin. Part II

Jenkins has remote agents!

Working with remote agents

Page 15: Take Control. Write a Plugin. Part II

Send closures to remote agentshudson.remoting.Callable

Working with remote agents

Java Serialization

Page 16: Take Control. Write a Plugin. Part II

Poor guy’s Java closureUsually anonymous inner class (not always)

Closure

1 private static class GetSystemProperties implements Callable<Properties,RuntimeException> { 2 public Properties call() { 3 return System.getProperties(); 4 } 5 private static final long serialVersionUID = 1L; 6 }

Page 17: Take Control. Write a Plugin. Part II

Channel?

Cast your bread on the waters

1 this.systemProperties = channel.call(new GetSystemProperties());

Page 18: Take Control. Write a Plugin. Part II

Represents a communication channel to the remote peer

Obtain from:

Channel

Page 19: Take Control. Write a Plugin. Part II

Where is the file?

Distribution Abstractions – FilePath

Page 20: Take Control. Write a Plugin. Part II

hudson.FilePathMuch like java.util.File

Consider pushing logic to the fileUse FilePath.act(FileCallable)

Distribution Abstractions – FilePath

Page 21: Take Control. Write a Plugin. Part II

Launch stuff remotely!

Distribution Abstractions – Launcher

Page 22: Take Control. Write a Plugin. Part II

hudson.LauncherMuch like java.lang.ProcessBuilder

Pick your environment variables wisely!

Distribution Abstractions – Launcher

Page 23: Take Control. Write a Plugin. Part II

Vote and guessingWorking with remote agentsWorking in multiple operation systemsCreating UI using GroovyWriting custom Jelly(?) tagsMaintaining backwards compatibility

Agenda

Page 24: Take Control. Write a Plugin. Part II

WORA. You know. But.

/ vs \.sh vs .batQuotes around commandsPermissions

(wait for it…)

Working in multiple OSs

Page 25: Take Control. Write a Plugin. Part II

Executing file…

remotely… platform independent…

Running script…

Page 26: Take Control. Write a Plugin. Part II

Can You Spot The Error?

1 String workspaceDir = build.getWorkspace().getRemote(); 2 String scriptName = launcher.isUnix() ? "proc.sh" : "proc.bat"; 3 Launcher.ProcStarter procStarter = launcher.launch().stdout(System.out); 4 procStarter.cmds(new File(workspaceDir, scriptName)).join();

Executedlocally!

Page 27: Take Control. Write a Plugin. Part II

Use FilePath – it will take care of all the details!Execute FilePath.act(FileCallable)

If you need the File API, invoke() method has it, converted to remote file properly

Going Remote with File

Page 28: Take Control. Write a Plugin. Part II

Permissions Dance

1 public boolean isDirectoryReadOnly(final FilePath filePath) throws IOException, 2 InterruptedException { 3 return filePath.getChannel().call(new Callable<Boolean, IOException>() { 4 public Boolean call() throws IOException { 5 Path path = FileSystems.getDefault().getPath(filePath.getRemote()); 6 Set<String> systems = FileSystems.getDefault().supportedFileAttributeViews(); 7 if (systems.contains("dos")) { 8 DosFileAttributeView dosView = 9 Files.getFileAttributeView(path, DosFileAttributeView.class); 10 DosFileAttributes dosAttributes = dosView.readAttributes(); 11 return dosAttributes.isReadOnly(); 12 } 13 if (systems.contains("posix")) { 14 PosixFileAttributeView posixView = 15 Files.getFileAttributeView(path, PosixFileAttributeView.class); 16 PosixFileAttributes posixAttributes = posixView.readAttributes(); 17 Set<PosixFilePermission> permissions = posixAttributes.permissions(); 18 return !permissions.contains(PosixFilePermission.OTHERS_WRITE) 19 } 20 throw new IOException("Unknown filesystem"); 21 } 22 }); 23 }

Page 29: Take Control. Write a Plugin. Part II

Vote and guessingWorking with remote agentsWorking in multiple operation systemsCreating UI using GroovyWriting custom Jelly(?) tagsMaintaining backwards compatibility

Agenda

Page 30: Take Control. Write a Plugin. Part II

First, let’s look at the docs:

Creating UI using Groovy

Page 31: Take Control. Write a Plugin. Part II

Analogous to JellyCan use Jelly tags and libraries

Kohsuke:

Creating UI using Groovy

When What

Lots of program logic Groovy

Lots of HTML layout markup Jelly

Page 32: Take Control. Write a Plugin. Part II

Analogous to JellyCan use Jelly tags and libraries

me:

Creating UI using Groovy

When What

Always! Groovy

Page 33: Take Control. Write a Plugin. Part II

Jelly:

Groovy:

Creating UI using Groovy

1 <j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form"> 2 <f:section title="Motivation Plugin"> 3 <f:entry title=" Motivating Message" field="motivatingMessage" 4 description="The motivational message to display when a build fails"> 5 <f:textbox/> 6 </f:entry> 7 </f:section> 8 </j:jelly>

1 f=namespace('lib/form') 2 3 f.section(title:'Motivation Plugin') { 4 f.entry(title:'Motivating Message', field:'motivatingMessage', 5 description:'The motivational message to display when a build fails'){ 6 f.textbox() 7 } 8 }

Page 34: Take Control. Write a Plugin. Part II

Creating UI using Groovy

1 f=namespace('lib/form') 2 3 f.section(title:'Motivation Plugin') { 4 f.entry(title:'Motivating Message', field:'motivatingMessage', 5 description:'The motivational message to display when a build fails'){ 6 f.textbox() 7 } 8 }

Real codeDebuggable, etc.

(stay tuned…)

Page 35: Take Control. Write a Plugin. Part II

Vote and guessingWorking with remote agentsWorking in multiple operation systemsCreating UI using GroovyWriting custom Jelly(?) tagsMaintaining backwards compatibility

Agenda

Page 36: Take Control. Write a Plugin. Part II

Documentation:

Writing custom Jelly(?) tags

Page 37: Take Control. Write a Plugin. Part II
Page 38: Take Control. Write a Plugin. Part II

Writing custom Jelly(?) tags

Page 39: Take Control. Write a Plugin. Part II

Simple as 1,2…that’s it.

Writing custom Jelly Groovy tags

Page 40: Take Control. Write a Plugin. Part II

1. Implement

1 class MotivationTagLib extends 2 AbstractGroovyViewModule { 3 def tools = .namespace( builder ) 'hudson/tools' 4 5 MotivationTagLib(JellyBuilder b) { 6 (b) super 7 } 8 9 def evilLaugh() { 10 .label(tools ) 'mu-ha-ha!'11 } 12 }

Page 41: Take Control. Write a Plugin. Part II

2. Use!

1 import org._10ne.jenkins.MotivationTagLib 2 3 f = namespace( ) 'lib/form' 4 m = new MotivationTagLib(builder); 5 6 f.entry( : title ) { '' 7 m.evilLaugh() 8 f.checkbox(…) 11 }

Page 42: Take Control. Write a Plugin. Part II

Vote and guessingWorking with remote agentsWorking in multiple operation systemsCreating UI using GroovyWriting custom Jelly(?) tagsMaintaining backwards compatibility

Agenda

Page 43: Take Control. Write a Plugin. Part II

Back to Motivation plugin…

Maintaining backwards compatibility

Page 44: Take Control. Write a Plugin. Part II

Rename defaultMotivatingMessageto

motivatingMessage

What happens to existing configuration on users machines?

Refactoring!

Page 45: Take Control. Write a Plugin. Part II

Register field (or class) aliasIn Initializer that runs before plugins started

More complex cases might reqiure XStream converter

XStream Aliasing To The Rescue

1 @Initializer(before = PLUGINS_STARTED) 2 public static void addAliases() { 3 Items.XSTREAM2.aliasField("defaultMotivatingMessage", 4 DescriptorImpl.class, "motivatingMessage"); 5 }

Page 46: Take Control. Write a Plugin. Part II

See you at our DEMOzone!

Thank you!

Page 47: Take Control. Write a Plugin. Part II

Thank You To Our Sponsors