¿Cómo hacemos branching en Dynamics 365?

He escrito este post después de que lo sugiriera Mötz Jensen en un largo y muy interesante hilo de Twitter acerca de control de versiones para Dynamics 365 for Finance and Operations. Este es el tweet de Denis Trunin que lo ha iniciado todo:

Leed las respuestas porque es de lo más interesante que he visto en Twitter en meses!

Branching en MSDyn365FO
Branching en MSDyn365FO

También puedes leer mi guía sobre MSDyn365FO y Azure DevOps ALM!

Branching

Cuando decidas qué estrategia de branching vas a usar tienes que pensar en qué será lo que mejor le vaya a tu equipo y en seguir el principio KISS. Usa una estrategia lo más sencilla posible! Lo que no quieres es pasarte el día limpiando código y solucionando merges mal hechos no?

También ten en cuenta que tu estrategia de branching puede no ser la misma si trabajas en un proyecto de implantación para un cliente que desarrollando un ISV.

Main – Release

Esta es de las más simples, trabajaremos en la rama Main, todos los desarrolladores. Seguiremos el trabajo ahí hasta el arranque.

Cuando vayamos a arrancar haremos un branch de Main y crearemos Release. Esta nueva rama será la que usaremos para promocionar el código a producción. El desarrollo de nuevas características y bugs se hará en Main.

Cuando terminamos un desarrollo, o arreglamos un bug, haremos un merge del changeset (o changesets) a la rama Release. Sí, haremos cherry picking, sé que tiene mala reputación pero dependemos de que los clientes validen los cambios…

En nuestros proyectos solemos tener por lo menos 2 entornos Tier 2+. Usamos uno para testing y validación. En éste entorno desplegamos el DP creado con la rama Main. En el otro Tier 2+ los usuarios hacen sus pruebas y es el que usamos para promocionar el código a prod. Este segundo entorno es el que se actualizará con el código de Release.

Dev – Main – Release

Esto es algo que hemos estado haciendo últimamente para intentar emular las ramas de desarrollo tipo Git. Estamos usando una rama Dev para cada desarrollador. Trabajamos cada uno en nuestra rama, hacemos todos los check-ins que queremos mientras desarrollamos y, cuando está terminado, lo mergeamos todo en un único changeset a Main. Después hacemos Forward Reverse Integrate de Main a nuestra rama Dev para traer todos los desarrollos de los demás programadores.

Sí, esto implica un poco más de merges en la parte de Dev-Main. Pero la idea es tener una lista limpia de changesets únicos en nuestra rama Main para cada desarrollo. ¿Por qué? Porque… cherry picking…

Trabajaremos con Dev y Main hasta el arranque, entonces haremos branch de Main y crearemos la rama Release. Actualizaremos los entornos Tier 2+ de la misma manera que con la estrategia Main ‘ Release.

Como he dicho la idea es tener una lista limpia de changesets para mover los desarrollos de Main a Release y resolver todos los conflictos de merging en las ramas Dev. Cada desarrollador es responsable de su rama y de resolver los conflictos ahí.

Hemos estado trabajando unos meses de esta forma y los resultados son positivos y no estamos teniendo problemas con la gestión. En el futuro lo probaremos con Git pero esto lo va a explicar Juanan!

Consejitos

Primero de todo: fórmate a ti y a tu equipo. Recuerda, usar un VCS es obligatorio, esto ahora es parte de tu trabajo. Busca a alguien que os pueda ayudar, incluso si no trabaja con AX. Los problemas de desarrollo de software son parecidos independientemente del lenguaje que usemos.

No dejéis changesets pendientes de ser mergeados. La cantidad de conflictos que aparecen es directamente proporcional al tiempo que lleva el changeset esperando a pasar de rama.

Recuerda, Keep it simple, stupid (o Keep it stupid simple), KISS, no te compliques la vida!! No sigas ciegamente los consejos que te da un tipo por internet, porque puede tener problemas distintos que los que tienes en tu proyecto!

