DEV Community

Cover image for Automatice el README para su perfil de GitHub con Go y GitHub Actions
charly3pins
charly3pins

Posted on • Originally published at charly3pins.dev on

Automatice el README para su perfil de GitHub con Go y GitHub Actions

Tras el post donde expliqué cómo crear un README para el perfil de GitHub, me faltó incluir en la sección del Blog un link al último post publicado. Principalmente no lo hice porque no quería tener que actualizar a mano cada vez el README con el último post y su link. Para resolver esto estuve pensando cómo podía automatizar esta actualización. Mientras hacía mi lectura diaria de RSS que sigo con la aplicación Feedly, caí en que yo también tenía feed RSS. Por lo tanto, podía leer yo mismo el feed de mi blog y obtener el último post de allí de forma sencilla.

Una vez cubierta la parte de cómo obtener el último post publicado me faltaba la parte de cómo actualizar el README y es donde probé por primera vez (ya hacía tiempo que tenía ganas) las GitHub Actions. Hace un tiempo que GitHub sacó al mercado estas acciones que básicamente sirven para crear workflows automáticos para CI/CD.

Con las dos partes del problema cubiertas, sólo me faltaba una pequeña cosa... ¡hacerlo! Así que explicaré en detalle como hice ambas cosas para que lo pueda utilizar en su proyecto si le interesa.

Obtener el último post con Go

Necesitaba escanear el feed del blog y lo quería hacer en Go, por tanto, lo primero que hice fue buscar si ya había alguna librería que me facilitara esta tarea para no reinventar la rueda y encontré la github.com/mmcdole/gofeed. Tenía un montón de funcionalidades pero yo con el uso básico descrito en su README tenía suficiente.

Con el siguiente trozo de código, creo un nuevo parser, escaneo la dirección de mi feed y los elementos resultantes, me quedo con el primero, ya que es el último post publicado.

p := gofeed.NewParser()
feed, err := p.ParseURL("https://charly3pins.dev/index.xml")
if err != nil {
    log.Fatalf("error getting feed: %v", err)
}
newestItem := feed.Items[0]
Enter fullscreen mode Exit fullscreen mode

Con esto ya tengo el item con toda la información. Su aspecto es similar a:

<item>
    <title>My productivity setup for VS Code</title>
    <link>http://charly3pins.dev/blog/my-productivity-setup-for-vs-code/</link>
    <pubDate>Tue, 09 Mar 2021</pubDate>
    <guid>http://charly3pins.dev/blog/my-productivity-setup-for-vs-code/</guid>
    <description>I am gonna show you my setup for VS Code editor which makes me more productive and I feel more comfortable with the tool that I spend most of my time during the day.</description>
    <content><p>I spend a lot of hours during the day coding for the company I work for and during nights or weekends for myself, so I want to be comfortable with the tools I use constantly. One of them is my editor of code, specifically <a href="https://code.visualstudio.com/">VS Code</a>.....</content>
</item>
Enter fullscreen mode Exit fullscreen mode

Lo que me interesa para mostrar al README es sólo el title y el link.

Leer y escribir el README

Una vez tenía la información necesaria ahora tocaba leer el fichero README.md del repositorio, escribir los cambios y guardarlo de nuevo.

Para ello podía leer el archivo usando la librería standard ioutil.ReadFile(), pero en este caso como no quiero reaprovechar nada del archivo, puedo llamar directamente al os.Create() para crear un nuevo archivo y así sobrescribir el README.md que ya tenía en el directorio.

Además, como que quiero poner la información del feed junto con la parte estática de texto que ya tenía, lo que haré es crear varias cadenas de texto con las diferentes secciones que quiero poner en el perfil y luego juntarlas todas con un fmt.Sprintf().

El código que hace todo esto es el siguiente:

file, err := os.Create(filename)
if err != nil {
    log.Println("error creating file", err)
    return
}
defer file.Close()

_, err = io.WriteString(file, data)
if err != nil {
    log.Println("error writing content to file", err)
    return
}
file.Sync()
Enter fullscreen mode Exit fullscreen mode

Lo que falta por ver aquí es el valor de filename y el de data. El primero es fácil, simplemente la ruta para llegar al README. En mi caso como tengo el proyecto en un subdirectorio de mi repositorio tengo que usar filename = ../README.md. En la otra variable, lo que hay es el siguiente:

hi := "# Hey there!"
blog := "## Blog\n\nMy latest blog post is: **[" + newestItem.Title + "](" + newestItem.Link + ")**."

data := fmt.Sprintf("%s\n\n%s\n\n%s\n\n%s\n", hi, blog)
Enter fullscreen mode Exit fullscreen mode

La parte importante es la de blog donde se ve claramente como leo la información del feed.

Puede ver el código completo en mi recompositorio.

Ejecutando automáticamente el proceso

Una vez ya tenemos el código que nos genera el README automático y de forma dinámica según el último post, lo que queda por hacer es que se ejecute de forma periódica y no nos tengamos que preocupar de nada. Para hacerlo usaré un trigger de GitHub Actions para que cada vez que haga un push a la rama master ejecute el proceso y también que se ejecute de forma planificada cada domingo a las 12am.

Primero de todo necesito la carpeta .github/worfklows y dentro creo el archivoupdate.yaml con el contenido siguiente:

on:
  push:
    branches:
      - master
  schedule:
    - cron: '0 0 * * 0'
Enter fullscreen mode Exit fullscreen mode

Cuando ya está el trigger listo, lo que se tienen que definir son los jobs. Se pueden definir tantos como se quieran, en mi caso con 3 sencillos tengo suficiente. El primero hará un checkout del proyecto, el segundo generarà el README y el tercero desplegarà los cambios. Para hacer el último paso tendremos que usar los mecanismos de autenticación que proporciona GitHub Actions. El código resultantes es:

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest

    steps:
      - name: checkout repo
        uses: actions/checkout@master
        with:
          fetch-depth: 1
      - name: generate README
        run: |
          cd ${GITHUB_WORKSPACE}/update/
          go run main.go
      - name: deploy changes
        run: |
          git config user.name "${GITHUB_ACTOR}"
          git config user.email "${GITHUB_ACTOR}@users.noreply.github.com"
          git add .
          git commit -am ":rocket:: updated content"
          git push --all -f https://${{ secrets.GITHUB_TOKEN }}@github.com/${GITHUB_REPOSITORY}.git
Enter fullscreen mode Exit fullscreen mode

Puede ver el código completo en mi repositorio.

No dude en comentar aquí o contactarme en mis redes sociales para cualquier comentario, pregunta o sugerencia.

Latest comments (0)