Motivación

Hay muchos tutoriales tratando de explicar cómo solucionar un problema siguiendo una lista de pasos, el problema es que asumen que vos compartís el mismo contexto que el autor, y aún más importante, asumen que vos tenes éxito en cada uno de los pasos.

Yo quiero hacer algo distinto, quiero hacer un post en pseudo tiempo real, explicando como crear un sitio usando DocFx. Nuestro contexto va a ser diferente, por su puesto, pero espero poder ayudarte a configurar tu sitio, explicándote no solo los paso correctos, sino también los problemas que voy encontrando, y que vos también podes llegar a encontrar.

¿Muy largo para leer? !Mirá el video!

Introducción

Toda la API de Puppeteer-Sharp está documentada utilizando Comentarios XML. Lo que queremos hacer es crear un sitio utilizando DocFX y Github Pages. Por último, queremos que el sitio esté disponible en http://www.puppeteer-sharp.com.

¿Qué es lo que sabemos?

  • Sabemos que le podemos pedir al compilador que genere un archivo XML con la documentación. Ya estamos haciendo eso.
  • También sabemos que queremos usar DocFX.
  • Y que queremos que sea un proceso automático en nuestro CI.

Pomodoro 1 - Setup

Como necesitamos correr el CI muchas veces y no queremos ensuciar el repositorio de Puppeteer, vamos a crear un nuevo repositorio. docfx-playground suena genial bien.

Repo Image

También necesitamos configurar un CI para este proyecto. App Veyor

Copiemos todos nuestros archivos a este nuevo repository.

DocFX

Bien, ahora vamos a necesitar 2 carpetas:

  • Sabemos que DocFX va a necesitar una carpeta para su proyecto. Una carpeta llamada docfx_project.
  • También sabemos que vamos a intentar generar un sitio usando la carpeta _site, pero como Github Pages va a buscar una carpeta llamada docs, vamos a crear nuestro sitio allí.

docfx_project

Si corremos docfx init, este debería crear una carpeta docfx_folder en nuestro proyecto.

docfx init -q

Dcofx

Fabuloso!

Ahora simplemente necesitamos setear la ruta de esa carpeta en el archivo docfx.json:

"metadata": [
    {
      "src": [
        {
          "cwd": "../",
          "files": [
            "lib/PuppeteerSharp/**.csproj"
          ]
        }
      ],
      "dest": "api",
      "disableGitFeatures": false
    }
  ],

Bien. Ahora si llamamos a docfx metadata debería… hacer algo…

docfx metadata docfx_project/docfx.json

BOOM! DocFx metadata

No se que son esos archivos todavía, pero es algo. Tratemos de buildear el sitio.

docfx build docfx_project/docfx.json -o docs

Bueno, podría haber sido peor. Primero, creo una carpeta _sites dentro de mi carpeta docs. No quería hacer eso seteando como output la carpeta docs.

A parte, la home page y la API index page podrían haber tenido más links conectando a las nuevas páginas…

Home del sitio Primera Home La Home de la API FirstAPI La documentación de una clase Doc Page

Fin del pomodoro 1

Pomodoro 2 - Dándole forma al sitio

Necesitamos deshacernos de la carpeta _sites, para ello vamos a cambiar la propiedad dest en el docfx.json.

“dest”: “.”

Perfecto, ahora nuestro sitio está usando la carpeta docs. Ahora vamos a intentar mejorar nuestro sitio: Voy a trabajar en el estilo. Agregar algo de contenido a la home page. Ver como agregar links a la documentación de la API.

Creí que iba a perder todo un pomodoro con esto, pero resulta que lo único que necesitas para tener el sitio corriendo es simplemente llamar a docfx serve.

docfx serve

Good API Page

Fin del Pomodoro 2

Pomodoro 3 - GitHub Pages y AppVeyor

Bien, ya tenemos nuestros sitio corriendo, vamos a hacer push y configurar Github Pages.

Githubpage

Tenemos un sitio!

Site

Si bien hay algunas cosas que mejorar, vamos a configurar AppVeyor. La idea es simple: Necesitamos compilar docfx solo cuando un Tag (release) es creado. También necesitamos actualizar la metadata de DocFx y el sitio. Por último, necesitamos hacer un push del sitio compilado nuevamente al repo.

AppVeyor tiene un muy buen documento para ayudarnos a configurar git, de modo que podamos hacer un push del contenido. Basicamente necesitamos configurar un personal access token en Github, encriptarlo y usarlo en nuestro script. La sección de configuración de git debería ser algo como esto:

- git config --global credential.helper store
- Add-Content "$HOME\.git-credentials" "https://$($env:git_access_token):x-oauth-basic@github.com`n"
- git config --global user.email "dariokondratiuk@gmail.com"
- git config --global user.name "Darío Kondratiuk"

Luego generamos la documentación

- docfx metadata docfx_project/docfx.json
- docfx build docfx_project/docfx.json -o docs

Finalmente, hacemos un commit a nuestro repo.

