diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 000000000000..fc50cc051553 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,15 @@ +# Use the official dev container base image +FROM mcr.microsoft.com/devcontainers/base:bookworm + +# Set up gradle cache directory +RUN mkdir -p /home/vscode/.gradle +RUN chown -R vscode:vscode /home/vscode/.gradle + +# Switch to vscode user +USER vscode + +# Create gradle cache directory +RUN mkdir -p ~/.gradle + +# Final workspace setup +WORKDIR /workspace \ No newline at end of file diff --git a/.devcontainer/README.md b/.devcontainer/README.md new file mode 100644 index 000000000000..ac74637cd307 --- /dev/null +++ b/.devcontainer/README.md @@ -0,0 +1,31 @@ +# Development Container Configuration + +This directory contains the development container configuration for the OpenTelemetry Java Instrumentation project. The dev container is designed to address the issue where Copilot agents timeout due to long build times (>5 minutes) by preinstalling dependencies and optimizing the build environment. + +## What this solves + +- **Faster builds**: Pre-downloads Gradle dependencies and sets up optimized build configurations +- **Consistent environment**: Ensures all developers and Copilot agents use the same Java/Gradle versions +- **Reduced timeouts**: Eliminates the need to download dependencies during each build + +## Files + +- `devcontainer.json`: Main configuration file defining the development container +- `Dockerfile`: Custom container image with pre-installed dependencies +- `post-create.sh`: Script that runs after container creation to optimize the environment +- `README.md`: This documentation file + +## How it works + +1. **Base Image**: Uses Microsoft's generic dev container base with Java 21 via dev container features +2. **Post-creation Setup**: Downloads Gradle dependencies during container startup +3. **Optimization**: Sets up Gradle daemon with optimized JVM settings +4. **Node.js**: Installs Node.js 16 via dev container features for Vaadin tests +5. **Dependency Caching**: Attempts to resolve and cache dependencies after container creation + +## Usage + +The dev container will automatically be used by: +- GitHub Copilot agents +- VS Code with Dev Containers extension +- Any tool that supports dev containers \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000000..9dd0ecbee8b5 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,32 @@ +{ + "name": "OpenTelemetry Java Instrumentation Dev Environment", + "build": { + "dockerfile": "Dockerfile", + "context": ".." + }, + "customizations": { + "vscode": { + "extensions": [ + "vscjava.vscode-java-pack", + "vscjava.vscode-gradle", + "ms-vscode.gradle" + ] + } + }, + "features": { + "ghcr.io/devcontainers/features/java:1": { + "version": "21" + }, + "ghcr.io/devcontainers/features/node:1": { + "version": "16" + } + }, + "postCreateCommand": ".devcontainer/post-create.sh", + "remoteUser": "vscode", + "containerEnv": { + "GRADLE_USER_HOME": "/home/vscode/.gradle" + }, + "mounts": [ + "source=opentelemetry-gradle-cache,target=/home/vscode/.gradle,type=volume" + ] +} \ No newline at end of file diff --git a/.devcontainer/post-create.sh b/.devcontainer/post-create.sh new file mode 100755 index 000000000000..ea500b33d338 --- /dev/null +++ b/.devcontainer/post-create.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +# This script runs after the dev container is created +# It performs additional dependency pre-loading to speed up builds + +echo "Setting up OpenTelemetry Java Instrumentation development environment..." + +# Ensure we're in the right directory +cd /workspace + +# Install pnpm for vaadin tests (Node.js installed via devcontainer features) +echo "Installing pnpm..." +npm install -g pnpm + +# Download Gradle wrapper and start daemon +echo "Starting Gradle daemon..." +./gradlew --version + +# Try to run the custom resolveDependencies task with timeout +echo "Pre-downloading some dependencies..." +timeout 180 ./gradlew resolveDependencies --no-daemon --parallel || echo "Dependency resolution completed or timed out" + +# As a fallback, try to just compile the basic Gradle plugins +echo "Pre-compiling build scripts..." +timeout 120 ./gradlew help --no-daemon || echo "Help task completed or timed out" + +echo "Development environment setup complete!" +echo "The Gradle daemon is now warmed up and build times should be faster." \ No newline at end of file diff --git a/.github/workflows/build-common.yml b/.github/workflows/build-common.yml index b23ff7e5ee35..3414c1747bf4 100644 --- a/.github/workflows/build-common.yml +++ b/.github/workflows/build-common.yml @@ -21,6 +21,10 @@ on: secrets: FLAKY_TEST_REPORTER_ACCESS_KEY: required: false + S3_BUILD_CACHE_ACCESS_KEY_ID: + required: false + S3_BUILD_CACHE_SECRET_ACCESS_KEY: + required: false permissions: contents: read @@ -195,6 +199,9 @@ jobs: - name: Build # javadoc task fails sporadically fetching https://docs.oracle.com/javase/8/docs/api/ + env: + S3_BUILD_CACHE_ACCESS_KEY_ID: ${{ secrets.S3_BUILD_CACHE_ACCESS_KEY_ID }} + S3_BUILD_CACHE_SECRET_ACCESS_KEY: ${{ secrets.S3_BUILD_CACHE_SECRET_ACCESS_KEY }} run: ./gradlew check spdxSbom -x javadoc -x spotlessCheck -PskipTests=true ${{ inputs.no-build-cache && '--no-build-cache' || '' }} - name: Check for jApiCmp diffs @@ -322,6 +329,9 @@ jobs: - name: Test # spotless is checked separately since it's a common source of failure + env: + S3_BUILD_CACHE_ACCESS_KEY_ID: ${{ secrets.S3_BUILD_CACHE_ACCESS_KEY_ID }} + S3_BUILD_CACHE_SECRET_ACCESS_KEY: ${{ secrets.S3_BUILD_CACHE_SECRET_ACCESS_KEY }} run: > ./gradlew ${{ env.test-tasks }} @@ -440,9 +450,15 @@ jobs: - name: Build # running suite "none" compiles everything needed by smoke tests without executing any tests # --no-daemon is used to free up the memory from the build step before running the test step below + env: + S3_BUILD_CACHE_ACCESS_KEY_ID: ${{ secrets.S3_BUILD_CACHE_ACCESS_KEY_ID }} + S3_BUILD_CACHE_SECRET_ACCESS_KEY: ${{ secrets.S3_BUILD_CACHE_SECRET_ACCESS_KEY }} run: ./gradlew :smoke-tests:test -PsmokeTestSuite=none --no-daemon ${{ inputs.no-build-cache && ' --no-build-cache' || '' }} - name: Test + env: + S3_BUILD_CACHE_ACCESS_KEY_ID: ${{ secrets.S3_BUILD_CACHE_ACCESS_KEY_ID }} + S3_BUILD_CACHE_SECRET_ACCESS_KEY: ${{ secrets.S3_BUILD_CACHE_SECRET_ACCESS_KEY }} run: ./gradlew :smoke-tests:test -PsmokeTestSuite=${{ matrix.smoke-test-suite }} ${{ inputs.no-build-cache && ' --no-build-cache' || '' }} - name: Build scan @@ -489,6 +505,9 @@ jobs: cache-read-only: ${{ inputs.cache-read-only }} - name: Build + env: + S3_BUILD_CACHE_ACCESS_KEY_ID: ${{ secrets.S3_BUILD_CACHE_ACCESS_KEY_ID }} + S3_BUILD_CACHE_SECRET_ACCESS_KEY: ${{ secrets.S3_BUILD_CACHE_SECRET_ACCESS_KEY }} run: ./gradlew build ${{ inputs.no-build-cache && '--no-build-cache' || '' }} working-directory: gradle-plugins @@ -513,25 +532,43 @@ jobs: - name: Local publish of artifacts # javadoc task fails sporadically fetching https://docs.oracle.com/javase/8/docs/api/ + env: + S3_BUILD_CACHE_ACCESS_KEY_ID: ${{ secrets.S3_BUILD_CACHE_ACCESS_KEY_ID }} + S3_BUILD_CACHE_SECRET_ACCESS_KEY: ${{ secrets.S3_BUILD_CACHE_SECRET_ACCESS_KEY }} run: ./gradlew publishToMavenLocal -x javadoc - name: Local publish of gradle plugins # javadoc task fails sporadically fetching https://docs.oracle.com/javase/8/docs/api/ + env: + S3_BUILD_CACHE_ACCESS_KEY_ID: ${{ secrets.S3_BUILD_CACHE_ACCESS_KEY_ID }} + S3_BUILD_CACHE_SECRET_ACCESS_KEY: ${{ secrets.S3_BUILD_CACHE_SECRET_ACCESS_KEY }} run: ./gradlew publishToMavenLocal -x javadoc working-directory: gradle-plugins - name: Build distro + env: + S3_BUILD_CACHE_ACCESS_KEY_ID: ${{ secrets.S3_BUILD_CACHE_ACCESS_KEY_ID }} + S3_BUILD_CACHE_SECRET_ACCESS_KEY: ${{ secrets.S3_BUILD_CACHE_SECRET_ACCESS_KEY }} run: ./gradlew build --init-script ../../.github/scripts/local.init.gradle.kts ${{ inputs.no-build-cache && ' --no-build-cache' || '' }} working-directory: examples/distro - name: Build extension + env: + S3_BUILD_CACHE_ACCESS_KEY_ID: ${{ secrets.S3_BUILD_CACHE_ACCESS_KEY_ID }} + S3_BUILD_CACHE_SECRET_ACCESS_KEY: ${{ secrets.S3_BUILD_CACHE_SECRET_ACCESS_KEY }} run: ./gradlew build --init-script ../../.github/scripts/local.init.gradle.kts ${{ inputs.no-build-cache && ' --no-build-cache' || '' }} working-directory: examples/extension - name: Build benchmark-overhead + env: + S3_BUILD_CACHE_ACCESS_KEY_ID: ${{ secrets.S3_BUILD_CACHE_ACCESS_KEY_ID }} + S3_BUILD_CACHE_SECRET_ACCESS_KEY: ${{ secrets.S3_BUILD_CACHE_SECRET_ACCESS_KEY }} run: ./gradlew assemble ${{ inputs.no-build-cache && ' --no-build-cache' || '' }} working-directory: benchmark-overhead - name: Run muzzle check against extension + env: + S3_BUILD_CACHE_ACCESS_KEY_ID: ${{ secrets.S3_BUILD_CACHE_ACCESS_KEY_ID }} + S3_BUILD_CACHE_SECRET_ACCESS_KEY: ${{ secrets.S3_BUILD_CACHE_SECRET_ACCESS_KEY }} run: ./gradlew muzzle --init-script ../../.github/scripts/local.init.gradle.kts working-directory: examples/extension diff --git a/.github/workflows/build-daily-no-build-cache.yml b/.github/workflows/build-daily-no-build-cache.yml index 652df1d810b6..9854a9d29d96 100644 --- a/.github/workflows/build-daily-no-build-cache.yml +++ b/.github/workflows/build-daily-no-build-cache.yml @@ -16,6 +16,8 @@ jobs: no-build-cache: true secrets: FLAKY_TEST_REPORTER_ACCESS_KEY: ${{ secrets.FLAKY_TEST_REPORTER_ACCESS_KEY }} + S3_BUILD_CACHE_ACCESS_KEY_ID: ${{ secrets.S3_BUILD_CACHE_ACCESS_KEY_ID }} + S3_BUILD_CACHE_SECRET_ACCESS_KEY: ${{ secrets.S3_BUILD_CACHE_SECRET_ACCESS_KEY }} test-latest-deps: uses: ./.github/workflows/reusable-test-latest-deps.yml diff --git a/.github/workflows/build-daily.yml b/.github/workflows/build-daily.yml index 7d76d7c02f8e..06163a1138dc 100644 --- a/.github/workflows/build-daily.yml +++ b/.github/workflows/build-daily.yml @@ -14,6 +14,8 @@ jobs: uses: ./.github/workflows/build-common.yml secrets: FLAKY_TEST_REPORTER_ACCESS_KEY: ${{ secrets.FLAKY_TEST_REPORTER_ACCESS_KEY }} + S3_BUILD_CACHE_ACCESS_KEY_ID: ${{ secrets.S3_BUILD_CACHE_ACCESS_KEY_ID }} + S3_BUILD_CACHE_SECRET_ACCESS_KEY: ${{ secrets.S3_BUILD_CACHE_SECRET_ACCESS_KEY }} test-latest-deps: uses: ./.github/workflows/reusable-test-latest-deps.yml diff --git a/.github/workflows/build-pull-request.yml b/.github/workflows/build-pull-request.yml index 121405d721a0..b12f15aff411 100644 --- a/.github/workflows/build-pull-request.yml +++ b/.github/workflows/build-pull-request.yml @@ -23,6 +23,9 @@ jobs: skip-openj9-tests: ${{ !contains(github.event.pull_request.labels.*.name, 'test openj9') }} skip-windows-smoke-tests: ${{ !contains(github.event.pull_request.labels.*.name, 'test windows') }} cache-read-only: true + secrets: + S3_BUILD_CACHE_ACCESS_KEY_ID: ${{ secrets.S3_BUILD_CACHE_ACCESS_KEY_ID }} + S3_BUILD_CACHE_SECRET_ACCESS_KEY: ${{ secrets.S3_BUILD_CACHE_SECRET_ACCESS_KEY }} test-latest-deps: uses: ./.github/workflows/reusable-test-latest-deps.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c99f34412c79..1e401d872a84 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,6 +15,8 @@ jobs: uses: ./.github/workflows/build-common.yml secrets: FLAKY_TEST_REPORTER_ACCESS_KEY: ${{ secrets.FLAKY_TEST_REPORTER_ACCESS_KEY }} + S3_BUILD_CACHE_ACCESS_KEY_ID: ${{ secrets.S3_BUILD_CACHE_ACCESS_KEY_ID }} + S3_BUILD_CACHE_SECRET_ACCESS_KEY: ${{ secrets.S3_BUILD_CACHE_SECRET_ACCESS_KEY }} test-latest-deps: # release branches are excluded @@ -84,6 +86,8 @@ jobs: SONATYPE_KEY: ${{ secrets.SONATYPE_KEY }} GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} GPG_PASSWORD: ${{ secrets.GPG_PASSWORD }} + S3_BUILD_CACHE_ACCESS_KEY_ID: ${{ secrets.S3_BUILD_CACHE_ACCESS_KEY_ID }} + S3_BUILD_CACHE_SECRET_ACCESS_KEY: ${{ secrets.S3_BUILD_CACHE_SECRET_ACCESS_KEY }} run: ./gradlew assemble spdxSbom publishToSonatype - name: Build and publish gradle plugin snapshots @@ -92,5 +96,7 @@ jobs: SONATYPE_KEY: ${{ secrets.SONATYPE_KEY }} GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} GPG_PASSWORD: ${{ secrets.GPG_PASSWORD }} + S3_BUILD_CACHE_ACCESS_KEY_ID: ${{ secrets.S3_BUILD_CACHE_ACCESS_KEY_ID }} + S3_BUILD_CACHE_SECRET_ACCESS_KEY: ${{ secrets.S3_BUILD_CACHE_SECRET_ACCESS_KEY }} run: ./gradlew build publishToSonatype working-directory: gradle-plugins diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 876e9792a663..fa9fa7abf666 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,6 +8,9 @@ permissions: jobs: common: uses: ./.github/workflows/build-common.yml + secrets: + S3_BUILD_CACHE_ACCESS_KEY_ID: ${{ secrets.S3_BUILD_CACHE_ACCESS_KEY_ID }} + S3_BUILD_CACHE_SECRET_ACCESS_KEY: ${{ secrets.S3_BUILD_CACHE_SECRET_ACCESS_KEY }} # test-latest-deps is intentionally not included in the release workflows # because any time a new library version is released to maven central diff --git a/.gitignore b/.gitignore index 308ea9e1651f..7478ab0507d1 100644 --- a/.gitignore +++ b/.gitignore @@ -59,6 +59,10 @@ replay_pid* .attach_pid* .telemetry* .lycheecache +build-scan.txt + +# Kotlin compiler sessions +**/.kotlin/sessions/ !java-agent/benchmark/releases/*.jar diff --git a/build.gradle.kts b/build.gradle.kts index d31dbfc326db..33572ccc9984 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -123,6 +123,25 @@ if (gradle.startParameter.taskNames.contains("listTestsInPartition")) { tasks { val stableVersion = version.toString().replace("-alpha", "") + val resolveDependencies by registering { + group = "Help" + description = "Resolve and download all dependencies for faster builds" + + doLast { + allprojects { + configurations.configureEach { + if (isCanBeResolved) { + try { + resolve() + } catch (e: Exception) { + logger.warn("Could not resolve configuration $name: ${e.message}") + } + } + } + } + } + } + val generateFossaConfiguration by registering { group = "Help" description = "Generate .fossa.yml configuration file" diff --git a/settings.gradle.kts b/settings.gradle.kts index 3ee0dd86e302..59591a82451a 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -8,6 +8,7 @@ pluginManagement { id("org.xbib.gradle.plugin.jflex") version "3.0.2" id("org.unbroken-dome.xjc") version "2.0.0" id("org.graalvm.buildtools.native") version "0.10.6" + id("com.github.burrunan.s3-build-cache") version "1.8.2" } } @@ -21,6 +22,7 @@ plugins { // ./gradlew :smoke-tests:images:servlet:buildWindowsTestImages pushMatrix -PsmokeTestServer=jetty id("com.bmuschko.docker-remote-api") version "9.4.0" apply false id("com.gradle.develocity") version "4.1" + id("com.github.burrunan.s3-build-cache") version "1.8.2" } dependencyResolutionManagement { @@ -64,6 +66,26 @@ develocity { } } +buildCache { + remote { + region = "us-phoenix-1" + bucket = "opentelemetry-java-instrumentation-build-cache" + endpoint = "https://objectstorage.us-phoenix-1.oraclecloud.com" + + // Configure credentials for write access + val accessKeyId = System.getenv("S3_BUILD_CACHE_ACCESS_KEY_ID") + val secretAccessKey = System.getenv("S3_BUILD_CACHE_SECRET_ACCESS_KEY") + + if (!accessKeyId.isNullOrEmpty() && !secretAccessKey.isNullOrEmpty()) { + awsAccessKeyId = accessKeyId + awsSecretKey = secretAccessKey + isPush = true + } else { + isPush = false + } + } +} + rootProject.name = "opentelemetry-java-instrumentation" includeBuild("conventions")