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

Escape spaces in paths #64

Merged
merged 10 commits into from
May 3, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
8 changes: 6 additions & 2 deletions .github/workflows/pre-merge.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ jobs:
os: [ ubuntu-latest, macos-latest ]
fail-fast: false
runs-on: ${{ matrix.os }}
env:
SENTRY_URL: http://127.0.0.1:8000

steps:
- name: Checkout Repo
Expand All @@ -25,5 +27,7 @@ jobs:
distribution: 'temurin'
java-version: '17'

- name: Build the Release variant
run: ./mvnw clean verify -PintegrationTests
- name: Build the Release variant, run integration tests
run: |
test/integration-test-server-start.sh &
./mvnw clean verify -PintegrationTests
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
### Fixes

- Fix `isSaas` check for telemetry ([#66](https://github.com/getsentry/sentry-maven-plugin/pull/66))
- Escape spaces in paths ([#64](https://github.com/getsentry/sentry-maven-plugin/pull/64))

### Features

Expand Down
7 changes: 4 additions & 3 deletions src/main/java/io/sentry/UploadSourceBundleMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -135,15 +135,16 @@ private void bundleSources(

bundleSourcesCommand.add("debug-files");
bundleSourcesCommand.add("bundle-jvm");
bundleSourcesCommand.add("--output=" + sourceBundleTargetDir.getAbsolutePath());
bundleSourcesCommand.add(
"--output=" + cliRunner.escape(sourceBundleTargetDir.getAbsolutePath()));
bundleSourcesCommand.add("--debug-id=" + bundleId);
if (org != null) {
bundleSourcesCommand.add("--org=" + org);
}
if (project != null) {
bundleSourcesCommand.add("--project=" + project);
}
bundleSourcesCommand.add(sourceRoot);
bundleSourcesCommand.add(cliRunner.escape(sourceRoot));

cliRunner.runSentryCli(String.join(" ", bundleSourcesCommand), true);
} else {
Expand Down Expand Up @@ -190,7 +191,7 @@ private void uploadSourceBundle(
if (project != null) {
command.add("--project=" + project);
}
command.add(sourceBundleTargetDir.getAbsolutePath());
command.add(cliRunner.escape(sourceBundleTargetDir.getAbsolutePath()));

cliRunner.runSentryCli(String.join(" ", command), true);
} catch (Throwable t) {
Expand Down
44 changes: 38 additions & 6 deletions src/main/java/io/sentry/cli/SentryCliRunner.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@ public SentryCliRunner(
public @Nullable String runSentryCli(
final @NotNull String sentryCliCommand, final boolean failOnError)
throws MojoExecutionException {
final boolean isWindows =
System.getProperty("os.name").toLowerCase(Locale.ROOT).startsWith("windows");
final boolean isWindows = isWindows();

final @NotNull String executable = isWindows ? "cmd.exe" : "/bin/sh";
final @NotNull String cArg = isWindows ? "/c" : "-c";
Expand All @@ -65,16 +64,17 @@ public SentryCliRunner(
attributes(
attribute("executable", executable),
attribute("failOnError", String.valueOf(failOnError)),
attribute("output", logFile.getAbsolutePath())),
attribute("output", escape(logFile.getAbsolutePath()))),
element(name("arg"), attributes(attribute("value", cArg))),
element(
name("arg"),
attributes(
attribute(
"value",
getCliPath(mavenProject, sentryCliExecutablePath)
+ " "
+ sentryCliCommand)))))),
wrapForWindows(
escape(getCliPath(mavenProject, sentryCliExecutablePath))
+ " "
+ sentryCliCommand))))))),
executionEnvironment(mavenProject, mavenSession, pluginManager));

return collectAndMaybePrintOutput(logFile, debugSentryCli);
Expand All @@ -92,6 +92,38 @@ public SentryCliRunner(
}
}

private static boolean isWindows() {
final boolean isWindows =
System.getProperty("os.name").toLowerCase(Locale.ROOT).startsWith("windows");
return isWindows;
}