Así que así es como hacemos branching en Axazure. ¿Hay formas mejores de hacerlo? Seguro que sí! ¿Se puede mejorar? No tengo la menor duda de que sí! Pero esto nos funciona, que es lo más importante.

Azure hosted build para Dynamics 365 Finance & SCM

¡Contemplad #XppGroupies! ¡El día que tanto hemos estado esperando ha llegado! Las Azure hosted builds (me cuesta mucho decir Build hospedada en Azure) ya están en preview pública con el PU35!! Ya podemos dejar de preguntarle a Joris cuando estará disponible, porque ya lo está!! Leed los Docs!!

He podido escribir esto porque, gracias a Antonio Gilabert, hemos podido probarlo durante la preview privada en Axazure durante unos meses. Y por supuesto gracias a Joris por habernos invitado a la preview!

Azure hosted builds
Cabalgando los Azure Pipelines por Caza Pelusas

¿Qué significa esto? No necesitamos ya la VM para ejecutar pipelines! Es broma, sí la necesitamos! Si estámos ejecutando tests o sincronizando la DB como parte de nuestro pipeline todavía necesitamos la VM. Pero podemos mover las builds de CI al agente de Azure.

También puedes leer mi guía sobre MSDyn365FO y Azure DevOps ALM.

Recordar que esto esta en preview privada. Si queréis uniros a la preview primero necesitáis ser parte del Insider Program donde podéis uniros al «Dynamics 365 for Finance and Operations Insider Community«. Una vez invitados deberías ver un nuevo proyecto en LCS llamado PEAP Assets, y dentro de la Asset Library en la sección Nuget package encontraréis los nugets.

Sigue leyendo «Azure hosted build para Dynamics 365 Finance & SCM»

LCS DB API: automatizando la copia de la DB de Prod a Dev

El nuevo endpoint de la LCS DB API para exportar una base de datos ha sido publicado! Con él ya tenemos una forma de automatizar el refresco de datos de tu Dynamics 365 FnO desde producción a un entorno de desarrollo Tier 1.

LCS DB API Automation
LCS DB API Automation

Puedes aprender más acerca de la LCS DB API leyendo estos posts que escribí hace un tiempo. Es una buena idea echarles un vistazo porque hay algunos pasos que doy por explicados:

También puedes leer la guía completa sobre MSDyn365FO y Azure DevOps ALM.

Recordar que esto esta en preview privada. Si queréis uniros a la preview primero necesitáis ser parte del Insider Program donde podéis uniros al «Dynamics 365 for Finance and Operations Insider Community«. Una vez invitados a la organización de Yammer podéis pedir acceso al grupo «Self-Service Database Movement / DataALM» donde recibiréis toda la info necesaria para uniros a la preview y activar la funcionalidad en LCS.

Sigue leyendo «LCS DB API: automatizando la copia de la DB de Prod a Dev»

Seguridad en Azure Pipelines con Azure Key Vault

Aquí puedes leer mi guía completa sobre Dynamics 365 for Finance and Operations y Azure DevOps.

Después de la actualización dl último post sobre llamar a la API de LCS desde Azure DevOps me di cuenta que crear una pipeline con una contraseña a la vista no era muy seguro. ¿Cómo podemos añadir un extra de seguridad a pipelines? Una vez más podemos acudir a una herramienta de Azure para ayudarnos, Azure Key Vault.

Azure Key Vault

Key Vault es un servicio que nos permite guardar certificados o secretos de forma segura y usarlos en nuestras apps o servicios. Y como muchos otros servicios de Azure tiene un coste pero es muy bajo y, para un uso normal, la factura será de 1 céntimo o ninguno al mes. ¡No seáis rancios con la seguridad!

Sigue leyendo «Seguridad en Azure Pipelines con Azure Key Vault»

Llama a la API de Movimiento de DB de LCS en tu pipeline de Azure DevOps

Aquí puedes leer mi guía completa sobre Dynamics 365 for Finance and Operations y Azure DevOps.

