Fix: consumption SKU agent runAfter bug β restore runAfter when re-adding agent loop #106
Workflow file for this run
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: PR Coverage Check | |
| on: | |
| pull_request: | |
| branches: [main, dev/*, hotfix/*] | |
| jobs: | |
| coverage: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| steps: | |
| - name: Checkout PR branch | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Cache turbo build setup | |
| uses: actions/cache@v4 | |
| with: | |
| path: .turbo | |
| key: ${{ runner.os }}-turbo-${{ github.sha }} | |
| restore-keys: | | |
| ${{ runner.os }}-turbo- | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 20.x | |
| - name: Install pnpm | |
| uses: pnpm/action-setup@v3 | |
| with: | |
| version: 9.1.3 | |
| run_install: | | |
| - recursive: true | |
| args: [--frozen-lockfile, --strict-peer-dependencies] | |
| - name: Build | |
| run: pnpm turbo run build --cache-dir=.turbo | |
| - name: Run tests with coverage | |
| run: | | |
| pnpm turbo run test:lib --cache-dir=.turbo | |
| pnpm turbo run test:iframe-app --cache-dir=.turbo | |
| pnpm turbo run test:extension-unit --cache-dir=.turbo | |
| - name: Merge coverage reports | |
| run: | | |
| mkdir -p coverage | |
| # Find all lcov.info files and merge them | |
| find . -path ./node_modules -prune -o -name 'lcov.info' -print 2>/dev/null | head -20 > lcov-files.txt | |
| if [ -s lcov-files.txt ]; then | |
| npx lcov-result-merger './libs/**/coverage/lcov.info' './apps/**/coverage/lcov.info' ./coverage/lcov.info || true | |
| fi | |
| - name: Get changed files | |
| id: changed-files | |
| uses: tj-actions/changed-files@v46 | |
| with: | |
| files: | | |
| **/*.ts | |
| **/*.tsx | |
| files_ignore: | | |
| # Test files | |
| **/*.test.ts | |
| **/*.test.tsx | |
| **/*.spec.ts | |
| **/*.spec.tsx | |
| **/__test__/** | |
| **/__tests__/** | |
| **/__mocks__/** | |
| **/test-setup.ts | |
| **/test-globals.ts | |
| **/setup.ts | |
| # Type definitions and models | |
| **/*.d.ts | |
| **/models/** | |
| **/types/** | |
| **/interfaces/** | |
| **/*Types.ts | |
| **/*Types.tsx | |
| **/*Model.ts | |
| **/*Models.ts | |
| **/*Interface.ts | |
| **/*Interfaces.ts | |
| **/types.ts | |
| **/types.tsx | |
| **/styles.ts | |
| **/constants.ts | |
| **/constants/** | |
| # Config files | |
| **/*.config.ts | |
| **/*.config.tsx | |
| **/vite.config.* | |
| **/vitest.config.* | |
| **/tsconfig.* | |
| # Index/barrel files (just re-exports) | |
| **/index.ts | |
| **/index.tsx | |
| # Node modules and build output | |
| **/node_modules/** | |
| **/dist/** | |
| **/build/** | |
| # Standalone app (dev environment, not covered by tests) | |
| apps/Standalone/** | |
| # Documentation site | |
| apps/docs/** | |
| # Manifest and swagger files (configuration/data, not logic) | |
| **/manifest/** | |
| **/manifests/** | |
| **/swagger/** | |
| # Service interfaces and base classes (tested via implementations) | |
| **/designer-client-services/lib/*.ts | |
| **/lib/base/** | |
| # Environment-specific service index/barrel files | |
| **/lib/consumption/index.ts | |
| **/lib/standard/index.ts | |
| # Static operation and schema definitions | |
| **/operations/** | |
| **/schemas/** | |
| **/staticresultschema/** | |
| # Application setup and providers (not business logic) | |
| **/*Context.ts | |
| **/*Context.tsx | |
| **/*Provider.ts | |
| **/*Provider.tsx | |
| **/providers/** | |
| - name: Check coverage on changed files | |
| id: coverage-check | |
| run: | | |
| echo "## π Coverage Report for Changed Files" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| # Get the list of changed source files | |
| CHANGED_FILES="${{ steps.changed-files.outputs.all_changed_files }}" | |
| if [ -z "$CHANGED_FILES" ]; then | |
| echo "No source files changed in this PR." >> $GITHUB_STEP_SUMMARY | |
| echo "coverage_status=skip" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| echo "### Changed Files:" >> $GITHUB_STEP_SUMMARY | |
| for file in $CHANGED_FILES; do | |
| echo "- \`$file\`" >> $GITHUB_STEP_SUMMARY | |
| done | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| # Check if coverage file exists | |
| if [ ! -f "./coverage/lcov.info" ]; then | |
| echo "β οΈ No merged coverage report found. Checking individual coverage files..." >> $GITHUB_STEP_SUMMARY | |
| # Look for individual coverage files | |
| COVERAGE_FILES=$(find . -path ./node_modules -prune -o -name 'lcov.info' -print 2>/dev/null | grep -v node_modules || true) | |
| if [ -z "$COVERAGE_FILES" ]; then | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "β **No coverage data found.** Please ensure tests generate coverage reports." >> $GITHUB_STEP_SUMMARY | |
| echo "coverage_status=no_data" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| fi | |
| # Parse coverage and check changed files | |
| UNCOVERED_FILES="" | |
| COVERED_FILES="" | |
| PARTIAL_FILES="" | |
| SKIPPED_FILES="" | |
| # Define packages that require coverage (libs with vitest configs) | |
| COVERED_PACKAGES="libs/designer libs/designer-ui libs/designer-v2 libs/logic-apps-shared libs/data-mapper libs/data-mapper-v2 libs/chatbot libs/a2a-core libs/vscode-extension apps/vs-code-designer apps/vs-code-react apps/iframe-app" | |
| for file in $CHANGED_FILES; do | |
| # Skip if file doesn't exist (might have been deleted) | |
| if [ ! -f "$file" ]; then | |
| continue | |
| fi | |
| # Find the corresponding coverage file for this source file | |
| # Look in the package's coverage directory | |
| PKG_DIR=$(echo "$file" | sed 's|/src/.*||') | |
| LCOV_FILE="$PKG_DIR/coverage/lcov.info" | |
| # Check if this package requires coverage | |
| PKG_REQUIRES_COVERAGE=false | |
| for pkg in $COVERED_PACKAGES; do | |
| if [ "$PKG_DIR" = "$pkg" ]; then | |
| PKG_REQUIRES_COVERAGE=true | |
| break | |
| fi | |
| done | |
| if [ -f "$LCOV_FILE" ]; then | |
| # Get the absolute path pattern to match in lcov (lcov uses paths relative to package root or absolute) | |
| # Extract the path after PKG_DIR to match against lcov SF entries | |
| FILE_RELATIVE_PATH=$(echo "$file" | sed "s|^$PKG_DIR/||") | |
| # Check if this file is mentioned in the coverage report using the relative path | |
| if grep -q "SF:.*${FILE_RELATIVE_PATH}$" "$LCOV_FILE" 2>/dev/null; then | |
| # Get line coverage for this file - use the full relative path for accurate matching | |
| FILE_SECTION=$(awk "/SF:.*${FILE_RELATIVE_PATH//\//\\/}\$/,/end_of_record/" "$LCOV_FILE" 2>/dev/null || true) | |
| if [ -n "$FILE_SECTION" ]; then | |
| LINES_FOUND=$(echo "$FILE_SECTION" | grep "^LF:" | cut -d: -f2 || echo "0") | |
| LINES_HIT=$(echo "$FILE_SECTION" | grep "^LH:" | cut -d: -f2 || echo "0") | |
| if [ "$LINES_FOUND" -gt 0 ] 2>/dev/null; then | |
| COVERAGE_PCT=$((LINES_HIT * 100 / LINES_FOUND)) | |
| if [ "$COVERAGE_PCT" -ge 80 ]; then | |
| COVERED_FILES="$COVERED_FILES\nβ \`$file\` - ${COVERAGE_PCT}% covered" | |
| elif [ "$COVERAGE_PCT" -gt 0 ]; then | |
| PARTIAL_FILES="$PARTIAL_FILES\nβ οΈ \`$file\` - ${COVERAGE_PCT}% covered (needs improvement)" | |
| else | |
| UNCOVERED_FILES="$UNCOVERED_FILES\nβ \`$file\` - 0% covered" | |
| fi | |
| fi | |
| fi | |
| else | |
| UNCOVERED_FILES="$UNCOVERED_FILES\nβ \`$file\` - Not covered by tests" | |
| fi | |
| elif [ "$PKG_REQUIRES_COVERAGE" = true ]; then | |
| # Package should have coverage but doesn't - this is a problem | |
| UNCOVERED_FILES="$UNCOVERED_FILES\nβ \`$file\` - No coverage data (package should have tests)" | |
| else | |
| # Package doesn't require coverage (not in the list) | |
| SKIPPED_FILES="$SKIPPED_FILES\nβοΈ \`$file\` - Package not configured for coverage" | |
| fi | |
| done | |
| echo "### Coverage Results:" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| if [ -n "$COVERED_FILES" ]; then | |
| echo "#### β Well Covered:" >> $GITHUB_STEP_SUMMARY | |
| echo -e "$COVERED_FILES" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| if [ -n "$PARTIAL_FILES" ]; then | |
| echo "#### β οΈ Partially Covered (< 80%):" >> $GITHUB_STEP_SUMMARY | |
| echo -e "$PARTIAL_FILES" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| if [ -n "$SKIPPED_FILES" ]; then | |
| echo "#### βοΈ Skipped (package not configured for coverage):" >> $GITHUB_STEP_SUMMARY | |
| echo -e "$SKIPPED_FILES" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| if [ -n "$UNCOVERED_FILES" ]; then | |
| echo "#### β Not Covered:" >> $GITHUB_STEP_SUMMARY | |
| echo -e "$UNCOVERED_FILES" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Please add tests for the uncovered files before merging.**" >> $GITHUB_STEP_SUMMARY | |
| echo "coverage_status=fail" >> $GITHUB_OUTPUT | |
| else | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "π **All changed files have adequate test coverage!**" >> $GITHUB_STEP_SUMMARY | |
| echo "coverage_status=pass" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Post coverage comment on PR | |
| if: always() | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const fs = require('fs'); | |
| // Check if this is a fork PR - forks don't have write permissions | |
| const isFork = context.payload.pull_request?.head?.repo?.fork === true; | |
| if (isFork) { | |
| console.log('βΉοΈ This PR is from a fork. Skipping PR comment (no write permissions).'); | |
| console.log('π Coverage results are available in the workflow summary above.'); | |
| return; | |
| } | |
| // Read the step summary | |
| const summaryPath = process.env.GITHUB_STEP_SUMMARY; | |
| let summary = ''; | |
| try { | |
| summary = fs.readFileSync(summaryPath, 'utf8'); | |
| } catch (e) { | |
| summary = 'π Coverage check completed. See workflow run for details.'; | |
| } | |
| try { | |
| // Find existing comment | |
| const { data: comments } = await github.rest.issues.listComments({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| }); | |
| const botComment = comments.find(comment => | |
| comment.user.type === 'Bot' && | |
| comment.body.includes('π Coverage Report for Changed Files') | |
| ); | |
| const commentBody = summary || 'π Coverage check completed. See workflow run for details.'; | |
| if (botComment) { | |
| await github.rest.issues.updateComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: botComment.id, | |
| body: commentBody | |
| }); | |
| } else { | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body: commentBody | |
| }); | |
| } | |
| } catch (error) { | |
| // Handle permission errors gracefully (e.g., for fork PRs) | |
| if (error.status === 403) { | |
| console.log('β οΈ Unable to post comment (permission denied). This is expected for fork PRs.'); | |
| console.log('π Coverage results are available in the workflow summary above.'); | |
| } else { | |
| throw error; | |
| } | |
| } | |
| - name: Fail if coverage is insufficient | |
| if: steps.coverage-check.outputs.coverage_status == 'fail' | |
| run: | | |
| echo "β Some changed files lack test coverage. Please add tests before merging." | |
| exit 1 |