Puedes usar la API REST para vincular las confirmaciones con un servicio de pruebas, de modo que cada push que realices pueda ser probado y quede reflejado en un pull request de GitHub. Para obtener más información sobre los puntos de conexión relevantes, consulta Puntos de conexión de la API de REST para estados de confirmaciones.
Esta guía utilizará la API para demostrar una configuración que puedes utilizar. En nuestro escenario, vamos a:
- Ejecutaremos nuestra suit de IC cuando se abra una Solicitud de Extracción (configuraremos el estado de IC como pendiente).
- Cuando el CI haya finalizado, estableceremos el estado del Pull Request en consecuencia.
Nuestro sistema de IC y nuestro servidor host serán imaginarios. Podrían ser Travis, Jenkins, o algo completamente distinto. El meollo de esta guía será configurar y ajustar el servidor que administra la comunicación.
Si todavía no lo has hecho, descarga ngrok y aprende a usarlo. Consideramos que es una herramienta muy útil para exponer las aplicaciones locales a Internet.
Nota: Puede descargar el código fuente completo de este proyecto desde el repositorio platform-samples.
Escribir tu servidor
Escribiremos rápidamente una aplicación de Sinatra para probar que nuestras conexiones locales están funcionando. Comencemos con esto:
require 'sinatra'
require 'json'
post '/event_handler' do
payload = JSON.parse(params[:payload])
"Well, it worked!"
end
(Si no está familiarizado con el funcionamiento de Sinatra, le recomendamos leer la guía de Sinatra).
Inicia este servidor. De manera predeterminada, Sinatra comienza en el puerto 4567, por lo que también tendrás que configurar ngrok para que empiece a escuchar en este puerto.
Para que este servidor funcione, necesitaremos configurar un repositorio con un webhook. El webhook debe configurarse para que se active cada que se crea o fusiona una solicitud de extracción.
Sigue adelante y crea un repositorio en el que quieras hacer tus experimentos. ¿Podríamos sugerir el repositorio de cucharas y cuchillos de @octocat?
Después de esto, crearás un webhook en el repositorio, le suministrarás la dirección URL que te ha proporcionado ngrok y seleccionarás application/x-www-form-urlencoded como el tipo de contenido.
Haga clic en Update Webhook. Debería ver una respuesta del cuerpo de Well, it worked!.
Magnífico. Haga clic en Permítame seleccionar eventos individuales y seleccione lo siguiente:
- Estado
- Solicitud de incorporación de cambios
Estos son los eventos que GitHub enviará al servidor cuando se produzca cualquier acción relevante. Actualicemos nuestro servidor para que solo gestione el escenario de solicitud de incorporación de cambios (Pull Request) por ahora:
post '/event_handler' do
@payload = JSON.parse(params[:payload])
case request.env['HTTP_X_GITHUB_EVENT']
when "pull_request"
if @payload["action"] == "opened"
process_pull_request(@payload["pull_request"])
end
end
end
helpers do
def process_pull_request(pull_request)
puts "It's #{pull_request['title']}"
end
end
¿Qué sucede? Cada evento que GitHub envía tiene adjunto un encabezado HTTP X-GitHub-Event. Solo nos interesan los eventos de PR por el momento. Desde ahí, se tomará la carga de información y se devolverá el campo de título. En un escenario ideal, nuestro servidor se ocuparía de cada vez que se actualiza un pull request, no solo cuando se abre. Eso garantizaría que todas las cargas pasen la prueba de IC.
Pero para efectos de esta demostración, solo nos interesará cuándo se abren.
Para probar esta prueba de concepto, realice algunos cambios en una rama del repositorio de pruebas y abra una solicitud de incorporación de cambios. ¡Tu servidor debería responder en consecuencia!
Trabajar con los estados
Después de implementar el servidor, ya se puede comenzar el primer requisito: configurar (y actualizar) los estados de CI. Tenga en cuenta que siempre que actualice el servidor, puede hacer clic en Redeliver para enviar la misma carga. No es necesario crear un pull request cada vez que realice un cambio.
Puesto que estamos interactuando con la API de GitHub, usaremos Octokit.rb para administrar nuestras interacciones. Configuraremos ese cliente con personal access token:
# !!! DO NOT EVER USE HARD-CODED VALUES IN A REAL APP !!!
# Instead, set and test environment variables, like below
ACCESS_TOKEN = ENV['MY_PERSONAL_TOKEN']
before do
@client ||= Octokit::Client.new(:access_token => ACCESS_TOKEN)
end
Después, solo habrá que actualizar la solicitud de incorporación de cambios en GitHub para dejar claro lo que se procesa en la CI:
def process_pull_request(pull_request)
puts "Processing pull request..."
@client.create_status(pull_request['base']['repo']['full_name'], pull_request['head']['sha'], 'pending')
end
Estamos haciendo tres cosas muy básicas aquí:
- Estamos buscando el nombre completo del repositorio
- Estamos buscando el último SHA del pull request
- Estamos configurando el estado como pendiente
Eso es todo. A partir de ahora, puede ejecutar el proceso que necesite para ejecutar el conjunto de pruebas. Es posible que tenga que pasar el código a Jenkins, o bien llamar a otro servicio web mediante su API, como Travis. Después, asegúrese de actualizar el estado nuevamente. En el ejemplo, simplemente se establecerá en "success":
def process_pull_request(pull_request)
@client.create_status(pull_request['base']['repo']['full_name'], pull_request['head']['sha'], 'pending')
sleep 2 # do busy work...
@client.create_status(pull_request['base']['repo']['full_name'], pull_request['head']['sha'], 'success')
puts "Pull request processed!"
end
Conclusión
En GitHub, hemos usado una versión de Janky para administrar nuestra CI durante años. El flujo básico es esencialmente exactamente igual al servidor que hemos creado anteriormente. En GitHub, nosotros:
- Notificamos todo a Jenkins cuando se crea o actualiza una solicitud de extracción (a través de Janky)
- Espera una respuesta sobre el estado de la CI
- Si el código tiene luz verde, fusionamos la pull request.
Todas estas comunicaciones se canalizan de vuelta a nuestras salas de chat. No es necesario crear una configuración de CI propia para utilizar este ejemplo. Siempre puede confiar en integraciones de GitHub.