Hace no mucho hablé en otro post sobre la API de movimiento de base de datos de LCS, y en este quiero mostrar como llamar a la API usando PowerShell desde nuestras pipelines de Azure DevOps.

¿Para qué?

Básicamente por automatización. Ahora mismo la API sólo permite el refresco de un entorno de Microsoft Dynamics 365 for Finance and Operations a otro, así que la idea es tener datos frescos de producción en nuestros entornos de UAT a diario. No sé qué nuevas operaciones soportará la API en el futuro pero otra idea sería añadir al pipeline la exportación de la DB (creando un bacpac) de un entorno de UAT para tener datos listos para restarurar en una máquina de desarrollo. Sigue leyendo «Llama a la API de Movimiento de DB de LCS en tu pipeline de Azure DevOps»

Automatización del ALM de desarrollo en Microsoft Dynamics 365 for Finance and Operations

Aquí puedes leer mi guía completa sobre Dynamics 365 for Finance and Operations y Azure DevOps.

Ya he escrito unos cuantos posts sobre la ALM (Application Lifecycle Management) de desarrollo  para Dynamics 365 for Finance and Operations in the past:

La posibilidad de hacer CI/CD real es una de mis cosas favoritas de MSDyn365FO, pasar del «¿Qué control de código?» a «O usas control de código o muere» ha sido una maravilla. Nunca me cansaré de decirlo.

Sigue leyendo «Automatización del ALM de desarrollo en Microsoft Dynamics 365 for Finance and Operations»

Configurar las nuevas tareas de Azure DevOps para generar el paquete y versiones de modelos

Aquí puedes leer mi guía completa sobre Dynamics 365 for Finance and Operations y Azure DevOps.

Durante la pasada noche (que por lo menos era noche para mí :P) se han publicado las nuevas tareas de Azure DevOps para desplegar los paquetes, actualizar versiones de modelos y añadir licencias a los DPs:

Se ha publicado tambien un anuncio en los blogs de Community con más detalles acerca de la configuración. Vamos a ver las nuevas tareas y cómo configurarlas.

Sigue leyendo «Configurar las nuevas tareas de Azure DevOps para generar el paquete y versiones de modelos»

Dynamics 365 for Finance & Operations y Azure DevOps (parte II)

Aquí puedes leer mi guía completa sobre Dynamics 365 for Finance and Operations y Azure DevOps.

En la primera parte de este post vimos a importancia de Azure DevOps y como configurarlo para MSDyn365FO.

Quiero empezar esta segunda parte con una pequeña pataleta. Como decía en la primera parte, los que llevamos años trabajando con AX nos habíamos acostumbrado a no usar un control de versiones. MSDyn365FO nos ha llevado a un terreno sin explorar, con lo que no es raro que cada equipo haya decidido trabajar de una forma u otra según las experiencias que se hayan ido encontrando. Evidentemente, hay un componente del interés de los miembros de estos equipos para investigar un poco por su cuenta sobre la gestión de código, ramas y metodologías. Muchas veces a base de experimentación y prueba-error, y con las prisas de algunos proyectos esto sale mal, o muy mal. Y aquí he echado de menos un poco de guidance por parte de Microsoft (que igual la hay y me lo he perdido).

A pesar de esta quejita el camino y el aprendizaje ha sido, y creo que lo que viene también será, bastante divertido 😉

Estrategias de branching

Vaya por delante que no soy, ni mucho menos, un experto en gestión del código ni Azure DevOps. Todo lo que viene a continuación es fruto, como comentaba antes, de la experiencia (y las meteduras de pata) de casi 3 años trabajando con MSDyn365Ops. En este artículo de la documentación sobre estrategias de branching hay más información sobre branching y links a artículos del equipo de DevOps. Y en la Biblioteca de herramientas y guías de los DevOps Rangers hay incluso muchísimo más!

La verdad es que me encantaría una sesión de FastTrack sobre esto y, creo que no la hay. EDIT: parece que no lo vi y sí que existe una sesión de FastTrack sobre esto que se llama Developer ALM. Gracias a Dag Calafell (twitter) por la información!

