Connexion



Register
Forgot Password ?

Inscription

L'inscription à DotNetNuke France est entièrement gratuite et vous permet de profiter pleinement des outils mis à votre disposition. L'inscription ne donne néanmoins pas le statut d'adhérent à l'association.

  • Discutez sur le forum et suivez son activité
  • Répondez aux articles
  • Soutenez l'association
  • Téléchargez les traductions

 

DotNetNuke France

Association francophone

Automatiser le packaging avec NAnt

Auteur : Sébastien Fichot

Date de pulication : 08 September 2010

Classement : Actualité, Développement

Article consulté 2103 fois Article Rating (3 votes)
 

NAnt est un projet Open-Source développé en technologies .Net permettant d'automatiser certaines tâches de la vie des développeurs. Très utilisé en combinaison d'un moteur permettant de réaliser des compilations à la volée (TFS 2010, SprintBuild, ...), NAnt permet à plus petite échelle d'automatiser la création de packages DotNetNuke, vite rébarbative lorsqu'on doit publier 15 nouveaux modules à cause d'un changement de version majeure de DotNetNuke. Cet article s'adresse donc aux développeurs soucieux d'aller plus vite dans leur livraison, et aux éditeurs de logiciels désirant automatiser et rendre plus fiable certaines tâches. L'intégration de la méthode dans le processus de livrason prend 15 minutes par développeur, et facilite énormément l'archivage et la livraison du package Install et Source.

A l'issue de ce tutoriel, vous pourrez réaliser en 1 clic la suite d'événements suivante : 
- Mise à jour du fichier .dnn,
- Création du fichier Resources.zip,
- Création d'un package PA,
- Création d'un package SOURCE,
- Archivage dans un dossier contenant la date et le numéro de version, 
- Mise à disposition rapide de la dernière compilation à l'aide d'un dossier "Latest".

D'autres tâches peuvent être accomplies à l'aide de NAnt, pas simplement le packaging, et vous êtes libre de proposer de nouvelles versions de ce fichier, sur le forum par exemple. Vous pourrez notamment étendre la compilation réalisée avec MSBuild qui propose un grand nombre d'options.
Le fichier original provient de l'article de Chris Hammond.




Installation de NAnt

Pour installer NAnt, rendez vous sur le site officiel (lien),  et téléchargez la dernière version. 

Dans mon cas la dernière version est une version Alpha, mais libre à vous de rester sur la 9.0 Stable car l'ensemble des fonctions utilisées dans notre exemple fonctionnent avec les deux versions.

Une fois le package téléchargé,  décompressez le contenu du dossier bin dans le dossier de votre choix. Par exemple, si vous utilisez C:\NAnt comme dossier de décompression, vous devriez trouver NAnt.exe avec le chemin C:\NAnt\NAnt.exe.

NAnt ne requiert aucun autre paramètre pour fonctionner en StandAlone, si ce n'est que nous souhaiterions pouvoir l'utiliser directement avec Visual Studio (2008 SP1 dans mon cas). Pour ce faire, cliquez sur Outils > Outils Externes (Tools > External Tools).



Cliquez ensuite sur Ajouter, puis renseignez les éléments suivants : 
- Titre : Donnez lui le titre qui semble le plus équivoque pour vous. Dans mn cas, j'ai choisi "NAnt - Package module DNN",
- Commande : Indiquez le chemin du fichier NAnt.exe. Dans mon cas, C:\NAnt\NAnt.exe,
- Dossier de référence : $(ProjectDir). C'est la valeur qui fonctionne nativement avec le .build présenté ici. Néanmoins, vous pourriez avoir besoin d'utiliser $(SolutionDir) à la place, si vous souhaitez créer un .build dont l'action couvre plusieurs modules.
- Cochez "Fermer automatiquement" (Close on exit) et "Fenêtre de sortie" (Output Window),
puis cliquez sur OK.



