Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integration of PR #102 (Implement REPLACE_ANCESTOR publish strategy) #122

Merged
merged 18 commits into from
Feb 7, 2019
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.sahli.asciidoc.confluence.publisher.client.http.ConfluencePage;
import org.sahli.asciidoc.confluence.publisher.client.http.ConfluenceRestClient;
import org.sahli.asciidoc.confluence.publisher.client.metadata.ConfluencePublisherMetadata;
import org.sahli.asciidoc.confluence.publisher.client.metadata.PublishingStrategy;
import org.sahli.asciidoc.confluence.publisher.converter.AsciidocConfluenceConverter;
import org.sahli.asciidoc.confluence.publisher.converter.AsciidocPagesStructureProvider;
import org.sahli.asciidoc.confluence.publisher.converter.FolderBasedAsciidocPagesStructureProvider;
Expand All @@ -41,6 +42,7 @@
import static java.nio.file.Files.delete;
import static java.nio.file.Files.walkFileTree;
import static java.util.Arrays.stream;
import static org.sahli.asciidoc.confluence.publisher.client.metadata.PublishingStrategy.APPEND_TO_ANCESTOR;

public class AsciidocConfluencePublisherCommandLineClient {

Expand All @@ -51,6 +53,8 @@ public static void main(String[] args) throws Exception {
String spaceKey = mandatoryArgument("spaceKey", args);
String ancestorId = mandatoryArgument("ancestorId", args);

PublishingStrategy publishingStrategy = PublishingStrategy.valueOf(optionalArgument("strategy", args).orElse(APPEND_TO_ANCESTOR.name()));

Path documentationRootFolder = Paths.get(mandatoryArgument("asciidocRootFolder", args));
Path buildFolder = createTempDirectory("confluence-publisher");

Expand All @@ -66,7 +70,7 @@ public static void main(String[] args) throws Exception {
ConfluencePublisherMetadata confluencePublisherMetadata = asciidocConfluenceConverter.convert(asciidocPagesStructureProvider, pageTitlePostProcessor, buildFolder);

ConfluenceRestClient confluenceClient = new ConfluenceRestClient(rootConfluenceUrl, username, password);
ConfluencePublisher confluencePublisher = new ConfluencePublisher(confluencePublisherMetadata, confluenceClient, new SystemOutLoggingConfluencePublisherListener());
ConfluencePublisher confluencePublisher = new ConfluencePublisher(confluencePublisherMetadata, publishingStrategy, confluenceClient, new SystemOutLoggingConfluencePublisherListener());
confluencePublisher.publish();
} finally {
deleteDirectory(buildFolder);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.sahli.asciidoc.confluence.publisher.client.http.ConfluenceRestClient;
import org.sahli.asciidoc.confluence.publisher.client.metadata.ConfluencePageMetadata;
import org.sahli.asciidoc.confluence.publisher.client.metadata.ConfluencePublisherMetadata;
import org.sahli.asciidoc.confluence.publisher.client.metadata.PublishingStrategy;

import java.nio.file.Paths;

Expand All @@ -32,6 +33,8 @@
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.fail;
import static org.sahli.asciidoc.confluence.publisher.client.metadata.PublishingStrategy.APPEND_TO_ANCESTOR;
import static org.sahli.asciidoc.confluence.publisher.client.metadata.PublishingStrategy.REPLACE_ANCESTOR;

/**
* @author Alain Sahli
Expand All @@ -42,13 +45,13 @@ public class ConfluencePublisherIntegrationTest {
private static final String ANCESTOR_ID = "327706";

@Test
public void publish_singlePage_pageIsCreatedInConfluence() {
public void publish_singlePageAndAppendToAncestorPublishingStrategy_pageIsCreatedInConfluence() {
// arrange
String title = uniqueTitle("Single Page");
ConfluencePageMetadata confluencePageMetadata = confluencePageMetadata(title, absolutePathTo("single-page/single-page.xhtml"));
ConfluencePublisherMetadata confluencePublisherMetadata = confluencePublisherMetadata(confluencePageMetadata);

ConfluencePublisher confluencePublisher = confluencePublisher(confluencePublisherMetadata);
ConfluencePublisher confluencePublisher = confluencePublisher(confluencePublisherMetadata, APPEND_TO_ANCESTOR);

// act
confluencePublisher.publish();
Expand All @@ -59,13 +62,31 @@ public void publish_singlePage_pageIsCreatedInConfluence() {
.then().body("results.title", hasItem(title));
}

@Test
public void publish_singlePageAndReplaceAncestorPublishingStrategy_pageIsUpdatedInConfluence() {
// arrange
String title = uniqueTitle("Single Page");
ConfluencePageMetadata confluencePageMetadata = confluencePageMetadata(title, absolutePathTo("single-page/single-page.xhtml"));
ConfluencePublisherMetadata confluencePublisherMetadata = confluencePublisherMetadata(confluencePageMetadata);

ConfluencePublisher confluencePublisher = confluencePublisher(confluencePublisherMetadata, REPLACE_ANCESTOR);

// act
confluencePublisher.publish();

// assert
givenAuthenticatedAsPublisher()
.when().get(rootPage())
.then().body("title", is(title));
}

@Test
public void publish_sameContentPublishedMultipleTimes_doesNotProduceMultipleVersions() {
// arrange
String title = uniqueTitle("Single Page");
ConfluencePageMetadata confluencePageMetadata = confluencePageMetadata(title, absolutePathTo("single-page/single-page.xhtml"));
ConfluencePublisherMetadata confluencePublisherMetadata = confluencePublisherMetadata(confluencePageMetadata);
ConfluencePublisher confluencePublisher = confluencePublisher(confluencePublisherMetadata);
ConfluencePublisher confluencePublisher = confluencePublisher(confluencePublisherMetadata, APPEND_TO_ANCESTOR);

// act
confluencePublisher.publish();
Expand All @@ -83,7 +104,7 @@ public void publish_validPageContentThenInvalidPageContentThenValidContentAgain_
String title = uniqueTitle("Invalid Markup Test Page");
ConfluencePageMetadata confluencePageMetadata = confluencePageMetadata(title, absolutePathTo("single-page/single-page.xhtml"));
ConfluencePublisherMetadata confluencePublisherMetadata = confluencePublisherMetadata(confluencePageMetadata);
ConfluencePublisher confluencePublisher = confluencePublisher(confluencePublisherMetadata);
ConfluencePublisher confluencePublisher = confluencePublisher(confluencePublisherMetadata, APPEND_TO_ANCESTOR);

// act
confluencePublisher.publish();
Expand Down Expand Up @@ -133,6 +154,10 @@ private static String childPages() {
return "http://localhost:8090/rest/api/content/" + ANCESTOR_ID + "/child/page";
}

private static String rootPage() {
return "http://localhost:8090/rest/api/content/" + ANCESTOR_ID;
}

private static String pageVersionOf(String contentId) {
return "http://localhost:8090/rest/api/content/" + contentId + "?expand=version";
}
Expand All @@ -147,8 +172,8 @@ private static String pageIdBy(String title) {
.then().extract().jsonPath().getString("results.find({it.title == '" + title + "'}).id");
}

private static ConfluencePublisher confluencePublisher(ConfluencePublisherMetadata confluencePublisherMetadata) {
return new ConfluencePublisher(confluencePublisherMetadata, confluenceRestClient());
private static ConfluencePublisher confluencePublisher(ConfluencePublisherMetadata confluencePublisherMetadata, PublishingStrategy publishingStrategy) {
return new ConfluencePublisher(confluencePublisherMetadata, publishingStrategy, confluenceRestClient());
}

private static RequestSpecification givenAuthenticatedAsPublisher() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.sahli.asciidoc.confluence.publisher.client.http.NotFoundException;
import org.sahli.asciidoc.confluence.publisher.client.metadata.ConfluencePageMetadata;
import org.sahli.asciidoc.confluence.publisher.client.metadata.ConfluencePublisherMetadata;
import org.sahli.asciidoc.confluence.publisher.client.metadata.PublishingStrategy;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
Expand All @@ -34,9 +35,11 @@

import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Collections.emptyList;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;
import static org.apache.commons.codec.digest.DigestUtils.sha256Hex;
import static org.apache.commons.lang.StringUtils.isNotBlank;
import static org.sahli.asciidoc.confluence.publisher.client.metadata.PublishingStrategy.REPLACE_ANCESTOR;
import static org.sahli.asciidoc.confluence.publisher.client.utils.AssertUtils.assertMandatoryParameter;
import static org.sahli.asciidoc.confluence.publisher.client.utils.InputStreamUtils.fileContent;

Expand All @@ -50,15 +53,17 @@ public class ConfluencePublisher {
static final int INITIAL_PAGE_VERSION = 1;

private final ConfluencePublisherMetadata metadata;
private final PublishingStrategy publishingStrategy;
private final ConfluenceClient confluenceClient;
private final ConfluencePublisherListener confluencePublisherListener;

public ConfluencePublisher(ConfluencePublisherMetadata metadata, ConfluenceClient confluenceClient) {
this(metadata, confluenceClient, new NoOpConfluencePublisherListener());
public ConfluencePublisher(ConfluencePublisherMetadata metadata, PublishingStrategy publishingStrategy, ConfluenceClient confluenceClient) {
this(metadata, publishingStrategy, confluenceClient, new NoOpConfluencePublisherListener());
}

public ConfluencePublisher(ConfluencePublisherMetadata metadata, ConfluenceClient confluenceClient, ConfluencePublisherListener confluencePublisherListener) {
public ConfluencePublisher(ConfluencePublisherMetadata metadata, PublishingStrategy publishingStrategy, ConfluenceClient confluenceClient, ConfluencePublisherListener confluencePublisherListener) {
this.metadata = metadata;
this.publishingStrategy = publishingStrategy;
this.confluenceClient = confluenceClient;
this.confluencePublisherListener = confluencePublisherListener;
}
Expand All @@ -67,16 +72,37 @@ public void publish() {
assertMandatoryParameter(isNotBlank(this.metadata.getSpaceKey()), "spaceKey");
assertMandatoryParameter(isNotBlank(this.metadata.getAncestorId()), "ancestorId");

startPublishingUnderAncestorId(this.metadata.getPages(), this.metadata.getSpaceKey(), this.metadata.getAncestorId());
switch (this.publishingStrategy) {
case APPEND_TO_ANCESTOR:
startPublishingUnderAncestorId(this.metadata.getPages(), this.metadata.getSpaceKey(), this.metadata.getAncestorId());
break;
case REPLACE_ANCESTOR:
// verify that only a single root exists
alainsahli marked this conversation as resolved.
Show resolved Hide resolved
if (this.metadata.getPages().size() > 1) {
String rootPageTitles = this.metadata.getPages().stream().map(page -> "'" + page.getTitle() + "'").collect(joining(", "));
alainsahli marked this conversation as resolved.
Show resolved Hide resolved
throw new IllegalArgumentException("Multiple root pages detected: " + rootPageTitles + ", but '" + REPLACE_ANCESTOR + "' publishing strategy only supports one single root page");
alainsahli marked this conversation as resolved.
Show resolved Hide resolved
}

if (this.metadata.getPages().size() > 0) {
// replace ancestor title with single root page title
alainsahli marked this conversation as resolved.
Show resolved Hide resolved
ConfluencePageMetadata rootPageMetaData = this.metadata.getPages().get(0);
updatePage(this.metadata.getAncestorId(), null, rootPageMetaData);

// publish children under root page
startPublishingUnderAncestorId(rootPageMetaData.getChildren(), this.metadata.getSpaceKey(), this.metadata.getAncestorId());
}
break;
default:
throw new IllegalArgumentException("Invalid publishing strategy '" + this.publishingStrategy + "'");
}

this.confluencePublisherListener.publishCompleted();
}

private void startPublishingUnderAncestorId(List<ConfluencePageMetadata> pages, String spaceKey, String ancestorId) {
deleteConfluencePagesNotPresentUnderAncestor(pages, ancestorId);

pages.forEach(page -> {
String content = fileContent(page.getContentFilePath(), UTF_8);
String contentId = addOrUpdatePage(spaceKey, ancestorId, page, content);
String contentId = addOrUpdatePageUnderAncestor(spaceKey, ancestorId, page);

deleteConfluenceAttachmentsNotPresentUnderPage(contentId, page.getAttachments());
addAttachments(contentId, page.getAttachments());
Expand Down Expand Up @@ -110,24 +136,14 @@ private void deleteConfluenceAttachmentsNotPresentUnderPage(String contentId, Ma
confluenceAttachmentsToDelete.forEach(this.confluenceClient::deleteAttachment);
}


private String addOrUpdatePage(String spaceKey, String ancestorId, ConfluencePageMetadata page, String content) {
private String addOrUpdatePageUnderAncestor(String spaceKey, String ancestorId, ConfluencePageMetadata page) {
String contentId;

try {
contentId = this.confluenceClient.getPageByTitle(spaceKey, page.getTitle());
ConfluencePage existingPage = this.confluenceClient.getPageWithContentAndVersionById(contentId);
String existingContentHash = this.confluenceClient.getPropertyByKey(contentId, CONTENT_HASH_PROPERTY_KEY);
String newContentHash = contentHash(content);

if (notSameContentHash(existingContentHash, newContentHash)) {
this.confluenceClient.deletePropertyByKey(contentId, CONTENT_HASH_PROPERTY_KEY);
int newPageVersion = existingPage.getVersion() + 1;
this.confluenceClient.updatePage(contentId, ancestorId, page.getTitle(), content, newPageVersion);
this.confluenceClient.setPropertyByKey(contentId, CONTENT_HASH_PROPERTY_KEY, newContentHash);
this.confluencePublisherListener.pageUpdated(existingPage, new ConfluencePage(contentId, page.getTitle(), content, newPageVersion));
}
updatePage(contentId, ancestorId, page);
} catch (NotFoundException e) {
String content = fileContent(page.getContentFilePath(), UTF_8);
contentId = this.confluenceClient.addPageUnderAncestor(spaceKey, ancestorId, page.getTitle(), content);
this.confluenceClient.setPropertyByKey(contentId, CONTENT_HASH_PROPERTY_KEY, contentHash(content));
this.confluencePublisherListener.pageAdded(new ConfluencePage(contentId, page.getTitle(), content, INITIAL_PAGE_VERSION));
Expand All @@ -136,6 +152,21 @@ private String addOrUpdatePage(String spaceKey, String ancestorId, ConfluencePag
return contentId;
}

private void updatePage(String contentId, String ancestorId, ConfluencePageMetadata page) {
String content = fileContent(page.getContentFilePath(), UTF_8);
ConfluencePage existingPage = this.confluenceClient.getPageWithContentAndVersionById(contentId);
String existingContentHash = this.confluenceClient.getPropertyByKey(contentId, CONTENT_HASH_PROPERTY_KEY);
String newContentHash = contentHash(content);

if (notSameContentHash(existingContentHash, newContentHash) || !existingPage.getTitle().equals(page.getTitle())) {
this.confluenceClient.deletePropertyByKey(contentId, CONTENT_HASH_PROPERTY_KEY);
int newPageVersion = existingPage.getVersion() + 1;
this.confluenceClient.updatePage(contentId, ancestorId, page.getTitle(), content, newPageVersion);
this.confluenceClient.setPropertyByKey(contentId, CONTENT_HASH_PROPERTY_KEY, newContentHash);
this.confluencePublisherListener.pageUpdated(existingPage, new ConfluencePage(contentId, page.getTitle(), content, newPageVersion));
}
}

private static String contentHash(String content) {
return sha256Hex(content);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,22 +227,12 @@ private <T> T sendRequestAndFailIfNot20x(HttpRequestBase request, Function<HttpR
}

<T> T sendRequest(HttpRequestBase httpRequest, Function<HttpResponse, T> responseHandler) {
CloseableHttpResponse response = null;

try {
httpRequest.addHeader(AUTHORIZATION, basicAuthorizationHeaderValue(this.username, this.password));
response = this.httpClient.execute(httpRequest);
httpRequest.addHeader(AUTHORIZATION, basicAuthorizationHeaderValue(this.username, this.password));

try (CloseableHttpResponse response = this.httpClient.execute(httpRequest)) {
return responseHandler.apply(response);
} catch (IOException e) {
throw new RuntimeException("Request could not be sent" + httpRequest, e);
} finally {
try {
if (response != null) {
response.close();
}
} catch (IOException ignored) {
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ HttpPost addPageUnderAncestorRequest(String spaceKey, String ancestorId, String

HttpPut updatePageRequest(String contentId, String ancestorId, String title, String content, int newVersion) {
assertMandatoryParameter(isNotBlank(contentId), "contentId");
assertMandatoryParameter(isNotBlank(ancestorId), "ancestorId");
assertMandatoryParameter(isNotBlank(title), "title");

PagePayload pagePayload = pagePayloadBuilder()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.sahli.asciidoc.confluence.publisher.client.metadata;

/**
* @author Laurent Verbruggen
*/
public enum PublishingStrategy {
alainsahli marked this conversation as resolved.
Show resolved Hide resolved

APPEND_TO_ANCESTOR,
REPLACE_ANCESTOR

}
Loading