Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
pedjak committed Nov 24, 2023
1 parent aef79a9 commit 44a6869
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 245 deletions.
223 changes: 9 additions & 214 deletions .github/workflows/diff.yaml
Original file line number Diff line number Diff line change
@@ -1,224 +1,19 @@
name: Crossplane Dynamic Diff

on:
pull_request:
branches: [main]

name: Crossplane Dynamic Diff

jobs:
pr:
name: prepare
runs-on: ubuntu-latest
steps:
- name: Setup QEMU
uses: docker/setup-qemu-action@v2
with:
platforms: all
- name: Check out current commit
uses: actions/checkout@v4
- name: Install Go
uses: actions/setup-go@v4
- name: Install yq
run: |
sudo add-apt-repository ppa:rmescandon/yq
sudo apt-get update
sudo apt-get install yq
- name: Install Crossplane CLI
run: go install github.com/crossplane/crossplane/cmd/crank@latest

# Discover YAML files and their annotations
- name: Discover YAML files
run: |
EXAMPLES_PATH="examples"
YAML_FILES=($(find $EXAMPLES_PATH -type f -name '*.yaml'))
INPUT_FILES=""
for file in "${YAML_FILES[@]}"; do
COMPOSITION=$(yq eval '.metadata.annotations."crossplane.io/render-composition-path"' $file)
FUNCTION=$(yq eval '.metadata.annotations."crossplane.io/render-function-path"' $file)
# Skip files where both annotations are null
if [[ "$COMPOSITION" == "null" && "$FUNCTION" == "null" ]]; then
continue
fi
INPUT_FILES+="$file,$COMPOSITION,$FUNCTION "
done
echo "INPUT_FILES=${INPUT_FILES}" >> $GITHUB_ENV
# Run a dynamic job for each input file
- name: Run Dynamic Jobs
run: |
IFS=' ' read -ra INPUT_FILES <<< "${{ env.INPUT_FILES }}"
for files in "${INPUT_FILES[@]}"; do
IFS=',' read -ra FILE_ARRAY <<< "$files"
FILE="${FILE_ARRAY[0]}"
COMPOSITION="${FILE_ARRAY[1]}"
FUNCTION="${FILE_ARRAY[2]}"
# Skip files where both annotations are null
if [[ "$COMPOSITION" == "null" && "$FUNCTION" == "null" ]]; then
continue
fi
crank beta render $FILE $COMPOSITION $FUNCTION >> diff-pr-${FILE//\//-}.yaml
done
- name: Install Python
uses: actions/setup-python@v4

# Sort YAML files
- name: Sort YAML files
run: |
for file in diff-pr-*.yaml; do
python3 -c "import yaml; data = list(yaml.load_all(open('$file'), Loader=yaml.FullLoader)); data.sort(key=lambda x: (x.get('kind', ''), str(x.get('metadata', {}).get('annotations', '')))); yaml.dump_all(data, open('$file', 'w'), default_flow_style=False)"
done
# Store outputs as artifacts
- name: Store outputs
uses: actions/upload-artifact@v3
with:
name: diff-pr-${{ github.sha }}
path: diff-*.yaml

main:
diff:
name: diff
needs: [pr]
runs-on: ubuntu-latest
steps:
- name: Setup QEMU
uses: docker/setup-qemu-action@v2
with:
platforms: all
- name: Install Go
uses: actions/setup-go@v4
- name: Install yq
run: |
sudo add-apt-repository ppa:rmescandon/yq
sudo apt-get update
sudo apt-get install yq
- name: Install Crossplane CLI
run: go install github.com/crossplane/crossplane/cmd/crank@latest

- name: Check out main
- name: Check out current commit
uses: actions/checkout@v4
with:
ref: main

# Download artifacts from the dynamic job
- name: Download artifacts
uses: actions/download-artifact@v2
with:
name: diff-pr-${{ github.sha }}

# Discover YAML files and their annotations
- name: Discover YAML files
run: |
EXAMPLES_PATH="examples"
YAML_FILES=($(find $EXAMPLES_PATH -type f -name '*.yaml'))
INPUT_FILES=""
for file in "${YAML_FILES[@]}"; do
COMPOSITION=$(yq eval '.metadata.annotations."crossplane.io/render-composition-path"' $file)
FUNCTION=$(yq eval '.metadata.annotations."crossplane.io/render-function-path"' $file)
# Skip files where both annotations are null
if [[ "$COMPOSITION" == "null" && "$FUNCTION" == "null" ]]; then
continue
fi
INPUT_FILES+="$file,$COMPOSITION,$FUNCTION "
done
echo "INPUT_FILES=${INPUT_FILES}" >> $GITHUB_ENV
# Run a dynamic job for each input file
- name: Run Dynamic Jobs
run: |
IFS=' ' read -ra INPUT_FILES <<< "${{ env.INPUT_FILES }}"
for files in "${INPUT_FILES[@]}"; do
IFS=',' read -ra FILE_ARRAY <<< "$files"
FILE="${FILE_ARRAY[0]}"
COMPOSITION="${FILE_ARRAY[1]}"
FUNCTION="${FILE_ARRAY[2]}"
# Skip files where both annotations are null
if [[ "$COMPOSITION" == "null" && "$FUNCTION" == "null" ]]; then
continue
fi
crank beta render $FILE $COMPOSITION $FUNCTION >> diff-main-${FILE//\//-}.yaml
done
- name: Install Python
uses: actions/setup-python@v4

# Sort YAML files
- name: Sort YAML files
run: |
for file in diff-main-*.yaml; do
python3 -c "import yaml; data = list(yaml.load_all(open('$file'), Loader=yaml.FullLoader)); data.sort(key=lambda x: (x.get('kind', ''), str(x.get('metadata', {}).get('annotations', '')))); yaml.dump_all(data, open('$file', 'w'), default_flow_style=False)"
done
# Store outputs as artifacts
- name: Store outputs
uses: actions/upload-artifact@v2
with:
name: diff-main-${{ github.sha }}
path: diff-main-*.yaml

# Diff the outputs between PR and main
- name: Diff
id: diff_rev
run: |
IFS=',' read -ra INPUT_FILES <<< "$INPUT_FILES"
for FILE in "${INPUT_FILES[@]}"; do
IFS=' ' read -ra FILE_PATHS <<< "$FILE"
for SUB_FILE in "${FILE_PATHS[@]}"; do
MAIN_FILE="diff-main-${SUB_FILE//\//-}.yaml"
PR_FILE="diff-pr-${SUB_FILE//\//-}.yaml"
echo "Checking differences for file: $SUB_FILE"
echo "Main file path: $MAIN_FILE"
echo "PR file path: $PR_FILE"
if [ -f "$MAIN_FILE" ] && [ -f "$PR_FILE" ]; then
DELTA_NAME=$(echo "DELTA_${SUB_FILE//[\./]/_}" | tr '[:upper:]' '[:lower:]' | sed 's/\//_/g')
DELTA_FILE="$DELTA_NAME.diff"
echo "Setting DELTA_NAME: $DELTA_NAME"
DELTA=$(diff -u "$MAIN_FILE" "$PR_FILE" || true)
echo "$DELTA" > "$DELTA_FILE"
echo "Differences found for $SUB_FILE. Diff saved in $DELTA_FILE"
else
echo "Either $MAIN_FILE or $PR_FILE does not exist!"
fi
done
done
- name: Generate Comment
id: generate_comment
run: |
ALL_DELTAS=""
# Iterate over all diff files
for DELTA_FILE in $(find . -name '*.diff'); do
echo "Processing diff file: $DELTA_FILE"
# Debugging statement
cat "$DELTA_FILE"
# Ensure the file exists and is not empty
if [ -s "$DELTA_FILE" ]; then
# Use printf to format newlines properly
ALL_DELTAS="${ALL_DELTAS}$(printf '\n```diff\n%s\n```' "$(cat "$DELTA_FILE")")"
echo "ALL_DELTAS so far: $ALL_DELTAS"
else
echo "Diff file $DELTA_FILE is either empty or not found!"
fi
done
# Debugging statement
echo "Final ALL_DELTAS: $ALL_DELTAS"
# Write the content to a file
echo -e "$ALL_DELTAS" > diff_content.txt

- name: comment PR
uses: machine-learning-apps/pr-comment@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Crossplane Dynamic Diff
uses: ./.
with:
path: diff_content.txt
# process XRs from the given directory
dir: examples
github-token: ${{ secrets.GITHUB_TOKEN }}
45 changes: 14 additions & 31 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -1,46 +1,29 @@
# Crossplane Dynamic Diff GitHub Action

This GitHub Action performs a dynamic diff between pull requests (PRs) and the main branch for Crossplane YAML files with specific annotations. It leverages the Crossplane CLI to render compositions and functions specified in the annotations. Differences are then compared between the PR and main branches, and a detailed diff is generated and commented on the PR.
This GitHub Action performs a dynamic diff between pull requests (PRs) and the target branch for Crossplane YAML files with specific annotations. It leverages the Crossplane CLI to render compositions and functions specified in the annotations. Differences are then compared between the PR and target branches, and a detailed diff is generated and commented on the PR.

## Usage

To use this GitHub Action, add the following YAML configuration to your repository's `.github/workflows` directory:
To use this GitHub Action, add the following step to your GitHub job:

```yaml
name: Crossplane Dynamic Diff

name: Example Workflow
on:
pull_request:
branches: [main]

jobs:
pr:
# ... (Same as in the provided workflow)

main:
# ... (Same as in the provided workflow)
example:
runs-on: ubuntu-latest
steps:
- name: Crossplane Dynamic Diff
uses: upbound/crossplane-diff-action@main
with:
# process XRs from the given directory
dir: examples
github-token: ${{ secrets.GITHUB_TOKEN }}

```

Make sure to customize the configuration as needed for your repository.

## Workflow Overview

The workflow consists of two main jobs:

1. **pr (Pull Request) Job:**
- Installs dependencies, including QEMU, Go, yq, and the Crossplane CLI.
- Discovers YAML files in the `examples` directory and extracts composition and function paths from annotations (`crossplane.io/render-composition-path` and `crossplane.io/render-function-path`).
- Executes a dynamic job for each input file, rendering compositions and functions and storing the output as `diff-pr-*.yaml`.
- Sorts the YAML files and stores the sorted versions as artifacts.

2. **main Job:**
- Installs dependencies, including QEMU, Go, yq, and the Crossplane CLI.
- Checks out the main branch and downloads artifacts from the PR job.
- Discovers YAML files in the `examples` directory and extracts composition and function paths from annotations (`crossplane.io/render-composition-path` and `crossplane.io/render-function-path`).
- Executes a dynamic job for each input file, rendering compositions and functions and storing the output as `diff-main-*.yaml`.
- Sorts the YAML files and stores the sorted versions as artifacts.
- Compares the outputs between the PR and main branches, generating a diff for each file.
- Generates a comment summarizing all differences and attaches the comment to the PR.

### Annotations

Expand Down Expand Up @@ -79,4 +62,4 @@ This information helps reviewers understand the changes introduced by the PR.

## Credits

This GitHub Action uses the [machine-learning-apps/pr-comment](https://github.com/machine-learning-apps/pr-comment) action for commenting on the PR. Special thanks to the Crossplane community for the development and maintenance of the Crossplane CLI.
Special thanks to the Crossplane community for the development and maintenance of the Crossplane CLI.
Loading

0 comments on commit 44a6869

Please sign in to comment.