-
Notifications
You must be signed in to change notification settings - Fork 39
migrate to central portal and add github workflows #45
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
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| name: CI | ||
|
|
||
| on: | ||
| push: | ||
| branches: [ master ] | ||
| pull_request: | ||
| branches: [ master ] | ||
|
|
||
| jobs: | ||
| test: | ||
| runs-on: ubuntu-latest | ||
| strategy: | ||
| matrix: | ||
| java-version: ['8', '11', '17', '21'] | ||
|
|
||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Set up JDK ${{ matrix.java-version }} | ||
| uses: actions/setup-java@v4 | ||
| with: | ||
| java-version: ${{ matrix.java-version }} | ||
| distribution: 'temurin' | ||
|
|
||
| - name: Cache Maven dependencies | ||
| uses: actions/cache@v4 | ||
| with: | ||
| path: ~/.m2/repository | ||
| key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} | ||
| restore-keys: | | ||
| ${{ runner.os }}-maven- | ||
|
|
||
| - name: Run tests | ||
| run: mvn clean test | ||
|
|
||
| - name: Build project | ||
| run: mvn clean package | ||
|
|
||
| - name: Generate JavaDoc | ||
| run: mvn javadoc:javadoc | ||
|
|
||
| - name: Upload test results | ||
| if: always() | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: test-results-java-${{ matrix.java-version }} | ||
| path: target/surefire-reports/ | ||
|
|
||
| code-quality: | ||
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Set up JDK 8 | ||
| uses: actions/setup-java@v4 | ||
| with: | ||
| java-version: '8' | ||
| distribution: 'temurin' | ||
|
|
||
| - name: Cache Maven dependencies | ||
| uses: actions/cache@v4 | ||
| with: | ||
| path: ~/.m2/repository | ||
| key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} | ||
| restore-keys: | | ||
| ${{ runner.os }}-maven- | ||
|
|
||
| - name: Check for dependency updates | ||
| run: mvn versions:display-dependency-updates |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,144 @@ | ||
| name: Release to Maven Central | ||
|
|
||
| on: | ||
| push: | ||
| tags: | ||
| - 'v*' | ||
| workflow_dispatch: | ||
| inputs: | ||
| version: | ||
| description: 'Version to release (e.g., 1.5.4)' | ||
| required: true | ||
| type: string | ||
|
|
||
| jobs: | ||
| release: | ||
| runs-on: ubuntu-latest | ||
| outputs: | ||
| version: ${{ steps.set-version.outputs.version }} | ||
|
|
||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Set up JDK 8 | ||
| uses: actions/setup-java@v4 | ||
| with: | ||
| java-version: '8' | ||
| distribution: 'temurin' | ||
|
|
||
| - name: Cache Maven dependencies | ||
| uses: actions/cache@v4 | ||
| with: | ||
| path: ~/.m2/repository | ||
| key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} | ||
| restore-keys: | | ||
| ${{ runner.os }}-maven- | ||
|
|
||
| - name: Import GPG key | ||
| env: | ||
| GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} | ||
| GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} | ||
| run: | | ||
| echo "$GPG_PRIVATE_KEY" | base64 --decode | gpg --batch --import | ||
| echo "allow-preset-passphrase" >> ~/.gnupg/gpg-agent.conf | ||
| echo "pinentry-mode loopback" >> ~/.gnupg/gpg.conf | ||
| gpg --list-secret-keys --keyid-format LONG | ||
|
|
||
| - name: Configure Maven settings | ||
| env: | ||
| MAVEN_CENTRAL_USERNAME: ${{ secrets.MAVEN_CENTRAL_USERNAME }} | ||
| MAVEN_CENTRAL_TOKEN: ${{ secrets.MAVEN_CENTRAL_TOKEN }} | ||
| run: | | ||
| mkdir -p ~/.m2 | ||
| cat > ~/.m2/settings.xml << EOF | ||
| <settings> | ||
| <servers> | ||
| <server> | ||
| <id>central</id> | ||
| <username>${MAVEN_CENTRAL_USERNAME}</username> | ||
| <password>${MAVEN_CENTRAL_TOKEN}</password> | ||
| </server> | ||
| </servers> | ||
| </settings> | ||
| EOF | ||
|
|
||
| - name: Set version from tag | ||
| id: set-version | ||
| if: startsWith(github.ref, 'refs/tags/') | ||
| run: | | ||
| VERSION=${GITHUB_REF#refs/tags/v} | ||
| echo "VERSION=$VERSION" >> $GITHUB_ENV | ||
| echo "version=$VERSION" >> $GITHUB_OUTPUT | ||
| mvn versions:set -DnewVersion=$VERSION -DgenerateBackupPoms=false | ||
|
|
||
| - name: Set version from input | ||
| id: set-version-input | ||
| if: github.event_name == 'workflow_dispatch' | ||
| run: | | ||
| VERSION=${{ github.event.inputs.version }} | ||
| echo "VERSION=$VERSION" >> $GITHUB_ENV | ||
| echo "version=$VERSION" >> $GITHUB_OUTPUT | ||
| mvn versions:set -DnewVersion=$VERSION -DgenerateBackupPoms=false | ||
|
|
||
| - name: Run tests | ||
| run: mvn clean test | ||
|
|
||
| - name: Deploy to Maven Central | ||
| env: | ||
| GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} | ||
| run: | | ||
| mvn clean deploy -Dgpg.passphrase=$GPG_PASSPHRASE | ||
|
|
||
| - name: Create GitHub Release | ||
| if: startsWith(github.ref, 'refs/tags/') | ||
| uses: actions/github-script@v7 | ||
| with: | ||
| github-token: ${{ secrets.GITHUB_TOKEN }} | ||
| script: | | ||
| const releaseBody = `## Mixpanel Java SDK v${process.env.VERSION} | ||
|
|
||
| ### Maven | ||
| \`\`\`xml | ||
| <dependency> | ||
| <groupId>com.mixpanel</groupId> | ||
| <artifactId>mixpanel-java</artifactId> | ||
| <version>${process.env.VERSION}</version> | ||
| </dependency> | ||
| \`\`\` | ||
|
|
||
| ### Changes | ||
| See [CHANGELOG](https://github.com/mixpanel/mixpanel-java/blob/master/CHANGELOG.md) for details. | ||
|
|
||
| ### Links | ||
| - [Maven Central](https://central.sonatype.com/artifact/com.mixpanel/mixpanel-java/${process.env.VERSION}) | ||
| - [JavaDoc](http://mixpanel.github.io/mixpanel-java/)`; | ||
|
|
||
| await github.rest.repos.createRelease({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| tag_name: context.ref.replace('refs/tags/', ''), | ||
| name: `Release ${process.env.VERSION}`, | ||
| body: releaseBody, | ||
| draft: false, | ||
| prerelease: false | ||
| }); | ||
|
|
||
| verify: | ||
| needs: release | ||
| runs-on: ubuntu-latest | ||
| if: success() | ||
|
|
||
| steps: | ||
| - name: Wait for Maven Central sync | ||
| run: sleep 300 # Wait 5 minutes for synchronization | ||
|
|
||
| - name: Verify artifact on Maven Central | ||
| run: | | ||
| VERSION=${{ needs.release.outputs.version }} | ||
| RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" https://repo1.maven.org/maven2/com/mixpanel/mixpanel-java/${VERSION}/mixpanel-java-${VERSION}.jar) | ||
| if [ $RESPONSE -eq 200 ]; then | ||
| echo "✅ Artifact successfully published to Maven Central" | ||
| else | ||
| echo "⚠️ Artifact not yet available on Maven Central (HTTP $RESPONSE). This is normal - it may take up to 30 minutes to appear." | ||
| fi | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,158 @@ | ||
| # CLAUDE.md | ||
|
|
||
| This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. | ||
|
|
||
| ## Project Overview | ||
|
|
||
| This is the official Mixpanel tracking library for Java - a production-ready library for sending analytics events and user profile updates to Mixpanel from Java server-side applications. | ||
|
|
||
| ## Release Process | ||
|
|
||
| ### Quick Commands for Releases | ||
|
|
||
| ```bash | ||
| # 1. Update version (remove -SNAPSHOT from pom.xml) | ||
| mvn versions:set -DnewVersion=1.5.4 | ||
|
|
||
| # 2. Run tests | ||
| mvn clean test | ||
|
|
||
| # 3. Deploy to Maven Central Portal | ||
| mvn clean deploy | ||
|
|
||
| # 4. After release, prepare next version | ||
| mvn versions:set -DnewVersion=1.5.5-SNAPSHOT | ||
| ``` | ||
|
|
||
| ### Key Files | ||
| - **RELEASE.md**: Complete release documentation with step-by-step instructions | ||
| - **.github/workflows/release.yml**: Automated release workflow triggered by version tags | ||
| - **.github/workflows/ci.yml**: Continuous integration for all PRs and master commits | ||
|
|
||
| ### Maven Central Portal | ||
| - The project uses the new Maven Central Portal (not the deprecated OSSRH) | ||
| - Deployments are visible at: https://central.sonatype.com/publishing/deployments | ||
| - Published artifacts: https://central.sonatype.com/artifact/com.mixpanel/mixpanel-java | ||
|
|
||
| ### Required GitHub Secrets for CI/CD | ||
| - `GPG_PRIVATE_KEY`: Base64-encoded GPG private key | ||
| - `GPG_PASSPHRASE`: GPG key passphrase | ||
| - `MAVEN_CENTRAL_USERNAME`: Maven Central Portal username | ||
| - `MAVEN_CENTRAL_TOKEN`: Maven Central Portal token | ||
|
|
||
| ## Build and Development Commands | ||
|
|
||
| ```bash | ||
| # Build the project and create JAR | ||
| mvn clean package | ||
|
|
||
| # Run all tests | ||
| mvn test | ||
|
|
||
| # Run a specific test class | ||
| mvn test -Dtest=MixpanelAPITest | ||
|
|
||
| # Run a specific test method | ||
| mvn test -Dtest=MixpanelAPITest#testBuildEventMessage | ||
|
|
||
| # Install to local Maven repository | ||
| mvn install | ||
|
|
||
| # Generate JavaDoc | ||
| mvn javadoc:javadoc | ||
|
|
||
| # Clean build artifacts | ||
| mvn clean | ||
|
|
||
| # Run the demo application (after building) | ||
| java -cp target/mixpanel-java-1.5.3.jar:target/classes:lib/json-20231013.jar com.mixpanel.mixpanelapi.demo.MixpanelAPIDemo <YOUR_MIXPANEL_TOKEN> | ||
jaredmixpanel marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ``` | ||
|
|
||
| ## High-Level Architecture | ||
|
|
||
| ### Core Design Pattern | ||
| The library implements a **Producer-Consumer** pattern with intentional thread separation: | ||
|
|
||
| 1. **Message Production** (`MessageBuilder`): Creates properly formatted JSON messages on application threads | ||
| 2. **Message Batching** (`ClientDelivery`): Collects messages into efficient batches (max 50 per request) | ||
| 3. **Message Transmission** (`MixpanelAPI`): Sends batched messages to Mixpanel servers | ||
|
|
||
| This separation allows for flexible threading models - the library doesn't impose any specific concurrency pattern, letting applications control their own threading strategy. | ||
|
|
||
| ### Key Architectural Decisions | ||
|
|
||
| **No Built-in Threading**: Unlike some analytics libraries, this one doesn't start background threads. Applications must manage their own async patterns, as demonstrated in `MixpanelAPIDemo` which uses a `ConcurrentLinkedQueue` with producer/consumer threads. | ||
|
|
||
| **Message Format Validation**: `MessageBuilder` performs validation during message construction, throwing `MixpanelMessageException` for malformed data before network transmission. | ||
|
|
||
| **Batch Encoding**: Messages are JSON-encoded, then Base64-encoded, then URL-encoded for HTTP POST transmission. This triple encoding ensures compatibility with Mixpanel's API requirements. | ||
|
|
||
| **Network Communication**: Uses Java's built-in `java.net.URL` and `URLConnection` classes - no external HTTP client dependencies. Connection timeout is 2 seconds, read timeout is 10 seconds. | ||
|
|
||
| ### Message Types and Endpoints | ||
|
|
||
| The library supports three message categories, each sent to different endpoints: | ||
|
|
||
| - **Events** (`/track`): User actions and behaviors | ||
| - **People** (`/engage`): User profile updates (set, increment, append, etc.) | ||
| - **Groups** (`/groups`): Group profile updates | ||
|
|
||
| Each message type has specific JSON structure requirements validated by `MessageBuilder`. | ||
|
|
||
| ## Package Structure | ||
|
|
||
| All production code is in the `com.mixpanel.mixpanelapi` package: | ||
|
|
||
| - `MixpanelAPI`: HTTP communication with Mixpanel servers | ||
| - `MessageBuilder`: Constructs and validates JSON messages | ||
| - `ClientDelivery`: Batches multiple messages for efficient transmission | ||
| - `Config`: Contains API endpoints and configuration constants | ||
| - `Base64Coder`: Base64 encoding utility (modified third-party code) | ||
| - `MixpanelMessageException`: Runtime exception for message format errors | ||
| - `MixpanelServerException`: IOException for server rejection responses | ||
|
|
||
| ## Testing Approach | ||
|
|
||
| Tests extend JUnit 4's `TestCase` and are located in `MixpanelAPITest`. The test suite covers: | ||
|
|
||
| - Message format validation for all message types | ||
| - Property operations (set, setOnce, increment, append, union, remove, unset) | ||
| - Large batch delivery behavior | ||
| - Encoding verification | ||
| - Error conditions and exception handling | ||
|
|
||
| When adding new functionality, follow the existing test patterns - each message type operation has corresponding test methods that verify both the JSON structure and the encoded format. | ||
|
|
||
| ## Common Development Tasks | ||
|
|
||
| ### Adding a New Message Type | ||
| 1. Add the message construction method to `MessageBuilder` | ||
| 2. Validate required fields and structure | ||
| 3. Add corresponding tests in `MixpanelAPITest` | ||
| 4. Update `ClientDelivery` if special handling is needed | ||
|
|
||
| ### Modifying Network Behavior | ||
| Network configuration is centralized in `MixpanelAPI.sendData()`. Connection and read timeouts are hardcoded but could be made configurable by modifying the `Config` class. | ||
|
|
||
| ### Debugging Failed Deliveries | ||
| The library throws `MixpanelServerException` with the HTTP response code and server message. Check: | ||
| 1. Token validity in `MessageBuilder` constructor | ||
| 2. Message size (batches limited to 50 messages) | ||
| 3. JSON structure using the test suite patterns | ||
|
|
||
| ## Dependencies | ||
|
|
||
| The library has minimal dependencies: | ||
| - **Production**: `org.json:json:20231013` for JSON manipulation | ||
| - **Test**: `junit:junit:4.13.2` for unit testing | ||
| - **Java Version**: Requires Java 8 or higher | ||
|
|
||
| ## API Patterns to Follow | ||
|
|
||
| When working with this codebase: | ||
|
|
||
| 1. **Immutable Messages**: Once created by `MessageBuilder`, JSON messages should not be modified | ||
| 2. **Fail Fast**: Validate message structure early in `MessageBuilder` rather than during transmission | ||
| 3. **Preserve Thread Safety**: `MessageBuilder` instances are NOT thread-safe; create one per thread | ||
| 4. **Batch Appropriately**: `ClientDelivery` handles batching; don't exceed 50 messages per delivery | ||
| 5. **Exception Handling**: Distinguish between `MixpanelMessageException` (client error) and `MixpanelServerException` (server error) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The release job doesn't define any outputs, so
needs.release.outputs.versionwill be undefined. The VERSION should be retrieved from the environment variable set in the release job or passed as a job output.