Skip to content

Commit ccbeed1

Browse files
committed
Add "aem-contentpackage" node model export plugin to generate "all" content packages to be used by Adobe Cloud Manager.
conga-aem-maven-plugin: Add "copy-all-packages" goal to copy generated "all" content packages to the target directory so they can be picked up by Adobe Cloud Manager.
1 parent f47f483 commit ccbeed1

12 files changed

Lines changed: 553 additions & 6 deletions

File tree

changes.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@
3333
<action type="add" dev="sseifert">
3434
Add new config parameter 'cryptoSkip' that allows to skip crypto encryption in aemCryptoEncrypt expression.
3535
</action>
36+
<action type="add" dev="sseifert">
37+
Add "aem-contentpackage" node model export plugin to generate "all" content packages to be used by Adobe Cloud Manager.
38+
</action>
39+
<action type="add" dev="sseifert">
40+
conga-aem-maven-plugin: Add "copy-all-packages" goal to copy generated "all" content packages to the target directory so they can be picked up by Adobe Cloud Manager.
41+
</action>
3642
<action type="update" dev="sseifert">
3743
aem-contentpackage-osgiconfig post processor: Include only generated *.config files in AEM content package, no other .content files (exception the package is empty otherwise).
3844
Automatically set 'packageType' for packages created by this post processor.
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/*
2+
* #%L
3+
* wcm.io
4+
* %%
5+
* Copyright (C) 2020 wcm.io
6+
* %%
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* #L%
19+
*/
20+
package io.wcm.devops.conga.plugins.aem.export;
21+
22+
import static io.wcm.devops.conga.plugins.aem.export.RunModeUtil.RUNMODE_AUTHOR;
23+
import static io.wcm.devops.conga.plugins.aem.export.RunModeUtil.RUNMODE_PUBLISH;
24+
import static io.wcm.devops.conga.plugins.aem.postprocessor.ContentPackageOptions.PROPERTY_PACKAGE_NAME;
25+
import static io.wcm.devops.conga.plugins.aem.postprocessor.ContentPackageOptions.PROPERTY_PACKAGE_ROOT_PATH;
26+
27+
import java.io.File;
28+
import java.io.IOException;
29+
import java.util.HashMap;
30+
import java.util.List;
31+
import java.util.Map;
32+
import java.util.stream.Collectors;
33+
34+
import io.wcm.devops.conga.generator.GeneratorException;
35+
import io.wcm.devops.conga.generator.spi.export.NodeModelExportPlugin;
36+
import io.wcm.devops.conga.generator.spi.export.context.ExportNodeRoleData;
37+
import io.wcm.devops.conga.generator.spi.export.context.NodeModelExportContext;
38+
import io.wcm.devops.conga.generator.util.FileUtil;
39+
import io.wcm.devops.conga.model.util.MapMerger;
40+
import io.wcm.devops.conga.plugins.aem.postprocessor.ContentPackageOptions;
41+
import io.wcm.devops.conga.plugins.aem.util.ContentPackageUtil;
42+
import io.wcm.tooling.commons.contentpackagebuilder.ContentPackage;
43+
import io.wcm.tooling.commons.contentpackagebuilder.ContentPackageBuilder;
44+
45+
/**
46+
* Export a combined "all" package including all content packages generated for this CONGA node.
47+
* This is useful for deploying to AEM cloud service.
48+
*/
49+
public final class ContentPackageNodeModelExport implements NodeModelExportPlugin {
50+
51+
/**
52+
* Plugin name
53+
*/
54+
public static final String NAME = "aem-contentpackage";
55+
56+
private static final String PACKAGE_NAME = "aem-all-packages";
57+
static final String MODEL_FILE = PACKAGE_NAME + ".zip";
58+
59+
@Override
60+
public String getName() {
61+
return NAME;
62+
}
63+
64+
@Override
65+
public void export(NodeModelExportContext context) {
66+
67+
// collect AEM content packages for this node
68+
List<EmbedPackage> contentPackages = context.getRoleData().stream()
69+
.flatMap(role -> role.getFiles().stream().map(file -> new EmbedPackage(file, role)))
70+
.filter(EmbedPackage::isValid)
71+
.collect(Collectors.toList());
72+
if (contentPackages.isEmpty()) {
73+
return;
74+
}
75+
76+
// build merged config from all roles and environment to pick best-matching content package properties for all package
77+
Map<String, Object> mergedConfig = new HashMap<>();
78+
mergedConfig.put(PROPERTY_PACKAGE_NAME, PACKAGE_NAME);
79+
mergedConfig = MapMerger.merge(context.getEnvironment().getConfig(), mergedConfig);
80+
for (ExportNodeRoleData role : context.getRoleData()) {
81+
mergedConfig = MapMerger.merge(mergedConfig, role.getConfig());
82+
}
83+
84+
// define root path for "all" package
85+
String rootPath = buildRootPath(mergedConfig);
86+
mergedConfig.put(PROPERTY_PACKAGE_ROOT_PATH, rootPath);
87+
88+
// build content package
89+
File zipFile = new File(context.getNodeDir(), MODEL_FILE);
90+
ContentPackageBuilder builder = ContentPackageUtil.getContentPackageBuilder(mergedConfig, context.getUrlFileManager());
91+
try (ContentPackage contentPackage = builder.build(zipFile)) {
92+
for (EmbedPackage pkg : contentPackages) {
93+
String path = buildPackagePath(pkg, rootPath);
94+
contentPackage.addFile(path, pkg.getFile().getFileContext().getFile());
95+
}
96+
}
97+
catch (IOException ex) {
98+
throw new GeneratorException("Unable to generate AEM content package: " + FileUtil.getCanonicalPath(zipFile), ex);
99+
}
100+
101+
}
102+
103+
/**
104+
* Build root path to be used for embedded package.
105+
* @param mergedConfig Merged configuration
106+
* @return Package path
107+
*/
108+
private static String buildRootPath(Map<String, Object> mergedConfig) {
109+
String groupName = ContentPackageUtil.getMandatoryProp(mergedConfig, ContentPackageOptions.PROPERTY_PACKAGE_GROUP);
110+
return "/apps/" + groupName + "-packages";
111+
}
112+
113+
/**
114+
* Build path to be used for embedded package.
115+
* @param pkg Package
116+
* @param rootPath Root path
117+
* @return Package path
118+
*/
119+
private static String buildPackagePath(EmbedPackage pkg, String rootPath) {
120+
String runModeSuffix = "";
121+
if (pkg.isOnlyAuthorRunMode()) {
122+
runModeSuffix = "." + RUNMODE_AUTHOR;
123+
}
124+
else if (pkg.isOnlyPublishRunMode()) {
125+
runModeSuffix = "." + RUNMODE_PUBLISH;
126+
}
127+
return rootPath + "/" + pkg.getPackageType() + "/install" + runModeSuffix + "/"
128+
+ pkg.getFile().getFileContext().getFile().getName();
129+
}
130+
131+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* #%L
3+
* wcm.io
4+
* %%
5+
* Copyright (C) 2020 wcm.io
6+
* %%
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* #L%
19+
*/
20+
package io.wcm.devops.conga.plugins.aem.export;
21+
22+
import static io.wcm.devops.conga.plugins.aem.export.RunModeUtil.RUNMODE_AUTHOR;
23+
import static io.wcm.devops.conga.plugins.aem.export.RunModeUtil.RUNMODE_PUBLISH;
24+
import static org.apache.jackrabbit.vault.packaging.PackageProperties.NAME_PACKAGE_TYPE;
25+
26+
import java.util.Map;
27+
import java.util.Set;
28+
29+
import io.wcm.devops.conga.generator.spi.export.context.ExportNodeRoleData;
30+
import io.wcm.devops.conga.generator.spi.export.context.GeneratedFileContext;
31+
import io.wcm.devops.conga.model.util.MapExpander;
32+
import io.wcm.devops.conga.plugins.aem.postprocessor.ContentPackagePropertiesPostProcessor;
33+
34+
class EmbedPackage {
35+
36+
private final GeneratedFileContext file;
37+
private final String packageType;
38+
private final Set<String> runModes;
39+
40+
EmbedPackage(GeneratedFileContext file, ExportNodeRoleData role) {
41+
this.file = file;
42+
this.packageType = getPackageType(file);
43+
this.runModes = RunModeUtil.mapVariantsToRunModes(role.getRoleVariants());
44+
}
45+
46+
private static String getPackageType(GeneratedFileContext file) {
47+
Map<String, Object> modelOptions = file.getFileContext().getModelOptions();
48+
if (modelOptions != null) {
49+
String key = ContentPackagePropertiesPostProcessor.MODEL_OPTIONS_PROPERTY + "." + NAME_PACKAGE_TYPE;
50+
return (String)MapExpander.getDeep(modelOptions, key);
51+
}
52+
return null;
53+
}
54+
55+
public GeneratedFileContext getFile() {
56+
return this.file;
57+
}
58+
59+
public String getPackageType() {
60+
return this.packageType;
61+
}
62+
63+
public boolean isValid() {
64+
// accept only files that are content packages and have a packageType set
65+
return this.packageType != null;
66+
}
67+
68+
public boolean isOnlyAuthorRunMode() {
69+
return runModes.contains(RUNMODE_AUTHOR) && !runModes.contains(RUNMODE_PUBLISH);
70+
}
71+
72+
public boolean isOnlyPublishRunMode() {
73+
return runModes.contains(RUNMODE_PUBLISH) && !runModes.contains(RUNMODE_AUTHOR);
74+
}
75+
76+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* #%L
3+
* wcm.io
4+
* %%
5+
* Copyright (C) 2020 wcm.io
6+
* %%
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* #L%
19+
*/
20+
package io.wcm.devops.conga.plugins.aem.export;
21+
22+
import java.util.List;
23+
import java.util.Set;
24+
import java.util.stream.Collectors;
25+
26+
final class RunModeUtil {
27+
28+
static final String RUNMODE_AUTHOR = "author";
29+
static final String RUNMODE_PUBLISH = "publish";
30+
31+
private RunModeUtil() {
32+
// static methods only
33+
}
34+
35+
static Set<String> mapVariantsToRunModes(List<String> variants) {
36+
return variants.stream()
37+
.map(RunModeUtil::mapVariantToRunMode)
38+
.collect(Collectors.toSet());
39+
}
40+
41+
/**
42+
* Maps well-known variant names from CONG AEM definitions to the corresponding run modes.
43+
* If the variant name is not well-known the variant name is used as run mode.
44+
* @param variant Variant
45+
* @return Run mode
46+
*/
47+
static String mapVariantToRunMode(String variant) {
48+
//
49+
if ("aem-author".equals(variant)) {
50+
return RUNMODE_AUTHOR;
51+
}
52+
else if ("aem-publish".equals(variant)) {
53+
return RUNMODE_PUBLISH;
54+
}
55+
return variant;
56+
}
57+
58+
}

conga-aem-plugin/src/main/java/io/wcm/devops/conga/plugins/aem/postprocessor/ContentPackageOsgiConfigPostProcessor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ public List<FileContext> apply(FileContext fileContext, PostProcessorContext con
100100

101101
String rootPath = ContentPackageUtil.getMandatoryProp(options, PROPERTY_PACKAGE_ROOT_PATH);
102102

103-
ContentPackageBuilder builder = ContentPackageUtil.getContentPackageBuilder(options, fileHeader);
103+
ContentPackageBuilder builder = ContentPackageUtil.getContentPackageBuilder(options, context.getUrlFileManager(), fileHeader);
104104

105105
// set package type depending on if config is present or not
106106
builder.packageType(hasAnyConfig ? "container" : "application");

conga-aem-plugin/src/main/java/io/wcm/devops/conga/plugins/aem/postprocessor/ContentPackagePostProcessor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ public List<FileContext> apply(FileContext fileContext, PostProcessorContext con
8989

9090
String rootPath = ContentPackageUtil.getMandatoryProp(options, PROPERTY_PACKAGE_ROOT_PATH);
9191

92-
ContentPackageBuilder builder = ContentPackageUtil.getContentPackageBuilder(options, fileHeader);
92+
ContentPackageBuilder builder = ContentPackageUtil.getContentPackageBuilder(options, context.getUrlFileManager(), fileHeader);
9393
try (ContentPackage contentPackage = builder.build(zipFile)) {
9494

9595
// add content from JSON file

conga-aem-plugin/src/main/java/io/wcm/devops/conga/plugins/aem/util/ContentPackageUtil.java

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,17 +68,36 @@ private ContentPackageUtil() {
6868
/**
6969
* Builds content package builder populated with options from options map.
7070
* @param options Options
71+
* @param urlFileManager URL file manager
72+
* @return Content package builder
73+
*/
74+
public static ContentPackageBuilder getContentPackageBuilder(Map<String, Object> options, UrlFileManager urlFileManager) {
75+
return getContentPackageBuilder(options, urlFileManager, null);
76+
}
77+
78+
/**
79+
* Builds content package builder populated with options from options map.
80+
* @param options Options
81+
* @param urlFileManager URL file manager
7182
* @param fileHeader File header
7283
* @return Content package builder
7384
*/
74-
public static ContentPackageBuilder getContentPackageBuilder(Map<String, Object> options, FileHeaderContext fileHeader) {
85+
public static ContentPackageBuilder getContentPackageBuilder(Map<String, Object> options, UrlFileManager urlFileManager,
86+
FileHeaderContext fileHeader) {
7587
ContentPackageBuilder builder = new ContentPackageBuilder()
7688
.group(getMandatoryProp(options, PROPERTY_PACKAGE_GROUP))
7789
.name(getMandatoryProp(options, PROPERTY_PACKAGE_NAME))
78-
.description(mergeDescriptionFileHeader(getOptionalProp(options, PROPERTY_PACKAGE_DESCRIPTION), fileHeader))
7990
.version(getOptionalProp(options, PROPERTY_PACKAGE_VERSION))
8091
.packageType(getOptionalProp(options, PROPERTY_PACKAGE_PACKAGE_TYPE));
8192

93+
// description
94+
if (fileHeader != null) {
95+
builder.description(mergeDescriptionFileHeader(getOptionalProp(options, PROPERTY_PACKAGE_DESCRIPTION), fileHeader));
96+
}
97+
else {
98+
builder.description(getOptionalProp(options, PROPERTY_PACKAGE_DESCRIPTION));
99+
}
100+
82101
// AC handling
83102
AcHandling acHandling = getAcHandling(options);
84103
if (acHandling != null) {
@@ -88,7 +107,6 @@ public static ContentPackageBuilder getContentPackageBuilder(Map<String, Object>
88107
// thumbnail image
89108
String thumbnailImageUrl = getOptionalProp(options, PROPERTY_PACKAGE_THUMBNAIL_IMAGE);
90109
if (StringUtils.isNotBlank(thumbnailImageUrl)) {
91-
UrlFileManager urlFileManager = fileHeader.getUrlFileManager();
92110
try {
93111
builder.thumbnailImage(urlFileManager.getFile(thumbnailImageUrl));
94112
}

conga-aem-plugin/src/main/java/io/wcm/devops/conga/plugins/aem/validator/ContentPackageValidator.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
*/
2020
package io.wcm.devops.conga.plugins.aem.validator;
2121

22+
import static org.apache.jackrabbit.vault.packaging.PackageProperties.NAME_PACKAGE_TYPE;
23+
2224
import java.io.File;
2325
import java.io.IOException;
2426
import java.lang.reflect.Field;
@@ -81,7 +83,7 @@ public Void apply(FileContext file, ValidatorContext context) throws ValidationE
8183
try {
8284
// validate package if a package type is defined
8385
// supported only within Maven
84-
String packageType = (String)ContentPackageProperties.get(file.getFile()).get("packageType");
86+
String packageType = (String)ContentPackageProperties.get(file.getFile()).get(NAME_PACKAGE_TYPE);
8587
if (packageType != null && context.getContainerContext() instanceof MavenContext) {
8688
validateContentPackage(file.getFile(), context, (MavenContext)context.getContainerContext());
8789
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
io.wcm.devops.conga.plugins.aem.export.ContentPackageNodeModelExport

0 commit comments

Comments
 (0)