|
6 | 6 | import java.io.InputStream; |
7 | 7 | import java.nio.file.Files; |
8 | 8 | import java.nio.file.Path; |
9 | | -import java.nio.file.StandardCopyOption; |
10 | 9 | import java.util.UUID; |
11 | 10 | import java.util.logging.Level; |
12 | 11 | import java.util.logging.Logger; |
@@ -72,34 +71,54 @@ private void captureScreenshots(ExtensionContext context) { |
72 | 71 | if (driver instanceof TakesScreenshot) { |
73 | 72 | source = new ByteArrayInputStream(((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES)); |
74 | 73 | } |
75 | | - try { |
76 | | - final File destinationDir = new File(screenshotFolder, context.getRequiredTestClass().getName()); |
77 | | - destinationDir.mkdirs(); |
78 | | - final File destination = new File(destinationDir, filename + SCREENSHOT_FILE_EXTENSION); |
79 | | - // copy screenshot |
80 | | - Files.copy(source, destination.toPath(), StandardCopyOption.REPLACE_EXISTING); |
81 | | - // base folder as Path (correct way) |
82 | | - final Path base = screenshotFolder.toPath().toAbsolutePath().normalize(); |
83 | | - final Path file = destination.toPath().toAbsolutePath().normalize(); |
84 | | - // relative path for Jenkins attachment plugin |
85 | | - final Path relative = base.relativize(file); |
86 | | - // ATTENTION: required for JUnit Attachment Plugin |
87 | | - final String attachmentLine = String.format(ATTACHMENT_FORMAT, relative.toString().replace("\\", "/")); |
88 | | - System.out.println(attachmentLine); |
89 | | - System.out.flush(); // replaced System.out may not auto-flush |
90 | | - // duplicate to System.err because tycho-surefire may read test stuff from there |
91 | | - System.err.println(attachmentLine); |
92 | | - System.err.flush(); // replaced System.err may not auto-flush |
93 | | - } catch (IOException exception) { |
94 | | - throw new RuntimeException(exception); |
95 | | - } |
| 74 | + final File destinationDir = new File(screenshotFolder, context.getRequiredTestClass().getName()); |
| 75 | + destinationDir.mkdirs(); |
| 76 | + final File destination = new File(destinationDir, filename + SCREENSHOT_FILE_EXTENSION); |
| 77 | + // Absolute path to the screenshot file |
| 78 | + final Path absoluteFile = destination.toPath().toAbsolutePath().normalize(); |
| 79 | + // Jenkins JUnit Attachments Plugin resolves [[ATTACHMENT|<path>]] markers against |
| 80 | + // the build's workspace root ($WORKSPACE), not against the directory containing the |
| 81 | + // JUnit XML. So we relativize against the workspace root (the repo root, identified |
| 82 | + // by walking up to the enclosing .git directory) and emit a workspace-relative path. |
| 83 | + final Path workspaceRoot = findWorkspaceRoot(absoluteFile); |
| 84 | + final Path attachmentPath = workspaceRoot != null |
| 85 | + ? workspaceRoot.relativize(absoluteFile) |
| 86 | + : screenshotFolder.toPath().toAbsolutePath().normalize().relativize(absoluteFile); |
| 87 | + // ATTENTION: required for JUnit Attachment Plugin |
| 88 | + final String attachmentLine = String.format(ATTACHMENT_FORMAT, |
| 89 | + attachmentPath.toString().replace("\\", "/")) + System.lineSeparator(); |
| 90 | + System.out.print(attachmentLine); |
| 91 | + System.out.flush(); |
| 92 | + System.err.print(attachmentLine); |
| 93 | + System.err.flush(); |
96 | 94 | } catch (Exception e) { |
97 | 95 | logger.log(Level.WARNING, "Could not capture screenshot for window: " + window.getWindowHandle(), e); |
98 | 96 | } |
99 | 97 | }); |
100 | 98 | } |
101 | 99 | } |
102 | | - |
| 100 | + |
| 101 | + /** |
| 102 | + * Walks up from the given path until it finds a directory containing a {@code .git} |
| 103 | + * entry (file or directory — submodule worktrees use a file). Returns that ancestor |
| 104 | + * directory, which corresponds to the Jenkins build workspace root for repository |
| 105 | + * checkouts. Returns {@code null} if no such ancestor exists (e.g. running outside |
| 106 | + * any git checkout), in which case callers should fall back to a different base. |
| 107 | + */ |
| 108 | + private static Path findWorkspaceRoot(final Path startFrom) { |
| 109 | + Path current = startFrom.toAbsolutePath().normalize(); |
| 110 | + if (Files.isRegularFile(current)) { |
| 111 | + current = current.getParent(); |
| 112 | + } |
| 113 | + while (current != null) { |
| 114 | + if (Files.exists(current.resolve(".git"))) { |
| 115 | + return current; |
| 116 | + } |
| 117 | + current = current.getParent(); |
| 118 | + } |
| 119 | + return null; |
| 120 | + } |
| 121 | + |
103 | 122 | private InputStream getScreenshotNotSupportedImage() { |
104 | 123 | return AbstractSeleniumTest.class.getResourceAsStream(NOT_SUPPORTED_IMAGE); |
105 | 124 | } |
|
0 commit comments