ci: k8s manifests diff detector (draft) #2
Workflow file for this run
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: helm-loki-ci | |
on: | |
pull_request: | |
paths: | |
- "production/helm/loki/**" | |
jobs: | |
publish-diff: | |
name: Publish Rendered Helm Chart Diff | |
runs-on: ubuntu-latest | |
steps: | |
- name: Setup Helm | |
uses: azure/setup-helm@v4 | |
- name: Add required Helm repositories | |
run: | | |
helm repo add minio https://charts.min.io/ --insecure-skip-tls-verify | |
helm repo add grafana https://grafana.github.io/helm-charts --insecure-skip-tls-verify | |
helm repo add grafana-operator https://grafana.github.io/helm-charts --insecure-skip-tls-verify | |
helm repo update | |
- name: Install required applications | |
run: | | |
sudo apt-get update && sudo apt-get install -y jq | |
- name: Prepare directories for base and PR branches | |
run: | | |
mkdir -p ${{ github.workspace }}/base | |
mkdir -p ${{ github.workspace }}/pr | |
mkdir -p ${{ github.workspace }}/output | |
mkdir -p ${{ github.workspace }}/output/base | |
mkdir -p ${{ github.workspace }}/output/pr | |
- name: Checkout base branch to 'base' folder within workspace | |
uses: actions/checkout@v4 | |
with: | |
ref: ${{ github.event.pull_request.base.ref }} | |
path: ${{ github.workspace }}/base | |
- name: Checkout PR branch to 'pr' folder within workspace | |
uses: actions/checkout@v4 | |
with: | |
ref: ${{ github.event.pull_request.head.ref }} | |
path: ${{ github.workspace }}/pr | |
- name: Render Helm chart for each scenario in the base branch | |
run: | | |
cd ${{ github.workspace }}/base/production/helm/loki | |
helm dependency build | |
for file in scenarios/*.yaml; do | |
cat "$file" | |
schenario_folder=${{ github.workspace }}/output/base/$(basename $file .yaml) | |
echo "$schenario_folder" | |
mkdir $schenario_folder | |
helm template loki-test-chart-name . -f $file --output-dir $schenario_folder | |
done | |
- name: Render Helm chart for each scenario in the PR branch | |
run: | | |
cd ${{ github.workspace }}/pr/production/helm/loki | |
helm dependency build | |
for file in scenarios/*.yaml; do | |
cat "$file" | |
schenario_folder=${{ github.workspace }}/output/pr/$(basename $file .yaml) | |
echo "$schenario_folder" | |
mkdir $schenario_folder | |
helm template loki-test-chart-name . -f $file --output-dir $schenario_folder | |
done | |
- name: Calculate the diff between base and PR rendered manifests for each scenario | |
run: | | |
cd ${{ github.workspace }}/pr/production/helm/loki | |
for scenario_file in scenarios/*.yaml; do | |
added_files='[]' | |
modified_files='[]' | |
removed_files='[]' | |
scenario_name=$(basename $scenario_file .yaml) | |
base_branch_dir=${{ github.workspace }}/output/base/$scenario_name | |
pr_branch_dir=${{ github.workspace }}/output/pr/$scenario_name | |
echo "Comparing directories: $base_branch_dir and $pr_branch_dir" | |
# Find all files in the left and right directories | |
base_branch_files=$(find "$base_branch_dir" -type f | sed "s|$base_branch_dir/||") | |
pr_branch_files=$(find "$pr_branch_dir" -type f | sed "s|$pr_branch_dir/||") | |
# Check for modified and removed files | |
for file in $base_branch_files; do | |
if [[ -f "$pr_branch_dir/$file" ]]; then | |
# File exists in both directories, check if it is modified | |
if ! diff -q "$base_branch_dir/$file" "$pr_branch_dir/$file" >/dev/null; then | |
echo "modified file detected" | |
file_diff=$(diff -c "$base_branch_dir/$file" "$pr_branch_dir/$file" || true) | |
diff_obj=$(jq -n --arg file "$file" --arg diff "$file_diff" '{"filename": $file, "diff": $diff}') | |
# Append the new object to the JSON array using jq | |
modified_files=$(echo "$modified_files" | jq --argjson diff_obj "$diff_obj" '. += [$diff_obj]') | |
fi | |
else | |
echo "removed file detected" | |
# File is missing in the PR directory | |
file_content=$(cat "$base_branch_dir/$file") | |
echo "file_content created" | |
removed_obj=$(jq -n --arg filename "$file" --arg content "$file_content" '{"filename": $filename, "content": $content}') | |
echo "removed_obj created" | |
# Append the new object to the JSON array using jq | |
modified_files=$(echo "$modified_files" | jq --argjson removed_obj "$removed_obj" '. += [$removed_obj]') | |
echo "removed_obj appended" | |
fi | |
done | |
# Check for added files in the right directory | |
for file in $pr_branch_files; do | |
if [[ ! -f "$base_branch_dir/$file" ]]; then | |
echo "added file detected" | |
# File is missing in the PR directory | |
file_content=$(cat "$pr_branch_dir/$file") | |
added_obj=$(jq -n --arg file "$file" --arg content "$file_content" '{"filename": $file, "content": $content}') | |
# Append the new object to the JSON array using jq | |
added_files=$(echo "$added_files" | jq --argjson added_obj "$added_obj" '. += [$added_obj]') | |
fi | |
done | |
scenario_output_dir="${{ github.workspace }}/output/$scenario_name" | |
mkdir $scenario_output_dir | |
echo $added_files > $scenario_output_dir/added_files.json | |
cat $scenario_output_dir/added_files.json | |
echo $modified_files > $scenario_output_dir/modified_files.json | |
echo $removed_files > $scenario_output_dir/removed_files.json | |
done | |
- name: Generate Markdown Summary | |
run: | | |
# Initialize the Markdown output file | |
output_file="${{ github.workspace }}/output/diff_summary.md" | |
echo "# Kubernetes Manifest Diff Summary" > $output_file | |
# Iterate over each scenario file | |
for file in ${{ github.workspace }}/pr/production/helm/loki/scenarios/*.yaml; do | |
scenario=$(basename "$file" .yaml) | |
echo "Processing scenario: $scenario" | |
# Read JSON data for added, modified, and removed files | |
added_files=$(cat ${{ github.workspace }}/output/$scenario/added_files.json) | |
modified_files=$(cat ${{ github.workspace }}/output/$scenario/modified_files.json) | |
removed_files=$(cat ${{ github.workspace }}/output/$scenario/removed_files.json) | |
# Count the number of added, modified, and removed files | |
num_added=$(echo "$added_files" | jq length) | |
num_modified=$(echo "$modified_files" | jq length) | |
num_removed=$(echo "$removed_files" | jq length) | |
# Create a header for the scenario | |
echo -e "\n<details><summary>Scenario: $scenario (Added: $num_added, Modified: $num_modified, Removed: $num_removed) </summary>\n" >> $output_file | |
echo -e "<p>\n\n" >> $output_file | |
# Add summary counts | |
echo -e "\n**Summary:**" >> $output_file | |
echo -e "\n- **Added:** $num_added" >> $output_file | |
echo -e "\n- **Modified:** $num_modified" >> $output_file | |
echo -e "\n- **Removed:** $num_removed" >> $output_file | |
# Add details for added files | |
echo -e "\n### Added Files" >> $output_file | |
if [[ "$num_added" -gt 0 ]]; then | |
echo "$added_files" | jq -c '.[]' | while read -r obj; do | |
filename=$(echo "$obj" | jq -r '.filename') | |
content=$(echo "$obj" | jq -r '.content') | |
echo -e "\n<details><summary>$filename</summary>" >> $output_file | |
echo -e "\n\`\`\`yaml\n$content\n\`\`\`\n</details>" >> $output_file | |
done | |
else | |
echo -e "\n_No added files_\n" >> $output_file | |
fi | |
# Add details for modified files | |
echo -e "\n### Modified Files" >> $output_file | |
if [[ "$num_modified" -gt 0 ]]; then | |
echo "$modified_files" | jq -c '.[]' | while read -r obj; do | |
filename=$(echo "$obj" | jq -r '.filename') | |
diff=$(echo "$obj" | jq -r '.diff') | |
echo -e "\n<details><summary>$filename</summary>" >> $output_file | |
echo -e "\n\`\`\`diff\n$diff\n\`\`\`\n</details>" >> $output_file | |
done | |
else | |
echo -e "\n_No modified files_\n" >> $output_file | |
fi | |
# Add details for removed files | |
echo -e "\n### Removed Files" >> $output_file | |
if [[ "$num_removed" -gt 0 ]]; then | |
echo "$removed_files" | jq -c '.[]' | while read -r obj; do | |
filename=$(echo "$obj" | jq -r '.filename') | |
content=$(echo "$obj" | jq -r '.content') | |
echo -e "\n<details><summary>$filename</summary>" >> $output_file | |
echo -e "\n\`\`\`yaml\n$content\n\`\`\`\n</details>" >> $output_file | |
done | |
else | |
echo -e "\n_No removed files_\n" >> $output_file | |
fi | |
# close <p> and <details> | |
echo -e "\n\n<\p>\n<\details>" >> $output_file | |
done | |
- name: Post diff as PR comment | |
uses: marocchino/sticky-pull-request-comment@v2 | |
with: | |
path: ${{ github.workspace }}/output/diff_summary.md |