diff --git a/src/main/java/org/eclipse/cbi/ws/macos/notarization/process/NativeProcess.java b/src/main/java/org/eclipse/cbi/ws/macos/notarization/process/NativeProcess.java index e67755d..d59d8ce 100644 --- a/src/main/java/org/eclipse/cbi/ws/macos/notarization/process/NativeProcess.java +++ b/src/main/java/org/eclipse/cbi/ws/macos/notarization/process/NativeProcess.java @@ -63,7 +63,14 @@ public static Result startAndWait(ProcessBuilder processBuilder, Duration timeou Thread.currentThread().interrupt(); } - try (AutoValue_NativeProcess_Result result = new AutoValue_NativeProcess_Result(p.exitValue(), arg0, out, err)) { + Result.Builder builder = + Result.builder() + .exitValue(p.exitValue()) + .arg0(arg0) + .stdout(out) + .stderr(err); + + try (Result result = builder.build()) { return result.log(); } } @@ -162,5 +169,19 @@ public void close() { deleteIfExists(stdout()); deleteIfExists(stderr()); } + + public static Result.Builder builder() { + return new AutoValue_NativeProcess_Result.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Result.Builder exitValue(int exitValue); + public abstract Result.Builder arg0(String arg0); + public abstract Result.Builder stdout(Path stdout); + public abstract Result.Builder stderr(Path stderr); + public abstract Result build(); + } + } } \ No newline at end of file diff --git a/src/main/java/org/eclipse/cbi/ws/macos/notarization/xcrun/altool/AltoolNotarizer.java b/src/main/java/org/eclipse/cbi/ws/macos/notarization/xcrun/altool/AltoolNotarizer.java index 8a53bcc..95efb7d 100644 --- a/src/main/java/org/eclipse/cbi/ws/macos/notarization/xcrun/altool/AltoolNotarizer.java +++ b/src/main/java/org/eclipse/cbi/ws/macos/notarization/xcrun/altool/AltoolNotarizer.java @@ -20,74 +20,39 @@ import org.slf4j.LoggerFactory; import org.xml.sax.SAXException; -import java.io.File; import java.io.IOException; -import java.nio.file.Files; import java.nio.file.Path; import java.time.Duration; import java.util.*; import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeoutException; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Stream; -public class AltoolNotarizer implements NotarizationTool { +public class AltoolNotarizer extends NotarizationTool { + + private static final Logger LOGGER = LoggerFactory.getLogger(AltoolNotarizer.class); private static final Pattern UPLOADID_PATTERN = Pattern.compile(".*The upload ID is ([A-Za-z0-9\\\\-]*).*"); private static final Pattern ERROR_MESSAGE_PATTERN = Pattern.compile(".*\"(.*)\".*"); - private static final String APPLEID_PASSWORD_ENV_VAR_NAME = "APPLEID_PASSWORD"; - - private static final Logger LOGGER = LoggerFactory.getLogger(AltoolNotarizer.class); - private static final String TMPDIR = "TMPDIR"; @Override - public NotarizerResult upload(String appleIDUsername, - String appleIDPassword, - String primaryBundleId, - Path fileToNotarize, - Duration uploadTimeout) throws ExecutionException, IOException { + protected List getUploadCommand(String appleIDUsername, String primaryBundleId, Path fileToNotarize) { List cmd = ImmutableList.builder() - .add("xcrun", "altool") - .add("--notarize-app") - .add("--output-format", "xml") - .add("--username", appleIDUsername) - .add("--password", "@env:" + APPLEID_PASSWORD_ENV_VAR_NAME) - .add("--primary-bundle-id", primaryBundleId) - .add("--file", fileToNotarize.toString()).build(); - - Path xcrunTempFolder = - Files.createTempDirectory(fileToNotarize.getParent(), - com.google.common.io.Files.getNameWithoutExtension(fileToNotarize.toString())+ "-xcrun-notarize-app-"); - - ProcessBuilder processBuilder = new ProcessBuilder().command(cmd); - processBuilder.environment().put(APPLEID_PASSWORD_ENV_VAR_NAME, appleIDPassword); - processBuilder.environment().put(TMPDIR, xcrunTempFolder.toString()); - - try(NativeProcess.Result nativeProcessResult = NativeProcess.startAndWait(processBuilder, uploadTimeout)) { - NotarizerResult result = analyzeResult(nativeProcessResult, fileToNotarize); - LOGGER.trace("Notarization upload result:\n" + result.toString()); - return result; - } catch (TimeoutException e) { - LOGGER.error("Timeout happened during notarization upload of file " + fileToNotarize, e); - throw new ExecutionException("Timeout happened during notarization upload", e); - } catch (IOException e) { - LOGGER.error("IOException happened during notarization upload of file " + fileToNotarize, e); - throw new ExecutionException("IOException happened during notarization upload", e); - } finally { - if (Files.exists(xcrunTempFolder)) { - LOGGER.trace("Deleting xcrun-notarize-app temporary folder " + xcrunTempFolder); - try (Stream filesToDelete = Files.walk(xcrunTempFolder).sorted(Comparator.reverseOrder()).map(Path::toFile)) { - filesToDelete.forEach(File::delete); - } catch (IOException e) { - LOGGER.warn("IOException happened during deletion of xcrun-notarize-app temporary folder " + xcrunTempFolder, e); - } - } - } + .add("xcrun", "altool") + .add("--notarize-app") + .add("--output-format", "xml") + .add("--username", appleIDUsername) + .add("--password", "@env:" + APPLEID_PASSWORD_ENV_VAR_NAME) + .add("--primary-bundle-id", primaryBundleId) + .add("--file", fileToNotarize.toString()).build(); + + return cmd; } - private NotarizerResult analyzeResult(NativeProcess.Result nativeProcessResult, Path fileToNotarize) throws ExecutionException { + protected NotarizerResult analyzeSubmissionResult(NativeProcess.Result nativeProcessResult, + Path fileToNotarize) throws ExecutionException { + NotarizerResult.Builder resultBuilder = NotarizerResult.builder(); try { PListDict plist = PListDict.fromXML(nativeProcessResult.stdoutAsStream()); @@ -167,54 +132,27 @@ private Optional parseAppleRequestID(String message) { } @Override - public NotarizationInfoResult retrieveInfo(String appleIDUsername, - String appleIDPassword, - String appleRequestUUID, - Duration pollingTimeout, - OkHttpClient httpClient) throws ExecutionException, IOException { + protected List getInfoCommand(String appleIDUsername, String appleRequestUUID) { List cmd = ImmutableList.builder().add("xcrun", "altool") - .add("--notarization-info", appleRequestUUID.toString()) - .add("--output-format", "xml") - .add("--username", appleIDUsername) - .add("--password", "@env:" + APPLEID_PASSWORD_ENV_VAR_NAME) - .build(); + .add("--notarization-info", appleRequestUUID.toString()) + .add("--output-format", "xml") + .add("--username", appleIDUsername) + .add("--password", "@env:" + APPLEID_PASSWORD_ENV_VAR_NAME) + .build(); - Path xcrunTempFolder = Files.createTempDirectory("-xcrun-notarization-info-"); + return cmd; + } - ProcessBuilder processBuilder = new ProcessBuilder().command(cmd); - processBuilder.environment().put(APPLEID_PASSWORD_ENV_VAR_NAME, appleIDPassword); - processBuilder.environment().put(TMPDIR, xcrunTempFolder.toString()); + @Override + protected NotarizationInfoResult analyzeInfoResult(NativeProcess.Result nativeProcessResult, + String appleRequestUUID, + OkHttpClient httpClient) throws ExecutionException { NotarizationInfoResult.Builder resultBuilder = NotarizationInfoResult.builder(); - try (NativeProcess.Result result = NativeProcess.startAndWait(processBuilder, pollingTimeout)) { - analyseResults(result, resultBuilder, appleRequestUUID, httpClient); - } catch (IOException e) { - LOGGER.error("Error while retrieving notarization info of request '" + appleRequestUUID + "'", e); - throw new ExecutionException("Failed to retrieve notarization info", e); - } catch (TimeoutException e) { - LOGGER.error("Timeout while retrieving notarization info of request '" + appleRequestUUID + "'", e); - throw new ExecutionException("Timeout while retrieving notarization info", e); - } finally { - LOGGER.trace("Deleting xcrun-notarization-info temporary folder " + xcrunTempFolder); - try (Stream filesToDelete = Files.walk(xcrunTempFolder).sorted(Comparator.reverseOrder()).map(Path::toFile)) { - filesToDelete.forEach(File::delete); - } catch (IOException e) { - LOGGER.warn("IOException happened during deletion of xcrun-notarization-info temporary folder " + xcrunTempFolder, e); - } - } - NotarizationInfoResult result = resultBuilder.build(); - LOGGER.trace("Notarization info retriever result:\n{}", result); - return result; - } - - private void analyseResults(NativeProcess.Result result, - NotarizationInfoResult.Builder resultBuilder, - String appleRequestUUID, - OkHttpClient httpClient) throws ExecutionException { try { - PListDict plist = PListDict.fromXML(result.stdoutAsStream()); + PListDict plist = PListDict.fromXML(nativeProcessResult.stdoutAsStream()); - if (result.exitValue() == 0) { + if (nativeProcessResult.exitValue() == 0) { Map notarizationInfoList = (Map) plist.get("notarization-info"); if (notarizationInfoList != null && !notarizationInfoList.isEmpty()) { parseNotarizationInfo(plist, notarizationInfoList, resultBuilder, httpClient); @@ -236,15 +174,15 @@ private void analyseResults(NativeProcess.Result result, .status(NotarizationInfoResult.Status.NOTARIZATION_IN_PROGRESS) .message("The software asset has already been uploaded. Notarization in progress"); default: - resultBuilder.message("Failed to notarize the requested file. Remote service error code = " + firstProductErrorCode.getAsInt() + " (xcrun altool exit value ="+result.exitValue()+")."); + resultBuilder.message("Failed to notarize the requested file. Remote service error code = " + firstProductErrorCode.getAsInt() + " (xcrun altool exit value ="+nativeProcessResult.exitValue()+")."); break; } } else { Optional errorMessage = plist.messageFromFirstProductError(); if (errorMessage.isPresent()) { - resultBuilder.message("Failed to notarize the requested file (xcrun altool exit value ="+result.exitValue()+"). Reason: " + errorMessage.get()); + resultBuilder.message("Failed to notarize the requested file (xcrun altool exit value ="+nativeProcessResult.exitValue()+"). Reason: " + errorMessage.get()); } else { - resultBuilder.message("Failed to notarize the requested file (xcrun altool exit value ="+result.exitValue()+")."); + resultBuilder.message("Failed to notarize the requested file (xcrun altool exit value ="+nativeProcessResult.exitValue()+")."); } } } @@ -252,6 +190,7 @@ private void analyseResults(NativeProcess.Result result, LOGGER.error("Cannot parse notarization info for request '" + appleRequestUUID + "'", e); throw new ExecutionException("Failed to retrieve notarization info.", e); } + return resultBuilder.build(); } private void parseNotarizationInfo(PListDict plist, Map notarizationInfo, @@ -284,6 +223,10 @@ private void parseNotarizationInfo(PListDict plist, Map notarizationInfo, } private String extractLogFromServer(Map notarizationInfo, OkHttpClient httpClient) { + if (httpClient == null) { + return "Can not retrieve log, httpClient is null"; + } + Object logFileUrlStr = notarizationInfo.get("LogFileURL"); if (logFileUrlStr instanceof String) { HttpUrl logfileUrl = HttpUrl.parse((String)logFileUrlStr); diff --git a/src/main/java/org/eclipse/cbi/ws/macos/notarization/xcrun/common/NotarizationTool.java b/src/main/java/org/eclipse/cbi/ws/macos/notarization/xcrun/common/NotarizationTool.java index 7df96b3..94f57ff 100644 --- a/src/main/java/org/eclipse/cbi/ws/macos/notarization/xcrun/common/NotarizationTool.java +++ b/src/main/java/org/eclipse/cbi/ws/macos/notarization/xcrun/common/NotarizationTool.java @@ -8,22 +8,107 @@ package org.eclipse.cbi.ws.macos.notarization.xcrun.common; import okhttp3.OkHttpClient; +import org.eclipse.cbi.ws.macos.notarization.process.NativeProcess; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.io.File; import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; import java.time.Duration; +import java.util.Comparator; +import java.util.List; import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; +import java.util.stream.Stream; -public interface NotarizationTool { - NotarizerResult upload(String appleIDUsername, - String appleIDPassword, - String primaryBundleId, - Path fileToNotarize, - Duration uploadTimeout) throws ExecutionException, IOException; - - NotarizationInfoResult retrieveInfo(String appleIDUsername, - String appleIDPassword, - String appleRequestUUID, - Duration pollingTimeout, - OkHttpClient httpClient) throws ExecutionException, IOException; +public abstract class NotarizationTool { + protected static final String APPLEID_PASSWORD_ENV_VAR_NAME = "APPLEID_PASSWORD"; + + private static final Logger LOGGER = LoggerFactory.getLogger(NotarizationTool.class); + private static final String TMPDIR = "TMPDIR"; + + public NotarizerResult upload(String appleIDUsername, + String appleIDPassword, + String primaryBundleId, + Path fileToNotarize, + Duration uploadTimeout) throws ExecutionException, IOException { + + List cmd = getUploadCommand(appleIDUsername, primaryBundleId, fileToNotarize); + + Path xcrunTempFolder = + Files.createTempDirectory(fileToNotarize.getParent(), + com.google.common.io.Files.getNameWithoutExtension(fileToNotarize.toString())+ "-xcrun-notarize-app-"); + + ProcessBuilder processBuilder = new ProcessBuilder().command(cmd); + processBuilder.environment().put(APPLEID_PASSWORD_ENV_VAR_NAME, appleIDPassword); + processBuilder.environment().put(TMPDIR, xcrunTempFolder.toString()); + + try(NativeProcess.Result nativeProcessResult = NativeProcess.startAndWait(processBuilder, uploadTimeout)) { + NotarizerResult result = analyzeSubmissionResult(nativeProcessResult, fileToNotarize); + LOGGER.trace("Notarization upload result:\n" + result.toString()); + return result; + } catch (TimeoutException e) { + LOGGER.error("Timeout happened during notarization upload of file " + fileToNotarize, e); + throw new ExecutionException("Timeout happened during notarization upload", e); + } catch (IOException e) { + LOGGER.error("IOException happened during notarization upload of file " + fileToNotarize, e); + throw new ExecutionException("IOException happened during notarization upload", e); + } finally { + if (Files.exists(xcrunTempFolder)) { + LOGGER.trace("Deleting xcrun-notarize-app temporary folder " + xcrunTempFolder); + try (Stream filesToDelete = Files.walk(xcrunTempFolder).sorted(Comparator.reverseOrder()).map(Path::toFile)) { + filesToDelete.forEach(File::delete); + } catch (IOException e) { + LOGGER.warn("IOException happened during deletion of xcrun-notarize-app temporary folder " + xcrunTempFolder, e); + } + } + } + } + + protected abstract List getUploadCommand(String appleIDUsername, String primaryBundleId, Path fileToNotarize); + + protected abstract NotarizerResult analyzeSubmissionResult(NativeProcess.Result nativeProcessResult, + Path fileToNotarize) throws ExecutionException; + + public NotarizationInfoResult retrieveInfo(String appleIDUsername, + String appleIDPassword, + String appleRequestUUID, + Duration pollingTimeout, + OkHttpClient httpClient) throws ExecutionException, IOException { + + List cmd = getInfoCommand(appleIDUsername, appleRequestUUID); + + Path xcrunTempFolder = Files.createTempDirectory("-xcrun-notarization-info-"); + + ProcessBuilder processBuilder = new ProcessBuilder().command(cmd); + processBuilder.environment().put(APPLEID_PASSWORD_ENV_VAR_NAME, appleIDPassword); + processBuilder.environment().put(TMPDIR, xcrunTempFolder.toString()); + + try (NativeProcess.Result nativeProcessResult = NativeProcess.startAndWait(processBuilder, pollingTimeout)) { + NotarizationInfoResult result = analyzeInfoResult(nativeProcessResult, appleRequestUUID, httpClient); + LOGGER.trace("Notarization info retriever result:\n{}", result); + return result; + } catch (IOException e) { + LOGGER.error("Error while retrieving notarization info of request '" + appleRequestUUID + "'", e); + throw new ExecutionException("Failed to retrieve notarization info", e); + } catch (TimeoutException e) { + LOGGER.error("Timeout while retrieving notarization info of request '" + appleRequestUUID + "'", e); + throw new ExecutionException("Timeout while retrieving notarization info", e); + } finally { + LOGGER.trace("Deleting xcrun-notarization-info temporary folder " + xcrunTempFolder); + try (Stream filesToDelete = Files.walk(xcrunTempFolder).sorted(Comparator.reverseOrder()).map(Path::toFile)) { + filesToDelete.forEach(File::delete); + } catch (IOException e) { + LOGGER.warn("IOException happened during deletion of xcrun-notarization-info temporary folder " + xcrunTempFolder, e); + } + } + } + + protected abstract List getInfoCommand(String appleIDUsername, String appleRequestUUID); + + protected abstract NotarizationInfoResult analyzeInfoResult(NativeProcess.Result nativeProcessResult, + String appleRequestUUID, + OkHttpClient httpClient) throws ExecutionException; } \ No newline at end of file diff --git a/src/main/java/org/eclipse/cbi/ws/macos/notarization/xcrun/notarytool/NotarytoolNotarizer.java b/src/main/java/org/eclipse/cbi/ws/macos/notarization/xcrun/notarytool/NotarytoolNotarizer.java index e09ab58..03f23cb 100644 --- a/src/main/java/org/eclipse/cbi/ws/macos/notarization/xcrun/notarytool/NotarytoolNotarizer.java +++ b/src/main/java/org/eclipse/cbi/ws/macos/notarization/xcrun/notarytool/NotarytoolNotarizer.java @@ -16,76 +16,39 @@ import org.slf4j.LoggerFactory; import org.xml.sax.SAXException; -import java.io.File; import java.io.IOException; -import java.nio.file.Files; import java.nio.file.Path; import java.time.Duration; import java.util.*; import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeoutException; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Stream; -public class NotarytoolNotarizer implements NotarizationTool { +public class NotarytoolNotarizer extends NotarizationTool { + + private static final Logger LOGGER = LoggerFactory.getLogger(NotarytoolNotarizer.class); private static final Pattern UPLOADID_PATTERN = Pattern.compile(".*The upload ID is ([A-Za-z0-9\\\\-]*).*"); private static final Pattern ERROR_MESSAGE_PATTERN = Pattern.compile(".*\"(.*)\".*"); - private static final String APPLEID_PASSWORD_ENV_VAR_NAME = "APPLEID_PASSWORD"; - - private static final Logger LOGGER = LoggerFactory.getLogger(NotarytoolNotarizer.class); - private static final String TMPDIR = "TMPDIR"; @Override - public NotarizerResult upload(String appleIDUsername, - String appleIDPassword, - String primaryBundleId, - Path fileToNotarize, - Duration uploadTimeout) throws ExecutionException, IOException { - // TODO: consider using --wait - + protected List getUploadCommand(String appleIDUsername, String primaryBundleId, Path fileToNotarize) { List cmd = ImmutableList.builder() .add("xcrun", "notarytool") .add("submit") .add("--output-format", "plist") .add("--apple-id", appleIDUsername) + //.add("--team-id", appleTeamID) .add("--password", "@env:" + APPLEID_PASSWORD_ENV_VAR_NAME) .add(fileToNotarize.toString()).build(); - Path xcrunTempFolder = - Files.createTempDirectory(fileToNotarize.getParent(), - com.google.common.io.Files.getNameWithoutExtension(fileToNotarize.toString())+ "-xcrun-notarize-app-"); - - ProcessBuilder processBuilder = new ProcessBuilder().command(cmd); - processBuilder.environment().put(APPLEID_PASSWORD_ENV_VAR_NAME, appleIDPassword); - processBuilder.environment().put(TMPDIR, xcrunTempFolder.toString()); - - try(NativeProcess.Result nativeProcessResult = NativeProcess.startAndWait(processBuilder, uploadTimeout)) { - NotarizerResult result = analyzeResult(nativeProcessResult, fileToNotarize); - LOGGER.trace("Notarization upload result:\n" + result.toString()); - return result; - } catch (TimeoutException e) { - LOGGER.error("Timeout happened during notarization upload of file " + fileToNotarize, e); - throw new ExecutionException("Timeout happened during notarization upload", e); - } catch (IOException e) { - LOGGER.error("IOException happened during notarization upload of file " + fileToNotarize, e); - throw new ExecutionException("IOException happened during notarization upload", e); - } finally { - if (Files.exists(xcrunTempFolder)) { - LOGGER.trace("Deleting xcrun-notarize-app temporary folder " + xcrunTempFolder); - try (Stream filesToDelete = Files.walk(xcrunTempFolder).sorted(Comparator.reverseOrder()).map(Path::toFile)) { - filesToDelete.forEach(File::delete); - } catch (IOException e) { - LOGGER.warn("IOException happened during deletion of xcrun-notarize-app temporary folder " + xcrunTempFolder, e); - } - } - } + return cmd; } - private NotarizerResult analyzeResult(NativeProcess.Result nativeProcessResult, Path fileToNotarize) throws ExecutionException { + @Override + protected NotarizerResult analyzeSubmissionResult(NativeProcess.Result nativeProcessResult, Path fileToNotarize) throws ExecutionException { NotarizerResult.Builder resultBuilder = NotarizerResult.builder(); try { PListDict plist = PListDict.fromXML(nativeProcessResult.stdoutAsStream()); @@ -165,11 +128,7 @@ private Optional parseAppleRequestID(String message) { } @Override - public NotarizationInfoResult retrieveInfo(String appleIDUsername, - String appleIDPassword, - String appleRequestUUID, - Duration pollingTimeout, - OkHttpClient httpClient) throws ExecutionException, IOException { + protected List getInfoCommand(String appleIDUsername, String appleRequestUUID) { List cmd = ImmutableList.builder().add("xcrun", "notarytool") .add("info") @@ -179,42 +138,19 @@ public NotarizationInfoResult retrieveInfo(String appleIDUsername, .add(appleRequestUUID.toString()) .build(); - Path xcrunTempFolder = Files.createTempDirectory("-xcrun-notarization-info-"); + return cmd; + } - ProcessBuilder processBuilder = new ProcessBuilder().command(cmd); - processBuilder.environment().put(APPLEID_PASSWORD_ENV_VAR_NAME, appleIDPassword); - processBuilder.environment().put(TMPDIR, xcrunTempFolder.toString()); + @Override + protected NotarizationInfoResult analyzeInfoResult(NativeProcess.Result nativeProcessResult, + String appleRequestUUID, + OkHttpClient httpClient) throws ExecutionException { NotarizationInfoResult.Builder resultBuilder = NotarizationInfoResult.builder(); - try (NativeProcess.Result result = NativeProcess.startAndWait(processBuilder, pollingTimeout)) { - analyseResults(result, resultBuilder, appleRequestUUID, httpClient); - } catch (IOException e) { - LOGGER.error("Error while retrieving notarization info of request '" + appleRequestUUID + "'", e); - throw new ExecutionException("Failed to retrieve notarization info", e); - } catch (TimeoutException e) { - LOGGER.error("Timeout while retrieving notarization info of request '" + appleRequestUUID + "'", e); - throw new ExecutionException("Timeout while retrieving notarization info", e); - } finally { - LOGGER.trace("Deleting xcrun-notarization-info temporary folder " + xcrunTempFolder); - try (Stream filesToDelete = Files.walk(xcrunTempFolder).sorted(Comparator.reverseOrder()).map(Path::toFile)) { - filesToDelete.forEach(File::delete); - } catch (IOException e) { - LOGGER.warn("IOException happened during deletion of xcrun-notarization-info temporary folder " + xcrunTempFolder, e); - } - } - NotarizationInfoResult result = resultBuilder.build(); - LOGGER.trace("Notarization info retriever result:\n{}", result); - return result; - } - - private void analyseResults(NativeProcess.Result result, - NotarizationInfoResult.Builder resultBuilder, - String appleRequestUUID, - OkHttpClient httpClient) throws ExecutionException { try { - PListDict plist = PListDict.fromXML(result.stdoutAsStream()); + PListDict plist = PListDict.fromXML(nativeProcessResult.stdoutAsStream()); - if (result.exitValue() == 0) { + if (nativeProcessResult.exitValue() == 0) { Map notarizationInfoList = (Map) plist.get("notarization-info"); if (notarizationInfoList != null && !notarizationInfoList.isEmpty()) { parseNotarizationInfo(plist, notarizationInfoList, resultBuilder, httpClient); @@ -236,15 +172,15 @@ private void analyseResults(NativeProcess.Result result, .status(NotarizationInfoResult.Status.NOTARIZATION_IN_PROGRESS) .message("The software asset has already been uploaded. Notarization in progress"); default: - resultBuilder.message("Failed to notarize the requested file. Remote service error code = " + firstProductErrorCode.getAsInt() + " (xcrun altool exit value ="+result.exitValue()+")."); + resultBuilder.message("Failed to notarize the requested file. Remote service error code = " + firstProductErrorCode.getAsInt() + " (xcrun altool exit value ="+nativeProcessResult.exitValue()+")."); break; } } else { Optional errorMessage = plist.messageFromFirstProductError(); if (errorMessage.isPresent()) { - resultBuilder.message("Failed to notarize the requested file (xcrun altool exit value ="+result.exitValue()+"). Reason: " + errorMessage.get()); + resultBuilder.message("Failed to notarize the requested file (xcrun altool exit value ="+nativeProcessResult.exitValue()+"). Reason: " + errorMessage.get()); } else { - resultBuilder.message("Failed to notarize the requested file (xcrun altool exit value ="+result.exitValue()+")."); + resultBuilder.message("Failed to notarize the requested file (xcrun altool exit value ="+nativeProcessResult.exitValue()+")."); } } } @@ -252,6 +188,7 @@ private void analyseResults(NativeProcess.Result result, LOGGER.error("Cannot parse notarization info for request '" + appleRequestUUID + "'", e); throw new ExecutionException("Failed to retrieve notarization info.", e); } + return resultBuilder.build(); } private void parseNotarizationInfo(PListDict plist, Map notarizationInfo, diff --git a/src/test/java/org/eclipse/cbi/ws/macos/notarization/xcrun/altool/AltoolNotarizerTest.java b/src/test/java/org/eclipse/cbi/ws/macos/notarization/xcrun/altool/AltoolNotarizerTest.java new file mode 100644 index 0000000..c2e4187 --- /dev/null +++ b/src/test/java/org/eclipse/cbi/ws/macos/notarization/xcrun/altool/AltoolNotarizerTest.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2023 Eclipse Foundation and others. + * This program and the accompanying materials are made available + * under the terms of the Eclipse Public License 2.0 + * which is available at http://www.eclipse.org/legal/epl-v20.html + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.cbi.ws.macos.notarization.xcrun.altool; + +import org.eclipse.cbi.ws.macos.notarization.process.NativeProcess; +import org.eclipse.cbi.ws.macos.notarization.xcrun.common.NotarizationInfoResult; +import org.eclipse.cbi.ws.macos.notarization.xcrun.common.NotarizerResult; +import org.junit.jupiter.api.Test; + +import java.nio.file.Path; +import java.util.concurrent.ExecutionException; + +import static org.junit.jupiter.api.Assertions.*; + +public class AltoolNotarizerTest { + + @Test + public void analyzeSuccessfulSubmission() throws ExecutionException { + Path stdout = Path.of(this.getClass().getResource("submission-success.log").getPath()); + Path stderr = Path.of("non-existing"); + + NativeProcess.Result r = + NativeProcess.Result.builder() + .exitValue(0) + .arg0("") + .stdout(stdout) + .stderr(stderr) + .build(); + + NotarizerResult result = new AltoolNotarizer().analyzeSubmissionResult(r, Path.of("Alfred_5.1.2_2145.dmg")); + + assertEquals(NotarizerResult.Status.UPLOAD_SUCCESSFUL, result.status()); + assertEquals("a518bb0a-fdaa-4f73-aa09-c7a9b699ac59", result.appleRequestUUID()); + assertEquals("No errors uploading 'Alfred_5.1.2_2145.dmg'.", result.message()); + } + + @Test + public void analyzeSubmissionInProgress() throws ExecutionException { + Path stdout = Path.of(this.getClass().getResource("submission-in-progress.log").getPath()); + Path stderr = Path.of("non-existing"); + + NativeProcess.Result r = + NativeProcess.Result.builder() + .exitValue(176) + .arg0("") + .stdout(stdout) + .stderr(stderr) + .build(); + + NotarizerResult result = new AltoolNotarizer().analyzeSubmissionResult(r, Path.of("Alfred_5.1.2_2145.dmg")); + + assertEquals(NotarizerResult.Status.UPLOAD_SUCCESSFUL, result.status()); + assertEquals("a518bb0a-fdaa-4f73-aa09-c7a9b699ac59", result.appleRequestUUID()); + assertEquals("Notarization in progress (software asset has been already previously uploaded to Apple notarization service)", result.message()); + } + + @Test + public void analyzeInfoSuccess() throws ExecutionException { + Path stdout = Path.of(this.getClass().getResource("info-success.log").getPath()); + Path stderr = Path.of("non-existing"); + + NativeProcess.Result r = + NativeProcess.Result.builder() + .exitValue(0) + .arg0("") + .stdout(stdout) + .stderr(stderr) + .build(); + + // Consider using a mock HttpClient for retrieving the log + NotarizationInfoResult result = new AltoolNotarizer().analyzeInfoResult(r, "a518bb0a-fdaa-4f73-aa09-c7a9b699ac59", null); + + assertEquals(NotarizationInfoResult.Status.NOTARIZATION_SUCCESSFUL, result.status()); + assertEquals("Notarization status: Package Approved", result.message()); + assertEquals("Can not retrieve log, httpClient is null", result.notarizationLog()); + } + +} diff --git a/src/test/resources/org/eclipse/cbi/ws/macos/notarization/xcrun/altool/info-success.log b/src/test/resources/org/eclipse/cbi/ws/macos/notarization/xcrun/altool/info-success.log new file mode 100644 index 0000000..c12a6e7 --- /dev/null +++ b/src/test/resources/org/eclipse/cbi/ws/macos/notarization/xcrun/altool/info-success.log @@ -0,0 +1,31 @@ + + + + + notarization-info + + Date + 2023-09-08T11:55:28Z + Hash + d21e85f383546a7ce25f6085fdd4008d6f1a52844cd4cce19bc4b0f0b17d13de + LogFileURL + https://osxapps-ssl.itunes.apple.com/itunes-assets/Enigma116/v4/90/15/8a/90158a1d-86e1-ae0b-04d8-c7de65e87fea/developer_log.json?accessKey=1694368623_3402154590843763083_o5FbouURu6QvyEq2URhbfAHstmFeDipn8QJ8Ar2IaHB3GRqyNtYZj4BrbKXEhbyuo1oplJmHbZRropbEbU6KoHhHCrPXeYWJ1UKgagu%2FK1Hp%2F%2Figh44UexdlaSaT9KL3Fr2iepWPl%2FoT8JaEZDDYiUObbQ0I9PCepsqt%2BLl3CrM%3D + RequestUUID + a518bb0a-fdaa-4f73-aa09-c7a9b699ac59 + Status + success + Status Code + 0 + Status Message + Package Approved + + os-version + 10.16.0 + success-message + No errors getting notarization info. + tool-path + /Applications/Xcode.app/Contents/SharedFrameworks/ContentDeliveryServices.framework/Versions/A/Frameworks/AppStoreService.framework + tool-version + 4.00.1181 + + diff --git a/src/test/resources/org/eclipse/cbi/ws/macos/notarization/xcrun/altool/submission-in-progress.log b/src/test/resources/org/eclipse/cbi/ws/macos/notarization/xcrun/altool/submission-in-progress.log new file mode 100644 index 0000000..216aab6 --- /dev/null +++ b/src/test/resources/org/eclipse/cbi/ws/macos/notarization/xcrun/altool/submission-in-progress.log @@ -0,0 +1,30 @@ + + + + + os-version + 10.16.0 + product-errors + + + code + -18000 + message + ERROR ITMS-90732: "The software asset has already been uploaded. The upload ID is a518bb0a-fdaa-4f73-aa09-c7a9b699ac59" at SoftwareAssets/EnigmaSoftwareAsset + userInfo + + NSLocalizedDescription + ERROR ITMS-90732: "The software asset has already been uploaded. The upload ID is a518bb0a-fdaa-4f73-aa09-c7a9b699ac59" at SoftwareAssets/EnigmaSoftwareAsset + NSLocalizedFailureReason + ERROR ITMS-90732: "The software asset has already been uploaded. The upload ID is a518bb0a-fdaa-4f73-aa09-c7a9b699ac59" at SoftwareAssets/EnigmaSoftwareAsset + NSLocalizedRecoverySuggestion + ERROR ITMS-90732: "The software asset has already been uploaded. The upload ID is a518bb0a-fdaa-4f73-aa09-c7a9b699ac59" at SoftwareAssets/EnigmaSoftwareAsset + + + + tool-path + /Applications/Xcode.app/Contents/SharedFrameworks/ContentDeliveryServices.framework/Versions/A/Frameworks/AppStoreService.framework + tool-version + 4.00.1181 + + diff --git a/src/test/resources/org/eclipse/cbi/ws/macos/notarization/xcrun/altool/submission-success.log b/src/test/resources/org/eclipse/cbi/ws/macos/notarization/xcrun/altool/submission-success.log new file mode 100644 index 0000000..22cebf5 --- /dev/null +++ b/src/test/resources/org/eclipse/cbi/ws/macos/notarization/xcrun/altool/submission-success.log @@ -0,0 +1,19 @@ + + + + + notarization-upload + + RequestUUID + a518bb0a-fdaa-4f73-aa09-c7a9b699ac59 + + os-version + 10.16.0 + success-message + No errors uploading 'Alfred_5.1.2_2145.dmg'. + tool-path + /Applications/Xcode.app/Contents/SharedFrameworks/ContentDeliveryServices.framework/Versions/A/Frameworks/AppStoreService.framework + tool-version + 4.00.1181 + +