--- name: Detect Plugin Extension Changes concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true permissions: {} on: pull_request: branches: - 'main' paths: - 'packages/**' - 'public/**' env: # Space-separated list of keywords referring to plugin extensions PLUGIN_EXTENSION_KEYWORDS: "usePluginLinks, usePluginComponent, usePluginComponents, usePluginFunctions, PluginExtensionPoints" jobs: detect-plugin-extension-changes: name: Detect Plugin Extension Changes runs-on: ubuntu-latest permissions: contents: read id-token: write if: github.event.pull_request.head.repo.full_name == github.repository steps: - uses: actions/checkout@v5 with: fetch-depth: 0 persist-credentials: false - name: Check for plugin extension changes id: check-changes uses: actions/github-script@v7 with: script: | const { execSync } = require('child_process'); const fs = require('fs'); // Plugin extension keywords from environment const keywords = process.env.PLUGIN_EXTENSION_KEYWORDS.split(','); const baseSha = '${{ github.event.pull_request.base.sha }}'; const headSha = '${{ github.event.pull_request.head.sha }}'; console.log('Checking for plugin extension changes...'); console.log('Keywords:', keywords); // Get changed files in packages/ and public/ directories let changedFiles = []; const diffOutput = execSync( `git diff --name-only ${baseSha}...${headSha} -- packages/ public/`, { encoding: 'utf8' } ).trim(); if (diffOutput) { changedFiles = diffOutput.split('\n').filter(file => { // Validate file path and ensure it's in target directories return file.match(/^(packages\/|public\/)/) && file.match(/^[a-zA-Z0-9._/-]+$/) && fs.existsSync(file); }); } console.log('Changed files to check:', changedFiles); // Check each file for plugin extension keywords const filesWithChanges = new Set(); let hasPluginExtensionChanges = false; for (const file of changedFiles) { try { // Get the diff for this specific file const fileDiff = execSync( `git diff ${baseSha}...${headSha} -- "${file}"`, { encoding: 'utf8' } ); // Check if any keywords are in the diff for (const keyword of keywords) { if (fileDiff.includes(keyword)) { console.log(`Found ${keyword} in ${file}`); filesWithChanges.add(file); hasPluginExtensionChanges = true; break; // Found at least one keyword, move to next file } } } catch (error) { console.log(`Error checking file ${file}:`, error.message); } } // Set outputs const filesArray = Array.from(filesWithChanges); const formattedFiles = filesArray.length > 0 ? '`' + filesArray.join('`\\n- `') + '`' : ''; core.setOutput('plugin_extension_changes', hasPluginExtensionChanges.toString()); core.setOutput('formatted_changed_files', formattedFiles); if (hasPluginExtensionChanges) { console.log('The following files have changes that may affect plugin extensions:'); console.log(filesArray); } else { console.log('No changes detected in core Grafana extensions or extension points.'); } - name: Send Slack Message via Payload id: slack if: steps.check-changes.outputs.plugin_extension_changes == 'true' uses: grafana/shared-workflows/actions/send-slack-message@0941e3408fa4789fec9062c44a2a9e1832146ba6 #v2.0.1 with: method: chat.postMessage payload-templated: true payload: | { "channel": "C031SLFH6G0", "text": "Plugin Extension changes in core Grafana *PR:* <${{ github.event.pull_request.html_url }}|#${{ github.event.pull_request.number }} :information_source:", "icon_emoji": ":grot:", "username": "Plugin Extension Bot", "blocks": [ { "type": "section", "text": { "type": "mrkdwn", "text": "*Plugin Extensions:* possible changes to extension points in core Grafana." } }, { "type": "section", "text": { "type": "mrkdwn", "text": "*PR:* <${{ github.event.pull_request.html_url }}|#${{ github.event.pull_request.number }}>\n*Job:* <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View Job>\n*Author:* ${{ github.event.pull_request.user.login }}" } }, { "type": "section", "text": { "type": "mrkdwn", "text": "*File(s) with changes:*\n- ${{ steps.check-changes.outputs.formatted_changed_files }}" } }, { "type": "section", "text": { "type": "mrkdwn", "text": "*What to do?*\nMake sure that:\n- All extension point ids start with `grafana/`\n- All extension point ids are exposed via \n- Core Grafana is not registering extensions to extension points offered by plugins" } } ] }