Migrar Spaces de Confluence a Azure DevOps

Si estás pensando en migrar tu documentación de Confluence a Azure DevOps habrás visto que no es posible hacerlo directamente con los formatos que te ofrece este primero como exportación (HTML, XML y PDF). Las wikis en Azure DevOps están pensadas para hacer uso de markdowns y es por ello que tenemos que ingeniárnoslas para conseguir este formato de nuestros Spaces. En este artículo te cuento mis investigaciones al respecto 🙂

Opción 1: Usar la herramienta Markdown Exporter for Confluence

Existe una herramienta llamada Markdown Exporter for Confluence que nos permite descargar como markdown las páginas. Por lo que he podido probar, los archivos obtenidos los convierte perfectamente sin caracteres especiales, súper limpio.

Resultado de la exportación con Markdown Exporter for Confluence

Los dos «peros» de esta herramienta es que tiene la limitación de que no se puede automatizar o elegir un Space completo, por lo que habría que ir página por página descargando el archivo que genera.

Export to Markdown con Markdown Exporter for Confluence

Por otro lado se trata de una herramienta de pago, aunque el precio no es muy elevado.

Opción 2: Exportar el Space a formato HTML y convertirlo a markdown

Uno de los formatos propuestos por Confluence para la exportación de los espacios es HTML. Podemos aprovechar el mismo para convertirlo posteriormente a markdown. Para ello debes ir al Space que quieres exportar y accede al apartado Space Settings > Content Tools > Exports, mantén seleccionada la opción HTML, y haz clic en Next.

Confluence – Space Settings – Content Tools – Export to HTML

En la siguiente ventana mantén la opción Normal Export.

Confluence – Space Settings – Content Tools – Export HTML Options

Una vez haya finalizado el proceso podrás descargarlo a través del siguiente enlace:

Confluence – Export completed

Esto descargará un zip con todos los elementos de tu Space en formato HTML.

Instalar Pandoc

Lo siguiente que necesitas es instalar la herramienta Pandoc, que es un convertidor de documentos. Elige la instalación en base a tu sistema operativo.

Instalar confluence-to-github-markdown

La herramienta confluence-to-github-markdown es la que nos ayudará a reconvertir estos HTMLs en el formato que necesitamos. Puedes instalarla a través del siguiente comando:

npm install -g confluence-to-github-markdown

Extrae el zip descargado anteriormente de Confluence y utiliza el siguiente comando para la conversión del contenido:

confluence-to-github-markdown NOMBRE_DEL_DIRECTORIO

El resultado será un nuevo directorio llamado Markdown con los archivos .md como resultado del comando anterior.

Resultado del comando confluence-to-github-markdown

Si bien esta opción mejora en cuanto al proceso de exportación, a diferencia de la opción 1, el paso de HTML a Markdown no es todo lo limpio que nos gustaría, como si ocurre con la primera opción:

Resultado de la conversión de HTML a markdown con confluence-to-github-markdown

Esto requeriría por nuestra parte hacer limpieza de la documentación una vez exportada. Si tenemos mucha documentación generada esto sería un proceso que necesitaría mucho tiempo por nuestra parte.

Opción 3: Convertir solo el contenido del div main-content

Como tercera opción, lo que he podido comprobar, y que estoy casi segura de que es lo que hace la herramienta de la opción 1, es una vez exportado el contenido del Space a HTML podríamos crear un proceso que solamente dejara como contenido de los HTML lo que hay dentro de main-content y posteriormente utilizar algún conversor de HTML a markdown. Para verlo con el mismo ejemplo, suponiendo que Confluence nos devuelve este HTML:

<!DOCTYPE html>
<html>
<head>
    <title>ffmpeg-on-aks : Streamings de audio de prueba</title>
    <link rel="stylesheet" href="styles/site.css" type="text/css" />
    <META http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body class="theme-default aui-theme-default">
    <div id="page">
        <div id="main" class="aui-page-panel">
            <div id="main-header">
                <div id="breadcrumb-section">
                    <ol id="breadcrumbs">
                        <li class="first">
                            <span><a href="index.html">ffmpeg-on-aks</a></span>
                        </li>
                        <li>
                            <span><a href="Grabar-streamings-de-audio-con-FFmpeg-en-AKS_1081424.html">Grabar streamings
                                    de audio con FFmpeg en AKS</a></span>
                        </li>
                    </ol>
                </div>
                <h1 id="title-heading" class="pagetitle">
                    <span id="title-text">
                        ffmpeg-on-aks : Streamings de audio de prueba
                    </span>
                </h1>
            </div>
            <div id="content" class="view">
                <div class="page-metadata">
                    Created by <span class='author'> Gisela Torres</span>, last modified on Mar 23, 2021
                </div>
                <div id="main-content" class="wiki-content group">
                    <p>Estos son algunos streams con los que puedes probar la herramienta:</p>
                    <ul>
                        <li>
                            <p><a href="http://stream2.cnmns.net/hope-mp3" class="external-link"
                                    rel="nofollow">http://stream2.cnmns.net/hope-mp3</a></p>
                        </li>
                        <li>
                            <p><a href="http://stream2.cnmns.net/inspire-mp3" class="external-link"
                                    rel="nofollow">http://stream2.cnmns.net/inspire-mp3</a></p>
                        </li>
                    </ul>
                </div>
            </div>
        </div>
        <div id="footer" role="contentinfo">
            <section class="footer-body">
                <p>Document generated by Confluence on Mar 24, 2021 13:33</p>
                <div id="footer-logo"><a href="http://www.atlassian.com/">Atlassian</a></div>
            </section>
        </div>
    </div>
