Писане на плъгин Jenkins

1. Общ преглед

Jenkins е сървър за непрекъсната интеграция с отворен код, който позволява да се създаде персонализирано създаване на приставки за конкретна задача / среда.

В тази статия ще преминем през целия процес на създаване на разширение, което добавя статистически данни към изхода на компилацията, а именно брой класове и редове код.

2. Настройка

Първото нещо, което трябва да направите, е да настроите проекта. За щастие, Дженкинс предоставя удобни архетипове на Maven за това.

Просто изпълнете командата по-долу от черупка:

mvn archetype:generate -Dfilter=io.jenkins.archetypes:plugin

Ще получим следния изход:

[INFO] Generating project in Interactive mode [INFO] No archetype defined. Using maven-archetype-quickstart (org.apache.maven.archetypes:maven-archetype-quickstart:1.0) Choose archetype: 1: remote -> io.jenkins.archetypes:empty-plugin (Skeleton of a Jenkins plugin with a POM and an empty source tree.) 2: remote -> io.jenkins.archetypes:global-configuration-plugin (Skeleton of a Jenkins plugin with a POM and an example piece of global configuration.) 3: remote -> io.jenkins.archetypes:hello-world-plugin (Skeleton of a Jenkins plugin with a POM and an example build step.)

Сега изберете първата опция и дефинирайте група / артефакт / пакет в интерактивен режим. След това е необходимо да направите уточнения в pom.xml - тъй като той съдържа записи като TODO Plugin .

3. Дизайн на приставката Jenkins

3.1. Точки за удължаване

Дженкинс предоставя редица точки за удължаване. Това са интерфейси или абстрактни класове, които дефинират договори за конкретни случаи на употреба и позволяват на други плъгини да ги изпълняват.

Например, всеки изграждане се състои от няколко стъпки, например "Checkout от VCS" , "Събиране" , "Тест", "Съберете", и т.н. Дженкинс определя hudson.tasks.BuildStep точка разширение, така че можем да го приложат, за да се осигури персонализирана стъпка, която може да бъде конфигурирана.

Друг пример е hudson.tasks.BuildWrapper - това ни позволява да дефинираме действия преди / след публикуване.

Разполагаме и с основна приставка за разширение за имейл, която определя точката на разширение hudson.plugins.emailext.plugins.RecipientProvider , която позволява да се предоставят получатели на имейли. Примерен вариант за изпълнение е наличен тук: hudson.plugins.emailext.plugins.recipients.UpstreamComitterRecipientProvider .

Забележка: има стар подход, при който класът на приставките трябва да разшири hudson.Plugin . Въпреки това, сега тя препоръчва да се използват за разширяване точки вместо.

3.2. Инициализация на приставката

Необходимо е да кажете на Дженкинс за нашето разширение и как то трябва да бъде създадено.

Първо дефинираме статичен вътрешен клас в приставката и го маркираме с помощта на анотацията hudson.Extention :

class MyPlugin extends BuildWrapper { @Extension public static class DescriptorImpl extends BuildWrapperDescriptor { @Override public boolean isApplicable(AbstractProject item) { return true; } @Override public String getDisplayName() { return "name to show in UI"; } } }

На второ място, трябва да дефинираме конструктор, който да се използва за инстанциране на обекта на приставката, и да го маркираме чрез анотацията org.kohsuke.stapler.DataBoundConstructor .

Възможно е да се използват параметри за него. Те се показват в потребителския интерфейс и се доставят автоматично от Дженкинс.

Например, помислете за приставката Maven:

@DataBoundConstructor public Maven( String targets, String name, String pom, String properties, String jvmOptions, boolean usePrivateRepository, SettingsProvider settings, GlobalSettingsProvider globalSettings, boolean injectBuildVariables) { ... }

Той е съпоставен със следния потребителски интерфейс:

Също така е възможно да използвате анотация org.kohsuke.stapler.DataBoundSetter със сетери.

4. Внедряване на приставки

Възнамеряваме да събираме основни статистически данни по проекта по време на компилация, така че hudson.tasks.BuildWrapper е правилният начин да отидем тук.

Нека го приложим:

class ProjectStatsBuildWrapper extends BuildWrapper { @DataBoundConstructor public ProjectStatsBuildWrapper() {} @Override public Environment setUp( AbstractBuild build, Launcher launcher, BuildListener listener) {} @Extension public static class DescriptorImpl extends BuildWrapperDescriptor { @Override public boolean isApplicable(AbstractProject item) { return true; } @Nonnull @Override public String getDisplayName() { return "Construct project stats during build"; } } }

Добре, сега трябва да приложим действителната функционалност.

Нека дефинираме клас на домейн за статистиката на проекта:

class ProjectStats { private int classesNumber; private int linesNumber; // standard constructors/getters }

И напишете кода, който изгражда данните:

private ProjectStats buildStats(FilePath root) throws IOException, InterruptedException { int classesNumber = 0; int linesNumber = 0; Stack toProcess = new Stack(); toProcess.push(root); while (!toProcess.isEmpty()) { FilePath path = toProcess.pop(); if (path.isDirectory()) { toProcess.addAll(path.list()); } else if (path.getName().endsWith(".java")) { classesNumber++; linesNumber += countLines(path); } } return new ProjectStats(classesNumber, linesNumber); }

И накрая, трябва да покажем статистиката на крайните потребители. Нека създадем HTML шаблон за това:

    $PROJECT_NAME$   Project $PROJECT_NAME$: 
    
Classes number Lines number
$CLASSES_NUMBER$ $LINES_NUMBER$

И го попълнете по време на изграждането:

public class ProjectStatsBuildWrapper extends BuildWrapper { @Override public Environment setUp( AbstractBuild build, Launcher launcher, BuildListener listener) { return new Environment() { @Override public boolean tearDown( AbstractBuild build, BuildListener listener) throws IOException, InterruptedException { ProjectStats stats = buildStats(build.getWorkspace()); String report = generateReport( build.getProject().getDisplayName(), stats); File artifactsDir = build.getArtifactsDir(); String path = artifactsDir.getCanonicalPath() + REPORT_TEMPLATE_PATH; File reportFile = new File("path"); // write report's text to the report's file } }; } }

5. Употреба

Време е да комбинираме всичко, което сме създали досега - и да го видим в действие.

Предполага се, че Дженкинс работи и работи в местната среда. Моля, обърнете се към подробностите за инсталиране в противен случай.

5.1. Добавете приставката към Jenkins

Сега нека да изградим нашия плъгин:

mvn install

Това ще създаде * .hpi файл в целевата директория. Трябва да го копираме в директорията на Jenkins plugins ( ~ / .jenkins / plugin по подразбиране):

cp ./target/jenkins-hello-world.hpi ~/.jenkins/plugins/

И накрая, нека рестартираме сървъра и се уверим, че приставката е приложена:

  1. Open CI dashboard at //localhost:8080
  2. Navigate to Manage Jenkins | Manage Plugins | Installed
  3. Find our plugin

5.2. Configure Jenkins Job

Let's create a new job for an open-source Apache commons-lang project and configure the path to its Git repo there:

We also need to enable our plugin for that:

5.3. Check the Results

We're all set now, let's check how it works.

We can build the project and navigate to the results. We can see that a stats.html file is available here:

Let's open it:

That's what we expected – a single class which has three lines of code.

6. Conclusion

In this tutorial, we created a Jenkins plugin from scratch and ensured that it works.

Естествено, ние не разгледахме всички аспекти на разработката на разширения на CI, а просто предоставихме основен преглед, идеи за дизайн и първоначална настройка.

И както винаги, изходният код може да бъде намерен в GitHub.