diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3b73d0730aee37c14cb56ecf29172077eaca7606..28e6272d550a417244798ff3c53b517e76fab087 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,33 +1,37 @@ -image: registry.gitlab.com/arkindex/backend:base-0.11.3 +image: registry.gitlab.com/arkindex/backend/base:latest stages: - test - build + - deploy -cache: - paths: - - .cache/pip +# For jobs that run backend scripts directly +.backend-setup: + cache: + paths: + - .cache/pip -before_script: - - apk --update add build-base - # Custom line to install our own deps from Git using GitLab CI credentials - - "pip install -e git+https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/arkindex/common#egg=arkindex-common" - - "pip install -e git+https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/arkindex/ponos#egg=ponos-server" - - pip install -r tests-requirements.txt codecov + before_script: + - apk --update add build-base + # Custom line to install our own deps from Git using GitLab CI credentials + - "pip install -e git+https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/arkindex/common#egg=arkindex-common" + - "pip install -e git+https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/arkindex/ponos#egg=ponos-server" + - pip install -r tests-requirements.txt codecov -variables: - # For the postgres image - POSTGRES_DB: arkindex_dev - POSTGRES_USER: devuser - POSTGRES_PASSWORD: devdata + variables: + # For the postgres image + POSTGRES_DB: arkindex_dev + POSTGRES_USER: devuser + POSTGRES_PASSWORD: devdata - # For the backend - DB_HOST: postgres - DB_PORT: 5432 + # For the backend + DB_HOST: postgres + DB_PORT: 5432 - # Pip cache - PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip" + # Pip cache + PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip" backend-tests: + extends: .backend-setup stage: test services: @@ -38,12 +42,14 @@ backend-tests: - codecov backend-lint: + extends: .backend-setup stage: test script: - flake8 backend-migrations: + extends: .backend-setup stage: test services: @@ -54,33 +60,81 @@ backend-migrations: - arkindex/manage.py makemigrations --check --noinput --dry-run -v 3 backend-openapi: + extends: .backend-setup stage: build script: - - mkdir -p output - - pip install -e . - - pip install uritemplate==3 apistar>=0.7.2 - - arkindex/manage.py generateschema --generator_class arkindex.project.openapi.SchemaGenerator > output/original.yml - - openapi/patch.py openapi/paths.yml output/original.yml > output/schema.yml - - variables: - PONOS_DATA_DIR: /tmp + - ci/openapi.sh artifacts: paths: - output/ backend-static: + extends: .backend-setup stage: build script: - - mkdir -p static - - pip install -e . - - STATIC_ROOT=$(pwd)/static arkindex/manage.py collectstatic - - variables: - PONOS_DATA_DIR: /tmp + - ci/static-collect.sh artifacts: paths: - static + +backend-build-base: + stage: build + image: docker:19.03.1 + services: + - docker:dind + variables: + DOCKER_DRIVER: overlay2 + DOCKER_HOST: tcp://docker:2375/ + + # Run this only on base tags + rules: + - if: '$CI_COMMIT_TAG =~ /^base-.*/' + when: on_success + - when: never + + script: + - ci/build-base.sh + +backend-build: + stage: build + image: docker:19.03.1 + services: + - docker:dind + variables: + DOCKER_DRIVER: overlay2 + DOCKER_HOST: tcp://docker:2375/ + + # Run this on master and tags except base tags + rules: + - if: '$CI_COMMIT_BRANCH == "master"' + when: on_success + - if: '$CI_COMMIT_TAG && $CI_COMMIT_TAG !~ /^base-.*/' + when: on_success + - when: never + + script: + - ci/build.sh + +backend-static-deploy: + stage: deploy + + # Run this on any version tag except base images + rules: + - if: '$CI_COMMIT_TAG && $CI_COMMIT_TAG !~ /^base-.*/' + when: on_success + - when: never + + # Run immediately once backend-static ends without waiting for others + needs: + - backend-static + + # Ensure artifacts are available + dependencies: + - backend-static + + script: + - ci/static-deploy.sh diff --git a/Dockerfile b/Dockerfile index e19ca8231939012d16a9f42281cd4eb065f80b05..3eb327cfba3e65931c3574dd76ef58195894d766 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,10 @@ -FROM registry.gitlab.com/arkindex/backend:base-0.11.3 +FROM registry.gitlab.com/arkindex/backend/base:latest as build + +RUN mkdir build +ADD . build +RUN cd build && python3 setup.py sdist + +FROM registry.gitlab.com/arkindex/backend/base:latest ARG COMMON_BRANCH=master ARG COMMON_ID=9855787 @@ -25,7 +31,7 @@ RUN \ # Install arkindex and its deps # Uses a source archive instead of full local copy to speedup docker build -COPY dist/arkindex-*.tar.gz /tmp/arkindex.tar.gz +COPY --from=build /build/dist/arkindex-*.tar.gz /tmp/arkindex.tar.gz RUN pip install /tmp/arkindex.tar.gz && rm /tmp/arkindex.tar.gz # Allow access to static files directory diff --git a/Makefile b/Makefile index 4e30a94a7c895c2689136f47a3b91ae5fca8c35e..fc55a4af5631094da03d83014e68e9e903507e93 100644 --- a/Makefile +++ b/Makefile @@ -1,47 +1,21 @@ ROOT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) -TUNNEL_HOST:=arkindex-dev -TUNNEL_PORT:=8000 PONOS_BRANCH=master COMMON_BRANCH=master -VERSION=$(shell git rev-parse --short HEAD) -TAG_APP=arkindex-app -.PHONY: build base +IMAGE_TAG=registry.gitlab.com/arkindex/backend +.PHONY: all all: clean build base: require-version - docker build $(ROOT_DIR)/base -t registry.gitlab.com/arkindex/backend:base-$(version) - docker push registry.gitlab.com/arkindex/backend:base-$(version) - sed -i '/image:/s/base-.*$$/base-$(version)/' $(ROOT_DIR)/.gitlab-ci.yml - sed -i '/FROM/s/base-.*$$/base-$(version)/' $(ROOT_DIR)/Dockerfile + VERSION=$(version) CI_PROJECT_DIR=$(ROOT_DIR) CI_REGISTRY_IMAGE=$(IMAGE_TAG) $(ROOT_DIR)/ci/build-base.sh clean: rm -rf *.egg-info build dist .eggs find . -name '*.pyc' -exec rm {} \; build: - rm -f dist/arkindex-*.tar.gz - python setup.py sdist - docker build --no-cache $(ROOT_DIR) -t $(TAG_APP):$(VERSION) -t $(TAG_APP):latest --build-arg PONOS_BRANCH=$(PONOS_BRANCH) --build-arg COMMON_BRANCH=$(COMMON_BRANCH) - -publish-version: require-docker-auth - [ -f $(ROOT_DIR)/arkindex/project/local_settings.py ] && mv $(ROOT_DIR)/arkindex/project/local_settings.py $(ROOT_DIR)/arkindex/project/local_settings.py.bak || true - $(MAKE) build TAG_APP=registry.gitlab.com/arkindex/backend - docker push registry.gitlab.com/arkindex/backend:$(VERSION) - [ -f $(ROOT_DIR)/arkindex/project/local_settings.py.bak ] && mv $(ROOT_DIR)/arkindex/project/local_settings.py.bak $(ROOT_DIR)/arkindex/project/local_settings.py || true - -latest: - $(MAKE) publish-version VERSION=latest - -release: - $(eval version:=$(shell cat VERSION)) - $(MAKE) publish-version VERSION=$(version) - docker push registry.gitlab.com/arkindex/backend:latest - git tag $(version) - -tunnel: - ssh $(TUNNEL_HOST) -NR *:$(TUNNEL_PORT):localhost:$(TUNNEL_PORT) + CI_PROJECT_DIR=$(ROOT_DIR) CI_REGISTRY_IMAGE=$(IMAGE_TAG) COMMON_BRANCH=$(COMMON_BRANCH) PONOS_BRANCH=$(PONOS_BRANCH) $(ROOT_DIR)/ci/build.sh test-fixtures: $(eval export PGPASSWORD=devdata) @@ -63,9 +37,6 @@ test-fixtures-restore: psql -h 127.0.0.1 -p 9100 -U devuser -c 'DROP DATABASE arkindex_dev' template1 psql -h 127.0.0.1 -p 9100 -U devuser -c 'ALTER DATABASE arkindex_dev_replace RENAME TO arkindex_dev' template1 -require-docker-auth: - @grep registry.gitlab.com ~/.docker/config.json > /dev/null || (echo "Docker Login on registry.gitlab.com"; docker login registry.gitlab.com) - require-version: @if [ ! "$(version)" ]; then echo "Missing version to publish"; exit 1; fi @git rev-parse $(version) >/dev/null 2>&1 && (echo "Version $(version) already exists on local git repo !" && exit 1) || true diff --git a/README.md b/README.md index 487f752689b105328b5c5d32873bce10133841ff..a031a6d27a6009a31bf7c30049f6b3132f589d92 100644 --- a/README.md +++ b/README.md @@ -97,10 +97,6 @@ At the root of the repository is a Makefile that provides commands for common op * `make base`: Create and push the `arkindex-base` Docker image that is used to build the `arkindex-app` image; * `make clean`: Cleanup the Python package build and cache files; * `make build`: Build the arkindex Python package and recreate the `arkindex-app:latest` without pushing to the GitLab container registry; -* `make latest`: Build and push the `latest` Docker image to the GitLab container registry; -* `make release`: Build and push a release Docker image to the GitLab container registry (use the `VERSION` file to update the version number); -* `make worker`: Start a local (non-Docker) Celery worker; -* `make tunnel`: Open a SSH tunnel via the preproduction server, making your dev server available on `arkindex.dev.teklia.com:8000` — useful for webhook related development; * `make test-fixtures`: Create the unit tests fixtures on a temporary PostgreSQL database and save them to the `data.json` file used by most Django unit tests. ### Django commands diff --git a/ci/build-base.sh b/ci/build-base.sh new file mode 100755 index 0000000000000000000000000000000000000000..83fb856ee1b58041de4848120cf908d430bf5a08 --- /dev/null +++ b/ci/build-base.sh @@ -0,0 +1,33 @@ +#!/bin/sh -e +# Build the backend base image. +# Requires CI_PROJECT_DIR and CI_REGISTRY_IMAGE as well as either VERSION or CI_COMMIT_TAG. +# If VERSION is not set, CI_COMMIT_TAG must start with "base-" and will be used as "base-$VERSION". +# If CI_REGISTRY is set, will push the image to the specified registry. +# If CI_REGISTRY, CI_REGISTRY_USER and CI_REGISTRY_PASSWORD are set, will run `docker login` before pushing. + +if [ -z "$VERSION" ]; then + # Ensure this is a base tag, then tell sh to remove the base- prefix. + case $CI_COMMIT_TAG in + base-*) + VERSION=${CI_COMMIT_TAG#base-};; + *) + echo build-base can only be used with 'base-*' tags. + exit 1;; + esac +fi + +if [ -z "$VERSION" -o -z "$CI_PROJECT_DIR" -o -z "$CI_REGISTRY_IMAGE" ]; then + echo Missing environment variables + exit 1 +fi + +if [ -n "$CI_REGISTRY" -a -n "$CI_REGISTRY_USER" -a -n "$CI_REGISTRY_PASSWORD" ]; then + echo Logging in to container registry… + echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY +fi + +IMAGE_TAG="$CI_REGISTRY_IMAGE/base:$VERSION" +IMAGE_LATEST="$CI_REGISTRY_IMAGE/base:latest" +docker build --no-cache "$CI_PROJECT_DIR/base" -t "$IMAGE_TAG" -t "$IMAGE_LATEST" +docker push "$IMAGE_TAG" +docker push "$IMAGE_LATEST" diff --git a/ci/build.sh b/ci/build.sh new file mode 100755 index 0000000000000000000000000000000000000000..e84a3c97b8cf32126dd58b1f7750659d09c19341 --- /dev/null +++ b/ci/build.sh @@ -0,0 +1,37 @@ +#!/bin/sh -e +# Build the backend Docker image. +# Requires CI_PROJECT_DIR and CI_REGISTRY_IMAGE to be set. +# VERSION defaults to latest. +# Will automatically login to a registry if CI_REGISTRY, CI_REGISTRY_USER and CI_REGISTRY_PASSWORD are set. +# Will only push an image if $CI_REGISTRY is set. + +if [ -z "$VERSION" ]; then + #Ensure this is not a base tag + case $CI_COMMIT_TAG in + base-*) + echo build can only be used with non-base tags. + exit 1;; + esac + VERSION=${CI_COMMIT_TAG:-latest} +fi + +if [ -z "$VERSION" -o -z "$CI_PROJECT_DIR" -o -z "$CI_REGISTRY_IMAGE" ]; then + echo Missing environment variables + exit 1 +fi + +if [ -n "$CI_REGISTRY" -a -n "$CI_REGISTRY_USER" -a -n "$CI_REGISTRY_PASSWORD" ]; then + echo Logging in to container registry… + echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY +fi + +PONOS_BRANCH=${PONOS_BRANCH:-master} +COMMON_BRANCH=${COMMON_BRANCH:-master} +IMAGE_TAG="$CI_REGISTRY_IMAGE:$VERSION" + +cd $CI_PROJECT_DIR +docker pull "$CI_REGISTRY_IMAGE/base:latest" +docker build . -t "$IMAGE_TAG" --build-arg "PONOS_BRANCH=$PONOS_BRANCH" --build-arg "COMMON_BRANCH=$COMMON_BRANCH" +if [ -n "$CI_REGISTRY" ]; then + docker push "$IMAGE_TAG" +fi diff --git a/ci/openapi.sh b/ci/openapi.sh new file mode 100755 index 0000000000000000000000000000000000000000..6433f8c6f91e8a5e3a56a6d152809dccf3f30fec --- /dev/null +++ b/ci/openapi.sh @@ -0,0 +1,6 @@ +#!/bin/sh -e +mkdir -p output +pip install -e . +pip install uritemplate==3 apistar>=0.7.2 +PONOS_DATA_DIR=/tmp arkindex/manage.py generateschema --generator_class arkindex.project.openapi.SchemaGenerator > output/original.yml +openapi/patch.py openapi/paths.yml output/original.yml > output/schema.yml diff --git a/ci/static-collect.sh b/ci/static-collect.sh new file mode 100755 index 0000000000000000000000000000000000000000..aa1e28588a7ad2234fa68e61a60b3686ceabc658 --- /dev/null +++ b/ci/static-collect.sh @@ -0,0 +1,4 @@ +#!/bin/sh +mkdir -p static +pip install -e . +PONOS_DATA_DIR=/tmp STATIC_ROOT=$(pwd)/static arkindex/manage.py collectstatic diff --git a/ci/static-deploy.sh b/ci/static-deploy.sh new file mode 100755 index 0000000000000000000000000000000000000000..fb837a450f1d77d9be13be8cd2eaa22ad3c45b29 --- /dev/null +++ b/ci/static-deploy.sh @@ -0,0 +1,5 @@ +VERSION=${VERSION:-${CI_COMMIT_TAG}} +[ -z "$VERSION" ] && echo "No version specified" && exit 1 + +pip install awscli +aws s3 cp --recursive static s3://teklia-assets-release/arkindex/$VERSION/