Skip to content

Commit

Permalink
feat(deploy): Display failed messages from Nexus2 activities
Browse files Browse the repository at this point in the history
Closes #1604
  • Loading branch information
aalmiray committed Feb 27, 2024
1 parent 768fb60 commit 8c9afe4
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,8 @@ ERROR_nexus_find_staging_repositories = Could not find staging repositories fo
ERROR_nexus_close_repository = Could not close staging repository {}
ERROR_nexus_release_repository = Could not release staging repository {}
ERROR_nexus_deploy_artifact = Error when deploying artifact {}
ERROR_nexus_find_staging_activities = Could not find a staging activities for {}
ERROR_nexus_find_staging_activity = Could not find staging activity {} for {}
ERROR_nexus_stage = Start stage is {} but end stage is {}
ERROR_deployer_stage_resolution = Some paths failed to be resolved
ERROR_deployer_unexpected_error_stage = Unexpected error when resolving staged artifacts
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import org.jreleaser.sdk.nexus2.api.NexusAPIException;
import org.jreleaser.sdk.nexus2.api.PromoteRequest;
import org.jreleaser.sdk.nexus2.api.StagedRepository;
import org.jreleaser.sdk.nexus2.api.StagingActivity;
import org.jreleaser.sdk.nexus2.api.StagingProfile;
import org.jreleaser.sdk.nexus2.api.StagingProfileRepository;

Expand All @@ -63,13 +64,16 @@
import java.util.Base64;
import java.util.Collection;
import java.util.Comparator;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;

import static java.lang.System.lineSeparator;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Comparator.comparing;
import static java.util.Objects.requireNonNull;
Expand Down Expand Up @@ -177,7 +181,7 @@ public void dropStagingRepository(String profileId, String stagingRepositoryId,
api.dropStagingRepository(
new Data<>(PromoteRequest.of(stagingRepositoryId, "Staging repository for " + groupId)),
profileId);
waitForState(stagingRepositoryId, StagingProfileRepository.State.NOT_FOUND);
waitForState(stagingRepositoryId, "drop", StagingProfileRepository.State.NOT_FOUND);
});
}

Expand All @@ -186,7 +190,7 @@ public void releaseStagingRepository(String profileId, String stagingRepositoryI
api.releaseStagingRepository(
new Data<>(PromoteRequest.of(stagingRepositoryId, "Staging repository for " + groupId)),
profileId);
waitForState(stagingRepositoryId, StagingProfileRepository.State.RELEASED, StagingProfileRepository.State.NOT_FOUND);
waitForState(stagingRepositoryId, "release", StagingProfileRepository.State.RELEASED, StagingProfileRepository.State.NOT_FOUND);
});
}

Expand All @@ -195,11 +199,11 @@ public void closeStagingRepository(String profileId, String stagingRepositoryId,
api.closeStagingRepository(
new Data<>(PromoteRequest.of(stagingRepositoryId, "Staging repository for " + groupId)),
profileId);
waitForState(stagingRepositoryId, StagingProfileRepository.State.CLOSED);
waitForState(stagingRepositoryId, "close", StagingProfileRepository.State.CLOSED);
});
}

