diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 4a92a94..1c35bd5 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -14,9 +14,25 @@ env: ARTIFACT_NAME: algorithm-exercises-cpp_${{ github.sha }} jobs: + setup: + name: "Setup matrix" + runs-on: ubuntu-26.04 + outputs: + matrix: ${{ steps.set-matrix.outputs.matrix }} + steps: + - name: Set base images matrix + id: set-matrix + run: | + echo 'matrix={"base_image":["alpine","debian","ubuntu"]}' \ + >> "$GITHUB_OUTPUT" + build-lint: - name: "Build Docker LINT image" + name: "Build Docker LINT image (${{ matrix.base_image }})" runs-on: ubuntu-26.04 + needs: setup + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.setup.outputs.matrix) }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 @@ -27,19 +43,26 @@ jobs: uses: docker/build-push-action@v7 with: context: . + file: Dockerfile.${{ matrix.base_image }} target: lint - outputs: | - type=docker,dest=/tmp/${{ env.ARTIFACT_NAME }}_lint.tar + outputs: + # yamllint disable-line rule:line-length + type=docker,dest=/tmp/${{ env.ARTIFACT_NAME }}_${{ matrix.base_image }}_lint.tar tags: | - ${{ env.IMAGE_NAME }}:lint + ${{ env.IMAGE_NAME }}-${{ matrix.base_image }}:lint - name: "LINT: Upload artifact" uses: actions/upload-artifact@v7 with: - name: ${{ env.ARTIFACT_NAME }}_lint - path: /tmp/${{ env.ARTIFACT_NAME }}_lint.tar + name: ${{ env.ARTIFACT_NAME }}_${{ matrix.base_image }}_lint + path: /tmp/${{ env.ARTIFACT_NAME }}_${{ matrix.base_image }}_lint.tar + build-test: - name: "Build Docker TEST image" + name: "Build Docker TEST image (${{ matrix.base_image }})" runs-on: ubuntu-26.04 + needs: setup + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.setup.outputs.matrix) }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 @@ -50,20 +73,26 @@ jobs: uses: docker/build-push-action@v7 with: context: . + file: Dockerfile.${{ matrix.base_image }} target: testing - outputs: | - type=docker,dest=/tmp/${{ env.ARTIFACT_NAME }}_test.tar + outputs: + # yamllint disable-line rule:line-length + type=docker,dest=/tmp/${{ env.ARTIFACT_NAME }}_${{ matrix.base_image }}_test.tar tags: | - ${{ env.IMAGE_NAME }}:test + ${{ env.IMAGE_NAME }}-${{ matrix.base_image }}:test - name: "TEST: Upload artifact" uses: actions/upload-artifact@v7 with: - name: ${{ env.ARTIFACT_NAME }}_test - path: /tmp/${{ env.ARTIFACT_NAME }}_test.tar + name: ${{ env.ARTIFACT_NAME }}_${{ matrix.base_image }}_test + path: /tmp/${{ env.ARTIFACT_NAME }}_${{ matrix.base_image }}_test.tar build-prod: - name: "Build Docker PRODUCTION image" + name: "Build Docker PRODUCTION image (${{ matrix.base_image }})" runs-on: ubuntu-26.04 + needs: setup + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.setup.outputs.matrix) }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 @@ -73,17 +102,19 @@ jobs: uses: docker/build-push-action@v7 with: context: . + file: Dockerfile.${{ matrix.base_image }} target: production - outputs: | - type=docker,dest=/tmp/${{ env.ARTIFACT_NAME }}_prod.tar + outputs: + # yamllint disable-line rule:line-length + type=docker,dest=/tmp/${{ env.ARTIFACT_NAME }}_${{ matrix.base_image }}_prod.tar tags: | - ${{ env.IMAGE_NAME }}:latest - ${{ env.IMAGE_NAME }}:${{ github.sha }} + ${{ env.IMAGE_NAME }}:latest-${{ matrix.base_image }} + ${{ env.IMAGE_NAME }}:${{ github.sha }}-${{ matrix.base_image }} - name: "PRODUCTION: Upload artifact" uses: actions/upload-artifact@v7 with: - name: ${{ env.ARTIFACT_NAME }}_prod - path: /tmp/${{ env.ARTIFACT_NAME }}_prod.tar + name: ${{ env.ARTIFACT_NAME }}_${{ matrix.base_image }}_prod + path: /tmp/${{ env.ARTIFACT_NAME }}_${{ matrix.base_image }}_prod.tar run-lint-markdown: name: "Run in docker: Markdown LINT" @@ -116,53 +147,65 @@ jobs: make compose/lint/json run-lint: - name: "Run in docker: LINT" + name: "Run in docker: LINT (${{ matrix.base_image }})" runs-on: ubuntu-26.04 - needs: build-lint + needs: [setup, build-lint] + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.setup.outputs.matrix) }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - name: Download artifact uses: actions/download-artifact@v8 with: - name: ${{ env.ARTIFACT_NAME }}_lint + name: ${{ env.ARTIFACT_NAME }}_${{ matrix.base_image }}_lint path: /tmp/ - name: Load image + env: + # yamllint disable-line rule:line-length + ARTIFACT_FILE: "${{ env.ARTIFACT_NAME }}_${{ matrix.base_image }}_lint.tar" run: | - docker load --input /tmp/${{ env.ARTIFACT_NAME }}_lint.tar + docker load --input /tmp/${{ env.ARTIFACT_FILE }} docker image ls -a - name: Run lint + env: + BASE_IMAGE: ${{ matrix.base_image }} run: > docker - compose --profile lint - run --rm ${{ env.IMAGE_NAME }}-lint + run --rm ${{ env.IMAGE_NAME }}-${{ matrix.base_image }}:lint make lint-no-deps run-test: - name: "Run in docker: TEST" + name: "Run in docker: TEST (${{ matrix.base_image }})" runs-on: ubuntu-26.04 - needs: build-test + needs: [setup, build-test] + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.setup.outputs.matrix) }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - name: Download artifact uses: actions/download-artifact@v8 with: - name: ${{ env.ARTIFACT_NAME }}_test + name: ${{ env.ARTIFACT_NAME }}_${{ matrix.base_image }}_test path: /tmp/ - name: Load image + env: + # yamllint disable-line rule:line-length + ARTIFACT_FILE: "${{ env.ARTIFACT_NAME }}_${{ matrix.base_image }}_test.tar" run: | - docker load --input /tmp/${{ env.ARTIFACT_NAME }}_test.tar + docker load --input /tmp/${{ env.ARTIFACT_FILE }} docker image ls -a - name: Run test run: > docker - compose --profile test - run --rm ${{ env.IMAGE_NAME }}-test + run --rm ${{ env.IMAGE_NAME }}-${{ matrix.base_image }}:test make test-no-deps # yamllint disable rule:line-length @@ -216,9 +259,12 @@ jobs: # yamllint enable rule:line-length scan: - name: "Trivy" + name: "Trivy (${{ matrix.base_image }})" runs-on: ubuntu-26.04 - needs: build-prod + needs: [setup, build-prod] + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.setup.outputs.matrix) }} permissions: actions: read contents: read @@ -227,18 +273,22 @@ jobs: - name: Download artifact uses: actions/download-artifact@v8 with: - name: ${{ env.ARTIFACT_NAME }}_prod + name: ${{ env.ARTIFACT_NAME }}_${{ matrix.base_image }}_prod path: /tmp/ - name: Load image + env: + # yamllint disable-line rule:line-length + ARTIFACT_FILE: "${{ env.ARTIFACT_NAME }}_${{ matrix.base_image }}_prod.tar" run: | - docker load --input /tmp/${{ env.ARTIFACT_NAME }}_prod.tar + docker load --input /tmp/${{ env.ARTIFACT_FILE }} docker image ls -a - name: Run Trivy vulnerability scanner (cli report) uses: aquasecurity/trivy-action@v0.36.0 with: - image-ref: ${{ env.IMAGE_NAME }}:${{ github.sha }} + # yamllint disable-line rule:line-length + image-ref: ${{ env.IMAGE_NAME }}:${{ github.sha }}-${{ matrix.base_image }} format: "table" env: TRIVY_DB_REPOSITORY: ${{ vars.TRIVY_DB_REPOSITORY }} @@ -246,13 +296,14 @@ jobs: - name: Run Trivy vulnerability scanner (sarif report) uses: aquasecurity/trivy-action@v0.36.0 with: - image-ref: ${{ env.IMAGE_NAME }}:${{ github.sha }} + # yamllint disable-line rule:line-length + image-ref: ${{ env.IMAGE_NAME }}:${{ github.sha }}-${{ matrix.base_image }} format: "sarif" - output: "trivy-results.sarif" + output: "trivy-results-${{ matrix.base_image }}.sarif" env: TRIVY_DB_REPOSITORY: ${{ vars.TRIVY_DB_REPOSITORY }} - name: Upload Trivy scan results to GitHub Security tab uses: github/codeql-action/upload-sarif@v4 with: - sarif_file: "trivy-results.sarif" + sarif_file: "trivy-results-${{ matrix.base_image }}.sarif" diff --git a/.github/workflows/hadolint.yml b/.github/workflows/hadolint.yml index bbaef80..a85d716 100644 --- a/.github/workflows/hadolint.yml +++ b/.github/workflows/hadolint.yml @@ -16,7 +16,7 @@ on: # yamllint disable-line rule:truthy # The branches below must be a subset of the branches above branches: ["main"] schedule: - - cron: '33 15 * * 3' + - cron: "33 15 * * 3" permissions: contents: read @@ -33,6 +33,12 @@ jobs: # only required for a private repository by # github/codeql-action/upload-sarif to get the Action run status actions: read + strategy: + fail-fast: false + matrix: + base_image: [alpine, debian, ubuntu] + env: + REPORT_FILE: hadolint-results-${{ matrix.base_image }}.sarif steps: - name: Checkout code uses: actions/checkout@v7.0.1 @@ -41,14 +47,14 @@ jobs: - name: Run hadolint uses: hadolint/hadolint-action@06be81baf89a55ffd0e24b8f04a4185738dd3387 # v3.5.0 with: - dockerfile: ./Dockerfile + dockerfile: ./Dockerfile.${{ matrix.base_image }} format: sarif - output-file: hadolint-results.sarif + output-file: ${{ env.REPORT_FILE }} no-fail: true # yamllint enable rule:line-length - name: Upload analysis results to GitHub uses: github/codeql-action/upload-sarif@v4.38.2 with: - sarif_file: hadolint-results.sarif + sarif_file: ${{ env.REPORT_FILE }} wait-for-processing: true diff --git a/Dockerfile.alpine b/Dockerfile.alpine new file mode 100644 index 0000000..014a815 --- /dev/null +++ b/Dockerfile.alpine @@ -0,0 +1,146 @@ +FROM alpine:3.24 AS init + +ENV WORKDIR=/app +WORKDIR ${WORKDIR} + +ARG DEBIAN_FRONTEND=noninteractive +ENV TZ=Etc/UTC + + +RUN apk add --update --no-cache \ + ## common permanent packages + "make=4.4.1-r4" + +COPY ./Makefile ${WORKDIR}/ + +SHELL ["/bin/ash", "-o", "pipefail", "-c"] +RUN apk --update add --no-cache \ + "ca-certificates=20260909-r0" \ + "tzdata=2026d-r0" \ + "gcompat=1.1.0-r4" \ + && update-ca-certificates \ + && apk --update add --no-cache \ + ## add ephemeral packages + "curl=8.22.0-r0" \ + "tar=1.35-r5" \ + # CMAKE from Kitware repository + && curl -fsSLH "Cache-Control: no-cache" --proto "=https" https://github.com/Kitware/CMake/releases/download/v4.4.0/cmake-4.4.0-linux-x86_64.tar.gz \ + | tar -xz --strip-components=1 -C /usr/local \ + ## remove ephemeral packages + && apk del curl gpg tar + +FROM init AS builder + +ARG GENERATE_ASM=0 +ENV GENERATE_ASM=${GENERATE_ASM} + +# build tools +RUN apk --update add --no-cache \ + "build-base=0.5-r4" \ + "pkgconf=2.5.1-r0" \ + ## test tools + && gcc --version \ + && g++ --version \ + && make --version \ + && cmake --version + +# # vcpkg Package Manager +ENV VCPKG_FORCE_SYSTEM_BINARIES=1 +ENV VCPKG_VERSION=2026.07.29 +ENV VCPKG_ROOT=/opt/vcpkg + +# vcpkg Package Manager +RUN apk --update add --no-cache \ + "curl=8.22.0-r0" \ + "git=2.54.0-r0" \ + "patchelf=0.18.0-r3" \ + "samurai=1.2-r8" \ + "unzip=6.0-r16" \ + "zip=3.0-r13" \ + && mkdir /opt/vcpkg \ + && git clone --branch "${VCPKG_VERSION}" https://github.com/microsoft/vcpkg "${VCPKG_ROOT}" \ + && /opt/vcpkg/bootstrap-vcpkg.sh \ + && ln -s /opt/vcpkg/vcpkg /usr/local/bin/vcpkg \ + && rm -rf /var/lib/apt/lists/* \ + && vcpkg version + +# sources +COPY ./src ${WORKDIR}/src +COPY ./vcpkg.json ${WORKDIR}/vcpkg.json +COPY ./CMakeLists.txt ${WORKDIR}/CMakeLists.txt +COPY ./CMakePresets.json ${WORKDIR}/CMakePresets.json +COPY ./Makefile ${WORKDIR}/ + +# dependencies +RUN make dependencies + +LABEL vcpkg=enabled + +# build +RUN ls -alhR && \ + mkdir build && \ + make build && \ + ls -alhR + +CMD ["make", "build"] + +FROM builder AS development + +CMD [] + +FROM init AS lint + +# # Instala sólo lo mínimo necesario para linting (cmake, clang-format, cppcheck) +RUN apk --update add --no-cache \ + "clang-extra-tools=22.1.3-r2" \ + "cppcheck=2.21.0-r0" + +LABEL lint-phase=enabled +LABEL clang-format=enabled +LABEL cppcheck=enabled + +# Tooling test +RUN clang-format --version && \ + cppcheck --version && \ + make --version + +# Copia sólo lo necesario para ejecutar las comprobaciones +COPY ./src ${WORKDIR}/src +COPY ./Makefile ${WORKDIR}/ +RUN mkdir -p "${WORKDIR}"/build +COPY --from=builder ${WORKDIR}/build/compile_commands.json ${WORKDIR}/build/compile_commands.json + +CMD ["make", "lint-no-deps"] + +FROM init AS testing + +RUN apk --update add --no-cache \ + # libasan required (AdressSanitizer) + "gcc=15.2.0-r5" \ + # coverage + "lcov=2.3.1-r1" \ + # runtime required libraries + "libgcc=15.2.0-r5" \ + "libstdc++=15.2.0-r5" + +# COPY --from=builder ${WORKDIR}/build ${WORKDIR}/build +COPY --from=builder ${WORKDIR} ${WORKDIR} + +CMD ["make", "test-no-deps"] + +FROM alpine:3.24 AS production + +ENV LOG_LEVEL=INFO +ENV BRUTEFORCE=false +ENV WORKDIR=/app +WORKDIR ${WORKDIR} + +COPY --from=builder ${WORKDIR}/build/src/lib/exercises/*.a ${WORKDIR}/ + +RUN addgroup -S -g 1001 app \ + && adduser -S -u 1001 -G app -h /home/app app +USER 1001 + +RUN ls -alhR + +CMD ["make", "run"] diff --git a/Dockerfile.debian b/Dockerfile.debian new file mode 100644 index 0000000..1f4d605 --- /dev/null +++ b/Dockerfile.debian @@ -0,0 +1,160 @@ +FROM debian:stable-20260918-slim AS init + +ENV WORKDIR=/app +WORKDIR ${WORKDIR} + +ARG DEBIAN_FRONTEND=noninteractive +ENV TZ=Etc/UTC +SHELL ["/bin/bash", "-o", "pipefail", "-c"] + +RUN apt-get update \ + && apt-get -y install --no-install-recommends --no-install-suggests \ + ## common permanent packages + "make=4.4.1-2" \ + && rm -rf /var/lib/apt/lists/* + +COPY ./Makefile ${WORKDIR}/ + +ARG CMAKE_VERSION=4.4.3 + +RUN apt-get update \ + && apt-get -y install --no-install-recommends --no-install-suggests \ + ## common permanent packages + "ca-certificates=20250419" \ + ## add ephemeral packages + "curl=8.14.1-2+deb13u5" \ + # CMAKE from Kitware repository + && curl -fsSLH "Cache-Control: no-cache" --proto "=https" \ + "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-linux-x86_64.tar.gz" \ + | tar -xz --strip-components=1 -C /usr/local \ + && cmake --version \ + ## remove ephemeral packages + && apt-get -y autoremove curl \ + ## clean up + && rm -rf /var/lib/apt/lists/* + +FROM init AS builder + +ARG GENERATE_ASM=0 +ENV GENERATE_ASM=${GENERATE_ASM} + +# # build tools +RUN apt-get update \ + && apt-get -y install --no-install-recommends --no-install-suggests \ + "build-essential=12.12" \ + "g++=4:14.2.0-1" \ + "gcc=4:14.2.0-1" \ + "pkg-config=1.8.1-4" \ + ## clean up + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* \ + ## test tools + && gcc --version \ + && g++ --version \ + && make --version \ + && cmake --version + +# vcpkg Package Manager +ENV VCPKG_FORCE_SYSTEM_BINARIES=1 +ENV VCPKG_VERSION=2026.07.29 +ENV VCPKG_ROOT=/opt/vcpkg + +# vcpkg Package Manager +RUN apt-get -y update \ + && apt-get -y install --no-install-recommends --no-install-suggests \ + "curl=8.14.1-2+deb13u5" \ + "git=1:2.47.3-0+deb13u1" \ + "ninja-build=1.12.1-1" \ + "patchelf=0.18.0-1.4" \ + "unzip=6.0-29+deb13u1" \ + "zip=3.0-15+deb13u1" \ + && rm -rf /var/lib/apt/lists/* \ + && mkdir /opt/vcpkg \ + && git clone --branch "${VCPKG_VERSION}" https://github.com/microsoft/vcpkg "${VCPKG_ROOT}" \ + && /opt/vcpkg/bootstrap-vcpkg.sh \ + && ln -s /opt/vcpkg/vcpkg /usr/local/bin/vcpkg \ + && rm -rf /var/lib/apt/lists/* \ + && vcpkg version + +# sources +COPY ./src ${WORKDIR}/src +COPY ./vcpkg.json ${WORKDIR}/vcpkg.json +COPY ./CMakeLists.txt ${WORKDIR}/CMakeLists.txt +COPY ./CMakePresets.json ${WORKDIR}/CMakePresets.json +COPY ./Makefile ${WORKDIR}/ + +# dependencies +RUN make dependencies + +LABEL vcpkg=enabled + +# build +RUN ls -alhR && \ + mkdir build && \ + make build && \ + ls -alhR + +CMD ["make", "build"] + +FROM builder AS development + +CMD [] + +FROM init AS lint + +# Instala sólo lo mínimo necesario para linting (cmake, clang-format, cppcheck) +RUN apt-get update && \ + apt-get -y install --no-install-recommends --no-install-suggests \ + "clang-format=1:19.0-63" \ + "cppcheck=2.17.1-2" && \ + rm -rf /var/lib/apt/lists/* + +LABEL lint-phase=enabled +LABEL clang-format=enabled +LABEL cppcheck=enabled + +# Tooling test +RUN clang-format --version && \ + cppcheck --version && \ + make --version + +# Copia sólo lo necesario para ejecutar las comprobaciones +COPY ./src ${WORKDIR}/src +COPY ./Makefile ${WORKDIR}/ +RUN mkdir -p "${WORKDIR}"/build +COPY --from=builder ${WORKDIR}/build/compile_commands.json ${WORKDIR}/build/compile_commands.json + +CMD ["make", "lint-no-deps"] + +FROM init AS testing + +RUN apt-get -y update && \ + apt-get -y install --no-install-recommends --no-install-suggests \ + "lcov=2.3.1-1" && \ + rm -rf /var/lib/apt/lists/* + +COPY --from=builder ${WORKDIR} ${WORKDIR} + +CMD ["make", "test-no-deps"] + +FROM debian:stable-20260918-slim AS production + +ENV LOG_LEVEL=INFO +ENV BRUTEFORCE=false +ENV WORKDIR=/app +WORKDIR ${WORKDIR} + +RUN apt-get update \ + && apt-get -y install --no-install-recommends --no-install-suggests \ + ## common permanent packages + "make=4.4.1-2" \ + && rm -rf /var/lib/apt/lists/* + +COPY --from=builder ${WORKDIR}/build/src/lib/exercises/*.a ${WORKDIR}/ + +RUN useradd --uid 1001 --user-group --system --create-home --no-log-init app +USER 1001 + +RUN ls -alhR + +CMD ["make", "run"] diff --git a/Dockerfile.ubuntu b/Dockerfile.ubuntu new file mode 100644 index 0000000..83c3f93 --- /dev/null +++ b/Dockerfile.ubuntu @@ -0,0 +1,164 @@ +FROM ubuntu:26.04 AS init + +ENV WORKDIR=/app +WORKDIR ${WORKDIR} + +ARG DEBIAN_FRONTEND=noninteractive +ENV TZ=Etc/UTC + +RUN apt-get update \ + && apt-get -y install --no-install-recommends --no-install-suggests \ + ## common permanent packages + "make=4.4.1-3" \ + && rm -rf /var/lib/apt/lists/* + +COPY ./Makefile ${WORKDIR}/ + +SHELL ["/bin/bash", "-o", "pipefail", "-c"] +RUN apt-get update \ + && apt-get -y install --no-install-recommends --no-install-suggests \ + ## common permanent packages + "ca-certificates=20260601~26.04.1" \ + ## add ephemeral packages + "curl=8.18.0-1ubuntu2.7" \ + "gpg=2.4.8-4ubuntu3.1" \ + # CMAKE from Kitware repository + && curl --proto "=https" -fsSL https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null \ + | gpg --dearmor -o /usr/share/keyrings/kitware-archive-keyring.gpg \ + && echo "deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu resolute main" \ + > /etc/apt/sources.list.d/kitware.list \ + # CMAKE from Kitware repository + && apt-get update \ + && apt-get -y install --no-install-recommends --no-install-suggests \ + "cmake=4.4.3-0kitware1ubuntu26.04.1" \ + "cmake-data=4.4.3-0kitware1ubuntu26.04.1" \ + ## remove ephemeral packages + && apt-get -y autoremove curl gpg \ + ## clean up + && rm -rf /var/lib/apt/lists/* + +FROM init AS builder + +ARG GENERATE_ASM=0 +ENV GENERATE_ASM=${GENERATE_ASM} + +# # build tools +RUN apt-get update \ + && apt-get -y install --no-install-recommends --no-install-suggests \ + "build-essential=12.12ubuntu2.26.04.2" \ + "g++=4:15.2.0-5ubuntu1" \ + "gcc=4:15.2.0-5ubuntu1" \ + "pkg-config=2.5.1-4" \ + ## clean up + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* \ + ## test tools + && gcc --version \ + && g++ --version \ + && make --version \ + && cmake --version + +# # vcpkg Package Manager +ENV VCPKG_FORCE_SYSTEM_BINARIES=1 +ENV VCPKG_VERSION=2026.07.29 +ENV VCPKG_ROOT=/opt/vcpkg + +# vcpkg Package Manager +RUN apt-get -y update \ + && apt-get -y install --no-install-recommends --no-install-suggests \ + "curl=8.18.0-1ubuntu2.7" \ + "git=1:2.53.0-1ubuntu1" \ + "ninja-build=1.13.2-1" \ + "patchelf=0.18.0-1.4build1" \ + "unzip=6.0-29ubuntu1" \ + "zip=3.0-15ubuntu3" \ + && rm -rf /var/lib/apt/lists/* \ + && mkdir /opt/vcpkg \ + && git clone --branch "${VCPKG_VERSION}" https://github.com/microsoft/vcpkg "${VCPKG_ROOT}" \ + && /opt/vcpkg/bootstrap-vcpkg.sh \ + && ln -s /opt/vcpkg/vcpkg /usr/local/bin/vcpkg \ + && rm -rf /var/lib/apt/lists/* \ + && vcpkg version + +# sources +COPY ./src ${WORKDIR}/src +COPY ./vcpkg.json ${WORKDIR}/vcpkg.json +COPY ./CMakeLists.txt ${WORKDIR}/CMakeLists.txt +COPY ./CMakePresets.json ${WORKDIR}/CMakePresets.json +COPY ./Makefile ${WORKDIR}/ + +# dependencies +RUN make dependencies + +LABEL vcpkg=enabled + +# build +RUN ls -alhR && \ + mkdir build && \ + make build && \ + ls -alhR + +CMD ["make", "build"] + +FROM builder AS development + +CMD [] + +FROM init AS lint + +# Instala sólo lo mínimo necesario para linting (cmake, clang-format, cppcheck) +RUN apt-get update && \ + apt-get -y install --no-install-recommends --no-install-suggests \ + "clang-format=1:21.1.6-71" \ + "cppcheck=2.19.0-3" && \ + rm -rf /var/lib/apt/lists/* + +LABEL lint-phase=enabled +LABEL clang-format=enabled +LABEL cppcheck=enabled + +# Tooling test +RUN clang-format --version && \ + cppcheck --version && \ + make --version + +# Copia sólo lo necesario para ejecutar las comprobaciones +COPY ./src ${WORKDIR}/src +COPY ./Makefile ${WORKDIR}/ +RUN mkdir -p "${WORKDIR}"/build +COPY --from=builder ${WORKDIR}/build/compile_commands.json ${WORKDIR}/build/compile_commands.json + +CMD ["make", "lint-no-deps"] + +FROM init AS testing + +RUN apt-get -y update && \ + apt-get -y install --no-install-recommends --no-install-suggests \ + "lcov=2.4-3" && \ + rm -rf /var/lib/apt/lists/* + +COPY --from=builder ${WORKDIR} ${WORKDIR} + +CMD ["make", "test-no-deps"] + +FROM ubuntu:26.04 AS production + +ENV LOG_LEVEL=INFO +ENV BRUTEFORCE=false +ENV WORKDIR=/app +WORKDIR ${WORKDIR} + +RUN apt-get update \ + && apt-get -y install --no-install-recommends --no-install-suggests \ + ## common permanent packages + "make=4.4.1-3" \ + && rm -rf /var/lib/apt/lists/* + +COPY --from=builder ${WORKDIR}/build/src/lib/exercises/*.a ${WORKDIR}/ + +RUN useradd --uid 1001 --user-group --system --create-home --no-log-init app +USER 1001 + +RUN ls -alhR + +CMD ["make", "run"] diff --git a/compose.yaml b/compose.yaml index 221ca49..d9f1f26 100644 --- a/compose.yaml +++ b/compose.yaml @@ -4,6 +4,7 @@ services: image: algorithm-exercises-cpp:test build: context: . + dockerfile: Dockerfile.${BASE_IMAGE:-alpine} target: testing environment: LOG_LEVEL: ${LOG_LEVEL:-info} ## (1) ## info | debug @@ -16,6 +17,7 @@ services: image: algorithm-exercises-cpp:lint build: context: . + dockerfile: Dockerfile.${BASE_IMAGE:-alpine} target: lint volumes: - ./.clang-format:/app/.clang-format @@ -48,6 +50,7 @@ services: image: algorithm-exercises-cpp:dev build: context: . + dockerfile: Dockerfile.${BASE_IMAGE:-alpine} target: development environment: LOG_LEVEL: ${LOG_LEVEL:-info} ## (1) ## info | debug @@ -60,6 +63,7 @@ services: image: algorithm-exercises-cpp:latest build: context: . + dockerfile: Dockerfile.${BASE_IMAGE:-alpine} target: production # volumes: # - ./:/app