Dans le menu Outils, vous devriez maintenant retrouver "NAnt - Package module DNN" (mais cliquer sur l'outil provoquera une erreur).



Utiliser NAnt pour packager un module DotNetNuke

Ouvrez maintenant la solution de votre module. Si votre module d'intitule "Mon.module", alors votre fichier Solution Visual Studio doit s'intituler "Mon.module.sln" (*), votre projet (VB.Net ou C#) "Mon.module.vbproj" ou "Mon.module.csproj", et votre manifeste DotNetNuke "Mon.module.dnn". Cela facile les traitements par la suite, mais libre à vous de modifier le .build pour convenir à votre configuration.

Dans le même ordre d'idées, placez le fichier suivant dans le répertoire de votre module et renommez le. Ouvrez le fichier à partir de Visual Studio et Remplacez "Mon.module" par le nom de votre module.

Télécharger le fichier .build (NAnt file - 11 KB)

(*) Par conséquent, votre Solution ne devrait contenir que les projets relatifs à votre module et se trouver dans le dossier DesktopModules de votre module. Dans mon cas, j'ai l'habitude de n'utiliser qu'un seul fichier SLN contenant tous mes projets. Pour le besoin du script, je créé un fichier SLN dans le dossier DesktopModules/MonModule/ en ouvrant le projet à partir de son fichier .vbproj ou .csproj directement (Puis Ctrl+S pour créer le fichier SLN).

Le contenu complet du fichier .build peut être consulté ci-dessous. Vous pouvez l'adapter à l'aide des commentaires de Chris et les miens. Par exemple, vous voudrez sûrement ajouter un dossier Components dans le package Resources.zip de la version Source ...

<!-- targets to be executed, when omitted from command line default is run -->
<!--EXTERNAL_PROPERTIES: sys.env.windir-->
<project name="Mon.module" default="BuildAndZip">
      <target name="init">
            <property name="nant.settings.currentframework" value="net-3.5" />
            <!-- This is where your packaged zips will build to from within the module folder -->
            <property name="package.dir" value="Package" overwrite="false" />
            <property name="latest.dir" value="Latest" overwrite="false" />
            <!-- This is where your resource.zip will be built so it can be zipped and distributed with the release install zips -->
            <property name="resourcezip.dir" value="ResourceZip" />
            <property name="bin.dir" value="../../bin" />
            <property name="controls.dir" value="controls" />
            <property name="localresource.dir" value="App_LocalResources" />
            <property name="globalresource.dir" value="App_GlobalResources" />
            <property name="binZip" value="_Install" />
            <property name="srcZip" value="_Source" />
            <property name="verbose" value="false" overwrite="false" />
            <!-- ModuleName value should be set specific to the project -->
            <property name="ModuleName" value="Mon.module" overwrite="false" />
            <property name="subproject.name" value="${ModuleName}"/>
            <property name="module.dll" value="${bin.dir}/${ModuleName}.dll" />
            <property name="module.pdb" value="${bin.dir}/${ModuleName}.pdb" />
            <property name="module.xml" value="${bin.dir}/${ModuleName}.xml" />
            <property name="debug" value="false" overwrite="false" />
            <property name="config" value="debug" if="${debug}" />
            <property name="config" value="release" unless="${debug}" />
            <property name="month" value="${datetime::get-month(datetime::now())}"/>
            <property name="day" value="${datetime::get-day(datetime::now())}"/>
            <property name="year" value="${datetime::get-year(datetime::now())}"/>
            <property name="hour" value="${datetime::get-hour(datetime::now())}"/>
            <property name="minute" value="${datetime::get-minute(datetime::now())}"/>
            <property name="second" value="${datetime::get-second(datetime::now())}"/>
            <property name="datePrefix" value="${year}-${month}-${day}_${hour}-${minute}-${second}"/>
            <sysinfo failonerror="false" />
            <if test="${verbose}">
                  <echo message="solutionName: ${subproject.name}" />
                  <echo message="debug: ${debug}" />
                  <echo message="config: ${config}" />
            </if>
      </target>
      <target name="Compile" depends="init">
            <exec program="C:\Windows\Microsoft.NET\Framework64\v3.5\msbuild.exe" failonerror="true">
                  <arg value="/p:Configuration=Release" />
                  <arg value="/p:Platform="Any CPU"" />
                  <arg value="${subproject.name}.sln" />
            </exec>
      </target>
      <!-- It is important that this target does not run before the Compile target since it will lock the assembly -->
      <target name="VersionInfo">
            <property name="version" value="${assemblyname::get-version(assembly::get-name(assembly::load-from-file(module.dll)))}" />
            <property name="shortVersion" value="${string::substring(version,0,string::last-index-of(version,'.'))}" />
            <if test="${verbose}">
                  <echo message="shortVersion: ${shortVersion}" />
                  <echo message="version: ${version}" />
            </if>
            <property name="packageSub.dir" value="${datePrefix}_${shortVersion}_${ModuleName}" overwrite="false" />
            <!--update the dnn package version-->
            <xmlpokefile="${ModuleName}.dnn" xpath="/dotnetnuke/packages/package[@name = '${ModuleName}']/@version" value="${shortVersion}" />
      </target>
      <!-- check for resourcezip folder, delete it and its contents if it exists -->
      <target name="CleanResourceZip" depends="init">
            <delete dir="${resourcezip.dir}" if="${directory::exists(resourcezip.dir)}" />
      </target>
      <!-- Begin area for creating resourcezip for installable PA zips (should depend on target that clears where this will build zip file to)-->
      <target name="CreateResourceZip" depends="CleanResourceZip">
            <!-- create a flat directory to zip for install -->
            <mkdir dir="temp" unless="${directory::exists('temp')}" />
            <!-- DO NOT flatten this as we want to retain folder structure in this and ONLY this zip -->
            <copy todir="temp" flatten="false">
                  <fileset>
                        <!-- Tell nant what files to grab -->
                        <!-- everything included here ends up in resource.zip, this should be excluded in the CreateBinZip -->
                        <include name="**/images/*" />
                        <include name="**/Documentation/*" />
                        <include name="**/js/**/*" />
                        <include name="**/${localresource.dir}/*.resx" />
                        <include name="**/${globalresource.dir}/*.resx" />
                        <include name="**/${globalresource.dir}/*.xml" />
                        <include name="**/*.ascx" />
                        <include name="**/*.css" />
                        <include name="**/*.aspx" />
                        <include name="**/*.js" />
                        <!-- everything in here is excluded from resource.zip -->
                        <exclude name="**/Resources.zip" />
                        <exclude name="**/Install/**/*" />
                        <exclude name="**/Package/**/*" />
                        <exclude name="**/thumbs.db" />
                        <exclude name="**/*.zip" />
                  </fileset>
            </copy>
            <mkdir dir="${resourcezip.dir}" unless="${directory::exists(resourcezip.dir)}" />
            <zip zipfile="${resourcezip.dir}/Resources.zip">
                  <fileset basedir="temp">
                        <include name="**/*" />
                        <exclude name="**/*.dll" />
                  </fileset>
            </zip>
            <!--Delete temp directory -->
            <delete dir="temp" failonerror="false" />
      </target>
      <!-- End area for resourcezip creation -->
      <!-- Begin area for creating resourcezip for installable PA zips (should depend on target that clears where this will build zip file to)-->
      <target name="CreateResourceSourceZip" depends="CleanResourceZip">
            <!-- create a flat directory to zip for install -->
            <mkdir dir="temp" unless="${directory::exists('temp')}" />
            <!-- DO NOT flatten this as we want to retain folder structure in this and ONLY this zip -->
            <copy todir="temp" flatten="false">
                  <fileset>
                        <!-- Tell nant what files to grab -->
                        <!-- everything included here ends up in resource.zip, this should be excluded in the CreateBinZip -->
                        <include name="**/images/*" />
                        <include name="**/Documentation/*" />
                        <include name="**/js/**/*" />
                        <include name="**/${localresource.dir}/*.resx" />
                        <include name="**/${globalresource.dir}/*.resx" />
                        <include name="**/${globalresource.dir}/*.xml" />
                        <include name="**/*.ascx" />
                        <include name="**/*.aspx" />
                        <include name="**/*.cs" />
                        <include name="**/*.vb" />
                        <include name="**/*.sln" />
                        <include name="**/*.csproj" />
                        <include name="**/*.vbproj" />
                        <include name="**/*.build" />
                        <include name="**/*.js" />
                        <!-- everything in here is excluded from resource.zip -->
                        <exclude name="**/Package/**/*" />
                        <exclude name="**/Install/**/*" />
                        <exclude name="**/thumbs.db" />
                        <exclude name="**/*.zip" />
                  </fileset>
            </copy>
            <mkdir dir="${resourcezip.dir}" unless="${directory::exists(resourcezip.dir)}" />
            <zip zipfile="${resourcezip.dir}/Resources.zip">
                  <fileset basedir="temp">
                        <include name="**/*" />
                        <exclude name="**/*.dll" />
                  </fileset>
            </zip>
            <!--Delete temp directory -->
            <delete dir="temp" failonerror="false" />
      </target>
      <!-- End area for resourceSourcezip creation -->
      <target name="CreateBinZip" depends="CreateResourceZip VersionInfo">
            <copy todir="temp" flatten="false">
                  <fileset>
                        <include name="**/*.sqldataprovider" />
                        <include name="**/*.dnn" />
                  </fileset>
            </copy>
            <copy todir="temp/bin" flatten="true">
                  <fileset>
                        <include name="${module.dll}" />
                        <include name="**/*.dll" />
                  </fileset>
            </copy>
            <copy todir="temp" flatten="true">
                  <fileset>
                        <include name="**${resourcezip.dir}/Resources.zip" />
                  </fileset>
            </copy>
            <mkdir dir="${package.dir}" unless="${directory::exists(package.dir)}" />
            <mkdir dir="${package.dir}\${packageSub.dir}" />
            <zip zipfile="${package.dir}/${packageSub.dir}/${ModuleName}_${shortVersion}${binZip}.zip">
                  <fileset basedir="temp">
                        <include name="**/*" />
                  </fileset>
            </zip>
            <mkdir dir="${package.dir}\${latest.dir}" />
            <delete>
                  <fileset basedir="${package.dir}/${latest.dir}" defaultexcludes="false">
                        <include name="**/*${binZip}.zip"/>
                  </fileset>
            </delete>
            <copy todir="${package.dir}\${latest.dir}" flatten="true">
                  <fileset>
                        <include name="**${package.dir}/${packageSub.dir}/${ModuleName}_${shortVersion}${binZip}.zip" />
                  </fileset>
            </copy>
            <!--Delete temp directory -->
            <delete dir="temp" failonerror="false" />
      </target>
      <!-- End area for installable PA -->
      <!-- Begin area for distributable source code zip (should depend on target that clears where this will build zip file to)-->
      <target name="CreateSrcZip" depends="CreateResourceSourceZip VersionInfo">
            <copy todir="temp" flatten="false">
                  <fileset>
                        <include name="**/*.sqldataprovider" />
                        <include name="**/*.dnn" />
                  </fileset>
            </copy>
            <copy todir="temp/bin" flatten="false">
                  <fileset>
                        <include name="${module.dll}" />
                        <include name="${module.pdb}" />
                        <include name="${module.xml}" />
                  </fileset>
            </copy>
            <copy todir="temp" flatten="true">
                  <fileset>
                        <include name="**${resourcezip.dir}/Resources.zip" />
                  </fileset>
            </copy>
            <mkdir dir="${package.dir}" unless="${directory::exists(package.dir)}" />
            <mkdir dir="${package.dir}\${packageSub.dir}" />
            <zip zipfile="${package.dir}/${packageSub.dir}/${ModuleName}_${shortVersion}${srcZip}.zip">
                  <fileset basedir="temp">
                        <include name="**/*" />
                  </fileset>
            </zip>
            <mkdir dir="${package.dir}\${latest.dir}" />
            <delete>
                  <fileset basedir="${package.dir}/${latest.dir}" defaultexcludes="false">
                        <include name="**/*${srcZip}.zip"/>
                  </fileset>
            </delete>
            <copy todir="${package.dir}\${latest.dir}" flatten="true">
                  <fileset>
                        <include name="**${package.dir}/${packageSub.dir}/${ModuleName}_${shortVersion}${srcZip}.zip" />
                  </fileset>
            </copy>
            <!--Delete temp directory -->
            <delete dir="temp" failonerror="false" />
      </target>
      <!-- End area for distributable source code zip -->
      <!-- SYNTHETIC TASKS -->
      <target name="build" depends="Compile" description="This target compiles the application." />
      <target name="BuildAndZip" depends="build CreateSrcZip CreateBinZip " description="This target compiles the application and then creates two-three zip files: - one that only contains the compiled code and runtime files - one is the resourceszip for installable pas - the other with compiled code and source code.">
            <delete dir="${resourcezip.dir}" failonerror="false" />
      </target>
</project>



Une fois le fichier placé au bon endroit, cliquez sur Outils > "NAnt - Package module DNN", et observez le résultat : la version contenue dans le fichier .dnn est mise à jour (en fonction du paramètre AssemblyVersion de votre fichier AssemblyInfo.vb/cs), votre module est packagé en version Install et Source, un dossier Package est créé, contenant un dossier Latest qui contiendra toujours le dernier package, et un ensemble de dossier permettant de retracer les versions au fil du temps.



 

Notez cet article !

DotNetNuke c'est ...

  • Facile à utiliser
  • Open Source et gratuit
  • 100% personnalisable
  • Des milliers d'extensions
  • Multilingue
  • Multi-site
  • Maintenu par une communauté d'experts
  • Sécurisé

Restez informé !

Inscrivez vous pour recevoir notre lettre d'information.

x

Restez connecté !

Le fichier que vous téléchargez sera probablement mis à jour très bientôt.

Inscrivez vous
et nous vous informerons des mises à jour