add the header/data divider #120
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build and Run Docker Image | |
| on: | |
| push: | |
| branches: | |
| - 'ci' # TODO: Trigger on push to release branches | |
| jobs: | |
| build: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| DOCKER_IMAGE_NAME: ${{ steps.build-image-name.outputs.DOCKER_IMAGE_NAME }} | |
| CODELINE: ${{ steps.build-image-name.outputs.CODELINE }} | |
| INSTANCE_NAME: ${{ steps.build-image-name.outputs.INSTANCE_NAME }} | |
| steps: | |
| - name: Checkout Code | |
| uses: actions/checkout@v4 | |
| - name: Build Image Name | |
| id: build-image-name | |
| run: | | |
| echo DOCKER_IMAGE_NAME=$(echo ${{ github.event.repository.name }} | tr '[A-Z]' '[a-z]') | tee -a $GITHUB_ENV | tee -a $GITHUB_OUTPUT | |
| echo CODELINE=$(echo ${{ github.ref_name }} | tr '[A-Z]' '[a-z]') | tee -a $GITHUB_ENV | tee -a $GITHUB_OUTPUT | |
| echo INSTANCE_NAME=${{ github.ref_name }}_InT | tee -a $GITHUB_ENV | tee -a $GITHUB_OUTPUT | |
| - name: Build Docker Image | |
| run: | | |
| docker build . --file Dockerfile --tag ${{ env.DOCKER_IMAGE_NAME }}:${{ env.CODELINE }} | |
| echo '## Image Details' >> $GITHUB_STEP_SUMMARY | |
| header=$(docker images | sed -r 's/\s{2,}/|/g' | grep -E '^R' | sed -r 's/^|$/\|/g') | |
| echo "$header" >> $GITHUB_STEP_SUMMARY | |
| echo "$header" | sed -r 's/[^|]/-/g' >> $GITHUB_STEP_SUMMARY | |
| docker images | sed -r 's/\s{2,}/|/g' | grep -E 'pyterrabacktyl' | sed -r 's/^|$/\|/g' >> $GITHUB_STEP_SUMMARY | |
| docker save ${{ env.DOCKER_IMAGE_NAME }}:${{ env.CODELINE }} -o /tmp/${{ github.event.repository.name }}.tar | |
| - name: Upload Docker Image | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ github.event.repository.name }}.tar | |
| path: /tmp/${{ github.event.repository.name }}.tar | |
| - name: Create summary header | |
| run: | | |
| echo '## Test Results' | tee -a $GITHUB_STEP_SUMMARY | |
| run_and_test: | |
| runs-on: ubuntu-latest | |
| needs: build | |
| strategy: | |
| matrix: | |
| # TODO: Test OpenTofu | |
| terraform_version: | |
| - '1.10.4' # Latest | |
| - '1.5.6' # Popular | |
| - '1.3.9' # Popular | |
| steps: | |
| - name: Checkout Code | |
| uses: actions/checkout@v4 | |
| - name: Download Docker Image | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: ${{ github.event.repository.name }}.tar | |
| path: /tmp | |
| - name: Load Docker Image | |
| run: | | |
| docker load -i /tmp/${{ github.event.repository.name }}.tar | |
| - name: Run Docker Container | |
| run: | | |
| docker run -d --name ${{ needs.build.outputs.INSTANCE_NAME }} -p 2442:2442 ${{ needs.build.outputs.DOCKER_IMAGE_NAME }}:${{ needs.build.outputs.CODELINE }} | |
| - name: Wait for PyTerraBackTYL to start | |
| run: | | |
| for ct in {0..9} | |
| do | |
| # '000' gets set if curl fails | |
| STATUS=$(curl -Ss -o /dev/null -w "%{http_code}" http://localhost:2442 || true) | |
| if [ ${STATUS} -ne 200 ]; then | |
| echo "waiting..." | |
| sleep 1 | |
| else | |
| exit 0 | |
| fi | |
| done | |
| exit 1 | |
| - name: Set up Terraform | |
| uses: hashicorp/setup-terraform@v3 | |
| with: | |
| terraform_version: ${{ matrix.terraform_version }} | |
| # TODO: nicely formatted summary output doesn't show the failures | |
| # Maybe just write a bunch of shell scripts and exec them here | |
| # Loop over them and report the name ($0), results (✅, ❌) | |
| - name: Set headers for test output | |
| run: | | |
| echo '## Terraform ${{ matrix.terraform_version }}' >> $GITHUB_STEP_SUMMARY | |
| COLS="|Test Name|Status|" | |
| echo "${COLS}" >> /tmp/summary | |
| echo "${COLS}" | sed -r 's/[^|]/-/g' >> /tmp/summary | |
| - name: Run 'happy-path' Test | |
| run: | | |
| cd .github/build_tests | |
| terraform init | |
| terraform plan | |
| terraform apply --auto-approve | |
| docker logs ${{ needs.build.outputs.INSTANCE_NAME }} | |
| echo TFSTATE=$(curl -sS http://localhost:2442/?env=InT) | tee -a $GITHUB_ENV | |
| echo "|Happy Path|✅ Success|" >> /tmp/summary | |
| - name: Validate Terraform State | |
| # Validate that Terraform state saved in PyTerraBackTYL matches the content of the file generated by Terraform | |
| run: | | |
| cd .github/build_tests | |
| TF_CONTENT=$(echo '${{ env.TFSTATE }}' | jq -r '.resources[].instances[].attributes.content | select(. != null)') | |
| FILE_CONTENT=$(cat test.txt) | |
| if [[ "${TF_CONTENT}" != "${FILE_CONTENT}" ]]; then | |
| echo ${TF_CONTENT} != ${FILE_CONTENT} >&2 | |
| exit 1 | |
| fi | |
| echo -e "|State Saved|✅ Success|" >> /tmp/summary | |
| - name: Validate Terraform State Changed | |
| # The ID of the null resource should change with every apply. Verify PyTerraBackTYL is saving the updated state | |
| run: | | |
| cd .github/build_tests | |
| CURRENT_NULL_RESOURCE_ID=$(echo '${{env.TFSTATE}}' | jq -r '.resources[] | select(.type == "null_resource") | .instances[].attributes.id') | |
| terraform apply --auto-approve | |
| NEW_NULL_RESOURCE_ID=$(curl -sS http://localhost:2442/?env=InT | jq -r '.resources[] | select(.type == "null_resource") | .instances[].attributes.id') | |
| [ -n "${NEW_NULL_RESOURCE_ID}" ] | |
| [ -n "${CURRENT_NULL_RESOURCE_ID}" ] | |
| [ "${CURRENT_NULL_RESOURCE_ID}" -ne "${NEW_NULL_RESOURCE_ID}" ] | |
| echo -e "|State Changed|✅ Success|" >> /tmp/summary | |
| - name: Run Terraform Test, Locked ENV | |
| # Manually lock the environment and capture how terraform exited | |
| id: prelock_InT | |
| continue-on-error: true | |
| run: | | |
| curl -X LOCK -sS http://localhost:2442/lock?env=InT | |
| cd .github/build_tests | |
| terraform apply --auto-approve | |
| - name: Verify Command Failed Successfully | |
| # Verify that terraform failed with a lock error when trying to run against a locked environment | |
| run: | | |
| if [ "${{ steps.prelock_InT.outcome }}" != "success" ]; then | |
| curl -X UNLOCK -sS http://localhost:2442/unlock?env=InT | |
| echo "|Locked Environment is Blocking|✅ Success|" >> /tmp/summary | |
| else | |
| # Picked confusing wording just to be silly | |
| echo "Step unexpectedly failed to fail as expected." | |
| exit 1 | |
| fi | |
| - name: Show results, Clean Up | |
| run: | | |
| cat /tmp/summary | tee -a $GITHUB_STEP_SUMMARY | |
| # Hopefully this is being nice to GHA infra and not just wasting CPU cycles | |
| docker rm -f ${{ needs.build.outputs.INSTANCE_NAME }} || true | |
| docker rmi ${{ needs.build.outputs.DOCKER_IMAGE_NAME }}:${{ needs.build.outputs.CODELINE }} || true |