private void waitForState(String stagingRepositoryId, StagingProfileRepository.State... states) {
private void waitForState(String stagingRepositoryId, String activity, StagingProfileRepository.State... states) throws Nexus2Exception {
logger.debug(RB.$("nexus.wait.repository.state", stagingRepositoryId, Arrays.asList(states)));

StagingProfileRepository repository = retrier.retry(StagingProfileRepository::isTransitioning,
Expand All @@ -210,10 +214,41 @@ private void waitForState(String stagingRepositoryId, StagingProfileRepository.S
}

if (Arrays.binarySearch(states, repository.getState()) < 0) {
throw new IllegalStateException(RB.$("nexus.wait.repository.invalid.state", stagingRepositoryId, Arrays.asList(states), repository.getState()));
Set<String> messages = resolveActivityMessages(stagingRepositoryId, activity);
String title = RB.$("nexus.wait.repository.invalid.state", stagingRepositoryId, Arrays.asList(states), repository.getState());
throw new Nexus2Exception(title + lineSeparator() + String.join(lineSeparator(), messages));
}
}

private Set<String> resolveActivityMessages(String stagingRepositoryId, String activityName) throws Nexus2Exception {
List<StagingActivity> data = api.getActivities(stagingRepositoryId);
if (null == data || data.isEmpty()) {
throw fail(RB.$("ERROR_nexus_find_staging_activities", stagingRepositoryId));
}

Optional<StagingActivity> activity = data.stream()
.filter(a -> activityName.equals(a.getName()))
.findFirst();

if (!activity.isPresent()) {
throw fail(RB.$("ERROR_nexus_find_staging_activity", activityName, stagingRepositoryId));
}

Set<String> messages = new LinkedHashSet<>();
for (StagingActivity.StagingActivityEvent event : activity.get().getEvents()) {
if (event.getName().endsWith("Failed")) {
for (StagingActivity.StagingProperty property : event.getProperties()) {
if ("failureMessage".equals(property.getName()) ||
"cause".equals(property.getName())) {
messages.add(property.getValue());
}
}
}
}

return messages;
}

private StagingProfileRepository getStagingRepository(String stagingRepositoryId) {
logger.debug(RB.$("nexus.get.staging.repository", stagingRepositoryId));

Expand Down Expand Up @@ -447,7 +482,7 @@ public Exception decode(String methodKey, Response response) {
response.status(),
response.reason(),
response.request().httpMethod(),
(Date) null,
(Long) null,
response.request());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,8 @@ public interface NexusAPI {
@RequestLine("POST /staging/profiles/{profileId}/drop")
@Headers("Content-Type: application/json")
void dropStagingRepository(Data<PromoteRequest> promoteRequest, @Param("profileId") String profileId);

@RequestLine("GET /staging/repository/{repositoryId}/activity")
@Headers("Content-Type: application/json")
List<StagingActivity> getActivities(@Param("repositoryId") String repositoryId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright 2020-2024 The JReleaser authors.
*
* 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
*
* https://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.jreleaser.sdk.nexus2.api;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

import java.time.Instant;
import java.util.ArrayList;
import java.util.List;

/**
* @author Andres Almiray
* @since 1.11.0
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class StagingActivity {
private String name;
private String startedByUserId;
private String startedByIpAddress;
private Instant started;
private Instant stopped;
private List<StagingActivityEvent> events = new ArrayList<>();

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getStartedByUserId() {
return startedByUserId;
}

public void setStartedByUserId(String startedByUserId) {
this.startedByUserId = startedByUserId;
}

public String getStartedByIpAddress() {
return startedByIpAddress;
}

public void setStartedByIpAddress(String startedByIpAddress) {
this.startedByIpAddress = startedByIpAddress;
}

public Instant getStarted() {
return started;
}

public void setStarted(Instant started) {
this.started = started;
}

public Instant getStopped() {
return stopped;
}

public void setStopped(Instant stopped) {
this.stopped = stopped;
}

public List<StagingActivityEvent> getEvents() {
return events;
}

public void setEvents(List<StagingActivityEvent> events) {
this.events = events;
}

@JsonIgnoreProperties(ignoreUnknown = true)
public static class StagingActivityEvent {
private String name;
private Instant timestamp;
private Integer severity;
private List<StagingProperty> properties = new ArrayList<>();

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Instant getTimestamp() {
return timestamp;
}

public void setTimestamp(Instant timestamp) {
this.timestamp = timestamp;
}

public Integer getSeverity() {
return severity;
}

public void setSeverity(Integer severity) {
this.severity = severity;
}

public List<StagingProperty> getProperties() {
return properties;
}

public void setProperties(List<StagingProperty> properties) {
this.properties = properties;
}
}

@JsonIgnoreProperties(ignoreUnknown = true)
public static class StagingProperty {
private String name;
private String value;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getValue() {
return value;
}

public void setValue(String value) {
this.value = value;
}
}
}

0 comments on commit 8c9afe4

Please sign in to comment.