Wednesday, June 5, 2019

AEM – Create Maven project using archetype


To create a simple AEM project using Maven you can use latest archetype from Adobe. Have a look at the GitHub project https://github.com/adobe/aem-project-archetype

To create new project use following command:


mvn archetype:generate  -DarchetypeGroupId=com.adobe.granite.archetypes  -DarchetypeArtifactId=aem-project-archetype  -DarchetypeVersion=19  -DoptionIncludeExamples=y  -DoptionIncludeErrorHandler=y

This will ask series of questions/inputs while generating project e.g. apps folder name, site name etc.


Once project folder structure is generated you can use the following command to build and install it on locally running AEM instance using following command:

mvn clean install -PautoInstallPackage

NOTE: Make sure that your AEM instance is running and it is running on port 4502. If you want to change host or port, please refer to pom.xml (available in root) of the generated project.


Sunday, June 2, 2019

Maven profiles – Operating Systems (OS) specific build profiles

Maven is a powerful build framework and it allows us to customize every aspect of build with simplicity.

In this article, we’ll learn about how to create different build profiles for windows and Mac OS. The same concept can be replicated to other operating systems or environment specific builds.

Let’s define a use case.

Let’s say we have project in which we want to compile and package Angular 2+ project using maven build. Angular 2+ project is dependent on Node.js (npm) and Angular CLI (ng CLI). We can use Maven Exec plugin for invoking npm and ng CLI commands.

On Mac OS “npm” and “ng” commands works without any additional extension. To run same commands on Windows operating system we need to append .cmd extension. This means if we have mixed folks in development team who uses both Windows and Mac OSx then every time pom.xml file needs to be updated. What if someone pushes this file to central code repository? This will obviously break the builds on CI/CD (e.g. Jenkins server). This is just one scenario, there may be other use cases where build command/process has to be different based on operating systems or environment and it is not good idea to modify pom.xml file locally for build and leave room for accidental commits/push. This is where Maven profiles comes handy.

Let’s continue with same Angular 2+ build example. On Mac OS, the build section (that is responsible for building Angular project using Maven exec plugin) of pom.xml file would look like:
        

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 <modelVersion>4.0.0</modelVersion>

 <!-- Omitted remaining pom.xml for simplicity -->

 <plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>exec-maven-plugin</artifactId>
  <executions>
   <!-- Execute UI Build as part of standard Maven "generate-resource" phase -->
   <execution>
    <id>ui-npm-install</id>
    <configuration>
     <workingDirectory>.</workingDirectory>
     <executable>npm</executable>
     <arguments>
      <argument>install</argument>
     </arguments>
     <workingDirectory>${basedir}</workingDirectory>
    </configuration>
    <phase>validate</phase>
    <goals>
     <goal>exec</goal>
    </goals>
   </execution>
   <execution>
    <id>ui-aem-build</id>
    <configuration>
     <workingDirectory>.</workingDirectory>
     <executable>ng</executable>
     <arguments>
      <argument>build</argument>
      <argument>--prod</argument>
      <argument>--outputHashing</argument>
      <argument>none</argument>
     </arguments>
     <workingDirectory>${basedir}</workingDirectory>
    </configuration>
    <!--<phase>prepare-package</phase> -->
    <phase>generate-sources</phase>
    <goals>
     <goal>exec</goal>
    </goals>
   </execution>
   <execution>
    <id>npm-clean</id>
    <configuration>
     <workingDirectory>.</workingDirectory>
     <executable>rm</executable>
     <arguments>
      <argument>-rf</argument>
      <argument>node_modules</argument>
     </arguments>
     <workingDirectory>${basedir}</workingDirectory>
    </configuration>
    <!--<phase>prepare-package</phase> -->
    <phase>install</phase>
    <goals>
     <goal>exec</goal>
    </goals>
   </execution>
  </executions>
 </plugin>

 <!-- Omitted remaining pom.xml for simplicity -->
</project>


Look at the line # 18, 33, 52 and 54. These commands are OS dependent and if we run a maven build with this configuration on Windows, it’ll fail.

