name: Dry Run on: pull_request: paths: - "state/*.json" jobs: detect: runs-on: ubuntu-latest outputs: envs: ${{ steps.changed.outputs.envs }} steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Detect changed environments id: changed run: | FILES=$(git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ github.sha }} -- 'state/*.json') ENVS="[]" for f in $FILES; do ENV=$(basename "$f" .json) ENVS=$(echo "$ENVS" | jq -c ". + [\"$ENV\"]") done echo "envs=$ENVS" >> "$GITHUB_OUTPUT" echo "Changed environments: $ENVS" dry-run: needs: detect runs-on: ubuntu-latest if: needs.detect.outputs.envs != '[]' strategy: matrix: env: ${{ fromJson(needs.detect.outputs.envs) }} steps: - uses: actions/checkout@v4 - name: Resolve environment secrets id: env run: | ENV_UPPER=$(echo "${{ matrix.env }}" | tr '[:lower:]-' '[:upper:]_') echo "token_key=${ENV_UPPER}_RECONCILER_TOKEN" >> "$GITHUB_OUTPUT" echo "url_key=${ENV_UPPER}_RECONCILER_URL" >> "$GITHUB_OUTPUT" - name: Run dry-run reconcile id: plan env: RECONCILER_TOKEN: ${{ secrets[steps.env.outputs.token_key] }} RECONCILER_URL: ${{ secrets[steps.env.outputs.url_key] }} run: | if [ -z "$RECONCILER_URL" ] || [ -z "$RECONCILER_TOKEN" ]; then echo "No secrets configured for environment '${{ matrix.env }}' — skipping" echo "response={}" >> "$GITHUB_OUTPUT" exit 0 fi RESPONSE=$(curl -sf \ -X POST \ -H "Authorization: Bearer ${RECONCILER_TOKEN}" \ -H "Content-Type: application/json" \ -d @state/${{ matrix.env }}.json \ "${RECONCILER_URL}/reconcile?dry_run=true") echo "response<> "$GITHUB_OUTPUT" echo "$RESPONSE" >> "$GITHUB_OUTPUT" echo "EOF" >> "$GITHUB_OUTPUT" - name: Format plan as markdown id: format if: steps.plan.outputs.response != '{}' run: | cat <<'SCRIPT' > format.py import json, sys data = json.loads(sys.stdin.read()) ops = data.get("operations", []) summary = data.get("summary", {}) env = sys.argv[1] lines = [f"## Reconciliation Plan: `{env}`\n"] if not ops: lines.append("No changes detected.\n") else: lines.append("| Operation | Name |") lines.append("|-----------|------|") for op in ops: lines.append(f"| `{op['type']}` | {op['name']} |") lines.append("") s = summary lines.append(f"**Summary:** {s.get('created',0)} create, {s.get('updated',0)} update, {s.get('deleted',0)} delete") print("\n".join(lines)) SCRIPT COMMENT=$(echo '${{ steps.plan.outputs.response }}' | python3 format.py "${{ matrix.env }}") echo "comment<> "$GITHUB_OUTPUT" echo "$COMMENT" >> "$GITHUB_OUTPUT" echo "EOF" >> "$GITHUB_OUTPUT" - name: Post PR comment if: steps.plan.outputs.response != '{}' env: GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} run: | curl -sf \ -X POST \ -H "Authorization: token ${GITEA_TOKEN}" \ -H "Content-Type: application/json" \ -d "{\"body\": $(echo '${{ steps.format.outputs.comment }}' | jq -Rs .)}" \ "${{ secrets.GITEA_URL }}/api/v1/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments"