Jenkins: Criando campos dinâmicos a partir de chamadas à APIs
Tags: jenkins, groovy, sre, devops
Published: 2022-08-28 18:49:00

Neste artigo mostraremos como criar campos dinâmicos com base em uma chamada API para *builds* parametrizados no Jenkins. Para isso nós utilizaremos cURL, Groovy, JsonSlurper, JSON e o [*plugin* Active Choices](https://plugins.jenkins.io/uno-choice/).

Para exemplificar a utilização, faremos uma chamada à API do IBGE retornando os Estados do Brasil. Segue abaixo um exemplo do JSON que ela retorna:

```json
[
    {
        "id": 11,
        "sigla": "RO",
        "nome": "Rondônia",
        "regiao": {
            "id": 1,
            "sigla": "N",
            "nome": "Norte"
        }
    },
    {
        "id": 12,
        "sigla": "AC",
        "nome": "Acre",
        "regiao": {
            "id": 1,
            "sigla": "N",
            "nome": "Norte"
        }
    },
    ...
]
```

Aqui nós iremos pegar apenas as UFs dos Estados armazenadas no campo `sigla` e popular um `single select` do Active Choices (que já deve estar instalado):

Você pode testar a API utilizando Postman, enviando uma requisição do tipo GET para https://servicodados.ibge.gov.br/api/v1/localidades/estados.

Vamos ao código da *pipeline*:

```groovy
import groovy.json.JsonSlurperClassic
node {
    properties([
        parameters([
            [$class: 'ChoiceParameter',
                choiceType: 'PT_SINGLE_SELECT',
                description: 'Selecione o Estado',
                name: 'estado',
                script: [$class: 'GroovyScript',
                    script: [
                        sandbox: false,
                        classpath: [],
                        script: 
                            """
                            import groovy.json.JsonSlurperClassic
                            def proc = "curl -s -H 'Accept:application/json;charset=UTF-8' https://servicodados.ibge.gov.br/api/v1/localidades/estados".execute()
                            proc.waitFor()

                            def output = proc.in.text
                            def exit_code = proc.exitValue()
                            def error = proc.err.text

                            if (error) {
                                print("Std err: \${error}")
                                print("Process exit code \${exitcode}")
                                return exitcode
                            }

                            def json = new JsonSlurperClassic().parseText(output)

                            def siglas = []

                            json.each { v ->
                                siglas.push(v.sigla)
                            }

                            return siglas.sort()
                            """
                    ]
                ]
            ]
        ])
    ])
    
    stage('Estágio único') {         
            print("O Estado escolhido foi ${estado}.")         
    }
}
```

Por meio da função `parameters()`, estamos definindo uma lista com todos os parâmetros que nosso *job* irá possuir. Neste caso, estamos definindo apenas um campo do tipo `ChoiceParameter`. Precisamos especificar o tipo da escolha, setando-a como `PT_SINGLE_SELECT`, damos um nome através da propriedade `name` e escrevemos então o *script* em Groovy que será executado para gerar as opções do campo.

> Importante: Todo *script* colocado aqui deve retornar uma lista para popular o campo.

Estamos utilizando aqui a biblioteca JsonSlurper para fazer o *deserialize* do JSON, transformando-o em um *array* do Groovy e após isso, iteramos sobre o mesmo retornando apenas as UFs.

Por fim, temos um único *stage* no *pipeline*, printando na tela a UF do Estado selecionado.

Alguns pontos importantes:

- Você pode utilizar tanto *scripted pipelines* quando *declarative pipelines* para chegar ao objetivo final. Inclusive, caso não queira colocar os parâmetros dentro do código da *pipeline*, você pode fazer isso (embora eu não recomende);
  
- Pode acontecer de ser necessária a autorização da execução de *scripts* e bibliotecas na área de Gerenciamento do Jenkins;
  
- O *plugin* Active Choices possui outros tipos de campos, inclusive reativos (imagine uma situação em que você possui dois campos, A e B, e os valores de B dependem do que foi selecionado em A);
  
- Pode ser necessária uma execução do *job* que falhará (isso é normal) para que a opção *Build with parameters* esteja disponível.
  

## Troubleshooting

Para que você consiga fazer um melhor *troubleshooting* do *script* Groovy executado para o Active Choices, você pode criar um *logger* especialmente para ele. Isso é útil quando queremos separar o *debug* desse *script* do *pipeline* principal. Para isso, vá em *Manage Jenkins* > *System Log* > Clique em *Add new log recorder* > Dê um nome como "ActiveChoices" > Clique em *Add* > No campo *Logger* digite `org.biouno.unochoice`, selecione o nível desejado e depois clique em *Save*.

## Referências

- [Documentação oficial do *plugin*](https://plugins.jenkins.io/uno-choice/)
  
- [Troubleshooting do *plugin*]([Jenkins : Troubleshooting](https://wiki.jenkins.io/display/JENKINS/Troubleshooting))

- [Post sobre Active Choices e suas funcionalidades](https://medium.com/globant/dynamic-and-reactive-parameterization-in-jenkins-pipelines-using-html-groovy-and-bash-27b031fcd69b)