Skip to content

Scale Resource

Scale Resource #7

name: Terraform plan check
on:
pull_request:
branches: ["main"]
permissions:
id-token: write
contents: read
pull-requests: write
issues: write
env:
ARM_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
ARM_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
ARM_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
ARM_USE_OIDC: true
TF_VAR_subscriptionId: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
TF_VAR_localAdminUser: ${{ secrets.localAdminUser }}
TF_VAR_localAdminPassword: ${{ secrets.localAdminPassword }}
TF_VAR_domainAdminUser: ${{ secrets.domainAdminUser }}
TF_VAR_domainAdminPassword: ${{ secrets.domainAdminPassword }}
TF_VAR_deploymentUserPassword: ${{ secrets.deploymentUserPassword }}
TF_VAR_servicePrincipalId: ${{ secrets.servicePrincipalId }}
TF_VAR_servicePrincipalSecret: ${{ secrets.servicePrincipalSecret }}
TF_VAR_rpServicePrincipalObjectId: ${{ secrets.rpServicePrincipalObjectId }}
TF_VAR_vmAdminPassword: ${{ secrets.vmAdminPassword }}
TF_VAR_domainJoinPassword: ${{ secrets.domainJoinPassword }}
jobs:
provide_paths:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Check diff to see what content is changed
id: check_diff
run: |
## the || true is to avoid the exit code 1 of grep when no tf files are changed
changedFiles=$(git diff --name-only origin/main HEAD -- | grep ".tf" || true)
if [ -z "$changedFiles" ]; then
echo "No terraform files are changed"
echo "isModuleChanged=false" >> $GITHUB_OUTPUT
echo "planNeeded=false" >> $GITHUB_OUTPUT
exit 0
fi
echo "changedFiles=$changedFiles"
if [[ $changedFiles == *"modules"* ]]; then
echo "changedFiles contain modules"
echo "isModuleChanged=true" >> $GITHUB_OUTPUT
else
echo "changedFiles do not contain modules"
echo "isModuleChanged=false" >> $GITHUB_OUTPUT
fi
## get changed directories
echo "generate directory based on changed files"
directories=$(echo "$changedFiles" | xargs -n 1 dirname | sort -u | tr '\n' ' ')
echo "directory=$directories" >> $GITHUB_OUTPUT
- name: Set matrix
id: set-matrix
run: |
array=()
if !${{ steps.check_diff.outputs.planNeeded }}; then
echo "No directories to process, no need to plan"
echo "planNeeded=false" >> $GITHUB_OUTPUT
exit 0
fi
if ${{ steps.check_diff.outputs.isModuleChanged }}; then
echo "the module is changed, so generate the matrix based on the stages and sites"
readarray -t stages < ./.stages
for count in "${!stages[@]}"; do
stage=${stages[$count]}
pushd ./$stage > /dev/null
for d in */ ; do
if [[ $d == "*/" ]]; then
break
fi
group=$(echo "$d" | sed 's/\///g' | sed 's/ /_/g')
array+=("$stage/$group")
break
done
popd > /dev/null
done
fi
echo "also generate the matrix based on the changed directories"
IFS=' ' read -ra dirs <<< "${{ steps.check_diff.outputs.directory }}"
for i in "${dirs[@]}"; do
if [[ "$i" != ".azure" && "$i" != *"module"* ]]
then
array+=("$i")
fi
done
if [ ${#array[@]} -eq 0 ]; then
echo "No directories to process"
echo "planNeeded=false" >> $GITHUB_OUTPUT
else
echo "planNeeded=true" >> $GITHUB_OUTPUT
fi
echo "remove duplicates directory and sort"
sorted_array=($(echo "${array[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '))
echo "check directories is exist"
checkarray=()
for i in "${sorted_array[@]}"; do
if [ -d "$i" ]; then
checkarray+=("$i")
fi
done
json=$(jq --compact-output --null-input '$ARGS.positional' --args -- "${checkarray[@]}")
echo "matrix=$json"
echo "matrix=$json" >> $GITHUB_OUTPUT
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
planNeeded: ${{ steps.check_diff.outputs.planNeeded }}
terraform_plan_comments:
runs-on: ubuntu-latest
needs: provide_paths
if: needs.provide_paths.outputs.planNeeded != 'false'
strategy:
matrix:
path: ${{fromJson(needs.provide_paths.outputs.matrix)}}
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Log in to Azure using OIDC
uses: azure/login@v1
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
# Install node
- uses: actions/setup-node@v4
with:
node-version: latest
- run: node --version
# Install the latest version of Terraform CLI
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_wrapper: false
# Initialize a new or existing Terraform working directory by creating initial files, loading any remote state, downloading modules, etc.
- name: Terraform Init
id: init
run: terraform init
working-directory: ${{ matrix.path }}
- name: Terraform Fmt
id: fmt
run: terraform fmt -check
working-directory: ${{ matrix.path }}
continue-on-error: true
- name: Terraform Validate
id: validate
run: terraform validate -no-color
working-directory: ${{ matrix.path }}
- run: mkdir -p "${{ runner.temp }}/${{ matrix.path }}"
# Generates an execution plan for Terraform
- name: Terraform Plan
id: plan
run: terraform plan -input=false -lock=false -out "${{ runner.temp }}/${{ matrix.path }}/terraform.plan"
working-directory: ${{ matrix.path }}
- run: terraform show -no-color "${{ runner.temp }}/${{ matrix.path }}/terraform.plan" > "${{ runner.temp }}/${{ matrix.path }}/terraform.text"
working-directory: ${{ matrix.path }}
# generate json output
- run: |
# this is a known issue for ahmadnassri/action-terraform-report when plan result is no change
terraform show -json ${{ runner.temp }}/${{ matrix.path }}/terraform.plan > ${{ runner.temp }}/${{ matrix.path }}/tf-temp.json
# check if the .resource_changes is null in the tf.plan file and if it is,
# add an empty array to the json file else don't do anything.
if [ "$(jq '.resource_changes' ${{ runner.temp }}/${{ matrix.path }}/tf-temp.json)" == "null" ]; then
echo "resource_changes is null"
jq --argjson to_add '{"resource_changes":[]}' '. * $to_add' ${{ runner.temp }}/${{ matrix.path }}/tf-temp.json > ${{ runner.temp }}/${{ matrix.path }}/terraform.json
else
echo "resource_changes is not null"
cp ${{ runner.temp }}/${{ matrix.path }}/tf-temp.json ${{ runner.temp }}/${{ matrix.path }}/terraform.json
fi
working-directory: ${{ matrix.path }}
if: steps.plan.outcome == 'success'
- name: Update Pull Request
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const output = `#### Terraform plan run for \`${{ matrix.path }}\`
#### Terraform Initialization 🤖\`${{ steps.init.outcome }}\`
#### Terraform Format and Style 🖌\`${{ steps.fmt.outcome }}\`
#### You can run terraform fmt to fix the formatting issues
#### Terraform Validation 🤖\`${{ steps.validate.outcome }}\`
#### Terraform Plan 🤖\`${{ steps.plan.outcome }}\`
*Pushed by: @${{ github.actor }}, Action: \`${{ github.event_name }}\`*`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: output
})
if: always()
- uses: ahmadnassri/action-terraform-report@v3
with:
# tell the action the plan outputs
terraform-text: ${{ runner.temp }}/${{ matrix.path }}/terraform.text
terraform-json: ${{ runner.temp }}/${{ matrix.path }}/terraform.json
remove-stale-reports: false
if: steps.plan.outcome == 'success'
- name: Terraform Plan Status
if: steps.plan.outcome == 'failure'
run: exit 1