Skip to content

Commit

Permalink
♻️👷 Refactor CICD Pipeline (#1311)
Browse files Browse the repository at this point in the history
* Set `MISE_JOBS` to 4 when setting up Mise
* Sort Docker Builds alphabetically
* Move NATS chart from `tilt` to `helm`
* Pin Redpanda Connect and update Postgres
* Helmfile
* JSON Serialize Logs
* NATS Job Pod Labels
* Toggleable PGAdmin
* Configure PGAdmin Ingress
* ReplicaCount 1
* Dev Test values
* Increase PGPool Max Connections
* Don't inject istio sidecar on PGAdmin
* Add Init Containers to verify NATS is ready
* Rename and deduplicate docker images
  * `d-cloud` -> `acapy-cloud`
  * `governance-web`, `multitenant-web`, `public-web`, `tenant-web` are
  now built once as `acapy-cloud/app`
  * `dockerfiles/fastapi` -> `dockerfiles/app`
* CICD Build depends on Lint, Style, and Unit tests
* Remove unneeded `style-check.yml` Workflow
* Don't deploy to EKS if draft PR
* Cache python venv
* Rename `continuous-deploy.yml` to `cicd.yml`
* Remove UV
  * We don't really use it for anything
* Bump Metrics Server
* `hyperledger/aries-cloudagent-python` -> `openwallet-foundation/acapy`
* 📝 `aries-cloudapi` -> `acapy-cloud`
* Remove Lint Job (Soon™ to be replaced with Ruff)

And more that I've probably forgotten
  • Loading branch information
rblaine95 authored Feb 7, 2025
1 parent 651a72b commit 4a2d3bc
Show file tree
Hide file tree
Showing 67 changed files with 3,580 additions and 1,255 deletions.
104 changes: 104 additions & 0 deletions .github/actions/deploy-eks/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
name: Deploy EKS
description: Deploy to EKS

inputs:
aws-region:
description: "The AWS region where the EKS cluster is located"
required: true
aws-role-arn:
description: "The ARN of the AWS role to assume"
required: true
aws-role-session-name:
description: "The name of the AWS role session"
required: true
clean-start:
description: "Whether to clean up the EKS cluster before deploying"
required: false
default: "false"
cluster-name:
description: "The name of the EKS cluster"
required: true
environment:
description: "The environment to deploy to"
required: true
helm-version:
description: "The version of Helm to use"
required: false
default: v3.17.0
helmfile-plugins:
description: "The Helmfile plugins to install"
required: false
default: https://github.com/databus23/helm-diff
helmfile-version:
description: "The version of Helmfile to use"
required: false
default: v0.170.1
image-tag:
description: "The tag of the Docker image to deploy"
required: true
namespace:
description: "The Kubernetes namespace to deploy to"
required: true

runs:
using: composite

steps:
- name: Configure AWS credentials
# https://github.com/aws-actions/configure-aws-credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: ${{ inputs.aws-region }}
role-to-assume: ${{ inputs.aws-role-arn }}
role-session-name: ${{ inputs.aws-role-session-name }}

- name: Update Kubeconfig
shell: bash
run: aws eks update-kubeconfig --name $CLUSTER_NAME --region $REGION
env:
CLUSTER_NAME: ${{ inputs.cluster-name }}
REGION: ${{ inputs.aws-region }}

- name: Helmfile Destroy
if: inputs.clean-start == 'true'
# https://github.com/helmfile/helmfile-action
uses: helmfile/[email protected]
with:
helmfile-args: |
destroy \
--environment ${{ inputs.environment }} \
-f ./helm/acapy-cloud.yaml.gotmpl \
--state-values-set namespace=${{ inputs.namespace }}
helm-plugins: ${{ inputs.helmfile-plugins }}
helmfile-version: ${{ inputs.helmfile-version }}
helm-version: ${{ inputs.helm-version }}

- name: Create Redpanda Connect Stream ConfigMap
shell: bash
# https://docs.redpanda.com/redpanda-connect/get-started/quickstarts/helm-chart/#run-multiple-pipelines-in-streams-mode
run: |
kubectl create configmap connect-cloud-streams \
--from-file=./resources/connect-processors/cloud/streams/cloud-events.yaml \
--from-file=./resources/connect-processors/cloud/streams/state-monitoring.yaml \
--dry-run=client \
-o yaml \
-n $NAMESPACE | kubectl apply -f -
kubectl -n $NAMESPACE rollout restart deploy/connect-cloud || true
env:
NAMESPACE: ${{ inputs.namespace }}

- name: Helmfile Apply
# https://github.com/helmfile/helmfile-action
uses: helmfile/[email protected]
with:
helmfile-args: |
apply \
--environment ${{ inputs.environment }} \
-f ./helm/acapy-cloud.yaml.gotmpl \
--state-values-set image.tag=${{ inputs.image-tag }} \
--state-values-set image.registry=ghcr.io/${{ github.repository_owner }} \
--state-values-set pgProxyEnabled=${{ inputs.clean-start == 'false' }} \
--state-values-set namespace=${{ inputs.namespace }}
helm-plugins: ${{ inputs.helmfile-plugins }}
helmfile-version: ${{ inputs.helmfile-version }}
helm-version: ${{ inputs.helm-version }}
291 changes: 291 additions & 0 deletions .github/actions/test-eks/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,291 @@
name: Test EKS
description: Run Tests against EKS

inputs:
clean-start:
description: "Whether this is a clean start or not"
required: false
default: "false"
environment:
description: "The environment to deploy to"
required: true
helm-version:
description: "The version of Helm to use"
required: false
default: v3.17.0
helmfile-plugins:
description: "The Helmfile plugins to install"
required: false
default: https://github.com/databus23/helm-diff
helmfile-version:
description: "The version of Helmfile to use"
required: false
default: v0.170.1
image-tag:
description: "The tag of the Docker image to deploy"
required: true
namespace:
description: "The Kubernetes namespace to deploy to"
required: true
pytest-completions:
description: "How many completions to run"
required: false
default: "1"
run-regression-tests:
description: "Whether to run regression tests"
required: false
default: "true"
run-tests:
description: "Whether to run tests"
required: false
default: "true"

runs:
using: composite

steps:
- name: Helmfile run regression tests
if: inputs.run-regression-tests == 'true'
id: pytest-regression
# https://github.com/helmfile/helmfile-action
uses: helmfile/[email protected]
with:
helmfile-args: |
apply \
--environment ${{ inputs.environment }} \
-f ./helm/acapy-test.yaml.gotmpl \
--set image.tag=${{ inputs.image-tag }} \
--set image.registry=ghcr.io/${{ github.repository_owner }} \
--set completions=${{ inputs.pytest-completions }} \
--state-values-set release=acapy-test-regression \
--set fullnameOverride=acapy-test-regression \
--set env.RUN_REGRESSION_TESTS=${{ inputs.run-regression-tests }} \
--set env.FAIL_ON_RECREATING_FIXTURES=${{ inputs.clean-start != 'true' }} \
--state-values-set regressionEnabled=${{ inputs.run-regression-tests }} \
--state-values-set namespace=${{ inputs.namespace }}
helm-plugins: ${{ inputs.helmfile-plugins }}
helmfile-version: ${{ inputs.helmfile-version }}
helm-version: ${{ inputs.helm-version }}

- name: Helmfile run pytest
if: inputs.run-tests != 'false'
id: pytest
# https://github.com/helmfile/helmfile-action
uses: helmfile/[email protected]
with:
helmfile-args: |
apply \
--environment ${{ inputs.environment }} \
-f ./helm/acapy-test.yaml.gotmpl \
--set image.tag=${{ inputs.image-tag }} \
--set image.registry=ghcr.io/${{ github.repository_owner }} \
--set completions=${{ inputs.pytest-completions }} \
--state-values-set release=acapy-test \
--set fullnameOverride=acapy-test \
--state-values-set namespace=${{ inputs.namespace }}
helm-plugins: ${{ inputs.helmfile-plugins }}
helmfile-version: ${{ inputs.helmfile-version }}
helm-version: ${{ inputs.helm-version }}

- name: Wait for pytest and print logs
if: steps.pytest.outcome == 'success'
shell: bash
run: |
while true; do
# Check if the job is complete or failed
COMPLETION_STATUS=$(kubectl get job $JOB_NAME -n $NAMESPACE -o jsonpath='{.status.succeeded}')
FAILURE_STATUS=$(kubectl get job $JOB_NAME -n $NAMESPACE -o jsonpath='{.status.failed}')
if [ "$COMPLETION_STATUS" == "${PYTEST_COMPLETIONS}" ] || [ "$FAILURE_STATUS" == "1" ]; then
echo "Job $JOB_NAME has completed."
break
else
echo "Waiting for $JOB_NAME to complete..."
sleep 10
fi
done
# Get all pods for the job
pods=$(kubectl get pods -n $NAMESPACE --selector=job-name=$JOB_NAME -o jsonpath='{.items[*].metadata.name}')
# Loop through the pods and get logs
for pod in $pods
do
echo "Logs for Pod: $pod"
kubectl logs -n $NAMESPACE $pod
done
env:
JOB_NAME: acapy-test
NAMESPACE: ${{ inputs.namespace }}
PYTEST_COMPLETIONS: ${{ inputs.pytest-completions }}

- name: Wait for pytest regression and print logs
if: steps.pytest-regression.outcome == 'success'
shell: bash
run: |
while true; do
# Check if the job is complete or failed
COMPLETION_STATUS=$(kubectl get job $JOB_NAME -n $NAMESPACE -o jsonpath='{.status.succeeded}')
FAILURE_STATUS=$(kubectl get job $JOB_NAME -n $NAMESPACE -o jsonpath='{.status.failed}')
if [ "$COMPLETION_STATUS" == "${PYTEST_COMPLETIONS}" ] || [ "$FAILURE_STATUS" == "1" ]; then
echo "Job $JOB_NAME has completed."
break
else
echo "Waiting for $JOB_NAME to complete..."
sleep 10
fi
done
# Get all pods for the job
pods=$(kubectl get pods -n $NAMESPACE --selector=job-name=$JOB_NAME -o jsonpath='{.items[*].metadata.name}')
# Loop through the pods and get logs
for pod in $pods
do
echo "Logs for Pod: $pod"
kubectl logs -n $NAMESPACE $pod
done
env:
JOB_NAME: acapy-test-regression
NAMESPACE: ${{ inputs.namespace }}
PYTEST_COMPLETIONS: ${{ inputs.pytest-completions }}

- name: Copy k8s pytest results
if: steps.pytest.outcome == 'success' || steps.pytest-regression.outcome == 'success'
shell: bash
run: |
echo "apiVersion: v1
kind: Pod
metadata:
name: $POD_NAME
namespace: $NAMESPACE
labels:
sidecar.istio.io/inject: \"false\"
spec:
containers:
- name: $POD_NAME
image: $CONTAINER_IMAGE
command: [\"sleep\", \"3600\"]
volumeMounts:
- name: pytest-volume
mountPath: $MOUNT_PATH/pytest
- name: pytest-regression-volume
mountPath: $MOUNT_PATH/pytest-regression
volumes:
- name: pytest-volume
persistentVolumeClaim:
claimName: $PVC_NAME
- name: pytest-regression-volume
persistentVolumeClaim:
claimName: $PVC_NAME_REGRESSION
restartPolicy: Never" > pytest-results-pod.yaml
kubectl apply -f pytest-results-pod.yaml
# Wait for the pod to be ready
echo "Waiting for pod to be ready..."
kubectl -n $NAMESPACE wait --for=condition=ready pod/$POD_NAME --timeout=60s
# Copy the files from the pod to your local system
echo "Copying files from pod..."
mkdir -p $LOCAL_PATH $LOCAL_PATH_REGRESSION
kubectl -n $NAMESPACE cp $POD_NAME:$MOUNT_PATH/pytest/$OUTPUT_FILE $LOCAL_PATH/$OUTPUT_FILE
kubectl -n $NAMESPACE cp $POD_NAME:$MOUNT_PATH/pytest/$COVERAGE_FILE $LOCAL_PATH/$COVERAGE_FILE
kubectl -n $NAMESPACE cp $POD_NAME:$MOUNT_PATH/pytest-regression/$OUTPUT_FILE $LOCAL_PATH_REGRESSION/$OUTPUT_FILE
kubectl -n $NAMESPACE cp $POD_NAME:$MOUNT_PATH/pytest-regression/$COVERAGE_FILE $LOCAL_PATH_REGRESSION/$COVERAGE_FILE
# Clean up: delete the temporary pod
echo "Cleaning up..."
kubectl -n $NAMESPACE delete pod $POD_NAME
echo "Done!"
env:
PVC_NAME: acapy-test
PVC_NAME_REGRESSION: acapy-test-regression
POD_NAME: pytest-results-pod
CONTAINER_IMAGE: busybox
MOUNT_PATH: /mnt
LOCAL_PATH: ./pytest
LOCAL_PATH_REGRESSION: ./pytest-regression
NAMESPACE: ${{ inputs.namespace }}
OUTPUT_FILE: test_output.xml
COVERAGE_FILE: test_coverage.txt

- name: Pytest coverage comment
if: steps.pytest.outcome == 'success'
# https://github.com/MishaKav/pytest-coverage-comment
uses: MishaKav/[email protected]
with:
pytest-coverage-path: ./pytest/test_coverage.txt
junitxml-path: ./pytest/test_output.xml
create-new-comment: true
title: "K8s Test Coverage"
# Resolves `Warning: Your comment is too long (maximum is 65536 characters), coverage report will not be added.`
hide-report: ${{ github.event_name != 'pull_request' }}
hide-comment: ${{ github.event_name != 'pull_request' }}

- name: Pytest regression coverage comment
if: steps.pytest-regression.outcome == 'success'
# https://github.com/MishaKav/pytest-coverage-comment
uses: MishaKav/[email protected]
with:
pytest-coverage-path: ./pytest-regression/test_coverage.txt
junitxml-path: ./pytest-regression/test_output.xml
create-new-comment: true
title: "K8s Regression Test Coverage"
# Resolves `Warning: Your comment is too long (maximum is 65536 characters), coverage report will not be added.`
hide-report: ${{ github.event_name != 'pull_request' }}
hide-comment: ${{ github.event_name != 'pull_request' }}

- name: Publish Pytest Report
# https://github.com/mikepenz/action-junit-report
uses: mikepenz/action-junit-report@v5
if: steps.pytest.outcome == 'success'
with:
check_name: JUnit Test Report
report_paths: "./pytest/test_output.xml"
fail_on_failure: true
detailed_summary: true
require_passed_tests: true

- name: Publish Pytest Regression Report
uses: mikepenz/action-junit-report@v5
if: steps.pytest-regression.outcome == 'success'
with:
check_name: JUnit Test Report Regression
report_paths: "./pytest-regression/test_output.xml"
fail_on_failure: true
detailed_summary: true
require_passed_tests: true

- name: Helmfile destroy pytest
# https://github.com/helmfile/helmfile-action
uses: helmfile/[email protected]
if: always()
with:
helmfile-args: |
destroy \
--environment ${{ inputs.environment }} \
-f ./helm/acapy-test.yaml.gotmpl \
--state-values-set release=acapy-test
helm-plugins: ${{ inputs.helmfile-plugins }}
helmfile-version: ${{ inputs.helmfile-version }}
helm-version: ${{ inputs.helm-version }}

- name: Helmfile destroy pytest regression
# https://github.com/helmfile/helmfile-action
uses: helmfile/[email protected]
if: always()
with:
helmfile-args: |
destroy \
--environment ${{ inputs.environment }} \
-f ./helm/acapy-test.yaml.gotmpl \
--state-values-set release=acapy-test-regression \
--state-values-set namespace=${{ inputs.namespace }}
helm-plugins: ${{ inputs.helmfile-plugins }}
helmfile-version: ${{ inputs.helmfile-version }}
helm-version: ${{ inputs.helm-version }}
Loading

0 comments on commit 4a2d3bc

Please sign in to comment.