To handle this in Maven way, we could create separate profile for Max OS and Windows. Following pom.xml file shows an example of OS specific build profiles.
        
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>  
    <!-- Omitted remaining pom.xml for simplicity -->
   <profiles>
     <!-- Max OSX specific build profile -->
    <profile>
     <id>macOSBuild</id>
     <activation>
       <!-- Profile is active by default -->
      <activeByDefault>true</activeByDefault> 
     </activation>
     <build>
         <plugin>
           <groupId>org.codehaus.mojo</groupId>
           <artifactId>exec-maven-plugin</artifactId>
           <executions>
             <!-- Execute UI Build as part of standard Maven "generate-resource" phase -->
             <execution>
               <id>ui-npm-install</id>
               <configuration>
                 <workingDirectory>.</workingDirectory>
                 <executable>npm</executable>
                 <arguments>
                   <argument>install</argument>
                 </arguments>
                 <workingDirectory>${basedir}</workingDirectory>
               </configuration>
               <phase>validate</phase>
               <goals>
                 <goal>exec</goal>
               </goals>
             </execution>
             <execution>
               <id>ui-aem-build</id>
               <configuration>
                 <workingDirectory>.</workingDirectory>
                 <executable>ng</executable>
                 <arguments>
                   <argument>build</argument>
                   <argument>--prod</argument>
                   <argument>--outputHashing</argument>
                   <argument>none</argument>
                 </arguments>
                 <workingDirectory>${basedir}</workingDirectory>
               </configuration>
               <!--<phase>prepare-package</phase> -->
               <phase>generate-sources</phase>
               <goals>
                 <goal>exec</goal>
               </goals>
             </execution>
             <execution>
               <id>npm-clean</id>
               <configuration>
                 <workingDirectory>.</workingDirectory>
                 <executable>rm</executable>
                 <arguments>
                   <argument>-rf</argument>
                   <argument>node_modules</argument>
                 </arguments>
                 <workingDirectory>${basedir}</workingDirectory>
               </configuration>
               <!--<phase>prepare-package</phase> -->
               <phase>install</phase>
               <goals>
                 <goal>exec</goal>
               </goals>
             </execution>
           </executions>
         </plugin>   
     </build>
    </profile>
    
    <!-- Windows OS specific build profile -->
      <profile>
        <id>winOSBuild</id>
        <activation>
          <!-- Profile is NOT active by default -->
          <activeByDefault>false</activeByDefault>
        </activation>
        <build>
          <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>exec-maven-plugin</artifactId>
            <executions>
              <!-- Execute UI Build as part of standard Maven "generate-resource" phase -->
              <execution>
                <id>ui-npm-install</id>
                <configuration>
                  <workingDirectory>.</workingDirectory>
                  <executable>npm.cmd</executable>
                  <arguments>
                    <argument>install</argument>
                  </arguments>
                  <workingDirectory>${basedir}</workingDirectory>
                </configuration>
                <phase>validate</phase>
                <goals>
                  <goal>exec</goal>
                </goals>
              </execution>
              <execution>
                <id>ui-aem-build</id>
                <configuration>
                  <workingDirectory>.</workingDirectory>
                  <executable>ng.cmd</executable>
                  <arguments>
                    <argument>build</argument>
                    <argument>--prod</argument>
                    <argument>--outputHashing</argument>
                    <argument>none</argument>
                  </arguments>
                  <workingDirectory>${basedir}</workingDirectory>
                </configuration>
                <!--<phase>prepare-package</phase> -->
                <phase>generate-sources</phase>
                <goals>
                  <goal>exec</goal>
                </goals>
              </execution>
              <execution>
                <id>npm-clean</id>
                <configuration>
                  <workingDirectory>.</workingDirectory>
                  <executable>rmdir</executable>
                  <arguments>
                    <argument>/s</argument>
                    <argument>node_modules</argument>
                  </arguments>
                  <workingDirectory>${basedir}</workingDirectory>
                </configuration>
                <!--<phase>prepare-package</phase> -->
                <phase>install</phase>
                <goals>
                  <goal>exec</goal>
                </goals>
              </execution>
            </executions>
          </plugin>     
        </build>
      </profile>  
   </profiles>
   <!-- Omitted remaining pom.xml for simplicity -->
  </project>

Few important observations

·      We have moved the plugin “exec-maven-plugin” configuration inside XML tag
·      Created two profiles “macOSBuild” and “winOSBuild” (line 9 and 78 respectively)
·      macOSBuild” profile is active by default (line 12). This means on Mac OS, we can simply run the “mvn clean install” command and Mac profile will be automatically picked up for build
·      To execute build on Windows OS, we need to explicitly tell maven to use “winOSBuild” profile. This can be done via “mvn clean install -PwinOSBuild

I hope this simple concept will help you to avoid manual changes of pom.xml and keep your project away from accidental risk of build failures.

Get in the Vibe with Copilot Agent: Supercharging Your Coding Flow

Have you ever felt "in the zone" while coding? That feeling of seamless flow, where the code practically writes itself? That's...