Pytest doesn't run with "docker-compose exec -T web_service pytest" in Gitlab CI Docker executor with Docker-Compose

Viewed 286

The main reason I'm trying to use Gitlab CI is to automate unit testing before deployment. I want to

  1. build my Docker images and push them to my image repository, then
  2. ensure all my pytest unit tests pass, and finally
  3. deploy to my production server.

However, my pytest command doesn't run at all if I include the -T flag as follows. It just instantly returns 0 and "succeeds", which is not correct because I have a failing test in there:

docker-compose exec -T web_service pytest /app/tests/ --junitxml=report.xml

On my local computer, I run the tests without the -T flag as follows, and it runs correctly (and the test fails as expected):

docker-compose exec web_service pytest /app/tests/ --junitxml=report.xml

But if I do that in Gitlab CI, I get the error the input device is not a TTY if I omit the -T flag.

Here's some of my ".gitlab-ci.yml" file:

image:
  name: docker/compose:1.29.2
  # Override the entrypoint (important)
  entrypoint: [""]

# Must have this service
# Note: --privileged is required for Docker-in-Docker to function properly,
# but it should be used with care as it provides full access to the host environment
services:
  - docker:dind

stages:
  - build
  - test
  - deploy

variables:
  # DOCKER_HOST is essential
  DOCKER_HOST: tcp://docker:2375
  DOCKER_DRIVER: overlay2

before_script:
  # First test that gitlab-runner has access to Docker
  - docker --version
  # Set variable names
  - export IMAGE=$CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME
  - export MY_IMAGE=$IMAGE:web_service
  # Install bash
  - apk add --no-cache bash
  # Add environment variables stored in GitLab, to .env file
  - chmod +x ./setup_env.sh
  - bash ./setup_env.sh
  # Login to the Gitlab registry and pull existing images to use as cache
  - docker login -u $CI_REGISTRY_USER -p $CI_JOB_TOKEN $CI_REGISTRY

build:
  stage: build
  script:
    # Pull the image for the build cache, and continue even if this image download fails (it'll fail the very first time)
    - docker pull $MY_IMAGE || true
    # Build and push Docker images to the Gitlab registry
    - docker-compose -f docker-compose.ci.build.yml build
    - docker push $MY_IMAGE
  only:
    - master

test:
  stage: test
  script:
    # Pull the image
    - docker pull $MY_IMAGE
    # Start the containers and run the tests before deployment
    - docker-compose -f docker-compose.ci.test.yml up -d
    # TODO: The following always succeeds instantly with "-T" flag,
    # but won't run at all if I exclude the "-T" flag...
    - docker-compose -f docker-compose.ci.test.yml exec -T web_service pytest --junitxml=report.xml
    - docker-compose -f docker-compose.ci.test.yml down
  artifacts:
    when: always
    paths:
      - report.xml
    reports:
      junit: report.xml
  only:
    - master

deploy:
  stage: deploy
  script:
    - bash deploy.sh
  only:
    - master
1 Answers

I've found a solution here. It's a quirk with docker-compose exec. Instead, I find the container ID with $(docker-compose -f docker-compose.ci.test.yml ps -q web_service) and use docker exec --tty <container_id> pytest ...

In the test stage, I've made the following substitution:

test:
  stage: test
  script:
    - # docker-compose -f docker-compose.ci.test.yml exec -T myijack pytest /app/tests/ --junitxml=report.xml
    - docker exec --tty $(docker-compose -f docker-compose.ci.test.yml ps -q web_service) pytest /app/tests --junitxml=report.xml
Related