Scale Resource #7
This file contains 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: 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 | |