Git Product home page Git Product logo

wttech / gradle-aem-plugin Goto Github PK

View Code? Open in Web Editor NEW
157.0 57.0 32.0 20.12 MB

Swiss army knife for Adobe Experience Manager related automation. Environment setup & incremental AEM application build which takes seconds, not minutes.

Home Page: https://tech.cognifide.com/tag/gradle-aem-plugin

License: Apache License 2.0

Kotlin 98.91% Batchfile 0.05% Shell 1.03%
aem aem-tools adobe-experience-manager cq apache-sling java kotlin gradle-plugin gradle-aem-plugin aem62

gradle-aem-plugin's Introduction

WTT logo

Apache License, Version 2.0, January 2004

Gradle AEM Plugin


🚧 Maintenance Mode: Limited to Bugfixes 🚧

We'd like to inform you that the Gradle AEM Plugin is now in maintenance mode. While we will continue to provide bugfixes and support for existing features, no new features or major enhancements will be added to this project.

As a better alternative we recommend checking out AEM Compose.


TL;DR

To add an automated AEM environment setup to the AEM Maven project click here.


Table of contents

About

Swiss army knife for AEM related automation. Incremental build which takes seconds, not minutes. Developer who does not loose focus between build time gaps. Extend freely your build system directly in project.

AEM developer - it's time to meet Gradle! You liked or used plugin? Don't forget to star this project on GitHub :)

Be inspired by:

Looking for a dedicated version of plugin for Apache Sling? Check out Gradle Sling Plugin!

Demo

The example below presents building & deploying AEM package - all handled by Gradle. To review building AEM package by Maven but all the rest handled by Gradle/GAP see Enhancing Maven build section.

Gradle AEM Multi Build

What is being done above by simply running super easy command sh gradlew <=> gw ?

  • :env:instanceProvision - configuring AEM instances / performing provisioning steps like:
    • deploying dependent CRX packages,
    • enabling access to CRX DE (e.g on all environments except production),
    • configuring replication agents (AEM platform wide changes),
  • :app:aem:all:packageDeploy -> building & deploying all-in-one CRX package to AEM instances in parallel, then awaiting for stable condition of AEM instances and built application.

Build is incremental which guarantees optimized time every time regardless of build command used. Only changed parts of application are processed again:

  • Dependent CRX packages are installed only when they are not already installed on particular AEM instances.
  • Provisioning steps are performed only once on each AEM instance (by default but customizable),
  • CRX package is rebuild only when JCR content / files under jcr_root are changed.
  • Java code is recompiled only when code in *.java files is changed.
  • Front-end / Webpack build is run again only when code in *.scss and *.js etc files is changed.

Want to see it in action? Follow here!

Features

Gradle AEM Plugin is following strategy convention over configuration. When following built-in conventions about project structure & naming, then only minimal configuration is required. Still all features are fully configurable.

Compatibility

Gradle AEM Plugin Gradle Build Tool AEM On-Prem AEMaaCS Java
4.x up to 5.x 4.0 up to 4.8 6.x and up not supported 8
6.0.0 up to 6.2.1 4.9 up to 5.0 6.x and up not supported 8
6.3.0 up to 6.x 5.1 up to 5.6 6.x and up not supported 8
7.2.0 up to 8.1.1 5.1 up to 5.6 6.x and up not supported 8,11
8.1.2 up to 13.x 6.0 and up 6.x and up not supported 8,11
14.1.0 and up 6.0 and up 6.x and up 2021.x and up 8,11
14.4.22 and up 6.7 and up 6.x and up 2021.x and up 8,11
16.0.1 and up 6.7 and up 6.x and up 2022.7.8005 and up 8,11

Note that since GAP 14.4.22 default Java version used to compile and run AEM instances is Java 11. To instruct GAP to use Java 8, consider setting property:

javaSupport.version=8

However since GAP 15.3.3, Java version automatically determined by Quickstart JAR (property below), so that Java support version does not need to be explicitly set up.

localInstance.quickstart.jarUrl=https://company-share.com/aem/cq-quicstart-6.5.0.jar

Getting started

Most effective way to experience Gradle AEM Plugin is to use:

The only software needed on your machine to start using plugin is Java 8 or newer (also to setup local native AEM instances). Optionally, Docker is needed (when using automatic AEM dispatcher setup).

As a build command, it is recommended to use Gradle Wrapper (gradlew) instead of locally installed Gradle (gradle) to easily have same version of build tool installed on all environments. Only at first build time, wrapper will be automatically downloaded and installed, then reused.