Como vimos en la primera parte cuando desplegamos la máquina de Build se crea la carpeta de Main. Lo normal es que en un proyecto de implantación se desarrolle sobre Main hasta el momento del arranque, y que justo antes del go live se cree una branch (rama) de desarrollo. El árbol de código quedaría así:

Ramas despues de branch

En ese momento los mapeos de las máquinas de desarrollo deben cambiarse para que apunten a esta nueva rama de dev. Esto permitirá seguir desarrollando mejoras o corrigiendo errores y decidir el momento en el que se van a mover a producción haciendo un merge a Main.

Esta estrategia es bastante sencilla y que no provoca muchos quebraderos de cabeza. En mi anterior trabajo en cliente final decidimos usar 3 ramas por peculiaridades de la empresa. Main, Dev y Test con merges de Dev a Test y de Test a Main. Un dolor de cabeza al final, gestionar las 3 ramas, con upgrades de versiones, decenas de changesets pendientes y un partner ISV que no ayudaba mucho era bastante divertido.  ¿Pero, y lo que aprendí? Buf.

En cualquier caso un consejo: intentad evitar que se queden changesets pendientes de mergear durante mucho tiempo. La cantidad de conflictos que aparecen y hay que resolver a mano es directamente proporcional a lo viejo que sea el changeset.

Llegado a este punto no puedo hacer suficiente hincapié en lo de normal de más arriba. Como digo, esto lo escribo basado en mis experiencias. Está claro que no es lo mismo trabajar en un partner de implantación que en un ISV. Un ISV tiene la necesidad de mantener diferentes versiones de su producto y no va a usar una rama Main y otra Dev sinó que puede tener una (o varias) por versión a mantener para dar soporte a todos los clientes (aunque desde la 8.1 y el fin del overlayering ya no es necesario). Para más «ideas» el artículo que he enlazado al principio es perfecto para empezar.

Builds

En la primera parte y en otro post (Builds que no responden en Azure DevOps) expliqué un poco acerca de las builds. Ya vimos que la definición de build que se genera por defecto al desplegar el servidor es como la de la imagen inferior:

Pasos de la definición de build por defecto

Esta build tiene todos los pasos con los que se ha creado activos. Podemos desactivar (o borrar) los pasos que no necesitemos. Por ejemplo, los 3 de testeo si no tenemos tests creados, o la sincronización y despliegue de informes.

Podemos crear nuevas definiciones de build a partir de esta o de 0 (pero es más sencillo y rápido duplicar esta y modificarla) para que se apliquen a otras ramas u otros motivos.

Con la versión 8.1 de MSDyn365FO han desaparecido los hotfixes de código X++, todos son binarios. Esto lo que implica es que en la carpeta Metadata de nuestras ramas ya no van a aparecer los modelos del estándar, solo los nuestros. Hasta la versión 8.0 era muy útil tener una definición de build únicamente para nuestros modelos y otra con todos los modelos. Con esto lo que se consigue es tener un DP en mucho menos tiempo que generándolo para todos los modelos. Si se aplica algún hotfix hay que generar el DP de la rama con todos los modelos, pero si sólo hay código propio no hace falta generar un paquete con todos los modelos.

Y hasta aquí la información desactualizada. A estas alturas todos los proyectos deberían estar en 8.1 o listos para estarlo, que en abril llega One Version!

Otra opción que es bastante útil es que, por ejemplo, podemos crear una nueva definición que lo único que haga es compilar una rama:

Definicion build continua

Esta build no hace nada más, solo compila. Así a priori no parece muy útil pero si activamos la opción de integración continua:

DevOps continuous integration

Después de cada check-in de cada desarrollador se lanzará una build que compilará todo el código y fallará si hay algún error. ¿Claro que no debería fallar no? Porque todos compilamos los proyectos antes de hacer el check-in, ¿verdad?

tysonjaja

Pues por eso y porque las prisas son malas y a veces tenemos que vivir con ellas, esta build puede ser bastante útil. Sobretodo cuando lo tengamos configurado para la rama Main y nos «chive» los errores que pueden aparecer después de un merge con conflictos. Y cuando hay que pasar algo urgente a producción y tenemos poco margen nos interesa poder generar el paquete lo antes posible. Usando esta estrategia conseguimos que generar un DP con nuestros paquetes tardara 9 minutos en vez de 1h15m generando todo.

Igual alguien con más conocimiento de esto piensa, pero eso no lo puedes hacer con…

Gated check-ins

Con este tipo de check-in el código se compila ANTES de que el check-in se haga efectivo. Si falla la build el changeset no se hace efectivo hasta que se corrijan los errores y se vuelva a hacer el check-in.

A priori esta opción parece ideal para los check-in de merges de una rama de desarrollo a Main. Los problemas que me he encontrado con esta opción son varios:

  • Si haces múltiples merge y check-ins de un mismo desarrollo y el primero falla no se mergea, pero si el segundo compila correctamente sí.
  • Problemas con las notificaciones de errores y código pendiente al fallar el check-in
  • En merges con más de un check-in se encolan muchas builds (y por defecto solo tenemos un build agent disponible…)

Seguro que esto tiene solución, pero no he sabido encontrarla. Y de todas formas la opción de integración contínua que comentaba antes nos ha funcionado perfectamente para validar que la rama compila sin errores. Como digo todo esto ha sido fruto de la investigación del equipo y prueba-error.

Conclusiones

Supongo que la mayor conclusión es que con MSDyn365FO hay que usar Azure DevOps. Es obligatorio, no hay otra opción. Los que no lo estéis haciendo, si es que alguien no lo hace, hacedlo. Ya. Revisad vuestra forma de trabajo y olvidemos de una vez por todas AX, MSDyn365FO a nivel técnico es otro producto.

La verdad es que, a los desarrolladores, MSDyn365FO nos ha acercado un poco más a lo que es un proyecto de desarrollo de software clásico como puede ser uno de .NET o Java. Pero no del todo. Un proyecto de ERP tiene muchas peculiaridades, y creo que no partir de zero en el desarrollo del producto, tener una base que nos «obliga» un poco a seguir una línea, nos limita en algunos aspectos y en el uso de ciertas técnicas y metodologías.

Y hasta aquí estos dos posts sobre Azure DevOps. Espero que le sean de ayuda a alguien. Y si alguien con más experiencia, o mejores ideas, quiere recomendar algo, ¡los comentarios están abiertos!

Configurar Release en Azure DevOps para Dynamics 365 for Finance and Operations

Aquí puedes leer mi guía completa sobre Dynamics 365 for Finance and Operations y Azure DevOps.

Vamos allá…

Hace unas semanas se publicó en el Marketplace de Azure DevOps la extensión para releases de #MSDyn365FO, con lo que nos acercamos un poco más al escenario de la integración continua. A falta de la documentación oficial tenemos las notas en el anuncio que se hizo, pero vamos a ver paso a paso como configurar todo lo que hace falta para que funcione en nuestro proyecto.

Para configurar el release necesitaremos lo siguiente:

  • Aplicación de AAD
  • Datos del proyecto de LCS
  • Un proyecto de Azure DevOps que esté vinculado al anterior de LCS
  • Usuario tipo cuenta de servicio

Al usuario es recomendable que no le caduque la contraseña (de ahí la cuenta de servicio) y que tenga permisos suficientes tanto en LCS, Azure y Azure DevOps. Esto no es obligatorio, se puede configurar con un usuario normal para hacer pruebas sin ningún problema.

Crear la app de AAD

El primer paso es crear una aplicación de Azure Active Directory para poder subir el paquete generado por la build a LCS, así que nos dirigiremos al portal de Azure y una vez nos hayamos logueado iremos a Azure ActiveDirectory, luego a App Registrations y crearemos una nueva de tipo Native:

Nueva app azure AD

A continuación vamos a «Settings» y «Required permissions» y añadimos la API de Dynamics Lifecycle Services:

Permiso de LCS

Seleccionamos el único permiso disponible en el paso 2 y aceptamos hasta que aparezca el nuevo permiso en la sección «Required permissions». En este paso nos falta únicamente pulsar en «Grant permissions» para que se apliquen los cambios:

Grant permission

Sin este último paso la subida a LCS no se podrá realizar. Una vez hemos hecho esto guardamos el Application ID para usarlo más adelante.

Crear release en Azure DevOps

Antes de configurar nada en Azure DevOps tenemos que asegurarnos que el proyecto que vamos a usar esté vinculado en LCS. Esto lo podemos comprobar en el apartado de «Visual Studio Team Services» en la configuración del proyecto de LCS.

Una vez comprobado esto crearemos la definición de release en DevOps desde Pipelines -> Releases. Seleccionamos «New release pipeline» y del listado que aparece elegimos el «Empty job».

Primero de todo asignaremos a qué build irá vinculada esa definición de release desde «Add an artifact»:

New release

En «Source» seleccionamos la definición de build que queremos usar, en «Default version» usaremos «Latest» y pulsamos «Add».

El siguiente paso es definir la Task con la extensión de release para Dynamics. Pulsamos en la pestaña Tasks y en el botón «+». Nos aparecerá una lista y buscaremos «Dynamics 365 Unified Operations Tools»:

Dynamics 365 Unified Operations Tools

Si no hemos añadido la extensión previamente lo podemos hacer desde esta misma pantalla. Para poderla añadir el usuario con el que estemos creando la release tiene que ser administrador de la cuenta de Azure DevOps en la que esté el proyecto, no es suficiente con que lo sea del proyecto.

Una vez añadida la tarea tenemos que rellenar una serie de parámetros:Release Dynamics Operations

Crear la conexión a LCS

El primer paso es crear la conexión a LCS con la aplicación de AAD que hemos creado antes. Pulsamos New y se abrirá la siguiente ventana:

Coenxión LCS Azure DevOps

Sólo es necesario rellenar el nombre, usuario, contraseña y el Application (Client) ID con el App ID que tenemos del paso inicial en Azure, los campos de «Endpoint» deberían completarse solos. Pulsamos OK y ya tenemos la conexión lista.

En el campo LCS Project Id ponemos el ID que aparece en la URL del proyecto de LCS, por ej. en https://lcs.dynamics.com/V2/ProjectOverview/1234567 el Id es 1234567.

Pulsamos el botón al lado del campo de «File to upload» y seleccionaremos el archivo del deployable package que genera la build:

DP Generado

Dependiendo de si habéis modificado la definición de build o no, el archivo tendrá un nombre u otro, pero normalmente es del tipo AXDeployableRuntime_VERSION_NUMEROBUILD.zip. Cambiad el número fijo de build por la variable de la siguiente manera:

BUildNumber

En «LCS Asset Name» y «LCS Asset Description» se define el nombre y descripción que tendrá el paquete en LCS. Para estos campos podéis usar todas las variables predefinidas de build y de release que ofrece Azure DevOps. Siguiendo con el caso anterior del nombre del archivo, usaremos un prefijo que describa qué tipo de paquete es (para producción o pre-producción) seguido de $(Build.BuildNumber), generando por ejemplo un DP llamado Prod 2019.1.29.1 con la fecha de build.

Ahora ya sólo nos queda guardar y probar. En la pantalla de Releases seleccionamos la que acabamos de crear, le damos al botón «Create a release» y sin cambiar ninguna opción seleccionamos OK en la pantalla que se ha abierto. Se lanzará la release y si todo va bien podremos ver el paquete en LCS:

LCS Asset Library

Si queremos automatizar la parte de release y que se ejecute cada vez que termine una build sólo tenemos que activar el trigger en el artefacto:

Release trigger

Desde el botón del rayo se nos abre un diálogo y simplemente hay que marcar la opción que aparece.

Nada más, con estos pasos ya tendremos configuradas las builds (que pueden estar automatizadas también) y los releases. Sólo falta que los despliegues también se puedan automatizar y ya estaremos en la integración continua que comentaba al principio.