diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..5b0cba03 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,194 @@ +name: CI + +on: + push: + branches: + - develop + pull_request: + branches: + - develop + +jobs: + build_and_push_dev: + runs-on: ubuntu-latest + steps: + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + - name: Checkout code + uses: actions/checkout@v2 + - name: DockerHub login + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Push dev + run: | + docker buildx create --use + docker buildx build \ + --cache-from ${{ vars.DOCKERHUB_ORGANIZATION }}/hope-support-images:cache-deduplication-engine-${{ github.sha }}-dev \ + --cache-from ${{ vars.DOCKERHUB_ORGANIZATION }}/hope-support-images:cache-deduplication-engine-latest-dev \ + --cache-to ${{ vars.DOCKERHUB_ORGANIZATION }}/hope-support-images:cache-deduplication-engine-${{ github.sha }}-dev \ + --cache-to ${{ vars.DOCKERHUB_ORGANIZATION }}/hope-support-images:cache-deduplication-engine-latest-dev \ + -t ${{ vars.DOCKERHUB_ORGANIZATION }}/hope-support-images:deduplication-engine-${{ github.sha }}-dev \ + -t ${{ vars.DOCKERHUB_ORGANIZATION }}/hope-support-images:deduplication-engine-latest-dev \ + -f ./docker/Dockerfile \ + --target dev \ + --push \ + ./ + + black: + runs-on: ubuntu-latest + needs: [build_and_push_dev] + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: DockerHub login + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Check + run: | + docker run --rm -i \ + ${{ vars.DOCKERHUB_ORGANIZATION }}/hope-support-images:deduplication-engine-${{ github.sha }}-dev \ + black . --check + + flake8: + runs-on: ubuntu-latest + needs: [build_and_push_dev] + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: DockerHub login + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Check + run: | + docker run --rm -i \ + ${{ vars.DOCKERHUB_ORGANIZATION }}/hope-support-images:deduplication-engine-${{ github.sha }}-dev \ + flake8 . + + unit_tests: + runs-on: ubuntu-latest + needs: [build_and_push_dev] + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: DockerHub login + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Unit tests + run: | + backend_image=${{ vars.DOCKERHUB_ORGANIZATION }}/hope-support-images:deduplication-engine-${{ github.sha }}-dev docker compose \ + -f ./ops/compose.ci-test.yml \ + up --exit-code-from backend + + build_and_push_prd: + needs: [build_and_push_dev] + runs-on: ubuntu-latest + steps: + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + - name: Checkout code + uses: actions/checkout@v2 + - name: DockerHub login + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Push prd + run: | + docker buildx create --use + + # Base part of the command + build_command="docker buildx build \ + --progress=plain \ + --cache-from ${{ vars.DOCKERHUB_ORGANIZATION }}/hope-support-images:cache-deduplication-engine-${{ github.sha }}-dev \ + --cache-from ${{ vars.DOCKERHUB_ORGANIZATION }}/hope-support-images:cache-deduplication-engine-latest-dev \ + --cache-from ${{ vars.DOCKERHUB_ORGANIZATION }}/hope-support-images:cache-deduplication-engine-${{ github.sha }}-prd \ + --cache-from ${{ vars.DOCKERHUB_ORGANIZATION }}/hope-support-images:cache-deduplication-engine-latest-prd \ + --cache-to ${{ vars.DOCKERHUB_ORGANIZATION }}/hope-support-images:cache-deduplication-engine-${{ github.sha }}-prd \ + --cache-to ${{ vars.DOCKERHUB_ORGANIZATION }}/hope-support-images:cache-deduplication-engine-latest-prd \ + -t ${{ vars.DOCKERHUB_ORGANIZATION }}/hope-support-images:deduplication-engine-${{ github.sha }}-prd \ + -t ${{ vars.DOCKERHUB_ORGANIZATION }}/hope-support-images:deduplication-engine-${{ github.sha }} \ + -f ./docker/Dockerfile \ + --target prd \ + --push ./" + + if [ "${{ github.ref }}" = "refs/heads/master" ]; then + version=$(python3 -c "import sys; version=None; [version:=line.split('=')[1].strip().strip('\"') for line in open('pyproject.toml', 'r') if line.strip().startswith('version =')]; print(version if version else sys.exit(1))") + tagged_image=${{ vars.DOCKERHUB_ORGANIZATION }}/hope:deduplication-engine-$version + build_command="$build_command -t $tagged_image" + fi + + eval $build_command + + trivy: + runs-on: ubuntu-latest + needs: [build_and_push_prd] + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: DockerHub login + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Run Trivy vulnerability scanner + uses: aquasecurity/trivy-action@master + with: + image-ref: '${{ vars.DOCKERHUB_ORGANIZATION }}/hope-support-images:deduplication-engine-${{ github.sha }}' + format: 'table' + exit-code: '0' + ignore-unfixed: true + vuln-type: 'os,library' + severity: 'CRITICAL,HIGH' + + deploy: + runs-on: ubuntu-latest + needs: [unit_tests, black, flake8, build_and_push_prd] + if: | + github.event_name == 'push' && + ( + github.ref == 'refs/heads/develop' + ) + steps: + - name: Trigger deploy + run: | + if [ ${{ github.ref }} == 'refs/heads/develop' ]; then + pipelineId=1309 + else + echo "No pipeline to trigger for ref ${{ github.ref }}" + exit 0 + fi + + IFS=',' read -ra pipelines <<< "$pipelineId" + for pipeline in "${pipelines[@]}"; do + jsonBody='{"variables": {"sha": {"isSecret": false, "value": "${{ github.sha }}"}, "tag": {"isSecret": false, "value": "deduplication-engine-${{ github.sha }}"}}}' + contentLength=$(echo -n $jsonBody | wc -c) + project=ICTD-HCT-MIS + organization=unicef + + echo Triggering deploy for pipeline $pipeline + echo JSON body: $jsonBody + + curl -f -v -L \ + -u ":${{ secrets.AZURE_PAT }}" \ + -H "Content-Type: application/json" \ + -H "Content-Length: $contentLength" \ + -d "$jsonBody" \ + https://dev.azure.com/$organization/$project/_apis/pipelines/$pipeline/runs?api-version=7.1-preview.1 + if [ $? -ne 0 ]; then + echo "Failed to trigger deploy for pipeline $pipeline" + exit 1 + fi + done \ No newline at end of file diff --git a/.gitignore b/.gitignore index ebc2229b..a6b021e1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -.* ~* *.sh *.egg-info @@ -21,3 +20,4 @@ Makefile site black.txt flake8 +.env \ No newline at end of file diff --git a/ops/ci.yaml b/ops/ci.yaml deleted file mode 100644 index e70d5eb3..00000000 --- a/ops/ci.yaml +++ /dev/null @@ -1,138 +0,0 @@ -trigger: - batch: true - branches: - include: - - develop -pr: - - develop -resources: - - repo: self - -variables: - # ======================================================================== - # Mandatory variables - # ======================================================================== - Docker.backend.repository: "hope-dedup-engine" - Docker.registryConnection: "ICTD-HOPE-DEV-ACR" - Docker.url: "uniappsakshopedev.azurecr.io" - tag: $(Build.SourceVersion) - additionalTag: $(Build.SourceBranchName) - pipelineId: 1309 - - -stages: - - stage: build_and_push_dev - dependsOn: [] - displayName: BUILD and PUSH DEV - jobs: - - job: build_push_backend_dev - pool: - vmImage: ubuntu-latest - displayName: "[BACKEND_BUILD]" - steps: - - task: Docker@2 - inputs: - containerRegistry: '$(Docker.registryConnection)' - command: 'login' - - script: | - docker buildx create --use - docker buildx build \ - --cache-from=$(Docker.url)/$(Docker.backend.repository)-cache:dev-$(additionalTag) \ - --cache-from=$(Docker.url)/$(Docker.backend.repository)-cache:dev-latest \ - --cache-to=$(Docker.url)/$(Docker.backend.repository)-cache:dev-$(additionalTag) \ - --cache-to=$(Docker.url)/$(Docker.backend.repository)-cache:dev-latest \ - -t $(Docker.url)/$(Docker.backend.repository):dev-$(tag) \ - --target dev \ - --push \ - -f docker/Dockerfile \ - ./ - displayName: Docker build dev - - - stage: test_dev - displayName: TEST - dependsOn: build_and_push_dev - jobs: - - job: tests - pool: - vmImage: ubuntu-latest - displayName: "[DJANGO TEST]" - steps: - - task: Docker@2 - displayName: "[ACR] Login" - inputs: - command: login - containerRegistry: $(Docker.registryConnection) - # - task: DockerCompose@0 - # displayName: "Run tests" - # inputs: - # containerregistrytype: 'Azure Container Registry' - # azureContainerRegistry: $(Docker.registryConnection) - # dockerComposeFile: 'ops/compose.ci-test.yml' - # action: 'Run a Docker Compose command' - # dockerComposeCommand: 'up --exit-code-from backend' - # dockerComposeFileArgs: | - # backend_image=$(Docker.url)/$(Docker.backend.repository):dev-$(tag) - - - - stage: build_and_push_prd - displayName: BUILD and PUSH PRD - dependsOn: test_dev - condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) - jobs: - - job: build_push_backend_prd - pool: - vmImage: ubuntu-latest - displayName: "[BACKEND_BUILD]" - steps: - - task: Docker@2 - inputs: - containerRegistry: '$(Docker.registryConnection)' - command: 'login' - - script: | - docker buildx create --use - docker buildx build \ - --cache-from=$(Docker.url)/$(Docker.backend.repository)-cache:prd-$(additionalTag) \ - --cache-from=$(Docker.url)/$(Docker.backend.repository)-cache:prd-latest \ - --cache-to=$(Docker.url)/$(Docker.backend.repository)-cache:prd-$(additionalTag) \ - --cache-to=$(Docker.url)/$(Docker.backend.repository)-cache:prd-latest \ - -t $(Docker.url)/$(Docker.backend.repository):prd-$(tag) \ - --target prd \ - --push \ - -f docker/Dockerfile \ - ./ - displayName: Docker build prd - - - stage: trigger_deploy - displayName: Trigger deploy - dependsOn: [build_and_push_prd] - jobs: - - job: trigger_deploy - pool: - vmImage: ubuntu-latest - displayName: "[TRIGGER_DEPLOY]" - steps: - - script: | - pipelineId=$(pipelineId) - IFS=',' read -ra pipelines <<< "$pipelineId" - for pipeline in "${pipelines[@]}"; do - jsonBody='{"variables": {"tag": {"isSecret": false, "value": "$(tag)"}}}' - contentLength=$(echo -n $jsonBody | wc -c) - project=ICTD-HCT-MIS - organization=unicef - - echo Triggering deploy for pipeline $pipeline - echo JSON body: $jsonBody - - curl -v -L \ - -u ":$(AZURE_PAT)" \ - -H "Content-Type: application/json" \ - -H "Content-Length: $contentLength" \ - -d "$jsonBody" \ - https://dev.azure.com/$organization/$project/_apis/pipelines/$pipeline/runs?api-version=7.1-preview.1 - if [ $? -ne 0 ]; then - echo "Failed to trigger deploy for pipeline $pipeline" - exit 1 - fi - done - displayName: "Trigger deploy" - condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) \ No newline at end of file