Launcher

To use Gradle AEM Plugin it is not needed to have configured a regular Gradle project. By using a single bash command, to be able to:

  • set up local AEM instances and be able to share command to others even on team chat,
  • download and deploy to AEM instances dependent CRX package from any source by single command run in terminal,
  • copy JCR content between instances using GAP run on continuous integration server,
  • and more,

consider using standalone launcher as it could be the easiest and fastest way to use GAP.

Plugins

Plugins setup

Released versions of plugin are available on Gradle Plugin Portal](https://plugins.gradle.org/search?term=com.cognifide.aem). Recommended way is to apply plugin using Gradle Plugin Portal and techniques described there.

Minimal plugins setup

Configuration assumes:

  • building and deploying CRX packages to AEM instance(s) via command: gradlew packageDeploy.
  • JCR content placed under directory src/main/content/jcr_root
  • Vault filters located at path src/main/content/META-INF/vault/filter.xml,

Then the only thing needed to build CRX package is plugin application (all the rest is obtained automatically by convention):

File build.gradle.kts:

plugins {
    id("com.cognifide.aem.package") version "<version>"
}

Complete plugins setup

Illustrative configuration below assumes building and deploying on AEM instance(s) via command: gradlew (default tasks will be used). Intention of snippet below is to demonstrate:

  • How particular values could be customized via Gradle AEM DSL,
  • What are the default values and how they are determined.
plugins {
    id("com.cognifide.environment") version "<version>" // useful to setup AEM dispatcher running on Docker
    id("com.cognifide.aem.instance.local") version "<version>" // useful to setup local AEM instances running natively, skip '.local' to work with remote only
    id("org.jetbrains.kotlin.jvm") // needed when AEM code written in Kotlin, yes it could be :)
    id("com.cognifide.aem.bundle") version "<version>" // needed to built OSGi bundle
    id("com.cognifide.aem.package") version "<version>" // needed to build CRX package from JCR content and built OSGi bundle
}

group = "com.company.aem"
version = "1.0.0"
defaultTasks(":instanceProvision", ":packageDeploy")

aem {
    `package` { // built CRX package options
        contentDir.set(project.file("src/main/content"))
        appPath.set(when {
            project == project.rootProject -> "/apps/${project.rootProject.name}"
            else -> "/apps/${project.rootProject.name}/${projectName}"
        })
        nodeTypesSync("PRESERVE_AUTO")
        validator {
            enabled.set(prop.boolean("package.validator.enabled") ?: true)
            verbose.set(prop.boolean("package.validator.verbose") ?: true)
            planName.set(prop.string("package.validator.plan") ?: "plan.json")
            severity("MAJOR")
        }       
        // ...
    }
    instance { // AEM instances to work with
        local("http://localhost:4502") // local-author
        local("http://localhost:4503") // local-publish
        remote("http://192.168.100.101:4502", "int-author")
        remote("http://192.168.100.101:4503", "int-publish")
        // etc
        
        http { // allows to customize HTTP connection to AEM instances
            connectionTimeout.set(prop.int("instance.http.connectionTimeout") ?: 30000)
            connectionRetries.set(prop.boolean("instance.http.connectionRetries") ?: true)
            connectionIgnoreSsl.set(prop.boolean("instance.http.connectionIgnoreSsl") ?: true)
    
            proxyHost.set(prop.string("instance.http.proxyHost"))
            proxyPort.set(prop.int("instance.http.proxyPort"))
            proxyScheme.set(prop.string("instance.http.proxyScheme"))
        }

        provisioner { // configuring AEM instances in various circumstances (e.g only once)
            enableCrxDe()
            deployPackage("com.adobe.cq:core.wcm.components.all:2.11.0@zip")
            deployPackage("com.neva.felix:search-webconsole-plugin:1.3.0")
            step("setup-replication-author") {
                condition { once() && instance.author }
                sync {
                    repository {
                        save("/etc/replication/agents.author/publish/jcr:content", mapOf(
                                "enabled" to true,
                                "userId" to instance.user,
                                "transportUri" to "http://localhost:4503/bin/receive?sling:authRequestLogin=1",
                                "transportUser" to instance.user,
                                "transportPassword" to instance.password
                        ))
                    }
                }
            }
            // ...
        }  
    }
    localInstance { // config for AEM instances to be created on local file system
        quickstart {
            jarUrl.set(prop.string("localInstance.quickstart.jarUrl"))
            licenseUrl.set(prop.string("localInstance.quickstart.licenseUrl"))
        }
        backup {
            uploadUrl.set(prop.string("localInstance.backup.uploadUrl"))
            downloadUrl.set(prop.string("localInstance.backup.downloadUrl"))
        }
        install { // CRX packages and OSGi bundles to be pre-installed on created AEM instances
            files(
                "http://.../package.zip" // CRX package downloaded over HTTP
                "group:name:version" // OSGi bundle from Maven repository
            )
        }
        init { // hook called once in scope of instance just created and up first time
            logger.info("Initializing instance '$name'")
            sync {
                // ...
            }
        }   
        rootDir.set(prop.string("localInstance.rootDir"))
        // ...
    }

    tasks {
        jar { 
            bundle {
                // customizing OSGi bundle manifest
                description = "Example application built by GAP"
                docUrl = "https://github.com/wttech/gradle-aem-example"
                exportPackage("com.company.example.aem.*") 
                slingModelPackages = "com.company.example.aem"
        
                // for checking OSGi component health on runtime
                javaPackage.set("com.company.example.aem")
    
                // other / more advanced options
                importPackageWildcard.set(true)
                // ...
            }
        }
        packageCompose { // customizing built CRX package
            nestPackageProject(":core")
            nestPackageProject(":config")
            
            archiveBaseName.set("example-for-changing-zip-name")
            
            vaultDefinition { // place for overriding CRX Package / Vault properties, defining hooks
                // ...
            }
        }
        // ... and all other tasks
    }
}

To see all available options and actual documentation, please follow to:

Plugins documentation

Gradle AEM Plugin to be more concise is now more like set of plugins. Each plugin has its own documentation:

  • Common Plugin - defining common options like AEM instances available etc, base for custom Gradle tasks scripting for AEM,
  • Package Plugin - building and deploying CRX package(s),
  • Package Sync Plugin - synchronizing JCR content from running AEM instances into built CRX packages,
  • Bundle Plugin - building and deploying OSGi bundle(s),
  • Instance Plugin - managing remote AEM instance(s), automatic installation of service packs, performing provisioning actions,
  • Local Instance Plugin - setting up local AEM instance(s),
  • Environment Plugin - standalone plugin for setting AEM dispatcher running on Docker,
  • Common Plugin - standalone plugin for transferring files over protocols SFTP/SMB/HTTP, e.g downloading AEM files, uploading AEM backups.

How to's

Set AEM configuration properly for all / concrete project(s)

Common configuration like root of content for JCR package, should be defined in allprojects section like below / e.g in root build.gradle.kts file:

import com.cognifide.gradle.aem.bundle.tasks.bundle

allprojects {
  plugins.withId("com.cognifide.aem.common") {
    configure<AemExtension> {
        `package` {
            contentDir.set(project.file("src/main/aem")) // overrides default dir named 'content'
        }
    }
  }
  
  plugins.withId("com.cognifide.aem.bundle") {
    tasks {
        jar {
            bundle {
                category = "example"
                vendor = "Company"
            }
        }
    }
      
    dependencies {
        "compileOnly"("com.adobe.aem:uber-jar:${Build.AEM_VERSION}:apis") // and more
    }
  }
}

For instance, subproject :aem:core specific configuration like OSGi bundle or CRX package options should be defined in aem/core/build.gradle.kts:

import com.cognifide.gradle.aem.bundle.tasks.bundle

plugins {
    id("com.cognifide.aem.bundle")
}

tasks {
    jar {
        bundle {
            javaPackage.set("com.company.example.aem.core")
        }
    }
    packageCompose {
        nestPackageProject(':content')
        archiveBaseName.set("example-core")
        duplicatesStrategy = DuplicatesStrategy.EXCLUDE
    }
}

Understand why there are one or two plugins to be applied in build script

Gradle AEM Plugin assumes separation of 5 plugins to properly fit into Gradle tasks structure correctly.

Most often, Gradle commands are being launched from project root and tasks are being run by their name e.g instanceStatus (which is not fully qualified, better if it will be :instanceStatus of root project). Let's imagine if task instanceStatus will come from package plugin, then Gradle will execute more than one instanceStatus (for all projects that have plugin applied), so that this is unintended behavior. Currently used plugin architecture solves that problem.

Work effectively on start and daily basis

Initially, to create fully configured local AEM instances simply run command gradlew instanceSetup. Later during development process, building and deploying to AEM should be done using the command: gradlew instanceProvision packageDeploy.

  • Firstly dependent packages (like AEM hotfixes, Vanity URL Components etc) will be installed lazily (only when they are not installed yet).
  • In next step application is being built and deployed to all configured AEM instances.
  • Finally build awaits till all AEM instances and built application are stable.

Customize convention for CRX package and OSGi bundle names and paths

Because of bug related with regresion introduced in Gradle 5.1, there are some difficulties with setting archives base names. AEM Plugin is overriding default Gradle convention for not only having project name in archive base name, but also to having prefix - root project name when project is one of subprojects (multi-project build case as in Gradle AEM Multi). However overriding this convention might not be trivial and is not recommended as of AEM Plugin in most cases proposes good enough battle-tested convention.

Still, if it is really needed to be done - setting customized name for CRX packages and OSGi bundles built, use snippet:

subprojects {
    afterEvaluate {
        tasks {
            withType<AbstractArchiveTask>().configureEach {
                archiveBaseName.set("acme-${project.name}")
            }
        }
    }
}

Then, also common case is to customize paths in which OSGi bundles should be placed in built CRX package. As practice shows up, mostly desired snippet to be used is:

subprojects {
    plugins.withId("com.cognifide.aem.package") {
        configure<AemExtension> {
            `package` {
                installPath.set("/apps/acme/${project.name}/install")
            }
        }
    }
}

Target individual instances when running tasks

The ability to perform tasks against individual instances is provided by the Common Plugin, which comes with instance filtering. Read more on instance filtering if you're looking for information on:

  • how to destroy an individual instance,
  • how to start or stop author/publish instances only,
  • how to deploy to a single instance,
  • etc.

Building

  1. Clone this project using command git clone https://github.com/wttech/gradle-aem-plugin.git
  2. To build plugin, simply enter cloned directory run command: gradlew
  3. To debug plugin under development in tests, use commands:
    • For functional tests: sh gradlew functionalTest --debug-jvm
    • For unit tests: sh gradlew test --debug-jvm
  4. To debug built plugin in project when published to local Maven repository:
    • Append to any build command parameters --no-daemon -Dorg.gradle.debug=true
    • Run build, it will suspend, then connect remote at port 5005 by using IDE
    • Build will proceed and stop at previously set up breakpoint.

Testing

Local instance tests

Part of functional tests are using real AEM to ensure correctness of features. As of AEM is not available to the public, it needs to be provided externally from remote server or by providing local file path.

AEM files available locally:

gradlew functionalTest \
-DlocalInstance.jarUrl=/Users/krystian.panek/Servers/aem65/cq-quickstart-6.5.0.jar \
-DlocalInstance.licenseUrl=/Users/krystian.panek/Servers/aem65/license.properties

AEM files hosted externally:

gradlew functionalTest \
-DlocalInstance.jarUrl=https://my-company.com/cq/6.5.0/cq-quickstart-6.5.0.jar \
-DlocalInstance.licenseUrl=https://my-company.com/cq/6.5.0/license.properties \
-DfileTransfer.user=foo \
-DfileTransfer.password=pass

Debugging tests

To debug plugin source code while:

  • running functional tests, append --debug-jvm -Porg.gradle.testkit.debug=true.
  • project using plugin, append --no-daemon -Dorg.gradle.debug=true.

Gradle will stop for a moment and wait until remote connection at port 5005 will be established from e.g IDE.

Contributing

Issues reported or pull requests created will be very appreciated.

  1. Fork plugin source code using a dedicated GitHub button.
  2. Do code changes on a feature branch created from develop branch.
  3. Create a pull request with a base of develop branch.

License

Gradle AEM Plugin is licensed under the Apache License, Version 2.0 (the "License")

gradle-aem-plugin's People

Contributors

dprzybyl avatar dymitrs avatar github-actions[bot] avatar hotowy avatar jaroslaw-pietraszek-wttech avatar jean-khechfe-wttech avatar jplucinski avatar krystian-panek-wttech avatar malaskowski avatar marcin-bakowski-wttech avatar mariusz-pacyga-wttech avatar mateusz-piwecki-wtt avatar mcavity avatar mierzwid avatar piotr-andruszkiewicz-wttech avatar piotr-rogacki-wttech avatar piotr-wilczynski avatar pun-ky avatar rafal-kociniewski-wttech avatar sabberworm avatar szymon-owczarzak avatar tomasz-niedzwiedz-wttech avatar twiernik avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gradle-aem-plugin's Issues

Instance JAR URL

Hi,
Im trying to execute "gradle aemCreate" on my wondows 7 machine . Hoever when i run this command i get

Instance JAR file not found at path:<path>
Is instance JAR URL configured? 

My path defined in the gradle.properties is like below

aem.instance.local.jarUrl="D:/6.2/cq-quickstart.jar"
aem.instance.local.licenseUrl="D:/6.2/license.properties"

The path is local on my D drive and i have tried every possible way to fix it . i have removed the quotes as well as changed "/"to "\" However i am facing this problem. I know copying Jar to the C:\Users\arath4.aem<ProjectName>\local-author will fix the problem but i need to know why the path is not being picked up during the aemCreate.

Grouping packages to be satisfied

Imagine

aemSatisfy {
    group('dependencies', {
        // local("pkg/vanityurls-components-1.0.2.zip")
    })

    group('tools', {
        download("https://github.com/Cognifide/APM/releases/download/cqsm-2.0.0/apm-2.0.0.zip")
    })

    group('others', {
        // ...
    })
}

then allow particular dev to install only deps or only dependencies by using command line parameter

gradle aemSatisfy -Daem.deploy.satisfy.group=tools,others

if parameter not specified, then all packages will be deployed/satisfied.

Automated deployment quick fixes mechanism

Basing on fact, that there is ability to execute any Groovy Script code via simple HTTP POST request, imagine:

aemCall {

    // sh gradlew aemCall -Paem.call.name=restart-scene7

    call "restart-scene7" { instance ->
        path = "/bin/groovyconsole/post.json"
        method = "POST"
        params = [
            "script": readFile("scripts/restart-scene7-bundle.groovy")
        ]
        headers = [
            "Referer": "${instance.url}/etc/groovyconsole.html",
            "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
        ]
    }

    groovyScript "restart-scene7-bundle" // same as above using built-in helper; this even could be skipped, because script could be find by convention

    // sh gradlew aemCall -Paem.call.name=remove-my-node
    // other built-in helper

    groovyCode "remove-my-node", """
        def myNode = resourceResolver.getResource("/tmp/my-node")
        resourceResolver.delete(myNode)
        resourceResolver.commit()

    """

}

Groovy script related API will require Groovy Console CRX package installed on instance (for instance using aemSatisfy) https://github.com/OlsonDigital/aem-groovy-console .

Unit Tests - No OSGi SCR metadata found (missing OSGI-INF in output folder)

Hello,

I am using your plugin and it works very well when I deploy the generated bundles in my AEM application. However, I'm having problems in unit tests environment.

I am trying to run a unit tests and I'm getting the following Error " No OSGi SCR metadata found for class ..." .

After some research I realized that this error is happening because (unlike in the jar file) there is no OSGI-INF folder with the OSGI SRC Metadata in gradle output folder (see image bellow).

captura de ecra 2017-12-14 as 10 59 58

(I generated the missing folder manually, and the tests run like a charm)

Would you please assist me by understanding this situation?

Thanks!

Convention tasks generation

Each of subproject have sth like that configured:

https://github.com/Cognifide/gradle-aem-example/blob/master/app/core/build.gradle#L25-L26

build.dependsOn aemCompose
task [project.path.camelCase()}Deploy](dependsOn: [build, aemDeploy])

