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

Support proguard mapping upload for any JVM app #403

Open
romtsn opened this issue Nov 7, 2022 · 11 comments
Open

Support proguard mapping upload for any JVM app #403

romtsn opened this issue Nov 7, 2022 · 11 comments

Comments

@romtsn
Copy link
Member

romtsn commented Nov 7, 2022

Description

Since compose-desktop receives more and more traction, and people usually like to minify their apps (to reduce the final .jar size, and also to optimize their bytecode), we should look into how to provide automatic support for uploading proguard/R8 mapping files.

Since there's no standardized way of using proguard/r8 with pure JVM apps, I guess we'll need to provide some configuration option, which task to depend on or where is the location of the mapping file.

This is also valid for any JVM desktop app (JavaFX, Swing, etc.) that uses a minification tool.

@alexstyl
Copy link

alexstyl commented Nov 7, 2022

Thanks for opening this issue @romtsn

For future reference, you can specify where you want the mapping file to be stored by passing a custom proguard configuration like this:

// desktop/build.gradle.kts

compose.desktop {
        // your app's configuration 

        buildTypes.release.proguard {
            obfuscate.set(true)
            configurationFiles.from(project.file("compose-desktop.pro"))
        }
    }
}

and in your compose-desktop.pro file. use the -printmapping option (see the doc):

-printmapping mapping.txt

# your other proguard configurations & rules

@leonard84
Copy link

(Moved from #429)

Problem Statement

Currently, sentry only has a Gradle plugin for Android builds that integrates tightly into AGP.

We are developing Java applications, and want to use the release announcement, the proguard mapping file upload, and source map upload functionality in a regular java Gradle build.

Solution Brainstorm

Extract common functionality from the sentry-android-gradle-plugin into a shared component and create a sentry-gradle-plugin that offers tasks to announce a release as well as upload proguard mapping files. These tasks should be able to accept all the required and optional parameters of the CLI commands. It should also register an extension to configure common parameters across the default tasks, such as the auth token.

@romtsn
Copy link
Member Author

romtsn commented Feb 6, 2023

@leonard84 thanks for moving it here. Could you please give more details about how you use proguard/r8? Is it through a custom task or through a gradle plugin (if so, which one)? Just wanna know better which tasks do we have to hook with. Thanks

@leonard84
Copy link

It is a custom subclass of the official proguard.gradle.ProGuardTask to fix some issues with build caching that the original has.

@Nohus
Copy link

Nohus commented Dec 19, 2023

While I appreciate that having this upload functionality in a Gradle plugin could be useful for someone, why can't we just upload the mapping files on the web interface?

My expectation was that when I open a Sentry issue with an obfuscated stracktrace, Sentry would show a prompt like "we don't have a mapping file for version 1.2.3, click to upload", and let me upload my mapping-1.2.3.txt right then.

I don't even use the Gradle plugin in my project and don't see a need to complicate my build.

@adinauer
Copy link
Member

adinauer commented Dec 19, 2023

@Nohus thanks for the feedback.

You could try to manually upload your mapping files to Sentry using CI. We have sentry-cli which allows you to upload. Here's how we use it to upload mapping files from the Gradle plugin. There's some docs available as well.

You'd also have to specify io.sentry.ProguardUuids or use setProguardUuid so events sent to Sentry know which mapping file should be used. Both the upload and running applications need to know the UUID of the mapping file.

As for doing this after the fact. That's currenlty not possible as events are processed as they come in so adding the mapping file after events arrived won't change the events as it is implemented now. There were discussions around doing source lookup when looking at events in the Sentry UI instead of doing it during processing but as far as I know nothing has been implemented yet and there's no ETA for this change. Applying mapping files could work the same way but since you'd have to keep versioned mapping files around then manually upload them and add the UUID to the running application anyways, I'd suggest setting up CI to do the upload for you using sentry-cli as suggested above.

@Nohus
Copy link

Nohus commented Dec 19, 2023

Thank you for the information and links, I have used sentry-cli to upload the mapping file from my CI and it is working correctly now.

@sproctor
Copy link

sproctor commented Feb 1, 2024

@Nohus Can you share how you did this? I'm working on the same thing currently.

@getsantry getsantry bot moved this to Waiting for: Product Owner in GitHub Issues with 👀 2 Feb 1, 2024
@Nohus
Copy link

Nohus commented Feb 2, 2024

@sproctor This is the gist of it:

# Create release on Sentry
sentry-cli releases new \
    --project "app" \
    --finalize "app@$version"

# Upload ProGuard mapping
sentry-cli upload-proguard \
    --uuid "$buildUuid" \
    "build/mapping-$version.txt" \
    --require-one \
    --project "app" \
    --app-id "app" \
    --platform "kotlin" \
    --version "$version" \

@sproctor
Copy link

sproctor commented Feb 6, 2024

This was about half of it. I'll add my solution here for anyone else interested. I had a terrible time getting a properties file generated. It worked fine locally but not on CI.

Gradle task:

abstract class SentryGenerateProguardUuidTask : DefaultTask() {

    init {
        outputs.upToDateWhen { false }
    }

    @get:Input
    abstract val output: Property<File>

    @TaskAction
    fun createUuidFile() {
        val outputFile = output.get()
        val uuid = UUID.randomUUID()
        val props = Properties().also {
            it.setProperty("io.sentry.ProguardUuids", uuid.toString())
        }
        outputFile.writer().use { writer ->
            props.store(writer, "")
        }
        logger.info("SentryGenerateProguardUuidTask - outputFile: ${outputFile.absolutePath}, uuid: $uuid")
    }
}

tasks {
    val sentryUuid = register<SentryGenerateProguardUuidTask>("sentryUuid") {
        dependsOn("processResources")
        output.set(layout.buildDirectory.file("resources/main/sentry_proguard_uuid.properties").get().asFile)
    }

    compileKotlin {
        dependsOn(sentryUuid)
    }
}

Github action:

...
      - name: Setup Sentry CLI
        run: npm install @sentry/cli

      - name: Upload mapping
        shell: bash
        run: |
          SENTRY=node_modules/.bin/sentry-cli
          VERSION=${GITHUB_REF_NAME:1}
          while IFS='=' read -r key value
          do
            key=$(echo $key | tr '.' '_')
            value=$(echo $value | tr -d '\n\r')
            eval ${key}=\${value}
          done < app/build/resources/main/sentry_proguard_uuid.properties
          $SENTRY releases new --project "app" --org "org" --finalize "desktop@$VERSION" --auth-token "${{ secrets.SENTRY_AUTH_TOKEN }}"
          $SENTRY upload-proguard --uuid "$io_sentry_ProguardUuids" "app/build/mapping.txt" --require-one --project "app" --org "org" --app-id "desktop" --platform "kotlin" --version "$VERSION" --auth-token "${{ secrets.SENTRY_AUTH_TOKEN }}"

@getsantry getsantry bot moved this to Waiting for: Product Owner in GitHub Issues with 👀 2 Feb 6, 2024
@adinauer
Copy link
Member

adinauer commented Feb 7, 2024

Thanks for sharing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: No status
Status: Backlog
Development

No branches or pull requests

8 participants