CI - Test Changed Features (PR) #26
This file contains hidden or 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: "CI - Test Changed Features (PR)" | |
| on: | |
| pull_request: | |
| paths: | |
| - 'src/**' | |
| - 'test/**' | |
| workflow_dispatch: | |
| inputs: | |
| features: | |
| description: 'Comma-separated list of features to test (e.g., yay,clone-repo)' | |
| required: false | |
| type: string | |
| force_all: | |
| description: 'Force test all features regardless of changes' | |
| required: false | |
| type: boolean | |
| default: false | |
| jobs: | |
| detect-changes: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| features: ${{ steps.changed-features.outputs.features }} | |
| has_changes: ${{ steps.changed-features.outputs.has_changes }} | |
| has_global_changes: ${{ steps.changed-features.outputs.has_global_changes }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Detect changed features | |
| id: changed-features | |
| run: | | |
| # Handle manual workflow dispatch | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
| if [ "${{ inputs.force_all }}" = "true" ]; then | |
| # Test all features | |
| FEATURES='["yay","clone-repo","node","rust-bin","dotnet","dotnet-bin","chaotic-aur"]' | |
| echo "Manual dispatch: Testing all features" | |
| elif [ -n "${{ inputs.features }}" ]; then | |
| # Test specified features | |
| FEATURES=$(echo "${{ inputs.features }}" | tr ',' '\n' | jq -R -s -c 'split("\n")[:-1] | map(select(length > 0))') | |
| echo "Manual dispatch: Testing specified features: ${{ inputs.features }}" | |
| else | |
| # No features specified, exit | |
| FEATURES='[]' | |
| echo "Manual dispatch: No features specified" | |
| fi | |
| else | |
| # Handle pull request - detect changed files | |
| echo "Pull request: Detecting changed features..." | |
| # Get changed files compared to main branch | |
| CHANGED_FILES=$(git diff --name-only origin/main...HEAD) | |
| echo "Changed files:" | |
| echo "$CHANGED_FILES" | |
| # Extract unique features from src/ and test/ paths | |
| FEATURES=$(echo "$CHANGED_FILES" | \ | |
| grep -E '^(src|test)/' | \ | |
| cut -d'/' -f2 | \ | |
| sort -u | \ | |
| grep -v '^$' | \ | |
| jq -R -s -c 'split("\n")[:-1] | map(select(length > 0))') | |
| # Handle feature dependencies | |
| # If dotnet-bin is changed, also include yay (dependency) | |
| if echo "$FEATURES" | jq -r '.[]' | grep -q "dotnet-bin"; then | |
| echo "dotnet-bin detected, adding yay dependency" | |
| FEATURES=$(echo "$FEATURES" | jq '. + ["yay"] | unique') | |
| fi | |
| echo "Detected features: $FEATURES" | |
| fi | |
| # Set outputs | |
| echo "features=$FEATURES" >> $GITHUB_OUTPUT | |
| # Check if we have any features to test | |
| HAS_CHANGES=$([ "$FEATURES" != "[]" ] && echo "true" || echo "false") | |
| echo "has_changes=$HAS_CHANGES" >> $GITHUB_OUTPUT | |
| # Check for global changes (workflow files, root configs, etc.) | |
| if [ "${{ github.event_name }}" = "pull_request" ]; then | |
| GLOBAL_CHANGES=$(echo "$CHANGED_FILES" | grep -E '^(\.github/|\.actrc|README\.md)' || true) | |
| HAS_GLOBAL_CHANGES=$([ -n "$GLOBAL_CHANGES" ] && echo "true" || echo "false") | |
| else | |
| HAS_GLOBAL_CHANGES="false" | |
| fi | |
| echo "has_global_changes=$HAS_GLOBAL_CHANGES" >> $GITHUB_OUTPUT | |
| # Summary | |
| echo "Summary:" | |
| echo " Features to test: $FEATURES" | |
| echo " Has changes: $HAS_CHANGES" | |
| echo " Has global changes: $HAS_GLOBAL_CHANGES" | |
| test-autogenerated-selective: | |
| runs-on: ubuntu-latest | |
| needs: detect-changes | |
| if: needs.detect-changes.outputs.has_changes == 'true' | |
| continue-on-error: true | |
| strategy: | |
| matrix: | |
| features: ${{ fromJson(needs.detect-changes.outputs.features) }} | |
| baseImage: | |
| - archlinux:latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: "Install latest devcontainer CLI" | |
| run: npm install -g @devcontainers/cli | |
| - name: "Testing autogenerated tests for '${{ matrix.features }}' against '${{ matrix.baseImage }}'" | |
| run: | | |
| echo "Running autogenerated tests for feature: ${{ matrix.features }}" | |
| devcontainer features test --skip-scenarios -f ${{ matrix.features }} -i ${{ matrix.baseImage }} . | |
| test-scenarios-selective: | |
| runs-on: ubuntu-latest | |
| needs: detect-changes | |
| if: needs.detect-changes.outputs.has_changes == 'true' | |
| continue-on-error: true | |
| strategy: | |
| matrix: | |
| features: ${{ fromJson(needs.detect-changes.outputs.features) }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: "Install latest devcontainer CLI" | |
| run: npm install -g @devcontainers/cli | |
| - name: "Testing scenarios for '${{ matrix.features }}'" | |
| run: | | |
| echo "Running scenario tests for feature: ${{ matrix.features }}" | |
| devcontainer features test -f ${{ matrix.features }} --skip-autogenerated --skip-duplicated . | |
| test-global-conditional: | |
| runs-on: ubuntu-latest | |
| needs: detect-changes | |
| if: needs.detect-changes.outputs.has_global_changes == 'true' | |
| continue-on-error: true | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: "Install latest devcontainer CLI" | |
| run: npm install -g @devcontainers/cli | |
| - name: "Testing global scenarios (triggered by global changes)" | |
| run: | | |
| echo "Running global scenario tests due to global file changes" | |
| devcontainer features test --global-scenarios-only . | |
| summary: | |
| runs-on: ubuntu-latest | |
| needs: [detect-changes, test-autogenerated-selective, test-scenarios-selective, test-global-conditional] | |
| if: always() | |
| steps: | |
| - name: "Test Summary" | |
| run: | | |
| echo "## π Selective Testing Summary" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| if [ "${{ needs.detect-changes.outputs.has_changes }}" = "true" ]; then | |
| echo "### β Features Tested" >> $GITHUB_STEP_SUMMARY | |
| echo "The following features were tested based on detected changes:" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| # Parse and display tested features | |
| FEATURES='${{ needs.detect-changes.outputs.features }}' | |
| echo "$FEATURES" | jq -r '.[]' | while read feature; do | |
| echo "- **$feature**" >> $GITHUB_STEP_SUMMARY | |
| done | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| # Test results | |
| echo "### π Test Results" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Autogenerated Tests**: ${{ needs.test-autogenerated-selective.result }}" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Scenario Tests**: ${{ needs.test-scenarios-selective.result }}" >> $GITHUB_STEP_SUMMARY | |
| if [ "${{ needs.detect-changes.outputs.has_global_changes }}" = "true" ]; then | |
| echo "- **Global Tests**: ${{ needs.test-global-conditional.result }}" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| else | |
| echo "### βΉοΈ No Feature Changes Detected" >> $GITHUB_STEP_SUMMARY | |
| echo "No changes detected in \`src/\` or \`test/\` directories." >> $GITHUB_STEP_SUMMARY | |
| echo "Selective testing was skipped." >> $GITHUB_STEP_SUMMARY | |
| fi | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### π Next Steps" >> $GITHUB_STEP_SUMMARY | |
| echo "- This workflow tests only changed features for quick feedback" >> $GITHUB_STEP_SUMMARY | |
| echo "- Full testing will run via the main CI workflow" >> $GITHUB_STEP_SUMMARY | |
| echo "- For local testing, use: \`act pull_request --input features=<feature-name>\`" >> $GITHUB_STEP_SUMMARY |