diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 6ed0ea4..9d465c1 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -7,6 +7,14 @@ name: Reusable - Docker Publish (chunked) # 100 MB Cloudflare limit): blobs larger than `blob-chunk` are split into # multiple smaller PATCH requests instead of one monolithic PUT. # The pushed image is optionally signed keyless with cosign via GitHub OIDC. +# +# Pure, toolchain-agnostic Docker build: it only turns a `context`/Dockerfile +# into a pushed image. Any project (Flutter, Node, Go, a plain multi-stage +# Dockerfile, …) can reuse it. There is no language/build step here on purpose. +# The context comes from either: +# - the checked-out repository (e.g. a self-contained multi-stage Dockerfile), or +# - a pre-built artifact (`artifact-name`) produced by an upstream job, e.g. +# `gradle-docker-context.yml` for Gradle/Micronaut optimized contexts. on: workflow_call: @@ -29,26 +37,15 @@ on: required: false type: string default: "" - build-command: - description: "Optional shell command run before the docker build to produce the context (e.g. a Gradle task). The version is available as $VERSION." + artifact-name: + description: | + Optional name of an artifact (uploaded by an upstream job in the same + run) to download into `context` before building. Use this to consume a + pre-built context, e.g. from gradle-docker-context.yml. Leave empty to + build straight from the checked-out repository. required: false type: string default: "" - setup-java: - description: "Set up JDK + Gradle before running build-command (for Gradle-produced contexts)" - required: false - type: boolean - default: false - java-version: - description: "JDK version to use when setup-java is true" - required: false - type: string - default: "25" - java-distribution: - description: "JDK distribution (temurin, zulu, ...)" - required: false - type: string - default: "temurin" extra-tags: description: "Additional docker/metadata-action tag lines appended to the default semver + sha tags" required: false @@ -128,25 +125,12 @@ jobs: run: | echo "image=${HARBOR_REGISTRY}/${IMAGE_NAME}" >> "$GITHUB_OUTPUT" - - name: Validate Gradle wrapper - if: ${{ inputs.setup-java }} - uses: gradle/actions/wrapper-validation@v6 - - - name: Set up JDK ${{ inputs.java-version }} - if: ${{ inputs.setup-java }} - uses: actions/setup-java@v5 + - name: Download context artifact + if: ${{ inputs.artifact-name != '' }} + uses: actions/download-artifact@v4 with: - distribution: ${{ inputs.java-distribution }} - java-version: ${{ inputs.java-version }} - - - name: Setup Gradle - if: ${{ inputs.setup-java }} - uses: gradle/actions/setup-gradle@v6 - - - name: Build context - if: ${{ inputs.build-command != '' }} - shell: bash - run: ${{ inputs.build-command }} + name: ${{ inputs.artifact-name }} + path: ${{ inputs.context }} - name: Docker meta id: meta diff --git a/.github/workflows/gradle-docker-context.yml b/.github/workflows/gradle-docker-context.yml new file mode 100644 index 0000000..f64c330 --- /dev/null +++ b/.github/workflows/gradle-docker-context.yml @@ -0,0 +1,120 @@ +name: Reusable - Gradle Docker Context + +# Builds a Docker build context with a Gradle/Micronaut toolchain and uploads it +# as an artifact for a downstream docker-publish.yml job to consume. This keeps +# docker-publish.yml toolchain-agnostic: all JDK/Gradle concerns live here. +# +# Typical use (Micronaut optimized context): +# gradle-command: "./gradlew jar optimizedBuildLayers optimizedDockerfile -Pversion=$VERSION" +# context-path: "build/docker/optimized" +# Then docker-publish.yml is called with the same `artifact-name` and a matching +# `context`. + +on: + workflow_call: + inputs: + gradle-command: + description: "Gradle command that produces the Docker context. $VERSION is exported from the version input." + required: true + type: string + version: + description: "Version exported as $VERSION for the build" + required: true + type: string + context-path: + description: "Directory produced by the build to upload as the context artifact, e.g. 'build/docker/optimized'" + required: true + type: string + artifact-name: + description: "Name of the uploaded context artifact (pass the same value to docker-publish's artifact-name)" + required: false + type: string + default: "docker-context" + java-version: + description: "JDK version to use" + required: false + type: string + default: "25" + java-distribution: + description: "JDK distribution (temurin, zulu, ...)" + required: false + type: string + default: "temurin" + validate-wrapper: + description: "Run gradle wrapper validation before building" + required: false + type: boolean + default: true + retention-days: + description: "How long to keep the context artifact (it is only needed for the downstream docker job in the same run)" + required: false + type: number + default: 1 + runs-on: + description: "Runner image" + required: false + type: string + default: "ubuntu-latest" + secrets: + # Optional credentials for the private OneLiteFeather Maven repository, + # mirroring gradle-publish.yml. Required only when the build resolves + # private artifacts. + ONELITEFEATHER_MAVEN_USERNAME: + required: false + ONELITEFEATHER_MAVEN_PASSWORD: + required: false + outputs: + artifact-name: + description: "Name of the uploaded context artifact" + value: ${{ inputs.artifact-name }} + +concurrency: + group: gradle-docker-context-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: false + +permissions: + contents: read + +jobs: + build-context: + name: Build Docker context (Gradle) + runs-on: ${{ inputs.runs-on }} + env: + VERSION: ${{ inputs.version }} + ONELITEFEATHER_MAVEN_USERNAME: ${{ secrets.ONELITEFEATHER_MAVEN_USERNAME }} + ONELITEFEATHER_MAVEN_PASSWORD: ${{ secrets.ONELITEFEATHER_MAVEN_PASSWORD }} + GRADLE_OPTS: "-Dorg.gradle.parallel=true -Dorg.gradle.caching=true -Dorg.gradle.welcome=never" + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Validate Gradle wrapper + if: ${{ inputs.validate-wrapper }} + uses: gradle/actions/wrapper-validation@v6 + + - name: Set up JDK ${{ inputs.java-version }} + uses: actions/setup-java@v5 + with: + distribution: ${{ inputs.java-distribution }} + java-version: ${{ inputs.java-version }} + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v6 + + - name: Build context + shell: bash + run: | + if [ "${RUNNER_DEBUG:-0}" = "1" ]; then + ${{ inputs.gradle-command }} --info --stacktrace + else + ${{ inputs.gradle-command }} + fi + + - name: Upload context artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ inputs.artifact-name }} + path: ${{ inputs.context-path }} + if-no-files-found: error + include-hidden-files: true + retention-days: ${{ inputs.retention-days }}