Desenvolvimento de Plugins Personalizados para Jenkins

Configuração do Ambiente de Desenvolvimento

O ecossistema do Jenkins é fundamentado em Java. Para iniciar a criação de extensões, é imprescindível ter o Java Development Kit (JDK) e o Apache Maven devidamente instalados e configurados nas variáveis de ambiente da máquina.

Geração do Projeto Base

O ponto de partida mais eficiente é utilizar os arquétipos oficiais fornecidos pela comunidade. Crie um diretório para o seu workspace e execute o comando Maven abaixo para filtrar os templates disponíveis para extensões vazias:

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

Durante a execução interativa, o Maven solicitará o preenchimento de metadados essenciais:

  • Selecione a versão do arquétipo desejada.
  • Defina o artifactId (por exemplo, custom-ci-extension).
  • Informe a versão base do Jenkins para a qual o plugin será compilado.

Confirme as configurações digitando Y para materializar a estrutura de diretórios do projeto.

Execução e Depuração Local

Para testar a extensão em um ambiente isolado, o plugin Maven HPI provê um servidor Jetty embutido. Navegue até a raiz do diretório recém-criado e dispare o ciclo de vida de execução:

mvn hpi:run

É comum encontrar falhas de compilação relacionadas à versão do Java. Muitas extensões legadas ou configurações específicas exigem o JDK 8. Caso enfrente este problema, aponte o Maven para a instalação correta antes de executar o comando:

export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home
export PATH=$JAVA_HOME/bin:$PATH
mvn hpi:run

Com o servidor ativo na porta padrão 8080 (certifique-se de que não haja conflitos de porta no sistema operacional), acesse http://localhost:8080/jenkins/ no navegador. Para validar o esqueleto inicial, crie um job do tipo Freestyle, adicione o passo de construção padrão gerado pelo template, execute a tarefa e inspecione os logs no console de saída.

Arquitetura e Modificação do Código Fonte

A estrutura do projeto gerado contém os componentes essenciais para uma extensão funcional, divididos entre classes Java (lógica de negócio) e arquivos Jelly/Groovy (renderização da interface). As propriedades expostas na UI são gerenciadas através de métodos get e construtores anotados com @DataBoundConstructor.

Abaixo, uma implementação robusta de um Builder personalizado. O código inclui a validação de parâmetros na interface de configuração (via DescriptorImpl) e o método perform, que concentra a regra de execução durante o build:

package com.empresa.ci;

import hudson.Extension;
import hudson.Launcher;
import hudson.model.AbstractBuild;
import hudson.model.BuildListener;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.Builder;
import hudson.util.FormValidation;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;
import java.io.IOException;

public class CustomTestRunner extends Builder {

    private final String targetEndpoint;
    private final int maxTimeout;

    @DataBoundConstructor
    public CustomTestRunner(String targetEndpoint, int maxTimeout) {
        this.targetEndpoint = targetEndpoint;
        this.maxTimeout = maxTimeout;
    }

    public String getTargetEndpoint() { return targetEndpoint; }
    public int getMaxTimeout() { return maxTimeout; }

    @Override
    public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) 
            throws InterruptedException, IOException {
        listener.getLogger().println("Iniciando execução da suíte no endpoint: " + targetEndpoint);
        listener.getLogger().println("Timeout configurado para: " + maxTimeout + " segundos");
        
        // Lógica de integração com API externa
        return true;
    }

    @Extension
    public static final class DescriptorImpl extends BuildStepDescriptor<Builder> {
        
        public FormValidation doCheckTargetEndpoint(@QueryParameter String value) {
            if (value == null || !value.startsWith("http")) {
                return FormValidation.error("Informe uma URL válida iniciando com http ou https.");
            }
            return FormValidation.ok();
        }

        @Override
        public boolean isApplicable(Class jobType) { return true; }

        @Override
        public String getDisplayName() { return "Executar Suite de Testes Customizada"; }
    }
}

Para validações que dependam do contexto de execução (em vez da configuração inicial do job), a lógica deve ser inserida dirteamente dentro do método perform, lançando exceções quando as condições não forem atendidas.

Compilação e Empactoamento

Para gerar o arquivo binário instalável no formato .hpi, utilize o ciclo de empacotamento do Maven. Caso os testes unitários apresentem falhas devido a restrições do ambiente local, é possível ignorá-los utilizando as flags apropriadas:

mvn clean package -DskipTests

Atenção à compatibilidade: Se ocorrerem erros de dependência durante a compilação, verifique a tag jenkins.version no arquivo pom.xml. Esta versão deve ser estritamente compatível com a instância do servidor Jenkins onde o plugin será implantado. Ajuste o parenet POM caso necessário.

Integração em Pipelines

Uma vez compilado e instalado, a extensão pode ser orquestrada via Jenkins Pipeline. Utilizando a anotação @Symbol na classe descritora, a sintaxe de invocação torna-se nativa e limpa.

Implementação utilizando o formato Scripted:

node {
    stage('Testes') {
        customTestRunner targetEndpoint: 'http://api.interno.local:8080/v2/run', maxTimeout: 300
    }
}

Implementação utilizando o formato Declarative:

pipeline {
    agent any
    stages {
        stage('Validação de Qualidade') {
            steps {
                customTestRunner targetEndpoint: 'http://api.interno.local:8080/v2/run', maxTimeout: 300
            }
        }
    }
}

Tags: Jenkins java maven continuous-integration groovy-pipeline

Publicado em 6-9 08:05 por Thomas