diff --git a/.config/.cprc.json b/.config/.cprc.json index aff7c03..12b4f12 100644 --- a/.config/.cprc.json +++ b/.config/.cprc.json @@ -1,3 +1,3 @@ { - "version": "4.6.2" + "version": "4.10.1" } diff --git a/.config/jest-setup.js b/.config/jest-setup.js index 1b9fc2f..b9f5738 100644 --- a/.config/jest-setup.js +++ b/.config/jest-setup.js @@ -6,6 +6,9 @@ */ import '@testing-library/jest-dom'; +import { TextEncoder, TextDecoder } from 'util'; + +Object.assign(global, { TextDecoder, TextEncoder }); // https://jestjs.io/docs/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom Object.defineProperty(global, 'matchMedia', { diff --git a/.config/webpack/webpack.config.ts b/.config/webpack/webpack.config.ts index 0ff00f2..9b7978a 100644 --- a/.config/webpack/webpack.config.ts +++ b/.config/webpack/webpack.config.ts @@ -12,6 +12,7 @@ import LiveReloadPlugin from 'webpack-livereload-plugin'; import path from 'path'; import ReplaceInFileWebpackPlugin from 'replace-in-file-webpack-plugin'; import { Configuration } from 'webpack'; +import { GrafanaPluginMetaExtractor } from '@grafana/plugin-meta-extractor'; import { getPackageJson, getPluginJson, hasReadme, getEntries, isWSL } from './utils'; import { SOURCE_DIR, DIST_DIR } from './constants'; @@ -140,6 +141,7 @@ const config = async (env): Promise => { }, plugins: [ + new GrafanaPluginMetaExtractor(), new CopyWebpackPlugin({ patterns: [ // If src/README.md exists use it; otherwise the root README @@ -149,14 +151,13 @@ const config = async (env): Promise => { { from: '../LICENSE', to: '.' }, { from: '../CHANGELOG.md', to: '.', force: true }, { from: '**/*.json', to: '.' }, // TODO - // { from: '**/*.svg', to: '.', noErrorOnMissing: true }, // Optional + { from: '**/*.svg', to: '.', noErrorOnMissing: true }, // Optional { from: '**/*.png', to: '.', noErrorOnMissing: true }, // Optional { from: '**/*.html', to: '.', noErrorOnMissing: true }, // Optional - // { from: 'img/**/*', to: '.', noErrorOnMissing: true }, // Optional + { from: 'img/**/*', to: '.', noErrorOnMissing: true }, // Optional { from: 'libs/**/*', to: '.', noErrorOnMissing: true }, // Optional { from: 'static/**/*', to: '.', noErrorOnMissing: true }, // Optional { from: '**/query_help.md', to: '.', noErrorOnMissing: true }, // Optional - { from: 'img/logo.svg', to: './img/', noErrorOnMissing: true }, // Copy logo ], }), // Replace certain template-variables in the README and plugin.json @@ -182,19 +183,19 @@ const config = async (env): Promise => { ]), ...(env.development ? [ - new LiveReloadPlugin(), - new ForkTsCheckerWebpackPlugin({ - async: Boolean(env.development), - issue: { - include: [{ file: '**/*.{ts,tsx}' }], - }, - typescript: { configFile: path.join(process.cwd(), 'tsconfig.json') }, - }), - new ESLintPlugin({ - extensions: ['.ts', '.tsx'], - lintDirtyModulesOnly: Boolean(env.development), // don't lint on start, only lint changed files - }), - ] + new LiveReloadPlugin(), + new ForkTsCheckerWebpackPlugin({ + async: Boolean(env.development), + issue: { + include: [{ file: '**/*.{ts,tsx}' }], + }, + typescript: { configFile: path.join(process.cwd(), 'tsconfig.json') }, + }), + new ESLintPlugin({ + extensions: ['.ts', '.tsx'], + lintDirtyModulesOnly: Boolean(env.development), // don't lint on start, only lint changed files + }), + ] : []), ], diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 902f566..b99a32c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,13 @@ permissions: read-all jobs: build: + name: Build, lint and unit tests runs-on: ubuntu-latest + outputs: + plugin-id: ${{ steps.metadata.outputs.plugin-id }} + plugin-version: ${{ steps.metadata.outputs.plugin-version }} + has-e2e: ${{ steps.check-for-e2e.outputs.has-e2e }} + has-backend: ${{ steps.check-for-backend.outputs.has-backend }} env: GRAFANA_ACCESS_POLICY_TOKEN: ${{ secrets.GRAFANA_ACCESS_POLICY_TOKEN }} steps: @@ -72,40 +78,6 @@ jobs: echo "has-e2e=true" >> $GITHUB_OUTPUT fi - - name: Install Playwright Browsers - if: steps.check-for-e2e.outputs.has-e2e == 'true' - run: npm exec playwright install --with-deps - - - name: Start grafana docker - if: steps.check-for-e2e.outputs.has-e2e == 'true' - run: docker-compose up -d - - - name: Wait for Grafana to start - if: steps.check-for-e2e.outputs.has-e2e == 'true' - uses: nev7n/wait_for_response@v1 - with: - url: 'http://localhost:3000/' - responseCode: 200 - timeout: 60000 - interval: 500 - - - name: Run e2e tests - id: run-e2e-tests - if: steps.check-for-e2e.outputs.has-e2e == 'true' - run: npm run e2e - - - name: Stop grafana docker - if: steps.check-for-e2e.outputs.has-e2e == 'true' - run: docker-compose down - - - name: Archive E2E output - uses: actions/upload-artifact@v4 - if: steps.check-for-e2e.outputs.has-e2e == 'true' && steps.run-e2e-tests.outcome != 'success' - with: - name: playwright-report - path: playwright-report/ - retention-days: 5 - - name: Sign plugin run: npm run sign if: ${{ env.GRAFANA_ACCESS_POLICY_TOKEN != '' }} @@ -135,3 +107,102 @@ jobs: name: ${{ steps.metadata.outputs.plugin-id }}-${{ steps.metadata.outputs.plugin-version }} path: ${{ steps.metadata.outputs.plugin-id }} retention-days: 5 + + resolve-versions: + name: Resolve e2e images + runs-on: ubuntu-latest + timeout-minutes: 3 + needs: build + if: ${{ needs.build.outputs.has-e2e == 'true' }} + outputs: + matrix: ${{ steps.resolve-versions.outputs.matrix }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Resolve Grafana E2E versions + id: resolve-versions + uses: grafana/plugin-actions/e2e-version@main + + playwright-tests: + needs: [resolve-versions, build] + timeout-minutes: 15 + strategy: + fail-fast: false + matrix: + GRAFANA_IMAGE: ${{fromJson(needs.resolve-versions.outputs.matrix)}} + name: e2e test ${{ matrix.GRAFANA_IMAGE.name }}@${{ matrix.GRAFANA_IMAGE.VERSION }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + sparse-checkout: | + provisioning + tests + .config + + - name: Download plugin + if: needs.build.outputs.has-backend == 'true' + uses: actions/download-artifact@v4 + with: + path: dist + name: ${{ needs.build.outputs.plugin-id }}-${{ needs.build.outputs.plugin-version }} + + - name: Execute permissions on binary + if: needs.build.outputs.has-backend == 'true' + run: | + chmod +x ./dist/gpx_cicd_linux_amd64 + + - name: Setup Node.js environment + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + + - name: Install dev dependencies + run: npm ci + + - name: Start Grafana + run: | + docker-compose pull + DEVELOPMENT=false GRAFANA_VERSION=${{ matrix.GRAFANA_IMAGE.VERSION }} GRAFANA_IMAGE=${{ matrix.GRAFANA_IMAGE.NAME }} docker-compose up -d + + - name: Wait for Grafana to start + uses: nev7n/wait_for_response@v1 + with: + url: 'http://localhost:3000/' + responseCode: 200 + timeout: 60000 + interval: 500 + + - name: Install Playwright Browsers + run: npx playwright install chromium --with-deps + + - name: Run Playwright tests + id: run-tests + run: npm run e2e + + - name: Docker logs + if: ${{ always() && steps.run-tests.outcome == 'failure' }} + run: | + docker logs xxxxxxxxx-zzzzzzz-panel >& grafana-server.log + + - name: Stop grafana docker + run: docker-compose down + + - name: Upload server log + uses: actions/upload-artifact@v4 + if: ${{ always() && steps.run-tests.outcome == 'failure' }} + with: + name: ${{ matrix.GRAFANA_IMAGE.NAME }}-v${{ matrix.GRAFANA_IMAGE.VERSION }}-${{github.run_id}}-server-log + path: grafana-server.log + retention-days: 5 + + # If your repository is public, uploading the Playwright report will make it public on the Internet. + # Beware not to expose sensitive information. + - name: Upload artifacts + uses: actions/upload-artifact@v4 + if: ${{ always() && steps.run-tests.outcome == 'failure' }} + with: + name: playwright-report-${{ matrix.GRAFANA_IMAGE.NAME }}-v${{ matrix.GRAFANA_IMAGE.VERSION }}-${{github.run_id}} + path: playwright-report/ + retention-days: 5 diff --git a/docker-compose.yaml b/docker-compose.yaml index c6f0847..3c11eb9 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -11,6 +11,7 @@ services: args: grafana_image: ${GRAFANA_IMAGE:-grafana-enterprise} grafana_version: ${GRAFANA_VERSION:-10.3.3} + development: ${DEVELOPMENT:-true} ports: - 3000:3000/tcp volumes: diff --git a/package.json b/package.json index bdaf338..60bdaba 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "@grafana/eslint-config": "^7.0.0", "@grafana/plugin-e2e": "^1.0.1", "@grafana/tsconfig": "^1.2.0-rc1", + "@grafana/plugin-meta-extractor": "^0.0.1", "@playwright/test": "^1.41.2", "@swc/core": "^1.3.90", "@swc/helpers": "^0.5.0",