</body>
</html>

Si pasamos todo él por una herramienta que convierta a markdown nos daría un resultado parecido al de la opción 2. Sin embargo, si solo cogemos el contenido dentro de main-content obtendremos el resultado que esperamos:

Estos son algunos streams con los que puedes probar la herramienta:
*   [http://stream2.cnmns.net/hope-mp3](http://stream2.cnmns.net/hope-mp3)
    
*   [http://stream2.cnmns.net/inspire-mp3](http://stream2.cnmns.net/inspire-mp3)

Para este punto me he generado un script en Node.js que hace la limpieza del HTML y la conversión con el módulo turndown:

var fs = require("fs"),
    { parse } = require("node-html-parser"),
    path = require('path'),
    TurndownService = require('turndown');
var turndownService = new TurndownService();

function readFiles(dirName, onFileContent, onError) {
    fs.readdir(dirName, (err, filesNames) => {
        if (err) {
            onError(err);
            return;
        }
        var targetFiles = filesNames.filter(function (file) {
            return path.extname(file).toLowerCase() === '.html';
        });
        targetFiles.forEach(fileName => {
            fs.readFile(`${dirName}//${fileName}`, 'utf-8', (err, content) => {
                if (err) {
                    onError(fileName, err);
                    return;
                }
                onFileContent(fileName, content);
            });
        });
    })
}
const markdownFolder = 'markdowns';
readFiles('FOLDER_NAME', (fileName, content) => {
    console.log(`Processing ${fileName}`);
    // console.log(content);
    const root = parse(content);
    var mainContentDiv = root.querySelector('#main-content');
    // console.log(mainContentDiv.innerHTML);
    //Create markdown folder if it doesn't exist
    if (!fs.existsSync(markdownFolder)) {
        fs.mkdirSync(markdownFolder);
    }
    //Create HTML files with the main-content div only
    fs.writeFile(`${markdownFolder}/${fileName}`, mainContentDiv.innerHTML, function (err) {
        if (err) {
            return console.log(err);
        }
        console.log(`${fileName} saved on ${markdownFolder}`);
    });
    console.log(turndownService.turndown(mainContentDiv.innerHTML));
    fs.writeFile(`${markdownFolder}/${fileName.replace(path.extname(fileName), '.md')}`, turndownService.turndown(mainContentDiv.innerHTML), function (err) {
        if (err) {
            return console.log(err);
        }
        console.log(`${fileName} saved on ${markdownFolder}`);
    });

}, (fileName, err) => {
    console.error(`[ERROR] on file ${fileName}`);
    throw err;
});

El código de ejemplo lo tienes en mi GitHub. En el caso de tener imágenes, videos o cualquier otro documento insertado recuerda que también debes copiar la carpeta attachments que se descarga cuando haces el export de Confluence.

Resultado utilizando la opción 3

Crear un repositorio en Azure Repos con el contenido exportado

Independientemente de la opción que utilices para obtener los markdowns de tu documentación en Confluence, el siguiente paso es crear un repositorio en Azure DevOps que almacene todos estos archivos. Dirígete al proyecto donde quieres almacenar esta información y en el apartado Repos crea un nuevo repositorio:

Azure DevOps – Repos – New repositorio

Para este ejemplo lo he llamado wiki y he eliminado el check que me genera un README.md de manera automática.

Ahora accede a través del terminal al directorio donde tienes los archivos markdown a subir y ejecuta los siguientes comandos:

git init
git add .
git commit -m "Add docs from Confluence"
git branch -m main
git remote add origin https://YOUR_ORG@dev.azure.com/YOUR_ORG/YOUR_PROJECT/_git/wiki
git push -u origin --all

Si todo ha ido bien deberías de ver tus archivos en el nuevo repositorio.

Enlazar el repositorio wiki a Wikis

El último paso de todo este proceso es enlazar el nuevo repositorio al apartado Wikis de tu proyecto en Azure DevOps. Para ello, basta con ir al apartado Overview – Wiki y hacemos clic en la opción Publish code as wiki.

Azure DevOps – Overview – Wiki – Publish code as wiki

Selecciona el repositorio wiki, añadiendo la ruta, en este caso /, en el apartado de Path y un nombre para esta documentación:

Azure DevOps – Wiki – Publish code as wiki

¡Saludos!