- git checkout master
- git add docfx_project/*
- git add docs/*
- git commit -m "Docs for"
- git push origin

Ouch… DocFx me está tirando este error:

[18-06-08 12:17:14.994]Warning:ExtractMetadata(C:/projects/docfx-playground/lib/PuppeteerSharp/PuppeteerSharp.csproj)Workspace failed with: [Failure] Msbuild failed when processing the file ‘C:\projects\docfx-playground\lib\PuppeteerSharp\PuppeteerSharp.csproj’ with message: C:\Program Files\dotnet\sdk\2.1.300\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.GenerateAssemblyInfo.targets: (161, 5): The “GetAssemblyVersion” task failed unexpectedly.

Y este cuando intento hacer un push a GitHub:

fatal: unable to access ‘https://github.com/kblok/docfx-playground.git/’: The requested URL returned error: 403 550

Fin del Pomodoro 3

Pomodoro 4 - Branch gh-pages

Cambio de planes! Encontré un artículo en GitHub el cual nos muestra como podemos publicar un GitHubPage usando un branch llamado gh-page. Es genial porque los commits relacionados con docfx no se van a mezclar con los commits del branch de master, tambien voy a ser capáz de mantener mi branch master protegido.

Encontré este gist con un script para crear un branch gh-page vacío.

cd /path/to/repo-name
git symbolic-ref HEAD refs/heads/gh-pages
rm .git/index
git clean -fdx
echo "My GitHub Page" > index.html
git add .
git commit -a -m "First pages commit"
git push origin gh-pages

Genial! Tenemos un branch llamado gh-pagesvacío y listo para usar. Vamos a volver a nuestro código en AppVeyor. Para poder hacer un push a GitHub, necesitamos agregar https a nuestro remote.

git remote add pages https://github.com/kblok/docfx-playground.git

Entonces vamos a poder usar git subtree push para hacer un push de nuestro sitio a este nuevo branch remoto.

git subtree push --prefix docs pages gh-pages

Ok, ahora AppVeyor me está tirando este error:

"GetAssemblyVersion" task failed unexpectedly.
331System.NullReferenceException: Object reference not set to an instance of an object.

Fin del Pomodoro 4 :(

Pomodoro 5 - Git subtree

Este post me muestra que tenemos que registrar el subtree antes de hacer un git subtree push.

git subtree add --prefix docs gh-pages

También aprendí que después de crear el subtree tenemos que hacer un commit y un push a ese subtree:

git checkout master
git subtree add --prefix docs gh-pages
docfx metadata docfx_project/docfx.json
docfx build docfx_project/docfx.json -o docs
git add docs/
git commit -m "Docs"
git subtree push --prefix docs pages gh-pages

Pero el comando push está trabado :(

Fin del Pomodoro 5

Pomodoro 6 - Configurando un GitHub Access Token

Encontré un buen script para configurar git.

El error 403 mientras tratamos de hacer un push a Github se debe a que tenemos que chequear la opción “Repo” cuando creamos el Token.

Repo check

También aprendí que esta es la manera correcta de registrar un subtree:

git subtree add --prefix docs pages/gh-pages

Listo! Ahora necesitamos poner todo este código dentro de un if de modo tal que solo se ejecute cuando estamos creando un nuevo Tag/Release en GitHub.

Este sería el script final:

if($env:APPVEYOR_REPO_TAG -eq 'True'){
    git config --global credential.helper store
    Add-Content "$env:USERPROFILE\.git-credentials" "https://$($env:git_access_token):x-oauth-basic@github.com`n"

    git config --global user.email "dariokondratiuk@gmail.com"
    git config --global user.name "Darío Kondratiuk"
    git remote add pages https://github.com/kblok/docfx-playground.git
    git fetch pages
    git checkout master
    git subtree add --prefix docs pages/gh-pages
   docfx metadata docfx_project/docfx.json
   docfx build docfx_project/docfx.json -o docs
    git add docs/* -f
    git commit -m "Docs build $($env:APPVEYOR_BUILD_VERSION)"
    git subtree push --prefix docs pages gh-pages
}

Ahora tenemos que configurar nuestro dominio y ya estamos listos!

Setup domain

Si te estás preguntando qué será este error:

[18-06-08 12:17:14.994]Warning:ExtractMetadataWorkspace failed with: [Failure] Msbuild failed when processing the file ‘C:\projects\docfx-playground\lib\PuppeteerSharp\PuppeteerSharp.csproj’ with message: C:\Program Files\dotnet\sdk\2.1.300\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.GenerateAssemblyInfo.targets: (161, 5): The “GetAssemblyVersion” task failed unexpectedly.

La verdad que ni idea, pero la metadata se está generando a pesar de eso.

Fin del Pomodoro 6

Conclusión

Fue un camino bastante divertido, aunque un poco más largo de lo que esperaba. Bueno, si bien seis pomodoros son solamente dos horas y media, como invertí solamente un pomodoro por día, todo esto me llevó casi una semana. Espero que este post te ayude a configurar DocFx en tu solución y te simplifique la vida.

Te estarás preguntando, por qué AppVeyor y no Github Actions? No te preocupes, ya lo vamos a implementar con Github actions ;)

No dejes de codear!