Implementación en PythonAnywhere desde GitHub



Todos pueden hacer esto:


proyecto local -> github


Con acceso ssh (pago), puede hacer esto:


proyecto local -> PythonAnywhere


El artículo muestra cómo (de forma gratuita) hacer esto:


proyecto local -> github -> PythonAnywhere


Primero, enumeraré por qué podría necesitar esto, y luego pasaré a cómo implementarlo. Siéntase libre de omitir el artículo si la primera parte no le interesa.




Por qué


¡PythonAnywhere es un gran servicio! Es gratuito, proporciona una buena potencia e incluso una base de datos, por lo que puede crear un sitio dinámico en un par de minutos. Esta es una gran opción para principiantes que desean probar algo en vivo, y para aquellos que necesitan alojar una API o algún proyecto personal.


Pero el servicio también tiene desventajas. ¿Qué sucede si desea abrir el código en el que está trabajando? ¿Apoyará y hará cambios en dos lugares a la vez? Una vez en la producción de PythonAnywhere y una segunda vez en GitHub para otros desarrolladores. ¿Qué sucede si acepta la solicitud de extracción o desea integrar CI? Duplicar constantemente todas las acciones es muy inconveniente.


GitHub es un gran servicio para trabajar juntos y ver el código fuente, su interfaz de usuario es mejor que en PythonAnywhere y, lo que llevo a decir, editar el código directamente en PythonAnywhere no es muy agradable. ¿Qué pasaría si pudiéramos combinar lo mejor de dos mundos?


Empuja todas las actualizaciones en GitHub, y la aplicación PythonAnywhere se sincroniza y reinicia automáticamente. Puede parpadear PR, usar tickets, ver su código desde cualquier dispositivo sin siquiera iniciar sesión y sin abrir un archivo en el editor de código; en general, hacer todo lo que GitHub le permite hacer.


Ya escucho un murmullo: "Bien, bien, convencido, pero ¿cómo se puede lograr esto?" ¡Ni una palabra más!




Como?


Utilizamos webhooks de Github para notificarle sobre una actualización de la aplicación, extraerla y volver a cargarla.


Como ejemplo, consideraré mi aplicación SwagLyrics , cuyo backend mantengo en PythonAnywhere. Estoy usando Flask, por lo que el proceso será diferente para otro marco.


Primero, sincronice el proyecto para que GitHub sea el origen. Si aún no ha creado un repositorio de PythonAnywhere, puede inicializarlo o codificarlo directamente desde GitHub.


Algo como:


git init git remote add origin https://github.com/yourusername/yourreponame.git 

Ahora ve a GitHub -> Configuración -> Webhooks -> Agregar webhook


Allí verás:



En el campo "URL de carga", agregue your_domain / route_to_update


Por ejemplo, el webhook de mi repositorio apunta a nbsp; https://aadibajpai.pythonanywhere.com/update_server


Cambie el "Tipo de contenido" de application / x-www-form-urlencoded a application / json (más adelante le diré por qué esto es necesario).


Todavía no tocaremos el campo Secreto.


Asegúrese de que la opción "evento de inserción" esté seleccionada y haga clic en "Agregar webhook".


Abra su aplicación en Flask, configuraremos una ruta para recibir información de GitHub cuando ocurra un evento push. La ruta debe ser la que especificó en el campo "URL de carga útil". No especificamos explícitamente la rama maestra, como por simplicidad, se implica que es el único en el repositorio.


La configuración más simple se vería así:


 from flask import Flask, request import git 

 app = Flask(__name__) 

 @app.route('/update_server', methods=['POST']) def webhook(): if request.method == 'POST': repo = git.Repo('path/to/git_repo') origin = repo.remotes.origin 

  origin.pull() 

  return 'Updated PythonAnywhere successfully', 200 else: return 'Wrong event type', 400 

Este es el ejemplo más trivial, una versión más completa será más baja.


