From 12a6db5b4a3e009e94b6a12bd216c62c64a8fe32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= Date: Mon, 27 Jan 2025 14:18:05 +0800 Subject: [PATCH 1/4] feat!: Switch to new entrypoint-based env prep --- .github/actions/rust-prepare/action.yml | 51 ---------------- .github/actions/rust-prepare/prepare_git.sh | 5 -- .github/actions/rust-prepare/prepare_rust.sh | 31 ---------- .github/actions/rust-prepare/prepare_ssh.sh | 18 ------ .github/workflows/publish-crate.yml | 11 ++-- .github/workflows/rust-workflow.yml | 62 ++++++++++---------- .github/workflows/~test-rust-workflow.yml | 2 - 7 files changed, 37 insertions(+), 143 deletions(-) delete mode 100644 .github/actions/rust-prepare/action.yml delete mode 100755 .github/actions/rust-prepare/prepare_git.sh delete mode 100755 .github/actions/rust-prepare/prepare_rust.sh delete mode 100755 .github/actions/rust-prepare/prepare_ssh.sh diff --git a/.github/actions/rust-prepare/action.yml b/.github/actions/rust-prepare/action.yml deleted file mode 100644 index aa282d5..0000000 --- a/.github/actions/rust-prepare/action.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: "Prepare rust environment" -description: "Sets up all environmental variables and ssh, potentially also container registry" -inputs: - ssh_auth_sock: - description: "SSH socket" - default: "/tmp/ssh_agent.sock" - required: true - gitlab_ssh: - description: "Gitlab ssh" - required: true - gitlab_user: - description: "Gitlab username" - required: true - gitlab_pass: - description: "Gitlab username" - required: true - cargo_home: - description: "Cargo home" - default: ".cargo" - famedly_crates_registry: - description: "Famedly registry name" - default: "famedly" - famedly_crates_registry_index: - description: "URL of famedly registry index" - default: "ssh://git@ssh.shipyard.rs/famedly/crate-index.git" - additional_packages: - description: "Additional package to install during preparation" - default: "" - -runs: - using: "composite" - steps: - - shell: bash - env: - SSH_AUTH_SOCK: ${{ inputs.ssh_auth_sock }} - GITLAB_SSH: ${{ inputs.gitlab_ssh }} - run: $GITHUB_ACTION_PATH/prepare_ssh.sh - - - shell: bash - env: - GITLAB_USER: ${{ inputs.gitlab_user }} - GITLAB_PASS: ${{ inputs.gitlab_pass }} - run: $GITHUB_ACTION_PATH/prepare_git.sh - - - shell: bash - env: - CARGO_HOME: ${{ inputs.cargo_home }} - ADDITIONAL_PACKAGES: ${{ inputs.additional_packages }} - FAMEDLY_CRATES_REGISTRY: ${{ inputs.famedly_crates_registry }} - FAMEDLY_CRATES_REGISTRY_INDEX: ${{ inputs.famedly_crates_registry_index }} - run: $GITHUB_ACTION_PATH/prepare_rust.sh diff --git a/.github/actions/rust-prepare/prepare_git.sh b/.github/actions/rust-prepare/prepare_git.sh deleted file mode 100755 index ffa3a4a..0000000 --- a/.github/actions/rust-prepare/prepare_git.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash -echo "Setting up git credentials" -echo "https://${GITLAB_USER}:${GITLAB_PASS}@gitlab.com" >> ~/.git-credentials -git config --global credential.helper store -git config --global --add safe.directory "$(pwd)" diff --git a/.github/actions/rust-prepare/prepare_rust.sh b/.github/actions/rust-prepare/prepare_rust.sh deleted file mode 100755 index 0c2c6c7..0000000 --- a/.github/actions/rust-prepare/prepare_rust.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env bash -# If we are root, there is no sudo command (needed). Makes sure we can run inside a docker container and outside. -if [[ "$(id -u)" -eq 0 ]]; then - SUDO="" -else - SUDO="sudo" -fi - -echo "Installing additional packages: ${ADDITIONAL_PACKAGES}" -$SUDO apt-get install -yqq --no-install-recommends "${ADDITIONAL_PACKAGES}" - -echo "Setting up development environment" - -echo "CARGO_HOME = ${HOME}/${CARGO_HOME}" -mkdir -p "${HOME}/${CARGO_HOME}" - -cat << EOF >> "${HOME}/${CARGO_HOME}/config.toml" -[net] -git-fetch-with-cli = true -EOF - -if [ "$FAMEDLY_CRATES_REGISTRY" != "crates-io" ]; then - cat << EOF >> "${HOME}/${CARGO_HOME}/config.toml" -[registries.${FAMEDLY_CRATES_REGISTRY}] -index = "${FAMEDLY_CRATES_REGISTRY_INDEX}" -EOF -fi - -echo "CARGO_HOME=${HOME}/${CARGO_HOME}" >> "$GITHUB_ENV" - -echo "Preparations finished" diff --git a/.github/actions/rust-prepare/prepare_ssh.sh b/.github/actions/rust-prepare/prepare_ssh.sh deleted file mode 100755 index 64a214b..0000000 --- a/.github/actions/rust-prepare/prepare_ssh.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash -echo "Preparing Rust build environment" - -echo "Setting up SSH" -USER="$(whoami)" -SSH_HOME="$(getent passwd "$USER" | cut -d: -f6)" # Is different from $HOME in docker containers, because github CI.. -ssh-agent -a "${SSH_AUTH_SOCK}" > /dev/null -echo "SSH_AUTH_SOCK=${SSH_AUTH_SOCK}" >> "$GITHUB_ENV" -ssh-add -vvv - <<< "${GITLAB_SSH}"$'\n' # ensure newline at the end of key - -echo "Adding public keys of remotes our CI interacts with" -mkdir -p "$SSH_HOME/.ssh" - -{ - ssh-keyscan -H gitlab.com - ssh-keyscan -H github.com - ssh-keyscan -H ssh.shipyard.rs -} >> "$SSH_HOME/.ssh/known_hosts" diff --git a/.github/workflows/publish-crate.yml b/.github/workflows/publish-crate.yml index 4fa3e9f..065474a 100644 --- a/.github/workflows/publish-crate.yml +++ b/.github/workflows/publish-crate.yml @@ -44,12 +44,13 @@ jobs: runs-on: ubuntu-latest container: docker-oss.nexus.famedly.de/rust-container:nightly steps: + - name: Run container entrypoint + run: /entrypoint.sh + env: + FRC_SSH_KEY: ${{ secrets.CI_SSH_PRIVATE_KEY }} + FRC_CRATES_REGISTRY: ${{ inputs.registry-name }} + FRC_CRATES_REGISTRY_INDEX: ${{ inputs.registry-index }} - uses: actions/checkout@v4 - - uses: famedly/backend-build-workflows/.github/actions/rust-prepare@main - with: - gitlab_ssh: ${{ secrets.CI_SSH_PRIVATE_KEY }} - famedly_crates_registry: ${{ inputs.registry-name }} - famedly_crates_registry_index: ${{ inputs.registry-index }} - name: Install registry token # Uses `echo` (bash built-in) to prevent leaking the token # through CLI args in /proc diff --git a/.github/workflows/rust-workflow.yml b/.github/workflows/rust-workflow.yml index 33e837c..202cac3 100644 --- a/.github/workflows/rust-workflow.yml +++ b/.github/workflows/rust-workflow.yml @@ -18,13 +18,21 @@ on: type: boolean default: true + additional_packages: + required: false + description: | + Additional ubuntu packages to install before running any + commands. + type: string + + container: + type: string + default: docker-oss.nexus.famedly.de/rust-container:nightly + clippy_args: {required: false, type: string, default: ""} test_args: {required: false, type: string, default: ""} testcov_args: {required: false, type: string, default: ""} udeps_args: {required: false, type: string, default: ""} - ref: - description: "The ref/version of this workflow; used to pull the correct dependency versions" - type: string secrets: CI_SSH_PRIVATE_KEY: @@ -41,32 +49,26 @@ on: will fail, however requiring secrets means that the `inherit` syntax does not work. -# Environment variables for all jobs. -env: - CARGO_TERM_COLOR: always - ADDITIONAL_PACKAGES: "" - # Defined CI jobs. jobs: rust-lints: runs-on: ${{ inputs.runs-on }} - container: docker-oss.nexus.famedly.de/rust-container:nightly + container: + image: ${{ inputs.container }} steps: - - name: Checkout workflow dependencies - uses: actions/checkout@v4 - with: - repository: famedly/backend-build-workflows - ref: ${{ inputs.ref }} + - name: Run container entrypoint + run: /entrypoint.sh + env: + FRC_SSH_KEY: ${{ secrets.CI_SSH_PRIVATE_KEY }} + FRC_ADDITIONAL_PACKAGES: ${{ inputs.additional_packages }} - - uses: ./.github/actions/rust-prepare - with: - gitlab_ssh: ${{ secrets.CI_SSH_PRIVATE_KEY}} - gitlab_user: ${{ secrets.GITLAB_USER }} - gitlab_pass: ${{ secrets.GITLAB_PASS }} - name: Checkout the repository to test uses: actions/checkout@v4 + - name: Tell git that the repo is safe + run: git config --global --add safe.directory $(pwd) + - name: Caching uses: Swatinem/rust-cache@68b3cb7503c78e67dae8373749990a220eb65352 @@ -88,23 +90,21 @@ jobs: rust-tests: runs-on: ${{ inputs.runs-on }} - container: docker-oss.nexus.famedly.de/rust-container:nightly + container: + image: ${{ inputs.container }} steps: - - name: Checkout workflow dependencies - uses: actions/checkout@v4 - with: - repository: famedly/backend-build-workflows - ref: ${{ inputs.ref }} - - - uses: ./.github/actions/rust-prepare - with: - gitlab_ssh: ${{ secrets.CI_SSH_PRIVATE_KEY}} - gitlab_user: ${{ secrets.GITLAB_USER }} - gitlab_pass: ${{ secrets.GITLAB_PASS }} + - name: Run container entrypoint + run: /entrypoint.sh + env: + FRC_SSH_KEY: ${{ secrets.CI_SSH_PRIVATE_KEY }} + FRC_ADDITIONAL_PACKAGES: ${{ inputs.additional_packages }} - name: Checkout the repository to test uses: actions/checkout@v4 + - name: Tell git that the repo is safe + run: git config --global --add safe.directory $(pwd) + - name: Caching uses: Swatinem/rust-cache@68b3cb7503c78e67dae8373749990a220eb65352 diff --git a/.github/workflows/~test-rust-workflow.yml b/.github/workflows/~test-rust-workflow.yml index 2bef1c8..42d701f 100644 --- a/.github/workflows/~test-rust-workflow.yml +++ b/.github/workflows/~test-rust-workflow.yml @@ -21,6 +21,4 @@ env: jobs: test-rust-workflow: uses: ./.github/workflows/rust-workflow.yml - with: - ref: ${{ github.ref }} secrets: inherit From f58885aadfd48085633a8246e53c21c5b89c15f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= Date: Wed, 5 Feb 2025 14:47:54 +0800 Subject: [PATCH 2/4] WIP: doc: Expand README to cover our workflows properly --- README.md | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index dc19b41..df17bdc 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,16 @@ -# Docker action +# Backend team CI actions and reusable workflows -To use the docker build, you can follow the example in [test](./.github/workflows/docker-test.yml) +This repository currently offers the following workflows: -We have two main use cases +## docker-publish -## Simple service with no subfolders +Publishes a docker image for a service to the correct docker registry. + +### Examples + +We have two main use cases: + +#### Simple service with no subfolders ```yaml jobs: @@ -17,7 +23,7 @@ jobs: should take care of everything -## Complex service with subfolders +#### Complex service with subfolders ```yaml jobs: @@ -28,3 +34,47 @@ jobs: path: ./foo/bar # path to where the Dockerfile resides name: bar # name of service ``` + +See also the [test case](.github/workflows/~test-docker-backend.yml). + +## rust-tests + +Runs basic rust lint checks, followed by the repository's test suite +(using `cargo nextest`), and reports code test coverage. + +### Using docker containers for test environments + +We pretty regularly use `docker compose` to set up test environments, +using `cargo nextest`'s startup script features. + +Since the CI environment uses a docker container, this requires a bit +of trickery. The CI env mounts the host docker socket, which *allows* +using docker containers, however to set up volume bind mounts paths +need to be set to their *host* location. + +As such, these invocations need to be changed a bit in CI. `cargo +nextest` allows adding scripts in specific profiles, this can be used +to add a setup step to the `ci` profile (though *not* to override the +default scripts). Order is determined by the order in which scripts +are defined. + +This sed line may be helpful: + +``` +sed 's|./|/home/runner/work//|g' -i tests/environment/docker-compose.yaml +``` + +### Examples + +#### Common, simple use case + +```yaml +jobs: + rust-tests: + uses: famedly/backend-build-workflows@v2 + secrets: inherit +``` + +#### Specifying various additional arguments + +See also the [test case](.github/workflows/~test-rust-workflow.yml) From a37871f67c824e9edef19edae271e4caac4310e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= Date: Tue, 11 Feb 2025 15:13:14 +0800 Subject: [PATCH 3/4] WIP: Switch to dev branch of rust container for testing --- .github/workflows/publish-crate.yml | 6 +++++- .github/workflows/rust-workflow.yml | 11 ++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish-crate.yml b/.github/workflows/publish-crate.yml index 065474a..12d021c 100644 --- a/.github/workflows/publish-crate.yml +++ b/.github/workflows/publish-crate.yml @@ -42,7 +42,11 @@ jobs: # Enforce only publishing tagged commits if: startsWith(github.ref, 'refs/tags/') runs-on: ubuntu-latest - container: docker-oss.nexus.famedly.de/rust-container:nightly + container: + image: docker-nightly.nexus.famedly.de/rust-container:dev-tlater-entrypoint + credentials: + username: ${{ vars.NEXUS_REGISTRY_USER }} + password: ${{ secrets.REGISTRY_PASSWORD }} steps: - name: Run container entrypoint run: /entrypoint.sh diff --git a/.github/workflows/rust-workflow.yml b/.github/workflows/rust-workflow.yml index 202cac3..531cfa5 100644 --- a/.github/workflows/rust-workflow.yml +++ b/.github/workflows/rust-workflow.yml @@ -27,7 +27,7 @@ on: container: type: string - default: docker-oss.nexus.famedly.de/rust-container:nightly + default: docker-nightly.nexus.famedly.de/rust-container:dev-tlater-entrypoint clippy_args: {required: false, type: string, default: ""} test_args: {required: false, type: string, default: ""} @@ -55,6 +55,9 @@ jobs: runs-on: ${{ inputs.runs-on }} container: image: ${{ inputs.container }} + credentials: + username: ${{ vars.NEXUS_REGISTRY_USER }} + password: ${{ secrets.REGISTRY_PASSWORD }} steps: - name: Run container entrypoint run: /entrypoint.sh @@ -92,6 +95,12 @@ jobs: runs-on: ${{ inputs.runs-on }} container: image: ${{ inputs.container }} + credentials: + username: ${{ vars.NEXUS_REGISTRY_USER }} + password: ${{ secrets.REGISTRY_PASSWORD }} + volumes: + # This permits running docker inside the container + - /var/run/docker.sock:/var/run/docker.sock steps: - name: Run container entrypoint run: /entrypoint.sh From 184486e6672c0b56acc7b882b700135c113a5d43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= Date: Fri, 28 Feb 2025 18:27:24 +0800 Subject: [PATCH 4/4] WIP: ci(rust-workflow): Separate out e2e tests --- .clippy.toml | 1 + .config/nextest.toml | 3 +++ .github/workflows/rust-workflow.yml | 15 ++++++++++++- .github/workflows/~test-rust-workflow.yml | 2 ++ Dockerfile | 27 +++++++++++++++++++++++ tests/e2e/call_external.rs | 9 ++++++++ tests/e2e/env/docker-compose.yml | 8 +++++++ tests/tests.rs | 3 +++ 8 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 .clippy.toml create mode 100644 tests/e2e/call_external.rs create mode 100644 tests/e2e/env/docker-compose.yml create mode 100644 tests/tests.rs diff --git a/.clippy.toml b/.clippy.toml new file mode 100644 index 0000000..6933b81 --- /dev/null +++ b/.clippy.toml @@ -0,0 +1 @@ +allow-expect-in-tests = true diff --git a/.config/nextest.toml b/.config/nextest.toml index 249a048..b2f8341 100644 --- a/.config/nextest.toml +++ b/.config/nextest.toml @@ -4,3 +4,6 @@ fail-fast = false path = "junit.xml" store-success-output = true store-failure-output = true + +[profile.e2e] +default-filter = "test(#e2e::*)" diff --git a/.github/workflows/rust-workflow.yml b/.github/workflows/rust-workflow.yml index 531cfa5..1bd0e02 100644 --- a/.github/workflows/rust-workflow.yml +++ b/.github/workflows/rust-workflow.yml @@ -18,6 +18,13 @@ on: type: boolean default: true + run-e2e-tests: + description: | + Whether to run e2e tests. + required: false + type: boolean + default: false + additional_packages: required: false description: | @@ -117,10 +124,16 @@ jobs: - name: Caching uses: Swatinem/rust-cache@68b3cb7503c78e67dae8373749990a220eb65352 - - name: Test + - name: Unit and integration tests shell: bash run: cargo llvm-cov nextest --profile ci --workspace --lcov --output-path lcov.info ${{inputs.testcov_args}} + - name: E2E tests + if: inputs.run-e2e-tests + run: | + docker build --target test -t famedly-workflow-tests:latest . + docker compose --project-directory tests/e2e/env up --quiet-pull --build --exit-code-from tests + - name: Doc-test shell: bash if: inputs.run-doctests diff --git a/.github/workflows/~test-rust-workflow.yml b/.github/workflows/~test-rust-workflow.yml index 42d701f..7c44d90 100644 --- a/.github/workflows/~test-rust-workflow.yml +++ b/.github/workflows/~test-rust-workflow.yml @@ -22,3 +22,5 @@ jobs: test-rust-workflow: uses: ./.github/workflows/rust-workflow.yml secrets: inherit + with: + run-e2e-tests: true diff --git a/Dockerfile b/Dockerfile index 981a98e..42a7596 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,2 +1,29 @@ +FROM docker-nightly.nexus.famedly.de/rust-container:dev-tlater-entrypoint AS test-builder + +# TODO: We currently cannot mount the repo because of +# https://github.com/nextest-rs/nextest/issues/2066 +# +# In the future, it would however be nice to use `--mount=target/repo` +# instead of copying. +COPY . /repo +WORKDIR /repo +RUN \ + --mount=type=cache,target=/build \ + --mount=type=cache,target=/cargo \ + export CARGO_TARGET_DIR=/build && \ + export CARGO_HOME=/cargo && \ + git archive HEAD --output=/git.tar && \ + cargo nextest archive --profile e2e --archive-file /tests.tar.zst + +FROM docker-nightly.nexus.famedly.de/rust-container:dev-tlater-entrypoint AS test + +RUN \ + --mount=from=test-builder,source=/git.tar,target=/git.tar \ + mkdir -p /repo && \ + tar xf /git.tar -C /repo +COPY --from=test-builder /tests.tar.zst /tests.tar.zst + +CMD cargo nextest run --profile e2e --archive-file /tests.tar.zst --workspace-remap /repo + FROM debian:bookworm-slim CMD ["/usr/local/bin/bash"] diff --git a/tests/e2e/call_external.rs b/tests/e2e/call_external.rs new file mode 100644 index 0000000..4e95af8 --- /dev/null +++ b/tests/e2e/call_external.rs @@ -0,0 +1,9 @@ +use std::process::Command; + +#[test] +fn test_stuff() { + Command::new("curl") + .args(["http://nginx"]) + .output() + .expect("Should be able to talk to nginx"); +} diff --git a/tests/e2e/env/docker-compose.yml b/tests/e2e/env/docker-compose.yml new file mode 100644 index 0000000..fa0c443 --- /dev/null +++ b/tests/e2e/env/docker-compose.yml @@ -0,0 +1,8 @@ +services: + tests: + image: famedly-workflow-tests:latest + command: ls / + depends_on: + - nginx + nginx: + image: nginx diff --git a/tests/tests.rs b/tests/tests.rs new file mode 100644 index 0000000..7d68b76 --- /dev/null +++ b/tests/tests.rs @@ -0,0 +1,3 @@ +mod e2e { + mod call_external; +}