Java tutorial
/** * JBoss, Home of Professional Open Source. * Copyright 2014-2019 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jboss.pnc.indyrepositorymanager; import org.apache.commons.lang.StringUtils; import org.commonjava.atlas.maven.ident.ref.ArtifactRef; import org.commonjava.atlas.maven.ident.ref.SimpleArtifactRef; import org.commonjava.atlas.maven.ident.util.ArtifactPathInfo; import org.commonjava.atlas.npm.ident.ref.NpmPackageRef; import org.commonjava.atlas.npm.ident.util.NpmPackagePathInfo; import org.commonjava.indy.client.core.Indy; import org.commonjava.indy.client.core.IndyClientException; import org.commonjava.indy.client.core.module.IndyContentClientModule; import org.commonjava.indy.folo.client.IndyFoloAdminClientModule; import org.commonjava.indy.folo.dto.TrackedContentDTO; import org.commonjava.indy.folo.dto.TrackedContentEntryDTO; import org.commonjava.indy.model.core.HostedRepository; import org.commonjava.indy.model.core.StoreKey; import org.commonjava.indy.model.core.StoreType; import org.commonjava.indy.promote.client.IndyPromoteClientModule; import org.commonjava.indy.promote.model.GroupPromoteRequest; import org.commonjava.indy.promote.model.GroupPromoteResult; import org.commonjava.indy.promote.model.PathsPromoteRequest; import org.commonjava.indy.promote.model.PathsPromoteResult; import org.commonjava.indy.promote.model.PromoteRequest; import org.commonjava.indy.promote.model.ValidationResult; import org.jboss.pnc.common.json.moduleconfig.IndyRepoDriverModuleConfig.IgnoredPathSuffixes; import org.jboss.pnc.common.json.moduleconfig.IndyRepoDriverModuleConfig.InternalRepoPatterns; import org.jboss.pnc.model.Artifact; import org.jboss.pnc.model.TargetRepository; import org.jboss.pnc.spi.coordinator.CompletionStatus; import org.jboss.pnc.spi.repositorymanager.RepositoryManagerException; import org.jboss.pnc.spi.repositorymanager.RepositoryManagerResult; import org.jboss.pnc.spi.repositorymanager.model.RepositoryConnectionInfo; import org.jboss.pnc.spi.repositorymanager.model.RepositorySession; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.validation.ConstraintViolation; import javax.validation.Validation; import javax.validation.Validator; import java.io.File; import java.time.Instant; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.jboss.pnc.enums.ArtifactQuality; import org.jboss.pnc.enums.RepositoryType; import static org.commonjava.indy.model.core.GenericPackageTypeDescriptor.GENERIC_PKG_KEY; import static org.commonjava.indy.pkg.maven.model.MavenPackageTypeDescriptor.MAVEN_PKG_KEY; import static org.commonjava.indy.pkg.npm.model.NPMPackageTypeDescriptor.NPM_PKG_KEY; import static org.jboss.pnc.indyrepositorymanager.IndyRepositoryConstants.SHARED_IMPORTS_ID; /** * {@link RepositorySession} implementation that works with the Maven {@link RepositoryManagerDriver} (which connects to an * Indy server instance for repository management). This session contains connection information for rendering Maven * settings.xml files and the like, along with the components necessary to extract the artifacts (dependencies, build uploads) * for the associated build. * * Artifact extraction also implies promotion of imported dependencies to a shared-imports Maven repository for safe keeping. In * the case of composed (chained) builds, it also implies promotion of the build output to the associated build-set repository * group, to expose them for use in successive builds in the chain. */ public class IndyRepositorySession implements RepositorySession { private final Logger logger = LoggerFactory.getLogger(getClass()); private static final Logger userLog = LoggerFactory.getLogger("org.jboss.pnc._userlog_.build-executor"); /** PackageType-specific ignored suffixes. */ private IgnoredPathSuffixes ignoredPathSuffixes; private boolean isTempBuild; private Indy indy; private Indy serviceAccountIndy; private final String buildContentId; private final String packageType; /** * PackageType-specific internal repository name patterns. */ private InternalRepoPatterns internalRepoPatterns; private final RepositoryConnectionInfo connectionInfo; private Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); private String buildPromotionTarget; public IndyRepositorySession(Indy indy, Indy serviceAccountIndy, String buildContentId, String packageType, IndyRepositoryConnectionInfo info, InternalRepoPatterns internalRepoPatterns, IgnoredPathSuffixes ignoredPathSuffixes, String buildPromotionTarget, boolean isTempBuild) { this.indy = indy; this.serviceAccountIndy = serviceAccountIndy; this.buildContentId = buildContentId; this.packageType = packageType; this.internalRepoPatterns = internalRepoPatterns; this.ignoredPathSuffixes = ignoredPathSuffixes; this.connectionInfo = info; this.buildPromotionTarget = buildPromotionTarget; this.isTempBuild = isTempBuild; //TODO define based on buildPromotionTarget } @Override public String toString() { return "MavenRepositoryConfiguration " + this.hashCode(); } @Override public RepositoryType getType() { return toRepoType(packageType); } @Override public String getBuildRepositoryId() { return buildContentId; } @Override public RepositoryConnectionInfo getConnectionInfo() { return connectionInfo; } /** * Retrieve tracking report from repository manager. Add each tracked download to the dependencies of the build result. Add * each tracked upload to the built artifacts of the build result. Promote uploaded artifacts to the product-level storage. * Finally, clear the tracking report, and delete the hosted repository + group associated with the completed build. */ @Override public RepositoryManagerResult extractBuildArtifacts() throws RepositoryManagerException { TrackedContentDTO report; try { IndyFoloAdminClientModule foloAdmin = indy.module(IndyFoloAdminClientModule.class); boolean sealed = foloAdmin.sealTrackingRecord(buildContentId); if (!sealed) { throw new RepositoryManagerException("Failed to seal content-tracking record for: %s.", buildContentId); } report = foloAdmin.getTrackingReport(buildContentId); } catch (IndyClientException e) { throw new RepositoryManagerException("Failed to retrieve tracking report for: %s. Reason: %s", e, buildContentId, e.getMessage()); } if (report == null) { throw new RepositoryManagerException("Failed to retrieve tracking report for: %s.", buildContentId); } Comparator<Artifact> comp = (one, two) -> one.getIdentifier().compareTo(two.getIdentifier()); List<Artifact> uploads = processUploads(report); Collections.sort(uploads, comp); List<Artifact> downloads = processDownloads(report); Collections.sort(downloads, comp); try { StoreKey key = new StoreKey(packageType, StoreType.group, buildContentId); serviceAccountIndy.stores().delete(key, "[Post-Build] Removing build aggregation group: " + buildContentId); } catch (IndyClientException e) { throw new RepositoryManagerException("Failed to retrieve Indy stores module. Reason: %s", e, e.getMessage()); } Logger logger = LoggerFactory.getLogger(getClass()); logger.info("Returning built artifacts / dependencies:\nUploads:\n {}\n\nDownloads:\n {}\n\n", StringUtils.join(uploads, "\n "), StringUtils.join(downloads, "\n ")); String log = ""; CompletionStatus status = CompletionStatus.SUCCESS; try { promoteToBuildContentSet(uploads); } catch (RepositoryManagerException rme) { status = CompletionStatus.FAILED; log = rme.getMessage(); logger.error("Promotion validation error(s): \n" + log); userLog.error("Artifact promotion failed. Promotion validation error(s): {}", log); // prevent saving artifacts and dependencies to a failed build downloads = Collections.emptyList(); uploads = Collections.emptyList(); } return new IndyRepositoryManagerResult(uploads, downloads, buildContentId, log, status); } /** * Promote all build dependencies NOT ALREADY CAPTURED to the hosted repository holding store for the shared imports and * return dependency artifacts meta data. * * @param report The tracking report that contains info about artifacts downloaded by the build * @return List of dependency artifacts meta data * @throws RepositoryManagerException In case of a client API transport error or an error during promotion of artifacts */ private List<Artifact> processDownloads(TrackedContentDTO report) throws RepositoryManagerException { Logger logger = LoggerFactory.getLogger(getClass()); IndyContentClientModule content; try { content = indy.content(); } catch (IndyClientException e) { throw new RepositoryManagerException("Failed to retrieve Indy content module. Reason: %s", e, e.getMessage()); } List<Artifact> deps = new ArrayList<>(); Set<TrackedContentEntryDTO> downloads = report.getDownloads(); if (downloads != null) { Map<StoreKey, Map<StoreKey, Set<String>>> toPromote = new HashMap<>(); Map<String, StoreKey> promotionTargets = new HashMap<>(); for (TrackedContentEntryDTO download : downloads) { String path = download.getPath(); StoreKey source = download.getStoreKey(); String packageType = source.getPackageType(); if (ignoreContent(packageType, path)) { logger.debug("Ignoring download (matched in ignored-suffixes): {} (From: {})", download.getPath(), source); continue; } // If the entry is from a hosted repository (also shared-imports), it shouldn't be auto-promoted. // New binary imports will be coming from a remote repository... if (isExternalOrigin(source)) { StoreKey target = null; Map<StoreKey, Set<String>> sources = null; Set<String> paths = null; // this has not been captured, so promote it. switch (packageType) { case MAVEN_PKG_KEY: case NPM_PKG_KEY: target = getPromotionTarget(packageType, promotionTargets); sources = toPromote.computeIfAbsent(target, t -> new HashMap<>()); paths = sources.computeIfAbsent(source, s -> new HashSet<>()); paths.add(download.getPath()); if (MAVEN_PKG_KEY.equals(packageType)) { paths.add(download.getPath() + ".md5"); paths.add(download.getPath() + ".sha1"); } break; case GENERIC_PKG_KEY: String remoteName = source.getName(); String hostedName; if (remoteName.startsWith("r-")) { hostedName = "h-" + remoteName.substring(2); } else { logger.warn("Unexpected generic http remote repo name {}. Using it for hosted repo " + "without change, but it probably doesn't exist.", remoteName); hostedName = remoteName; } target = new StoreKey(source.getPackageType(), StoreType.hosted, hostedName); sources = toPromote.computeIfAbsent(target, t -> new HashMap<>()); paths = sources.computeIfAbsent(source, s -> new HashSet<>()); paths.add(download.getPath()); break; default: // do not promote anything else anywhere break; } } String identifier = computeIdentifier(download); logger.info("Recording download: {}", identifier); String originUrl = download.getOriginUrl(); if (originUrl == null) { // this is from a hosted repository, either shared-imports or a build, or something like that. originUrl = download.getLocalUrl(); } TargetRepository targetRepository = getDownloadsTargetRepository(download, content); Artifact.Builder artifactBuilder = Artifact.Builder.newBuilder().md5(download.getMd5()) .sha1(download.getSha1()).sha256(download.getSha256()).size(download.getSize()) .deployPath(download.getPath()).originUrl(originUrl).importDate(Date.from(Instant.now())) .filename(new File(path).getName()).identifier(identifier) .targetRepository(targetRepository); Artifact artifact = validateArtifact(artifactBuilder.build()); deps.add(artifact); } for (Map.Entry<StoreKey, Map<StoreKey, Set<String>>> targetToSources : toPromote.entrySet()) { StoreKey target = targetToSources.getKey(); for (Map.Entry<StoreKey, Set<String>> sourceToPaths : targetToSources.getValue().entrySet()) { StoreKey source = sourceToPaths.getKey(); PathsPromoteRequest req = new PathsPromoteRequest(source, target, sourceToPaths.getValue()) .setPurgeSource(false); // set read-only only the generic http proxy hosted repos, not shared-imports doPromoteByPath(req, GENERIC_PKG_KEY.equals(target.getPackageType())); } } } return deps; } private StoreKey getPromotionTarget(String packageType, Map<String, StoreKey> promotionTargets) { if (!promotionTargets.containsKey(packageType)) { StoreKey storeKey = new StoreKey(packageType, StoreType.hosted, SHARED_IMPORTS_ID); promotionTargets.put(packageType, storeKey); } return promotionTargets.get(packageType); } private TargetRepository getDownloadsTargetRepository(TrackedContentEntryDTO download, IndyContentClientModule content) throws RepositoryManagerException { String identifier; String repoPath; StoreKey sk = download.getStoreKey(); RepositoryType repoType = toRepoType(sk.getPackageType()); if (repoType == RepositoryType.MAVEN || repoType == RepositoryType.NPM) { identifier = "indy-" + repoType.name().toLowerCase(); repoPath = getTargetRepositoryPath(download, content); } else if (repoType == RepositoryType.GENERIC_PROXY) { identifier = "indy-http:" + sk.getName(); repoPath = "/not-available/"; //TODO set the path for http cache } else { throw new RepositoryManagerException( "Repository type " + repoType + " is not supported by Indy repo manager driver."); } return TargetRepository.newBuilder().identifier(identifier).repositoryType(repoType) .repositoryPath(repoPath).temporaryRepo(false).build(); } private String getTargetRepositoryPath(TrackedContentEntryDTO download, IndyContentClientModule content) { String result; StoreKey sk = download.getStoreKey(); String packageType = sk.getPackageType(); if (isExternalOrigin(sk)) { result = "/api/" + content.contentPath(new StoreKey(packageType, StoreType.hosted, SHARED_IMPORTS_ID)); } else { result = "/api/" + content.contentPath(sk); } return result; } private TargetRepository getUploadsTargetRepository(RepositoryType repoType, IndyContentClientModule content) throws RepositoryManagerException { StoreType storeType = (isTempBuild ? StoreType.group : StoreType.hosted); StoreKey storeKey; String identifier; if (repoType == RepositoryType.MAVEN) { storeKey = new StoreKey(MAVEN_PKG_KEY, storeType, buildPromotionTarget); identifier = "indy-maven"; } else if (repoType == RepositoryType.NPM) { storeKey = new StoreKey(NPM_PKG_KEY, storeType, buildPromotionTarget); identifier = "indy-npm"; } else { throw new RepositoryManagerException( "Repository type " + repoType + " is not supported for uploads by Indy repo manager driver."); } String repoPath = "/api/" + content.contentPath(storeKey); return TargetRepository.newBuilder().identifier(identifier).repositoryType(repoType) .repositoryPath(repoPath).temporaryRepo(isTempBuild).build(); } private boolean isExternalOrigin(StoreKey storeKey) { if (storeKey.getType() == StoreType.hosted) { return false; } else { String repoName = storeKey.getName(); List<String> patterns; switch (storeKey.getPackageType()) { case MAVEN_PKG_KEY: patterns = internalRepoPatterns.getMaven(); break; case NPM_PKG_KEY: patterns = internalRepoPatterns.getNpm(); break; case GENERIC_PKG_KEY: patterns = internalRepoPatterns.getGeneric(); break; default: throw new IllegalArgumentException("Package type " + storeKey.getPackageType() + " is not supported by Indy repository manager driver."); } for (String pattern : patterns) { // Logger logger = LoggerFactory.getLogger(getClass()); // logger.info( "Checking ") if (pattern.equals(repoName)) { return false; } if (repoName.matches(pattern)) { return false; } } return true; } } /** * Return output artifacts metadata. * * @param report The tracking report that contains info about artifacts uploaded (output) from the build * @return List of output artifacts meta data * @throws RepositoryManagerException In case of a client API transport error or an error during promotion of artifacts */ private List<Artifact> processUploads(TrackedContentDTO report) throws RepositoryManagerException { Logger logger = LoggerFactory.getLogger(getClass()); Set<TrackedContentEntryDTO> uploads = report.getUploads(); if (uploads != null) { List<Artifact> builds = new ArrayList<>(); for (TrackedContentEntryDTO upload : uploads) { String path = upload.getPath(); StoreKey storeKey = upload.getStoreKey(); if (ignoreContent(storeKey.getPackageType(), path)) { logger.debug("Ignoring upload (matched in ignored-suffixes): {} (From: {})", path, storeKey); continue; } String identifier = computeIdentifier(upload); logger.info("Recording upload: {}", identifier); IndyContentClientModule content; try { content = indy.content(); } catch (IndyClientException e) { throw new RepositoryManagerException("Failed to retrieve Indy content module. Reason: %s", e, e.getMessage()); } RepositoryType repoType = toRepoType(storeKey.getPackageType()); TargetRepository targetRepository = getUploadsTargetRepository(repoType, content); ArtifactQuality artifactQuality = getArtifactQuality(isTempBuild); Artifact.Builder artifactBuilder = Artifact.Builder.newBuilder().md5(upload.getMd5()) .sha1(upload.getSha1()).sha256(upload.getSha256()).size(upload.getSize()) .deployPath(upload.getPath()).filename(new File(path).getName()).identifier(identifier) .targetRepository(targetRepository).artifactQuality(artifactQuality); Artifact artifact = validateArtifact(artifactBuilder.build()); builds.add(artifact); } return builds; } return Collections.emptyList(); } /** * Computes identifier string for an artifact. If the download path is valid for a package-type specific artifact it * creates the identifier accordingly. * * @param transfer the download or upload that we want to generate identifier for * @return generated identifier */ private String computeIdentifier(final TrackedContentEntryDTO transfer) { String identifier = null; switch (transfer.getStoreKey().getPackageType()) { case MAVEN_PKG_KEY: ArtifactPathInfo pathInfo = ArtifactPathInfo.parse(transfer.getPath()); if (pathInfo != null) { ArtifactRef aref = new SimpleArtifactRef(pathInfo.getProjectId(), pathInfo.getType(), pathInfo.getClassifier()); identifier = aref.toString(); } break; case NPM_PKG_KEY: NpmPackagePathInfo npmPathInfo = NpmPackagePathInfo.parse(transfer.getPath()); if (npmPathInfo != null) { NpmPackageRef packageRef = new NpmPackageRef(npmPathInfo.getName(), npmPathInfo.getVersion()); identifier = packageRef.toString(); } break; case GENERIC_PKG_KEY: // handle generic downloads along with other invalid download paths for other package types break; default: // do not do anything by default logger.warn("Package type {} is not handled by Indy repository session.", transfer.getStoreKey().getPackageType()); break; } if (identifier == null) { identifier = computeGenericIdentifier(transfer.getOriginUrl(), transfer.getLocalUrl(), transfer.getSha256()); } return identifier; } /** * Compute the identifier string for a generic download, that does not match package type specific files structure. * It prefers to use the origin URL if it is not empty. In case it is then it uses local URL, which can never be * empty, it is the local file mirror in Indy. After that it attaches the sha256 separated by a pipe. * * @param originUrl the origin URL of the transfer, it can be null * @param localUrl url where the artifact was backed up in Indy * @param sha256 the SHA-256 of the transfer * @return the generated identifier */ private String computeGenericIdentifier(String originUrl, String localUrl, String sha256) { String identifier = originUrl; if (identifier == null) { // this is from/to a hosted repository, either the build repo or something like that. identifier = localUrl; } identifier += '|' + sha256; return identifier; } /** * Check artifact for any validation errors. If there are constraint violations, then a RepositoryManagerException is thrown. * Otherwise the artifact is returned. * * @param artifact to validate * @return the same artifact * @throws RepositoryManagerException if there are constraint violations */ private Artifact validateArtifact(Artifact artifact) throws RepositoryManagerException { Set<ConstraintViolation<Artifact>> violations = validator.validate(artifact); if (!violations.isEmpty()) { throw new RepositoryManagerException("Repository manager returned invalid artifact: " + artifact.toString() + " Constraint Violations: %s", violations); } return artifact; } /** * Promotes a set of artifact paths (or everything, if the path-set is missing) from a particular Indy artifact store to * another, and handle the various error conditions that may arise. If the promote call fails, attempt to rollback before * throwing an exception. * * @param req The promotion request to process, which contains source and target store keys, and (optionally) the set of * paths to promote * @param setReadonly flag telling if the target repo should be set to readOnly * @throws RepositoryManagerException When either the client API throws an exception due to something unexpected in * transport, or if the promotion process results in an error. */ private void doPromoteByPath(PathsPromoteRequest req, boolean setReadonly) throws RepositoryManagerException { IndyPromoteClientModule promoter; try { promoter = serviceAccountIndy.module(IndyPromoteClientModule.class); } catch (IndyClientException e) { throw new RepositoryManagerException("Failed to retrieve Indy promote client module. Reason: %s", e, e.getMessage()); } try { PathsPromoteResult result = promoter.promoteByPath(req); if (result.getError() == null) { if (setReadonly && !isTempBuild) { HostedRepository hosted = serviceAccountIndy.stores().load(req.getTarget(), HostedRepository.class); hosted.setReadonly(true); try { serviceAccountIndy.stores().update(hosted, "Setting readonly after successful build and promotion."); } catch (IndyClientException ex) { try { promoter.rollbackPathPromote(result); } catch (IndyClientException ex2) { logger.error("Failed to set readonly flag on repo: %s. Reason given was: %s.", ex, req.getTarget(), ex.getMessage()); throw new RepositoryManagerException( "Subsequently also failed to rollback the promotion of paths from %s to %s. Reason given was: %s", ex2, req.getSource(), req.getTarget(), ex2.getMessage()); } throw new RepositoryManagerException( "Failed to set readonly flag on repo: %s. Reason given was: %s", ex, req.getTarget(), ex.getMessage()); } } } else { String addendum = ""; try { PathsPromoteResult rollback = promoter.rollbackPathPromote(result); if (rollback.getError() != null) { addendum = "\nROLLBACK WARNING: Promotion rollback also failed! Reason given: " + result.getError(); } } catch (IndyClientException e) { throw new RepositoryManagerException("Rollback failed for promotion of: %s. Reason: %s", e, req, e.getMessage()); } throw new RepositoryManagerException("Failed to promote: %s. Reason given was: %s%s", req, result.getError(), addendum); } } catch (IndyClientException e) { throw new RepositoryManagerException("Failed to promote: %s. Reason: %s", e, req, e.getMessage()); } } /** * Promote the build output to the consolidated build repo (using path promotion, where the build * repo contents are added to the repo's contents) and marks the build output as readonly. * * @param uploads artifacts to be promoted */ public void promoteToBuildContentSet(List<Artifact> uploads) throws RepositoryManagerException { IndyPromoteClientModule promoter; try { promoter = serviceAccountIndy.module(IndyPromoteClientModule.class); } catch (IndyClientException e) { throw new RepositoryManagerException("Failed to retrieve Indy promote client module. Reason: %s", e, e.getMessage()); } StoreKey buildRepoKey = new StoreKey(packageType, StoreType.hosted, buildContentId); PromoteRequest<?> request = null; try { if (isTempBuild) { request = new GroupPromoteRequest(buildRepoKey, buildPromotionTarget); GroupPromoteRequest gpReq = (GroupPromoteRequest) request; GroupPromoteResult result = promoter.promoteToGroup(gpReq); if (!result.succeeded()) { String reason = result.getError(); if (reason == null) { ValidationResult validations = result.getValidations(); if (validations != null) { StringBuilder sb = new StringBuilder(); sb.append("One or more validation rules failed in rule-set ") .append(validations.getRuleSet()).append(":\n"); validations.getValidatorErrors().forEach((rule, error) -> { sb.append("- ").append(rule).append(":\n").append(error).append("\n\n"); }); reason = sb.toString(); } } throw new RepositoryManagerException("Failed to promote: %s to group: %s. Reason given was: %s", request.getSource(), gpReq.getTargetGroup(), reason); } } else { StoreKey buildTarget = new StoreKey(packageType, StoreType.hosted, buildPromotionTarget); Set<String> paths = new HashSet<>(); for (Artifact a : uploads) { paths.add(a.getDeployPath()); paths.add(a.getDeployPath() + ".md5"); paths.add(a.getDeployPath() + ".sha1"); } request = new PathsPromoteRequest(buildRepoKey, buildTarget, paths); PathsPromoteRequest ppReq = (PathsPromoteRequest) request; // TODO request.setPurgeSource(true); PathsPromoteResult result = promoter.promoteByPath(ppReq); if (result.getError() == null) { HostedRepository buildRepo = serviceAccountIndy.stores().load(buildRepoKey, HostedRepository.class); buildRepo.setReadonly(true); try { serviceAccountIndy.stores().update(buildRepo, "Setting readonly after successful build and promotion."); } catch (IndyClientException ex) { logger.error( "Failed to set readonly flag on repo: %s. Reason given was: %s." + " But the promotion to consolidated repo %s succeeded.", ex, buildRepoKey, ex.getMessage(), buildPromotionTarget); } } else { String reason = result.getError(); if (reason == null) { ValidationResult validations = result.getValidations(); if (validations != null) { StringBuilder sb = new StringBuilder(); sb.append("One or more validation rules failed in rule-set ") .append(validations.getRuleSet()).append(":\n"); validations.getValidatorErrors().forEach((rule, error) -> { sb.append("- ").append(rule).append(":\n").append(error).append("\n\n"); }); reason = sb.toString(); } } throw new RepositoryManagerException( "Failed to promote files from %s to target %s. Reason given was: %s", request.getSource(), ppReq.getTarget(), reason); } } } catch (IndyClientException e) { throw new RepositoryManagerException("Failed to promote: %s. Reason: %s", e, request, e.getMessage()); } } private boolean ignoreContent(String packageType, String path) { List<String> suffixes; switch (packageType) { case MAVEN_PKG_KEY: suffixes = ignoredPathSuffixes.getMavenWithShared(); break; case NPM_PKG_KEY: suffixes = ignoredPathSuffixes.getNpmWithShared(); break; case GENERIC_PKG_KEY: suffixes = ignoredPathSuffixes.getShared(); break; default: throw new IllegalArgumentException( "Package type " + packageType + " is not supported by Indy repository manager driver."); } for (String suffix : suffixes) { if (path.endsWith(suffix)) { return true; } } return false; } private RepositoryType toRepoType(String packageType) { switch (packageType) { case MAVEN_PKG_KEY: return RepositoryType.MAVEN; case NPM_PKG_KEY: return RepositoryType.NPM; case GENERIC_PKG_KEY: return RepositoryType.GENERIC_PROXY; default: return RepositoryType.GENERIC_PROXY; } } private ArtifactQuality getArtifactQuality(boolean isTempBuild) { if (isTempBuild) { return ArtifactQuality.TEMPORARY; } else { return ArtifactQuality.NEW; } } }