Plugin can autogenerate such tasks with names compose by convention (basing on project path).

aem {
    config {
       conventionDeployTasks = true
    }
}

this switch can be disabled to let gradle user to create and configure this tasks from the scratch, but by default will be enabled to even make build.gradle shorter ;)

Root project will be an edge case because it has path ':', so that [rootProject.name]Deploy will be used as tasks name instead of using its path.

Introduce assembly profiles

Imagine


aemCompose {
    def profile = project.properties["aemProfile"]

    classifier = profile // effectively: example-1.0.0-SNAPSHOT-bundle.jar // etc

    if (profile == "bundle") {}
        includeProject(':app:core')
        includeProject(':app:common')
    } else if (profile == "content") {
        includeProject(':content:init')
        includeProject(':content:demo')
    } else {
        includeProject(':app:core')
        includeProject(':app:common')
        includeProject(':content:init')
        includeProject(':content:demo')
    }

}

maybe introduce some more Gradle DSL like convention to declare this and force projects to have using same property name for this behavior??

Caching improvements

For each build SCR is changing date in OSGI-INF/*.properties

#Thu Jun 01 09:10:22 CEST 2017
com.example.aem.bundle.services.posts.PostsService.postsUrl.description=Endpoint must return JSON with list of objects containing 'userId', 'id', 'title' and 'body'.
com.example.aem.bundle.services.posts.PostsService.postsUrl.name=Data source URL for posts.
com.example.aem.bundle.services.posts.PostsService.description=Serves post data from external data source.
com.example.aem.bundle.services.posts.PostsService.name=Example Posts Service

so that JAR compilation is not cacheable fully
so that aemUpdateManifest must be run also (interesting what we could cache / mark as output in that task / manifest properties, any ideas how?)

Executing task ':example.bundle:aemUpdateManifest' (up-to-date check took 0.0 secs) due to:
  Task has not declared any outputs.

then aemCompose cannot be cached also:, because of above issues:

Executing task ':example.bundle:aemCompose' (up-to-date check took 0.25 secs) due to:
  Input property 'rootSpec$1$1' file C:\Users\krystian.panek\Projects\gradle-aem-example\bundle\build\libs\example.bundle-1.0.0-SNAPSHOT.jar has changed.

There are areas uncacheable right now, however build is still quick because of e.g incremental compilation. I hope that maybe contributors have some ideas how to improve full process, especially caching and resolving issues listed above.

Dependency on local Jar

Hi,

A section of my pom.xml looks like

-<dependency>
	<groupId>commons-collections</groupId>
	<artifactId>commons-collections</artifactId>
	<version>3.2.2</version>
</dependency>

-<dependency>
	<groupId>commons-beanutils</groupId>
	<artifactId>commons-beanutils</artifactId>
	<version>1.8.3</version>
</dependency>

-<dependency>
	<groupId>com.project.wcms.aem</groupId>
	<artifactId>project-root.core</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<scope>system</scope>
<systemPath>${basedir}/../ui.apps/src/main/content/jcr_root/apps/project/install/project-root.core-1.0.0-SNAPSHOT.jar</systemPath> 

I have resolved the external dependencies like

      ```
  compile group: 'javax.xml.rpc', name: 'javax.xml.rpc-api', version: '1.1'
	compile group: 'org.mybatis', name: 'mybatis', version: '3.2.4'

However i dont know how to resolve the internal dependencies like this

-<dependency>
	<groupId>com.project.wcms.aem</groupId>
	<artifactId>project-root.core</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<scope>system</scope>
<systemPath>${basedir}/../ui.apps/src/main/content/jcr_root/apps/project/install/project-root.core-1.0.0-SNAPSHOT.jar</systemPath>

I have tried many ways but all the times it got failed. Could you please help how to do this ?

Thanks,
Aditya Rathore

Introduce await relax time

Imagine:

aem {
     awaitRests = 3
}

Currently once all instances are stable then aemAwait ends. What if this moment is only temporary? Then such extra configuration will help to cover such edge case.

AEM gradle plugin for productive projects

Hi all.

Would you say that AEM gradle plugin is the way to go for future productive projects?

We have been playing around with it and we are very happy with the results so we would like to know if you have built this thinking about using it in "real life projects" or just for fun.

Your answer on this is pretty appreciated by us.

Thanks a lot for your time.

Vault commands don't work

Command connected with fetching content from CRX by Vault doesn't work:

gradle :content:aemVlt -Paem.vlt.command='checkout --force --filter ${filter} ${instance.httpUrl}/crx/server/crx.default'

output

Problem configuring task :content:aemVlt from command line.
Unknown command-line option '--force'.

gradle :content:aemSync -Paem.vlt.filter=src/main/content/META-INF/vault/filter-content-only.xml
gradle :content:aemCheckout -Paem.vlt.filter=src/main/content/META-INF/vault/filter-content-only.xml

output

checkout: java.net.URISyntaxException: Illegal character in path at index 1: ${instance.httpUrl}/crx/server/crx.default

Create and download package from remote instance

Imagine:

gradle aemGrab -Paem.grab.filter=/content/some/subtree -Paem.grab.name='Subtree package name'` -Paem.grab.target=backup-dir

this will create package on remote server, build it then download to local directory

will be a base for #51

Improve caching 'aemCompose'

Make aemCompose that it could be upToDate

currently new Date() in AemConfig makes it not cacheable. what is more @nested annotation could be used, so that gradle inputs described in '-i' log will be more precise

Consider nested multiple projects / instance plugin applied more than once

Affects / to be improved:

  • generating more appropriate package names and jar names in case of nested path. now package name is based on root project name and sub project name, but... it will be better if it will be well formatted project path

  • aemCollect depends on all subprojects that have applied package plugin, but filtering should also respect situation when we have two applications in same project structure (and 2 instance plugins applied)

Sample project structure:

/aem-app1/[bundle,content]
/aem-app2/[bundle,content]
/integration-tests
/other-stuff

Lack of support for SCR annotations is not well documented

While using gradle-aem-plugin I spent a lot of time to figure out, why an example from Adobe documentation for AEM does not work. In the end it turned out, that gradle-aem-plugin does not support SCR annotations.
I went through documentation and there is an information about lack of support, but it is easy to miss it.
My proposal is to write it in a way, that every user is aware, that he shouldn't use it, so something like:
WARNING:
SCR annotations are not supported in gradle-aem-plugin. Instead using package:
org.apache.felix.scr.annotations
Please use official OSGi annotations from package:
org.osgi.service.component.annotations.

Publish plugin artifact to BinTray

In progress. Should be available after 18th of May.

Temporarily build and publish plugin to local Maven repository by running command:

gradle clean build publishToMavenLocal

Rollouting local AEM instances by configuration

Imagine:

gradle aemUp will which will dependsOn([aemSetup aemSatisfy])

aemSetup will create
~/.gradle/aem/example/local-author/[crx-quickstart.jar,licence.properties,start.bat|sh]
~/.gradle/aem/example/local-publish/[crx-quickstart.jar,licence.properties,start.bat|sh]

then aemSatisfy will install needed dependencies
then aemUp will run AEM in background, corresponding aemHalt can stop it (like in Vagrant).

aemSetup {
   jar = 'smb://some-server/aem/6.2/crx-quickstart.jar'
   license = 'smb://some-server/aem/6.2/license.properties'
}

motivation to create that improvement is fact, that AEM on Vagrant is noticeable more slower.... and that full automation project related could be very helpful in case of small projects, PoC in which SE is not available to configure Vagrant for us.

SCR annotations support

SCR annotations are not supported but should be.
AEM is tightly coupled with Felix thus support for Felix SCR annotations is crucial.
Raising awareness of lack of support as in #72 should not be the way to go.

Actual behaviour:

Manifest does not contain any entries for classes annotated with SCR annotations.

Expected behaviour:

Proper Manifest generating logic for classes annotated with SCR annotations is present.

SCR generator classloading issue

For fields defined in services, for instance:

@Service(PostsService::class)
@Component(
        immediate = true,
        metatype = true
)
class PostsService {

    internal var stat = QueryStatImpl()

}

SCR generator has a problem with classloading in case of reflection at this line:

https://github.com/apache/felix/blob/trunk/tools/org.apache.felix.scr.generator/src/main/java/org/apache/felix/scrplugin/helper/ClassScanner.java#L261

following error is shown in log:

[ant:null] NoClassDefFoundError: org/apache/jackrabbit/api/stats/QueryStat

to fix that, buildscript classpath (on which plugin is working) must be extended:

https://github.com/Cognifide/gradle-aem-example/blob/master/gradle/buildscript.gradle#L28

by adding line with dependency which contains class that cannot be loaded:

classpath 'org.apache.jackrabbit:jackrabbit-api:2.7.4'

Seems that Ant Task classloader configured here: https://github.com/Cognifide/gradle-aem-plugin/blob/master/src/main/kotlin/com/cognifide/gradle/aem/jar/AbstractClassesTask.kt#L63

is not respected in reflection called in ClassScanner mentioned earlier. Workaround is done by the same reason as in Maven, see: http://felix.apache.org/documentation/faqs/apache-felix-scr-plugin-faq.html#noclassdeffounderror-during-build .

Does somebody have an idea how to fix that instead of using workaround above? I'd like to do not force AEM plugin users to extend buildscript (redeclaring dependencies twice)...

Refactor `AemConfig`

It should have constructor with Project so that default values calculation will be more verbose.

Vault Filter absolut path

For now -Paem.vlt.filter allow user to pass filter file relative to module.
I want to be able to pass absolut path

Create 'aemUninstall'

This can be also automated.

It would be nice if this operation require additional interactive confirmation "Are you sure?" (or bypassed in non-interactive mode)

New task `aemReload`

will run aemDown then wait until port will be utilised, then being run aemUp in a same way as currently.

Also aemDestroy could depend on aemDown and could destroy only if AEM is really down (port is opened and some delay spent).

Content sync

In projects we often propagate a content via CRX packages. We sync the content from higher environments like an agency environment to lower one. We want to sync the content to local / dev environments also.
It would be nice to have a task aemContentSync which:

  • sync content at author instance
  • sync content at publish instance
  • clear dispatcher
    Additionally if the content package we sync has not updated we do not want to synchronize (idempotent).

Detect malformed URL address to instance

E.g when url is specified in aem.deploy.instance.list in some variable injected (by Bamboo) and for some reason that var does not exist ...

Deploying to "${bamboo.authorUrl}/crx/pacmgr/..."
host parameter is null / sth like that http client is reporting.

it would be nice if more descriptive error will be reported.

aemSatisfy to download packages list once

Right now, aemSatisfy checks the list of packages for each package. This is quite expensive operation in terms of time. The list of packages installed can be requested once, and then used to check against for each package.

At the other hand, some of the packages can actually contain other ones, so in some cases downloading package list each time does make sense. But does reinstalling of these will harm instance in any way? hard to say.

I think that a parameter needs to be introduced to decide whether check once or every time. I'm not sure what default behavior should be, however.

-Paem.satisfy.retrievePackageListOnce=true|false

It should be strictly a performance tuning flag.

Configurable default instance name filtering for aemSatisfy and aemDeploy

Imagine:


aemSatisfy {
    packages {
        group 'lib-apm', {
            url("https://github.com/Cognifide/APM/releases/download/cqsm-3.0.1/apm-3.0.1.zip")
        }, ['instanceFilter': '*'] // same as default if not specified
        group 'tool-groovy-console', {
            downloadHttpAuth("https://rshare.cognifide.com/zen-garden-public/releases/groovy/aem-groovy-console-10.1.1.zip", rshareUser, rsharePass)
        }, ['instanceFilter': 'local-*']
    }
}

Local AEM dispatcher setup

AEM on Vagrant / VirtualBox works, but its performance is not enough good as native.

Taks aemSetup is now able to rollout easily native AEM instances.
The missing parts of typical production ready AEM stack are:

  • Apache with Dispatcher module
  • MongoDB
  • Apache Solr
  • Knot.X (optionally)

Imagine:

sh gradlew aemSetup

  • will create native AEM instances as usual
  • will run Vagrant Box with AEM stack described above
  • AEM stack will use project local folder mounted e.g /stack which will holds configurations for Dispatcher, Rewrite, Solr, Mongo, Knot.x

We will achieve full AEM stack configured in one place (one project VCS repository) with native AEM performance.

Question: How to write plugin block in gradle?

Hello,

How do we define plugins in gradle? e.g how we would write plugin like below


<build>
		<plugins>
			<plugin>
				<groupId>org.apache.felix</groupId>
				<artifactId>maven-scr-plugin</artifactId>
			</plugin>
			<plugin>
				<groupId>org.apache.felix</groupId>
				<artifactId>maven-bundle-plugin</artifactId>
				<extensions>true</extensions>
				<configuration>
					<instructions>
					   <Embed-Dependency>gson;scope=!test;inline=false</Embed-Dependency>

						<Embed-Transitive>true</Embed-Transitive>
						<Import-Package>*;resolution:=optional</Import-Package>
						<!-- <Embed-Dependency> artifactId1, artifactId2;inline=true </Embed-Dependency> -->
						<Sling-Model-Packages>
							com.project.wcms.aem.project
						</Sling-Model-Packages>
					</instructions>
				</configuration>
			</plugin>
		</plugins>

Too specific front-end ignoredFiles defaults

Currently contentIgnoreFiles default configuration contains 3 front-end related entries:

            "**/package.json", // 1)
            "**/clientlibs/Gruntfile.js", // 2)
            "**/node_modules/**",

node_modules is fine as I cannot imagine situation where you would like to have it on instance however I have problem with 1) and 2).

Regarding 1)

When working with tools like aem-sync front-end developers should be able to export CRX package and work directly on it. It's not possible without package.json to install required dependencies.

Regarding 2)

This seems super specific - Grunt is one of many front-end development tools (Gulp, Webpack, Brunch, Rollup - there are tons and tons of them). Also Gruntfile can be present on any level under clientlibs, this path is very specific. The same idea as for 1) applies here, Gruntfile may be required when working with aem-sync.

I would suggest removing this entries from default configuration.

issue with vault filter.xml

I got a problem, content package is always generated with a filter

i tried to use vaultFilterPath param, but it didn't help

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.