Ahora, cada vez que ocurre un evento push, la aplicación se actualizará haciendo pull.


Si todo salió bien, esto es lo que verá después de la próxima confirmación:



Antes de pasar a proteger el webhook de extraños, le diré cómo reiniciar la aplicación después de extraer para que no tenga que hacerlo manualmente.


Recarga automática de aplicaciones web


Usaremos ganchos git. Estos son solo comandos de shell ejecutados después de los eventos. No hay gancho para el evento después del tirón, pero ...


Utilizamos el hecho de que git pull no es más que git fetchgit merge , pero existe un enlace para el evento después de la fusión . Se ejecuta si la extracción se completa con éxito.


En su repositorio de PythonAnywhere, vaya a .git / hooks /


Ya habrá varios ganchos existentes, agregue el suyo creando un archivo posterior a la fusión


Escriba el siguiente código en él:


 #!/bin/sh touch /path/to/username_pythonanywhere_com_wsgi.py 

Use la ruta a su wsgi, que, cuando se cambia (toque), reinicia la aplicación.


Para hacer que el archivo sea ejecutable, abra la consola y ejecute


 chmod +x post-merge 

Asegúrese de que el reinicio funcione haciendo una nueva confirmación.


Ahora pasemos a asegurar un webhook.




Protección Webhook


Es necesario proteger un webhook para que otra persona no pueda enviar constantemente solicitudes para reiniciar la aplicación. Usaremos esta guía.


Primero, agregue un token secreto en PythonAnywhere como una variable de entorno, así como en el campo "Secreto" en la configuración del webhook de GitHub. Aquí el proceso se describe con más detalle.


GitHub ofrece sus métodos en Ruby, pero usamos Python, por lo que usaremos esta función de comparación:


 import hmac import hashlib def is_valid_signature(x_hub_signature, data, private_key): # x_hub_signature and data are from the webhook payload # private key is your webhook secret hash_algorithm, github_signature = x_hub_signature.split('=', 1) algorithm = hashlib.__dict__.get(hash_algorithm) encoded_key = bytes(private_key, 'latin-1') mac = hmac.new(encoded_key, msg=data, digestmod=algorithm) return hmac.compare_digest(mac.hexdigest(), github_signature) 

Ahora modifique el controlador update_server para verificar si la firma es válida agregando estas líneas antes de la parte de actualización de código:


 x_hub_signature = request.headers.get('X-Hub-Signature') if not is_valid_signature(x_hub_signature, request.data, w_secret): 

w_secret debe coincidir con el valor que estableció un poco antes como variable de entorno.


En general, tiene sentido agregar el registro y algunas comprobaciones más para asegurarse de que el webhook de GitHub o que el evento contenga datos, por lo que si lo desea, puede copiar el código relevante de mi repositorio , cambiándolo cuando sea necesario, ya que ya lo sabe todo lo importante


Espero que la información haya sido útil. Sé que hay muchas cosas, pero quería que entendieras lo que estaba sucediendo.




No se me ocurrió todo, sino que reuní lo más importante de varias fuentes y creé una solución completa.


Aquí están los enlaces que me ayudaron y pueden ayudarte:
  1. https://stackoverflow.com/a/54268132/9044659 (configuración básica)
  2. https://developer.github.com/webhooks/ (documentación del webhook de GitHub)
  3. https://github.com/CCExtractor/sample-platform/blob/master/mod_deploy/controllers.py (una implementación muy detallada con un montón de comprobaciones si desea pasar tiempo en esto)
  4. https://github.com/SwagLyrics/swaglyrics-issue-maker/blob/35d23d0ba416e742e381da931d592ce6f58fc13f/issue_maker.py#L268 (implementación de mi controlador para PythonAnywhere)
  5. https://github.com/SwagLyrics/SwagLyrics-For-Spotify (repositorio donde lo uso en la práctica)

Gracias por leer!

Source: https://habr.com/ru/post/457348/


All Articles