private @Nullable String wrapForWindows(final @Nullable String toWrap) {
// Wrap whole command in double quotes as Windows cmd will remove the first and last double
// quote
if (toWrap != null && isWindows()) {
return "\"" + toWrap + "\"";
} else {
return toWrap;
}
}

public @Nullable String escape(final @Nullable String escapePath) {
if (escapePath == null) {
return null;
}
if (isWindows()) {
// Wrap paths that contain a whitespace in double quotes
// For some reason wrapping paths that do not contain a whitespace leads to an error
if (escapePath.contains(" ")) {
return "\"" + escapePath + "\"";
}
return escapePath;
} else {
return escapePath.replaceAll(" ", "\\\\ ");
}
}

private @Nullable String collectAndMaybePrintOutput(
final @NotNull File logFile, final boolean shouldPrint) {
try {
Expand Down
66 changes: 66 additions & 0 deletions src/test/java/io/sentry/integration/cli/PomUtils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package io.sentry.integration.cli

fun basePom(
skipPlugin: Boolean = false,
skipSourceBundle: Boolean = false,
sentryCliPath: String? = null,
): String {
return """
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>io.sentry.maven</groupId>
<artifactId>cli-tests</artifactId>
<version>1.0-SNAPSHOT</version>

<packaging>jar</packaging>

<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>

<dependencies>
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-java</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>io.sentry</groupId>
<artifactId>sentry-graphql</artifactId>
<version>6.32.0</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>io.sentry</groupId>
<artifactId>sentry-maven-plugin</artifactId>
<version>1.0-SNAPSHOT</version>
<extensions>true</extensions>
<configuration>
<debugSentryCli>true</debugSentryCli>
<skip>$skipPlugin</skip>
<skipSourceBundle>$skipSourceBundle</skipSourceBundle>
<skipTelemetry>true</skipTelemetry>
<org>sentry-sdks</org>
<project>sentry-maven</project>
<authToken>\&lt;token\&gt;</authToken>
${if (sentryCliPath.isNullOrBlank()) "" else "<sentryCliExecutablePath>$sentryCliPath</sentryCliExecutablePath>"}
</configuration>
<executions>
<execution>
<goals>
<goal>uploadSourceBundle</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
""".trimIndent()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package io.sentry.integration.cli

import io.sentry.SentryCliProvider
import io.sentry.integration.installMavenWrapper
import org.apache.maven.it.VerificationException
import org.apache.maven.it.Verifier
import org.apache.maven.project.MavenProject
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.io.TempDir
import java.io.File
import java.io.FileInputStream
import java.io.IOException
import java.nio.charset.Charset
import java.nio.file.Files
import java.nio.file.StandardOpenOption
import java.util.Properties
import kotlin.io.path.Path
import kotlin.io.path.absolutePathString
import kotlin.test.assertEquals
import kotlin.test.assertTrue

class SentryCliWhitespacesTestIT {
@TempDir()
lateinit var file: File

fun getPOM(
baseDir: File,
skipPlugin: Boolean = false,
skipSourceBundle: Boolean = false,
sentryCliPath: String? = null,
): String {
val pomContent = basePom(skipPlugin, skipSourceBundle, sentryCliPath)

Files.write(Path("${baseDir.absolutePath}/pom.xml"), pomContent.toByteArray(), StandardOpenOption.CREATE)

return baseDir.absolutePath
}

@Test
@Throws(VerificationException::class, IOException::class)
fun sentryCliExecutionInProjectPathWithSpaces() {
val baseDir = setupProject()
val path = getPOM(baseDir)
val verifier = Verifier(path)
verifier.isAutoclean = false
verifier.executeGoal("install")
verifier.verifyErrorFreeLog()

val output = verifier.loadLines(verifier.logFileName, Charset.defaultCharset().name()).joinToString("\n")

val uploadedId = getUploadedBundleIdFromLog(output)
val bundleId = getBundleIdFromProperties(baseDir.absolutePath)

assertEquals(bundleId, uploadedId, "Bundle ID from properties file should match the one from the log")

verifier.resetStreams()
}

@Test
@Throws(VerificationException::class, IOException::class)
fun sentryCliExecutionInProjectAndCliPathWithSpaces() {
val cliPath = SentryCliProvider.getCliPath(MavenProject(), null)
val baseDir = setupProject()
val cliPathWithSpaces = Files.copy(Path(cliPath), Path(baseDir.absolutePath, "sentry-cli"))
cliPathWithSpaces.toFile().setExecutable(true)

val path = getPOM(baseDir, sentryCliPath = cliPathWithSpaces.absolutePathString())

val verifier = Verifier(path)
verifier.isAutoclean = false
verifier.executeGoal("install")
verifier.verifyErrorFreeLog()

val output = verifier.loadLines(verifier.logFileName, Charset.defaultCharset().name()).joinToString("\n")

val uploadedId = getUploadedBundleIdFromLog(output)
val bundleId = getBundleIdFromProperties(baseDir.absolutePath)

assertEquals(bundleId, uploadedId, "Bundle ID from properties file should match the one from the log")

verifier.resetStreams()
}

private fun setupProject(): File {
val baseDir = File(file, "base with spaces")
val srcDir = File(baseDir, "/src/main/java")
val srcFile = File(srcDir, "Main.java")
val baseDirResult = baseDir.mkdir()
val srcDirResult = srcDir.mkdirs()
val srcFileResult = srcFile.createNewFile()

assertTrue(baseDirResult, "Error creating base directory")
assertTrue(srcDirResult, "Error creating source directory")
assertTrue(srcFileResult, "Error creating source file")
installMavenWrapper(baseDir, "3.8.6")

return baseDir
}

private fun getUploadedBundleIdFromLog(output: String): String? {
val uploadedIdRegex = """\w+":\{"state":"ok","missingChunks":\[],"uploaded_id":"(\w+-\w+-\w+-\w+-\w+)""".toRegex()
return uploadedIdRegex.find(output)?.groupValues?.get(1)
}

private fun getBundleIdFromProperties(baseDir: String): String {
val myProps = Properties()
myProps.load(FileInputStream("$baseDir/target/sentry/properties/sentry-debug-meta.properties"))
return myProps.getProperty("io.sentry.bundle-ids")
}
}
10 changes: 10 additions & 0 deletions test/assets/artifact.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"id": "fixture-id",
"sha1": "fixture-sha1",
"name": "fixture-name",
"size": 1,
"dist": null,
"headers": {
"fixture-header-key": "fixture-header-value"
}
}
22 changes: 22 additions & 0 deletions test/assets/artifacts.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[
{
"id": "6796495645",
"name": "~/dist/bundle.min.js",
"dist": "foo",
"headers": {
"Sourcemap": "dist/bundle.min.js.map"
},
"size": 497,
"sha1": "2fb719956748ab7ec5ae9bcb47606733f5589b72",
"dateCreated": "2022-05-12T11:08:01.520199Z"
},
{
"id": "6796495646",
"name": "~/dist/bundle.min.js.map",
"dist": "foo",
"headers": {},
"size": 1522,
"sha1": "f818059cbf617a8fae9b4e46d08f6c0246bb1624",
"dateCreated": "2022-05-12T11:08:01.496220Z"
}
]
5 changes: 5 additions & 0 deletions test/assets/assemble-artifacts-response.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"state": "ok",
"missingChunks": [],
"detail": null
}
15 changes: 15 additions & 0 deletions test/assets/associate-dsyms-response.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"associatedDsymFiles": [
{
"uuid": null,
"debugId": null,
"objectName": "fixture-objectName",
"cpuName": "fixture-cpuName",
"sha1": "fixture-sha1",
"data": {
"type": null,
"features": ["fixture-feature"]
}
}
]
}
13 changes: 13 additions & 0 deletions test/assets/debug-info-files.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[
{
"uuid": null,
"debugId": null,
"objectName": "fixture-objectName",
"cpuName": "fixture-cpuName",
"sha1": "fixture-sha1",
"data": {
"type": null,
"features": ["fixture-feature"]
}
}
]
8 changes: 8 additions & 0 deletions test/assets/deploy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"id": "1",
"environment": "production",
"dateStarted": null,
"dateFinished": "2022-01-01T12:00:00.000000Z",
"name": "fixture-deploy",
"url": null
}
Loading
Loading