mirror of https://github.com/grafana/grafana.git
Actions: Introduce A11y test (#106806)
This commit is contained in:
parent
bb03ed54d3
commit
1264b5a619
|
@ -28,7 +28,6 @@ jobs:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: dagger/dagger-for-github@e47aba410ef9bb9ed81a4d2a97df31061e5e842e
|
- uses: dagger/dagger-for-github@e47aba410ef9bb9ed81a4d2a97df31061e5e842e
|
||||||
with:
|
with:
|
||||||
version: "8.0.0"
|
|
||||||
verb: run
|
verb: run
|
||||||
args: go -C grafana run ./pkg/build/cmd artifacts -a targz:grafana:linux/amd64 --grafana-dir="${PWD}/grafana" > out.txt
|
args: go -C grafana run ./pkg/build/cmd artifacts -a targz:grafana:linux/amd64 --grafana-dir="${PWD}/grafana" > out.txt
|
||||||
- run: mv "$(cat out.txt)" grafana.tar.gz
|
- run: mv "$(cat out.txt)" grafana.tar.gz
|
||||||
|
@ -119,7 +118,6 @@ jobs:
|
||||||
- name: Run E2E tests
|
- name: Run E2E tests
|
||||||
uses: dagger/dagger-for-github@e47aba410ef9bb9ed81a4d2a97df31061e5e842e
|
uses: dagger/dagger-for-github@e47aba410ef9bb9ed81a4d2a97df31061e5e842e
|
||||||
with:
|
with:
|
||||||
version: "8.0.0"
|
|
||||||
verb: run
|
verb: run
|
||||||
args: go run ./pkg/build/e2e --package=grafana.tar.gz
|
args: go run ./pkg/build/e2e --package=grafana.tar.gz
|
||||||
--suite=${{ matrix.path }}
|
--suite=${{ matrix.path }}
|
||||||
|
@ -139,12 +137,50 @@ jobs:
|
||||||
path: videos
|
path: videos
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|
||||||
|
run-a11y-test:
|
||||||
|
needs:
|
||||||
|
- build-grafana
|
||||||
|
- build-e2e-runner
|
||||||
|
name: A11y test
|
||||||
|
runs-on: ubuntu-latest-8-cores
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
- uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ${{ needs.build-grafana.outputs.artifact }}
|
||||||
|
- uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ${{ needs.build-e2e-runner.outputs.artifact }}
|
||||||
|
- name: chmod +x
|
||||||
|
run: chmod +x ./e2e-runner
|
||||||
|
- name: Run PR a11y test
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
uses: dagger/dagger-for-github@e47aba410ef9bb9ed81a4d2a97df31061e5e842e
|
||||||
|
with:
|
||||||
|
verb: run
|
||||||
|
args: go run ./pkg/build/a11y --package=grafana.tar.gz
|
||||||
|
--flags="--json --config ./.pa11yci-pr.conf.js"
|
||||||
|
- name: Run non-PR a11y test
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
|
uses: dagger/dagger-for-github@e47aba410ef9bb9ed81a4d2a97df31061e5e842e
|
||||||
|
with:
|
||||||
|
verb: run
|
||||||
|
args: go run ./pkg/build/a11y --package=grafana.tar.gz
|
||||||
|
--flags="--json --config ./.pa11yci.conf.js"
|
||||||
|
|
||||||
# This is the job that is actually required by rulesets.
|
# This is the job that is actually required by rulesets.
|
||||||
# We want to only require one job instead of all the individual tests.
|
# We want to only require one job instead of all the individual tests.
|
||||||
# Future work also allows us to start skipping some tests based on changed files.
|
# Future work also allows us to start skipping some tests based on changed files.
|
||||||
required-e2e-tests:
|
required-e2e-tests:
|
||||||
needs:
|
needs:
|
||||||
- run-e2e-tests
|
- run-e2e-tests
|
||||||
|
# a11y test is not listed on purpose: it is not an important E2E test.
|
||||||
|
# It is also totally fine to fail right now.
|
||||||
# always() is the best function here.
|
# always() is the best function here.
|
||||||
# success() || failure() will skip this function if any need is also skipped.
|
# success() || failure() will skip this function if any need is also skipped.
|
||||||
# That means conditional test suites will fail the entire requirement check.
|
# That means conditional test suites will fail the entire requirement check.
|
||||||
|
|
|
@ -0,0 +1,135 @@
|
||||||
|
package a11y
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/e2e/internal/fpaths"
|
||||||
|
"github.com/grafana/grafana/e2e/internal/outs"
|
||||||
|
"github.com/urfave/cli/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewCmd() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
|
Name: "a11y",
|
||||||
|
Usage: "Run accessibility tests on the Grafana frontend",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "config",
|
||||||
|
Usage: "Path to the accessibility test configuration file",
|
||||||
|
Required: true,
|
||||||
|
TakesFile: true,
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "json",
|
||||||
|
Usage: "Output results in JSON format",
|
||||||
|
Value: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "grafana-host",
|
||||||
|
Usage: "Host for the Grafana server",
|
||||||
|
Value: "localhost",
|
||||||
|
},
|
||||||
|
&cli.Uint16Flag{
|
||||||
|
Name: "grafana-port",
|
||||||
|
Usage: "Port for the Grafana server",
|
||||||
|
Value: 3001,
|
||||||
|
},
|
||||||
|
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "start-grafana",
|
||||||
|
Usage: "Start and wait for Grafana before running the tests",
|
||||||
|
Value: true,
|
||||||
|
Category: "Grafana Server",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "license-path",
|
||||||
|
Usage: "Path to the Grafana Enterprise license file (optional; requires --start-grafana)",
|
||||||
|
Value: "",
|
||||||
|
TakesFile: true,
|
||||||
|
Category: "Grafana Server",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Action: runAction,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func runAction(ctx context.Context, c *cli.Command) error {
|
||||||
|
cfgPath, err := fpaths.NormalisePath(c.String("config"))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to normalise config path %q: %w", c.String("config"), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
repoRoot, err := fpaths.RepoRoot(ctx, ".")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get repository root: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if c.Bool("start-grafana") {
|
||||||
|
startServerPath := path.Join(repoRoot, "scripts", "grafana-server", "start-server")
|
||||||
|
waitForGrafanaPath := path.Join(repoRoot, "scripts", "grafana-server", "wait-for-grafana")
|
||||||
|
go func() {
|
||||||
|
defer cancel()
|
||||||
|
var args []string
|
||||||
|
if c.String("license-path") != "" {
|
||||||
|
args = append(args, c.String("license-path"))
|
||||||
|
}
|
||||||
|
//nolint:gosec
|
||||||
|
cmd := exec.CommandContext(ctx, startServerPath, args...)
|
||||||
|
cmd.Dir = repoRoot
|
||||||
|
cmd.Env = os.Environ()
|
||||||
|
cmd.Env = append(cmd.Env, fmt.Sprintf("TZ=%s", c.String("timezone")))
|
||||||
|
cmd.Stdout = prefixGrafana(os.Stdout)
|
||||||
|
cmd.Stderr = prefixGrafana(os.Stderr)
|
||||||
|
cmd.Stdin = nil
|
||||||
|
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
fmt.Println("Error running Grafana:", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
//nolint:gosec
|
||||||
|
cmd := exec.CommandContext(ctx, waitForGrafanaPath)
|
||||||
|
cmd.Dir = repoRoot
|
||||||
|
cmd.Env = os.Environ()
|
||||||
|
cmd.Env = append(cmd.Env, fmt.Sprintf("TZ=%s", c.String("timezone")))
|
||||||
|
cmd.Stdout = prefixGrafana(os.Stdout)
|
||||||
|
cmd.Stderr = prefixGrafana(os.Stderr)
|
||||||
|
cmd.Stdin = nil
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
return fmt.Errorf("failed to wait for Grafana: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
args := []string{"run", "pa11y-ci", "--config", cfgPath}
|
||||||
|
if c.Bool("json") {
|
||||||
|
args = append(args, "--json")
|
||||||
|
}
|
||||||
|
//nolint:gosec
|
||||||
|
cmd := exec.CommandContext(ctx, "yarn", args...)
|
||||||
|
cmd.Dir = repoRoot
|
||||||
|
cmd.Env = os.Environ()
|
||||||
|
cmd.Env = append(cmd.Env,
|
||||||
|
fmt.Sprintf("HOST=%s", c.String("grafana-host")),
|
||||||
|
fmt.Sprintf("PORT=%d", c.Uint16("grafana-port")))
|
||||||
|
cmd.Stdout = prefixA11y(os.Stdout)
|
||||||
|
cmd.Stderr = prefixA11y(os.Stderr)
|
||||||
|
cmd.Stdin = os.Stdin
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func prefixA11y(w io.Writer) io.Writer {
|
||||||
|
return outs.Prefix(w, "A11y", outs.CyanColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
func prefixGrafana(w io.Writer) io.Writer {
|
||||||
|
return outs.Prefix(w, "Grafana", outs.YellowColor)
|
||||||
|
}
|
|
@ -0,0 +1,251 @@
|
||||||
|
package cypress
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/e2e/internal/fpaths"
|
||||||
|
"github.com/grafana/grafana/e2e/internal/outs"
|
||||||
|
"github.com/urfave/cli/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewCmd() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
|
Name: "cypress",
|
||||||
|
Usage: "Run a Cypress test suite",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "command",
|
||||||
|
Usage: "Cypress command to run. 'open' can be useful for development (enum: run, open)",
|
||||||
|
Value: "run",
|
||||||
|
Validator: func(s string) error {
|
||||||
|
if s != "run" && s != "open" {
|
||||||
|
return fmt.Errorf("invalid command: %s, must be 'run' or 'open'", s)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "browser",
|
||||||
|
Usage: "Browser to run tests with (e.g.: chrome, electron)",
|
||||||
|
Value: "chrome",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "grafana-base-url",
|
||||||
|
Usage: "Base URL for Grafana",
|
||||||
|
Value: "http://localhost:3001",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "cypress-video",
|
||||||
|
Usage: "Enable Cypress video recordings",
|
||||||
|
Value: false,
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "smtp-plugin",
|
||||||
|
Usage: "Enable SMTP plugin",
|
||||||
|
Value: false,
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "benchmark-plugin",
|
||||||
|
Usage: "Enable Benchmark plugin",
|
||||||
|
Value: false,
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "slowmo",
|
||||||
|
Usage: "Slow down the test run",
|
||||||
|
Value: false,
|
||||||
|
},
|
||||||
|
&cli.StringSliceFlag{
|
||||||
|
Name: "env",
|
||||||
|
Usage: "Additional Cypress environment variables to set (format: KEY=VALUE)",
|
||||||
|
Validator: func(s []string) error {
|
||||||
|
pattern := regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]*=.*`)
|
||||||
|
for _, v := range s {
|
||||||
|
if !pattern.MatchString(v) {
|
||||||
|
return fmt.Errorf("invalid environment variable format: %s, must be KEY=VALUE", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&cli.StringSliceFlag{
|
||||||
|
Name: "parameters",
|
||||||
|
Usage: "Additional parameters to pass to the Cypress command (e.g. --headed)",
|
||||||
|
},
|
||||||
|
&cli.DurationFlag{
|
||||||
|
Name: "timeout",
|
||||||
|
Usage: "Timeout for the Cypress command (precision: milliseconds)",
|
||||||
|
Value: time.Second * 30,
|
||||||
|
Validator: func(d time.Duration) error {
|
||||||
|
if d < 0 {
|
||||||
|
return fmt.Errorf("timeout must be a positive duration")
|
||||||
|
}
|
||||||
|
if d.Round(time.Millisecond) != d {
|
||||||
|
return fmt.Errorf("timeout must be a whole number of milliseconds")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "start-grafana",
|
||||||
|
Usage: "Start and wait for Grafana before running the tests",
|
||||||
|
Value: true,
|
||||||
|
Category: "Grafana Server",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "license-path",
|
||||||
|
Usage: "Path to the Grafana Enterprise license file (optional; requires --start-grafana)",
|
||||||
|
Value: "",
|
||||||
|
TakesFile: true,
|
||||||
|
Category: "Grafana Server",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "image-renderer",
|
||||||
|
Usage: "Install the image renderer plugin (requires --start-grafana)",
|
||||||
|
Category: "Grafana Server",
|
||||||
|
},
|
||||||
|
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "suite",
|
||||||
|
Usage: "Path to the suite to run (e.g. './e2e/dashboards-suite')",
|
||||||
|
TakesFile: true,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Action: runAction,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func runAction(ctx context.Context, c *cli.Command) error {
|
||||||
|
suitePath := c.String("suite")
|
||||||
|
suitePath, err := fpaths.NormalisePath(suitePath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to normalise suite path: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
repoRoot, err := fpaths.RepoRoot(ctx, suitePath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get git repo root: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
screenshotsFolder := path.Join(suitePath, "screenshots")
|
||||||
|
videosFolder := path.Join(suitePath, "videos")
|
||||||
|
fileServerFolder := path.Join(repoRoot, "e2e", "cypress")
|
||||||
|
fixturesFolder := path.Join(fileServerFolder, "fixtures")
|
||||||
|
downloadsFolder := path.Join(fileServerFolder, "downloads")
|
||||||
|
benchmarkPluginResultsFolder := path.Join(suitePath, "benchmark-results")
|
||||||
|
reporter := path.Join(repoRoot, "e2e", "log-reporter.js")
|
||||||
|
|
||||||
|
env := map[string]string{
|
||||||
|
"BENCHMARK_PLUGIN_ENABLED": fmt.Sprintf("%t", c.Bool("benchmark-plugin")),
|
||||||
|
"SMTP_PLUGIN_ENABLED": fmt.Sprintf("%t", c.Bool("smtp-plugin")),
|
||||||
|
"BENCHMARK_PLUGIN_RESULTS_FOLDER": benchmarkPluginResultsFolder,
|
||||||
|
"SLOWMO": "0",
|
||||||
|
"BASE_URL": c.String("grafana-base-url"),
|
||||||
|
}
|
||||||
|
for _, v := range c.StringSlice("env") {
|
||||||
|
parts := strings.SplitN(v, "=", 2)
|
||||||
|
if len(parts) != 2 {
|
||||||
|
return fmt.Errorf("invalid environment variable format: %s, must be KEY=VALUE", v)
|
||||||
|
}
|
||||||
|
env[parts[0]] = parts[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
cypressConfig := map[string]string{
|
||||||
|
"screenshotsFolder": screenshotsFolder,
|
||||||
|
"fixturesFolder": fixturesFolder,
|
||||||
|
"videosFolder": videosFolder,
|
||||||
|
"downloadsFolder": downloadsFolder,
|
||||||
|
"fileServerFolder": fileServerFolder,
|
||||||
|
"reporter": reporter,
|
||||||
|
|
||||||
|
"specPattern": path.Join(suitePath, "*.spec.ts"),
|
||||||
|
"defaultCommandTimeout": fmt.Sprintf("%d", c.Duration("timeout").Milliseconds()),
|
||||||
|
"viewportWidth": "1920",
|
||||||
|
"viewportHeight": "1080",
|
||||||
|
"trashAssetsBeforeRuns": "false",
|
||||||
|
"baseUrl": c.String("grafana-base-url"),
|
||||||
|
"video": fmt.Sprintf("%t", c.Bool("cypress-video")),
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if c.Bool("start-grafana") {
|
||||||
|
startServerPath := path.Join(repoRoot, "scripts", "grafana-server", "start-server")
|
||||||
|
waitForGrafanaPath := path.Join(repoRoot, "scripts", "grafana-server", "wait-for-grafana")
|
||||||
|
go func() {
|
||||||
|
defer cancel()
|
||||||
|
var args []string
|
||||||
|
if c.String("license-path") != "" {
|
||||||
|
args = append(args, c.String("license-path"))
|
||||||
|
}
|
||||||
|
//nolint:gosec
|
||||||
|
cmd := exec.CommandContext(ctx, startServerPath, args...)
|
||||||
|
cmd.Dir = repoRoot
|
||||||
|
cmd.Env = os.Environ()
|
||||||
|
cmd.Env = append(cmd.Env, fmt.Sprintf("TZ=%s", c.String("timezone")))
|
||||||
|
if c.Bool("image-renderer") {
|
||||||
|
cmd.Env = append(cmd.Env, "INSTALL_IMAGE_RENDERER=true")
|
||||||
|
}
|
||||||
|
cmd.Stdout = prefixGrafana(os.Stdout)
|
||||||
|
cmd.Stderr = prefixGrafana(os.Stderr)
|
||||||
|
cmd.Stdin = nil
|
||||||
|
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
fmt.Println("Error running Grafana:", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
//nolint:gosec
|
||||||
|
cmd := exec.CommandContext(ctx, waitForGrafanaPath)
|
||||||
|
cmd.Dir = repoRoot
|
||||||
|
cmd.Env = os.Environ()
|
||||||
|
cmd.Env = append(cmd.Env, fmt.Sprintf("TZ=%s", c.String("timezone")))
|
||||||
|
cmd.Stdout = prefixGrafana(os.Stdout)
|
||||||
|
cmd.Stderr = prefixGrafana(os.Stderr)
|
||||||
|
cmd.Stdin = nil
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
return fmt.Errorf("failed to wait for Grafana: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
args := []string{"run", "cypress", c.String("command"),
|
||||||
|
"--env", joinCypressCfg(env),
|
||||||
|
"--config", joinCypressCfg(cypressConfig),
|
||||||
|
"--browser", c.String("browser")}
|
||||||
|
args = append(args, c.StringSlice("parameters")...)
|
||||||
|
//nolint:gosec
|
||||||
|
cmd := exec.CommandContext(ctx, "yarn", args...)
|
||||||
|
cmd.Dir = repoRoot
|
||||||
|
cmd.Env = os.Environ()
|
||||||
|
cmd.Env = append(cmd.Env, fmt.Sprintf("TZ=%s", c.String("timezone")))
|
||||||
|
cmd.Stdout = prefixCypress(os.Stdout)
|
||||||
|
cmd.Stderr = prefixCypress(os.Stderr)
|
||||||
|
cmd.Stdin = os.Stdin
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func joinCypressCfg(cfg map[string]string) string {
|
||||||
|
config := make([]string, 0, len(cfg))
|
||||||
|
for k, v := range cfg {
|
||||||
|
config = append(config, fmt.Sprintf("%s=%s", k, v))
|
||||||
|
}
|
||||||
|
return strings.Join(config, ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
func prefixCypress(w io.Writer) io.Writer {
|
||||||
|
return outs.Prefix(w, "Cypress", outs.CyanColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
func prefixGrafana(w io.Writer) io.Writer {
|
||||||
|
return outs.Prefix(w, "Grafana", outs.YellowColor)
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/grafana/grafana/e2e/internal/cmd/a11y"
|
||||||
|
"github.com/grafana/grafana/e2e/internal/cmd/cypress"
|
||||||
|
"github.com/urfave/cli/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Root() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
|
Name: "e2e",
|
||||||
|
Usage: "Run an end-to-end test suite",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "timezone",
|
||||||
|
Usage: "Timezone to set for all containers (e.g. 'America/New_York')",
|
||||||
|
Value: "Pacific/Honolulu",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Commands: []*cli.Command{
|
||||||
|
a11y.NewCmd(),
|
||||||
|
cypress.NewCmd(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package fpaths
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os/exec"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RepoRoot finds the root directory of the git repository.
|
||||||
|
func RepoRoot(ctx context.Context, dir string) (string, error) {
|
||||||
|
cmd := exec.CommandContext(ctx, "git", "rev-parse", "--show-toplevel")
|
||||||
|
cmd.Dir = dir
|
||||||
|
out, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to get git repo root: %w", err)
|
||||||
|
}
|
||||||
|
p := strings.TrimSpace(string(out))
|
||||||
|
p, err = NormalisePath(p)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to normalise git repo root path: %w", err)
|
||||||
|
}
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NormalisePath converts a path to an absolute path, cleans it, and converts it to a forward-slash format.
|
||||||
|
func NormalisePath(p string) (string, error) {
|
||||||
|
absPath, err := filepath.Abs(p)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to get absolute path: %w", err)
|
||||||
|
}
|
||||||
|
return path.Clean(filepath.ToSlash(absPath)), nil
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
package outs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ResetColor = "\033[0m"
|
||||||
|
YellowColor = "\033[0;33m"
|
||||||
|
CyanColor = "\033[0;36m"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Prefix(w io.Writer, name, colour string) io.Writer {
|
||||||
|
if _, ok := os.LookupEnv("CI"); ok {
|
||||||
|
return newWrappingOutput(name+": ", "", w)
|
||||||
|
}
|
||||||
|
|
||||||
|
return newWrappingOutput(colour+name+": ", ResetColor, w)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ io.Writer = (*wrappingOutput)(nil)
|
||||||
|
|
||||||
|
type wrappingOutput struct {
|
||||||
|
prefix string
|
||||||
|
suffix string
|
||||||
|
mu *sync.Mutex
|
||||||
|
inner io.Writer
|
||||||
|
writtenPrefix bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newWrappingOutput(prefix, suffix string, inner io.Writer) *wrappingOutput {
|
||||||
|
return &wrappingOutput{
|
||||||
|
prefix: prefix,
|
||||||
|
suffix: suffix,
|
||||||
|
mu: &sync.Mutex{},
|
||||||
|
inner: inner,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *wrappingOutput) Write(b []byte) (int, error) {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
|
||||||
|
for line := range bytes.Lines(b) {
|
||||||
|
if !p.writtenPrefix {
|
||||||
|
if _, err := p.inner.Write([]byte(p.prefix)); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
p.writtenPrefix = true
|
||||||
|
}
|
||||||
|
if _, err := p.inner.Write(line); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if bytes.HasSuffix(line, []byte("\n")) {
|
||||||
|
p.writtenPrefix = false
|
||||||
|
if _, err := p.inner.Write([]byte(p.suffix)); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len(b), nil
|
||||||
|
}
|
334
e2e/main.go
334
e2e/main.go
|
@ -1,351 +1,21 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"path"
|
|
||||||
"path/filepath"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/grafana/grafana/e2e/internal/cmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
|
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := Run().Run(ctx, os.Args); err != nil {
|
if err := cmd.Root().Run(ctx, os.Args); err != nil {
|
||||||
cancel()
|
cancel()
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Run() *cli.Command {
|
|
||||||
var suitePath string
|
|
||||||
|
|
||||||
return &cli.Command{
|
|
||||||
Name: "e2e",
|
|
||||||
Usage: "Run the test suite",
|
|
||||||
Flags: []cli.Flag{
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "command",
|
|
||||||
Usage: "Cypress command to run. 'open' can be useful for development (enum: run, open)",
|
|
||||||
Value: "run",
|
|
||||||
Validator: func(s string) error {
|
|
||||||
if s != "run" && s != "open" {
|
|
||||||
return fmt.Errorf("invalid command: %s, must be 'run' or 'open'", s)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "browser",
|
|
||||||
Usage: "Browser to run tests with (e.g.: chrome, electron)",
|
|
||||||
Value: "chrome",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "grafana-base-url",
|
|
||||||
Usage: "Base URL for Grafana",
|
|
||||||
Value: "http://localhost:3001",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "cypress-video",
|
|
||||||
Usage: "Enable Cypress video recordings",
|
|
||||||
Value: false,
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "smtp-plugin",
|
|
||||||
Usage: "Enable SMTP plugin",
|
|
||||||
Value: false,
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "benchmark-plugin",
|
|
||||||
Usage: "Enable Benchmark plugin",
|
|
||||||
Value: false,
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "slowmo",
|
|
||||||
Usage: "Slow down the test run",
|
|
||||||
Value: false,
|
|
||||||
},
|
|
||||||
&cli.StringSliceFlag{
|
|
||||||
Name: "env",
|
|
||||||
Usage: "Additional Cypress environment variables to set (format: KEY=VALUE)",
|
|
||||||
Validator: func(s []string) error {
|
|
||||||
pattern := regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]*=.*`)
|
|
||||||
for _, v := range s {
|
|
||||||
if !pattern.MatchString(v) {
|
|
||||||
return fmt.Errorf("invalid environment variable format: %s, must be KEY=VALUE", v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&cli.StringSliceFlag{
|
|
||||||
Name: "parameters",
|
|
||||||
Usage: "Additional parameters to pass to the Cypress command (e.g. --headed)",
|
|
||||||
},
|
|
||||||
&cli.DurationFlag{
|
|
||||||
Name: "timeout",
|
|
||||||
Usage: "Timeout for the Cypress command (precision: milliseconds)",
|
|
||||||
Value: time.Second * 30,
|
|
||||||
Validator: func(d time.Duration) error {
|
|
||||||
if d < 0 {
|
|
||||||
return fmt.Errorf("timeout must be a positive duration")
|
|
||||||
}
|
|
||||||
if d.Round(time.Millisecond) != d {
|
|
||||||
return fmt.Errorf("timeout must be a whole number of milliseconds")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "timezone",
|
|
||||||
Usage: "Timezone to set for the Cypress run (e.g. 'America/New_York')",
|
|
||||||
Value: "Pacific/Honolulu",
|
|
||||||
},
|
|
||||||
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "start-grafana",
|
|
||||||
Usage: "Start and wait for Grafana before running the tests",
|
|
||||||
Value: true,
|
|
||||||
Category: "Grafana Server",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "license-path",
|
|
||||||
Usage: "Path to the Grafana Enterprise license file (optional; requires --start-grafana)",
|
|
||||||
Value: "",
|
|
||||||
TakesFile: true,
|
|
||||||
Category: "Grafana Server",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "image-renderer",
|
|
||||||
Usage: "Install the image renderer plugin (requires --start-grafana)",
|
|
||||||
Category: "Grafana Server",
|
|
||||||
},
|
|
||||||
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "suite",
|
|
||||||
Usage: "Path to the suite to run (e.g. './e2e/dashboards-suite')",
|
|
||||||
TakesFile: true,
|
|
||||||
Required: true,
|
|
||||||
Destination: &suitePath,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Action: runAction,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func runAction(ctx context.Context, c *cli.Command) error {
|
|
||||||
suitePath := c.String("suite")
|
|
||||||
suitePath, err := normalisePath(suitePath)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to normalise suite path: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
repoRoot, err := gitRepoRoot(ctx, suitePath)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to get git repo root: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
screenshotsFolder := path.Join(suitePath, "screenshots")
|
|
||||||
videosFolder := path.Join(suitePath, "videos")
|
|
||||||
fileServerFolder := path.Join(repoRoot, "e2e", "cypress")
|
|
||||||
fixturesFolder := path.Join(fileServerFolder, "fixtures")
|
|
||||||
downloadsFolder := path.Join(fileServerFolder, "downloads")
|
|
||||||
benchmarkPluginResultsFolder := path.Join(suitePath, "benchmark-results")
|
|
||||||
reporter := path.Join(repoRoot, "e2e", "log-reporter.js")
|
|
||||||
|
|
||||||
env := map[string]string{
|
|
||||||
"BENCHMARK_PLUGIN_ENABLED": fmt.Sprintf("%t", c.Bool("benchmark-plugin")),
|
|
||||||
"SMTP_PLUGIN_ENABLED": fmt.Sprintf("%t", c.Bool("smtp-plugin")),
|
|
||||||
"BENCHMARK_PLUGIN_RESULTS_FOLDER": benchmarkPluginResultsFolder,
|
|
||||||
"SLOWMO": "0",
|
|
||||||
"BASE_URL": c.String("grafana-base-url"),
|
|
||||||
}
|
|
||||||
for _, v := range c.StringSlice("env") {
|
|
||||||
parts := strings.SplitN(v, "=", 2)
|
|
||||||
if len(parts) != 2 {
|
|
||||||
return fmt.Errorf("invalid environment variable format: %s, must be KEY=VALUE", v)
|
|
||||||
}
|
|
||||||
env[parts[0]] = parts[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
cypressConfig := map[string]string{
|
|
||||||
"screenshotsFolder": screenshotsFolder,
|
|
||||||
"fixturesFolder": fixturesFolder,
|
|
||||||
"videosFolder": videosFolder,
|
|
||||||
"downloadsFolder": downloadsFolder,
|
|
||||||
"fileServerFolder": fileServerFolder,
|
|
||||||
"reporter": reporter,
|
|
||||||
|
|
||||||
"specPattern": path.Join(suitePath, "*.spec.ts"),
|
|
||||||
"defaultCommandTimeout": fmt.Sprintf("%d", c.Duration("timeout").Milliseconds()),
|
|
||||||
"viewportWidth": "1920",
|
|
||||||
"viewportHeight": "1080",
|
|
||||||
"trashAssetsBeforeRuns": "false",
|
|
||||||
"baseUrl": c.String("grafana-base-url"),
|
|
||||||
"video": fmt.Sprintf("%t", c.Bool("cypress-video")),
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
if c.Bool("start-grafana") {
|
|
||||||
startServerPath := path.Join(repoRoot, "scripts", "grafana-server", "start-server")
|
|
||||||
waitForGrafanaPath := path.Join(repoRoot, "scripts", "grafana-server", "wait-for-grafana")
|
|
||||||
go func() {
|
|
||||||
var args []string
|
|
||||||
if c.String("license-path") != "" {
|
|
||||||
args = append(args, c.String("license-path"))
|
|
||||||
}
|
|
||||||
//nolint:gosec
|
|
||||||
cmd := exec.CommandContext(ctx, startServerPath, args...)
|
|
||||||
cmd.Dir = repoRoot
|
|
||||||
cmd.Env = os.Environ()
|
|
||||||
cmd.Env = append(cmd.Env, fmt.Sprintf("TZ=%s", c.String("timezone")))
|
|
||||||
if c.Bool("image-renderer") {
|
|
||||||
cmd.Env = append(cmd.Env, "INSTALL_IMAGE_RENDERER=true")
|
|
||||||
}
|
|
||||||
cmd.Stdout = prefixGrafana(os.Stdout)
|
|
||||||
cmd.Stderr = prefixGrafana(os.Stderr)
|
|
||||||
cmd.Stdin = nil
|
|
||||||
|
|
||||||
if err := cmd.Run(); err != nil {
|
|
||||||
fmt.Println("Error running Grafana:", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
//nolint:gosec
|
|
||||||
cmd := exec.CommandContext(ctx, waitForGrafanaPath)
|
|
||||||
cmd.Dir = repoRoot
|
|
||||||
cmd.Env = os.Environ()
|
|
||||||
cmd.Env = append(cmd.Env, fmt.Sprintf("TZ=%s", c.String("timezone")))
|
|
||||||
cmd.Stdout = prefixGrafana(os.Stdout)
|
|
||||||
cmd.Stderr = prefixGrafana(os.Stderr)
|
|
||||||
cmd.Stdin = nil
|
|
||||||
if err := cmd.Run(); err != nil {
|
|
||||||
return fmt.Errorf("failed to wait for Grafana: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
args := []string{"run", "cypress", c.String("command"),
|
|
||||||
"--env", joinCypressCfg(env),
|
|
||||||
"--config", joinCypressCfg(cypressConfig),
|
|
||||||
"--browser", c.String("browser")}
|
|
||||||
args = append(args, c.StringSlice("parameters")...)
|
|
||||||
//nolint:gosec
|
|
||||||
cmd := exec.CommandContext(ctx, "yarn", args...)
|
|
||||||
cmd.Dir = repoRoot
|
|
||||||
cmd.Env = os.Environ()
|
|
||||||
cmd.Env = append(cmd.Env, fmt.Sprintf("TZ=%s", c.String("timezone")))
|
|
||||||
cmd.Stdout = prefixCypress(os.Stdout)
|
|
||||||
cmd.Stderr = prefixCypress(os.Stderr)
|
|
||||||
cmd.Stdin = os.Stdin
|
|
||||||
return cmd.Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
func gitRepoRoot(ctx context.Context, dir string) (string, error) {
|
|
||||||
cmd := exec.CommandContext(ctx, "git", "rev-parse", "--show-toplevel")
|
|
||||||
cmd.Dir = dir
|
|
||||||
out, err := cmd.Output()
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to get git repo root: %w", err)
|
|
||||||
}
|
|
||||||
p := strings.TrimSpace(string(out))
|
|
||||||
p, err = normalisePath(p)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to normalise git repo root path: %w", err)
|
|
||||||
}
|
|
||||||
return p, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func normalisePath(p string) (string, error) {
|
|
||||||
absPath, err := filepath.Abs(p)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to get absolute path: %w", err)
|
|
||||||
}
|
|
||||||
return path.Clean(filepath.ToSlash(absPath)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func joinCypressCfg(cfg map[string]string) string {
|
|
||||||
config := make([]string, 0, len(cfg))
|
|
||||||
for k, v := range cfg {
|
|
||||||
config = append(config, fmt.Sprintf("%s=%s", k, v))
|
|
||||||
}
|
|
||||||
return strings.Join(config, ",")
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
resetColor = "\033[0m"
|
|
||||||
yellowColor = "\033[0;33m"
|
|
||||||
cyanColor = "\033[0;36m"
|
|
||||||
)
|
|
||||||
|
|
||||||
func prefixCypress(w io.Writer) io.Writer {
|
|
||||||
if _, ok := os.LookupEnv("CI"); ok {
|
|
||||||
return w
|
|
||||||
}
|
|
||||||
|
|
||||||
return newWrappingOutput(cyanColor+"Cypress: ", resetColor, w)
|
|
||||||
}
|
|
||||||
|
|
||||||
func prefixGrafana(w io.Writer) io.Writer {
|
|
||||||
if _, ok := os.LookupEnv("CI"); ok {
|
|
||||||
return w
|
|
||||||
}
|
|
||||||
|
|
||||||
return newWrappingOutput(yellowColor+"Grafana: ", resetColor, w)
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ io.Writer = (*wrappingOutput)(nil)
|
|
||||||
|
|
||||||
type wrappingOutput struct {
|
|
||||||
prefix string
|
|
||||||
suffix string
|
|
||||||
mu *sync.Mutex
|
|
||||||
inner io.Writer
|
|
||||||
writtenPrefix bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func newWrappingOutput(prefix, suffix string, inner io.Writer) *wrappingOutput {
|
|
||||||
return &wrappingOutput{
|
|
||||||
prefix: prefix,
|
|
||||||
suffix: suffix,
|
|
||||||
mu: &sync.Mutex{},
|
|
||||||
inner: inner,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *wrappingOutput) Write(b []byte) (int, error) {
|
|
||||||
p.mu.Lock()
|
|
||||||
defer p.mu.Unlock()
|
|
||||||
|
|
||||||
for line := range bytes.Lines(b) {
|
|
||||||
if !p.writtenPrefix {
|
|
||||||
if _, err := p.inner.Write([]byte(p.prefix)); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
p.writtenPrefix = true
|
|
||||||
}
|
|
||||||
if _, err := p.inner.Write(line); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
if bytes.HasSuffix(line, []byte("\n")) {
|
|
||||||
p.writtenPrefix = false
|
|
||||||
if _, err := p.inner.Write([]byte(p.suffix)); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return len(b), nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -224,6 +224,7 @@
|
||||||
"node-notifier": "10.0.1",
|
"node-notifier": "10.0.1",
|
||||||
"nx": "20.7.1",
|
"nx": "20.7.1",
|
||||||
"openapi-types": "^12.1.3",
|
"openapi-types": "^12.1.3",
|
||||||
|
"pa11y-ci": "^3.1.0",
|
||||||
"pdf-parse": "^1.1.1",
|
"pdf-parse": "^1.1.1",
|
||||||
"plop": "^4.0.1",
|
"plop": "^4.0.1",
|
||||||
"postcss": "8.5.1",
|
"postcss": "8.5.1",
|
||||||
|
|
|
@ -0,0 +1,152 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"dagger.io/dagger"
|
||||||
|
"github.com/urfave/cli/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if err := NewApp().Run(ctx, os.Args); err != nil {
|
||||||
|
cancel()
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewApp() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
|
Name: "a11y",
|
||||||
|
Usage: "Run Grafana accessibility tests",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "grafana-dir",
|
||||||
|
Usage: "Path to the grafana/grafana clone directory",
|
||||||
|
Value: ".",
|
||||||
|
Validator: mustBeDir("grafana-dir"),
|
||||||
|
TakesFile: true,
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "package",
|
||||||
|
Usage: "Path to the grafana tar.gz package",
|
||||||
|
Value: "grafana.tar.gz",
|
||||||
|
Validator: mustBeFile("package", false),
|
||||||
|
TakesFile: true,
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "license",
|
||||||
|
Usage: "Path to the Grafana Enterprise license file (optional)",
|
||||||
|
Validator: mustBeFile("license", true),
|
||||||
|
TakesFile: true,
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "flags",
|
||||||
|
Usage: "Flags to pass through to the e2e runner",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Action: run,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func run(ctx context.Context, cmd *cli.Command) error {
|
||||||
|
grafanaDir := cmd.String("grafana-dir")
|
||||||
|
targzPath := cmd.String("package")
|
||||||
|
licensePath := cmd.String("license")
|
||||||
|
runnerFlags := cmd.String("flags")
|
||||||
|
|
||||||
|
d, err := dagger.Connect(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to connect to Dagger: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
yarnCache := d.CacheVolume("yarn")
|
||||||
|
|
||||||
|
//nolint:gosec
|
||||||
|
nvmrcContents, err := os.ReadFile(filepath.Join(grafanaDir, ".nvmrc"))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to read .nvmrc file: %w", err)
|
||||||
|
}
|
||||||
|
nodeVersion := string(nvmrcContents)
|
||||||
|
|
||||||
|
grafana := d.Host().Directory(grafanaDir, dagger.HostDirectoryOpts{
|
||||||
|
Exclude: []string{"node_modules", "*.tar.gz"},
|
||||||
|
})
|
||||||
|
targz := d.Host().File(targzPath)
|
||||||
|
|
||||||
|
var license *dagger.File
|
||||||
|
if licensePath != "" {
|
||||||
|
license = d.Host().File(licensePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
svc, err := GrafanaService(ctx, d, GrafanaServiceOpts{
|
||||||
|
GrafanaDir: grafana,
|
||||||
|
GrafanaTarGz: targz,
|
||||||
|
License: license,
|
||||||
|
YarnCache: yarnCache,
|
||||||
|
NodeVersion: nodeVersion,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create Grafana service: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c := RunTest(d, svc, grafana, yarnCache, nodeVersion, runnerFlags)
|
||||||
|
c, err = c.Sync(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to run a11y test suite: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
code, err := c.ExitCode(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get exit code of a11y test suite: %w", err)
|
||||||
|
}
|
||||||
|
if code != 0 {
|
||||||
|
return fmt.Errorf("a11y tests failed with exit code %d", code)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("a11y tests completed successfully")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func mustBeFile(arg string, emptyOk bool) func(string) error {
|
||||||
|
return func(s string) error {
|
||||||
|
if s == "" {
|
||||||
|
if emptyOk {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return cli.Exit(arg+" cannot be empty", 1)
|
||||||
|
}
|
||||||
|
stat, err := os.Stat(s)
|
||||||
|
if err != nil {
|
||||||
|
return cli.Exit(arg+" does not exist or cannot be read: "+s, 1)
|
||||||
|
}
|
||||||
|
if stat.IsDir() {
|
||||||
|
return cli.Exit(arg+" must be a file, not a directory: "+s, 1)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func mustBeDir(arg string) func(string) error {
|
||||||
|
return func(s string) error {
|
||||||
|
if s == "" {
|
||||||
|
return cli.Exit(arg+" cannot be empty", 1)
|
||||||
|
}
|
||||||
|
stat, err := os.Stat(s)
|
||||||
|
if err != nil {
|
||||||
|
return cli.Exit(arg+" does not exist or cannot be read: "+s, 1)
|
||||||
|
}
|
||||||
|
if !stat.IsDir() {
|
||||||
|
return cli.Exit(arg+" must be a directory: "+s, 1)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"dagger.io/dagger"
|
||||||
|
)
|
||||||
|
|
||||||
|
func RunTest(
|
||||||
|
d *dagger.Client,
|
||||||
|
svc *dagger.Service,
|
||||||
|
src *dagger.Directory, cache *dagger.CacheVolume,
|
||||||
|
nodeVersion, runnerFlags string) *dagger.Container {
|
||||||
|
command := fmt.Sprintf(
|
||||||
|
"./e2e-runner a11y --start-grafana=false"+
|
||||||
|
" --grafana-host grafana --grafana-port 3001 %s", runnerFlags)
|
||||||
|
|
||||||
|
return GrafanaFrontend(d, cache, nodeVersion, src).
|
||||||
|
WithExec([]string{"/bin/sh", "-c", "apt-get update && apt-get install -y git curl"}).
|
||||||
|
WithExec([]string{"curl", "-LO", "https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb"}).
|
||||||
|
WithExec([]string{"apt-get", "install", "-y", "./google-chrome-stable_current_amd64.deb"}).
|
||||||
|
WithWorkdir("/src").
|
||||||
|
WithServiceBinding("grafana", svc).
|
||||||
|
WithExec([]string{"/bin/bash", "-c", command}, dagger.ContainerWithExecOpts{Expect: dagger.ReturnTypeAny})
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"dagger.io/dagger"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NodeImage(version string) string {
|
||||||
|
return fmt.Sprintf("node:%s-slim", strings.TrimPrefix(strings.TrimSpace(version), "v"))
|
||||||
|
}
|
||||||
|
|
||||||
|
type GrafanaServiceOpts struct {
|
||||||
|
GrafanaDir *dagger.Directory
|
||||||
|
GrafanaTarGz *dagger.File
|
||||||
|
License *dagger.File
|
||||||
|
YarnCache *dagger.CacheVolume
|
||||||
|
NodeVersion string
|
||||||
|
}
|
||||||
|
|
||||||
|
func Frontend(src *dagger.Directory) *dagger.Directory {
|
||||||
|
return src.
|
||||||
|
WithoutFile("go.mod").
|
||||||
|
WithoutFile("go.sum").
|
||||||
|
WithoutFile("go.work").
|
||||||
|
WithoutFile("go.work.sum").
|
||||||
|
WithoutDirectory(".github").
|
||||||
|
WithoutDirectory("docs").
|
||||||
|
WithoutDirectory("pkg").
|
||||||
|
WithoutDirectory("apps").
|
||||||
|
WithoutDirectory("videos")
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithGrafanaFrontend(c *dagger.Container, src *dagger.Directory) *dagger.Container {
|
||||||
|
return c.WithDirectory("/src", Frontend(src), dagger.ContainerWithDirectoryOpts{
|
||||||
|
Exclude: []string{
|
||||||
|
"*drone*",
|
||||||
|
"*.go",
|
||||||
|
"*.md",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithYarnCache(c *dagger.Container, cache *dagger.CacheVolume) *dagger.Container {
|
||||||
|
return c.
|
||||||
|
WithWorkdir("/src").
|
||||||
|
WithMountedCache("/yarn/cache", cache)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GrafanaFrontend(d *dagger.Client, yarnCache *dagger.CacheVolume, nodeVersion string, grafanaDir *dagger.Directory) *dagger.Container {
|
||||||
|
container := d.Container().From(NodeImage(nodeVersion))
|
||||||
|
container = WithGrafanaFrontend(container, grafanaDir)
|
||||||
|
return WithYarnCache(container, yarnCache).
|
||||||
|
WithEnvVariable("YARN_CACHE_FOLDER", "/yarn/cache").
|
||||||
|
WithExec([]string{"yarn", "install", "--immutable"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func GrafanaService(ctx context.Context, d *dagger.Client, opts GrafanaServiceOpts) (*dagger.Service, error) {
|
||||||
|
src := GrafanaFrontend(d, opts.YarnCache, opts.NodeVersion, opts.GrafanaDir)
|
||||||
|
|
||||||
|
container := d.Container().From("alpine:3").
|
||||||
|
WithExec([]string{"apk", "add", "--no-cache", "bash", "tar", "netcat-openbsd"}).
|
||||||
|
WithMountedFile("/src/grafana.tar.gz", opts.GrafanaTarGz).
|
||||||
|
WithExec([]string{"mkdir", "-p", "/src/grafana"}).
|
||||||
|
WithExec([]string{"tar", "--strip-components=1", "-xzf", "/src/grafana.tar.gz", "-C", "/src/grafana"}).
|
||||||
|
WithDirectory("/src/grafana/devenv", src.Directory("/src/devenv")).
|
||||||
|
WithDirectory("/src/grafana/e2e", src.Directory("/src/e2e")).
|
||||||
|
WithDirectory("/src/grafana/scripts", src.Directory("/src/scripts")).
|
||||||
|
WithDirectory("/src/grafana/tools", src.Directory("/src/tools")).
|
||||||
|
WithWorkdir("/src/grafana").
|
||||||
|
WithEnvVariable("GF_APP_MODE", "development").
|
||||||
|
WithEnvVariable("GF_SERVER_HTTP_PORT", "3001").
|
||||||
|
WithEnvVariable("GF_SERVER_ROUTER_LOGGING", "1").
|
||||||
|
WithExposedPort(3001)
|
||||||
|
|
||||||
|
var licenseArg string
|
||||||
|
if opts.License != nil {
|
||||||
|
container = container.WithMountedFile("/src/license.jwt", opts.License)
|
||||||
|
licenseArg = "/src/license.jwt"
|
||||||
|
}
|
||||||
|
|
||||||
|
// We add all GF_ environment variables to allow for overriding Grafana configuration.
|
||||||
|
// It is unlikely the runner has any such otherwise.
|
||||||
|
for _, env := range os.Environ() {
|
||||||
|
if strings.HasPrefix(env, "GF_") {
|
||||||
|
parts := strings.SplitN(env, "=", 2)
|
||||||
|
container = container.WithEnvVariable(parts[0], parts[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
svc := container.AsService(dagger.ContainerAsServiceOpts{Args: []string{"bash", "-x", "scripts/grafana-server/start-server", licenseArg}})
|
||||||
|
|
||||||
|
return svc, nil
|
||||||
|
}
|
|
@ -8,7 +8,7 @@ import (
|
||||||
|
|
||||||
func RunSuite(d *dagger.Client, svc *dagger.Service, src *dagger.Directory, cache *dagger.CacheVolume, suite, runnerFlags string) *dagger.Container {
|
func RunSuite(d *dagger.Client, svc *dagger.Service, src *dagger.Directory, cache *dagger.CacheVolume, suite, runnerFlags string) *dagger.Container {
|
||||||
command := fmt.Sprintf(
|
command := fmt.Sprintf(
|
||||||
"./e2e-runner --start-grafana=false --cypress-video"+
|
"./e2e-runner cypress --start-grafana=false --cypress-video"+
|
||||||
" --grafana-base-url http://grafana:3001 --suite %s %s", suite, runnerFlags)
|
" --grafana-base-url http://grafana:3001 --suite %s %s", suite, runnerFlags)
|
||||||
|
|
||||||
return WithYarnCache(WithGrafanaFrontend(d.Container().From("cypress/included:13.1.0"), src), cache).
|
return WithYarnCache(WithGrafanaFrontend(d.Container().From("cypress/included:13.1.0"), src), cache).
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
. scripts/grafana-server/variables
|
. scripts/grafana-server/variables
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
set -eo pipefail
|
set -eo pipefail
|
||||||
|
|
||||||
. scripts/grafana-server/variables
|
. scripts/grafana-server/variables
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
DEFAULT_RUNDIR=scripts/grafana-server/tmp
|
DEFAULT_RUNDIR=scripts/grafana-server/tmp
|
||||||
RUNDIR=${RUNDIR:-$DEFAULT_RUNDIR}
|
RUNDIR=${RUNDIR:-$DEFAULT_RUNDIR}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
set -eo pipefail
|
set -eo pipefail
|
||||||
|
|
||||||
. scripts/grafana-server/variables
|
. scripts/grafana-server/variables
|
||||||
|
|
334
yarn.lock
334
yarn.lock
|
@ -11487,6 +11487,15 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"array-union@npm:^1.0.1":
|
||||||
|
version: 1.0.2
|
||||||
|
resolution: "array-union@npm:1.0.2"
|
||||||
|
dependencies:
|
||||||
|
array-uniq: "npm:^1.0.1"
|
||||||
|
checksum: 10/82cec6421b6e6766556c484835a6d476a873f1b71cace5ab2b4f1b15b1e3162dc4da0d16f7a2b04d4aec18146c6638fe8f661340b31ba8e469fd811a1b45dc8d
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"array-union@npm:^2.1.0":
|
"array-union@npm:^2.1.0":
|
||||||
version: 2.1.0
|
version: 2.1.0
|
||||||
resolution: "array-union@npm:2.1.0"
|
resolution: "array-union@npm:2.1.0"
|
||||||
|
@ -11494,6 +11503,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"array-uniq@npm:^1.0.1":
|
||||||
|
version: 1.0.3
|
||||||
|
resolution: "array-uniq@npm:1.0.3"
|
||||||
|
checksum: 10/1625f06b093d8bf279b81adfec6e72951c0857d65b5e3f65f053fffe9f9dd61c2fc52cff57e38a4700817e7e3f01a4faa433d505ea9e33cdae4514c334e0bf9e
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"array.prototype.findlast@npm:^1.2.5":
|
"array.prototype.findlast@npm:^1.2.5":
|
||||||
version: 1.2.5
|
version: 1.2.5
|
||||||
resolution: "array.prototype.findlast@npm:1.2.5"
|
resolution: "array.prototype.findlast@npm:1.2.5"
|
||||||
|
@ -11655,7 +11671,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"async@npm:^2.6.4":
|
"async@npm:^2.6.4, async@npm:~2.6.4":
|
||||||
version: 2.6.4
|
version: 2.6.4
|
||||||
resolution: "async@npm:2.6.4"
|
resolution: "async@npm:2.6.4"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -11765,6 +11781,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"axe-core@npm:~4.2.1":
|
||||||
|
version: 4.2.4
|
||||||
|
resolution: "axe-core@npm:4.2.4"
|
||||||
|
checksum: 10/fc45c087241da298be1e35ea898a1d7189903ddc52ad6f6eb46b27fb47955cb4e097eb854da5b60bedb5eab2df66fabcf334f6bb09105d404e89323cf82e8773
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"axios@npm:^1, axios@npm:^1.7.9, axios@npm:^1.8.2, axios@npm:^1.8.3":
|
"axios@npm:^1, axios@npm:^1.7.9, axios@npm:^1.8.2, axios@npm:^1.8.3":
|
||||||
version: 1.8.4
|
version: 1.8.4
|
||||||
resolution: "axios@npm:1.8.4"
|
resolution: "axios@npm:1.8.4"
|
||||||
|
@ -12021,6 +12044,18 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"bfj@npm:~7.0.2":
|
||||||
|
version: 7.0.2
|
||||||
|
resolution: "bfj@npm:7.0.2"
|
||||||
|
dependencies:
|
||||||
|
bluebird: "npm:^3.5.5"
|
||||||
|
check-types: "npm:^11.1.1"
|
||||||
|
hoopy: "npm:^0.1.4"
|
||||||
|
tryer: "npm:^1.0.1"
|
||||||
|
checksum: 10/e1040fe6aec2afeb6f6c5231bbbc055616fa99c23c5249c7d20a2919507a69d8fd4d82d2245eca5ee08cbfcd3e70ce817328b8a20acda69af4638f1c11343bc7
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"big.js@npm:^5.2.2":
|
"big.js@npm:^5.2.2":
|
||||||
version: 5.2.2
|
version: 5.2.2
|
||||||
resolution: "big.js@npm:5.2.2"
|
resolution: "big.js@npm:5.2.2"
|
||||||
|
@ -12090,7 +12125,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"bluebird@npm:^3.7.2":
|
"bluebird@npm:^3.5.5, bluebird@npm:^3.7.2":
|
||||||
version: 3.7.2
|
version: 3.7.2
|
||||||
resolution: "bluebird@npm:3.7.2"
|
resolution: "bluebird@npm:3.7.2"
|
||||||
checksum: 10/007c7bad22c5d799c8dd49c85b47d012a1fe3045be57447721e6afbd1d5be43237af1db62e26cb9b0d9ba812d2e4ca3bac82f6d7e016b6b88de06ee25ceb96e7
|
checksum: 10/007c7bad22c5d799c8dd49c85b47d012a1fe3045be57447721e6afbd1d5be43237af1db62e26cb9b0d9ba812d2e4ca3bac82f6d7e016b6b88de06ee25ceb96e7
|
||||||
|
@ -12308,7 +12343,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"buffer@npm:^5.5.0, buffer@npm:^5.7.1":
|
"buffer@npm:^5.2.1, buffer@npm:^5.5.0, buffer@npm:^5.7.1":
|
||||||
version: 5.7.1
|
version: 5.7.1
|
||||||
resolution: "buffer@npm:5.7.1"
|
resolution: "buffer@npm:5.7.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -12725,6 +12760,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"check-types@npm:^11.1.1":
|
||||||
|
version: 11.2.3
|
||||||
|
resolution: "check-types@npm:11.2.3"
|
||||||
|
checksum: 10/557e119fa018d7de4e873ada0a6c8917a0f6e0955dc19293396405f5292cfcfe190457557f4cc422e6845d715ef6bbb1d0ab9198ff6735dd96ac50e3ef1e2424
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"cheerio-select@npm:^2.1.0":
|
"cheerio-select@npm:^2.1.0":
|
||||||
version: 2.1.0
|
version: 2.1.0
|
||||||
resolution: "cheerio-select@npm:2.1.0"
|
resolution: "cheerio-select@npm:2.1.0"
|
||||||
|
@ -12739,7 +12781,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"cheerio@npm:^1.0.0":
|
"cheerio@npm:^1.0.0, cheerio@npm:~1.0.0-rc.10":
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
resolution: "cheerio@npm:1.0.0"
|
resolution: "cheerio@npm:1.0.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -12793,6 +12835,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"chownr@npm:^1.1.1":
|
||||||
|
version: 1.1.4
|
||||||
|
resolution: "chownr@npm:1.1.4"
|
||||||
|
checksum: 10/115648f8eb38bac5e41c3857f3e663f9c39ed6480d1349977c4d96c95a47266fcacc5a5aabf3cb6c481e22d72f41992827db47301851766c4fd77ac21a4f081d
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"chownr@npm:^2.0.0":
|
"chownr@npm:^2.0.0":
|
||||||
version: 2.0.0
|
version: 2.0.0
|
||||||
resolution: "chownr@npm:2.0.0"
|
resolution: "chownr@npm:2.0.0"
|
||||||
|
@ -13232,7 +13281,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"commander@npm:^6.2.0, commander@npm:^6.2.1":
|
"commander@npm:^6.2.0, commander@npm:^6.2.1, commander@npm:~6.2.1":
|
||||||
version: 6.2.1
|
version: 6.2.1
|
||||||
resolution: "commander@npm:6.2.1"
|
resolution: "commander@npm:6.2.1"
|
||||||
checksum: 10/25b88c2efd0380c84f7844b39cf18510da7bfc5013692d68cdc65f764a1c34e6c8a36ea6d72b6620e3710a930cf8fab2695bdec2bf7107a0f4fa30a3ef3b7d0e
|
checksum: 10/25b88c2efd0380c84f7844b39cf18510da7bfc5013692d68cdc65f764a1c34e6c8a36ea6d72b6620e3710a930cf8fab2695bdec2bf7107a0f4fa30a3ef3b7d0e
|
||||||
|
@ -13246,6 +13295,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"commander@npm:~8.0.0":
|
||||||
|
version: 8.0.0
|
||||||
|
resolution: "commander@npm:8.0.0"
|
||||||
|
checksum: 10/fdae6767935000431360bc72eefb20e8f0e1c639dc5fac956dc5495877dfbc5d18fcdbd32a0abf59854e013efcb2533957d11dbdbdd42b1d76aa2b54328bb15e
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"comment-parser@npm:1.4.1":
|
"comment-parser@npm:1.4.1":
|
||||||
version: 1.4.1
|
version: 1.4.1
|
||||||
resolution: "comment-parser@npm:1.4.1"
|
resolution: "comment-parser@npm:1.4.1"
|
||||||
|
@ -14983,6 +15039,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"devtools-protocol@npm:0.0.869402":
|
||||||
|
version: 0.0.869402
|
||||||
|
resolution: "devtools-protocol@npm:0.0.869402"
|
||||||
|
checksum: 10/fd3d12947047c6d6ef597b86cad1e5cf956780dac0237f0ac5de0091a1f449e3ea1eef10c65eb7c416785fb7d9e588c2588995b91b4db2830d7f23cea421472e
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"diff-sequences@npm:^27.5.1":
|
"diff-sequences@npm:^27.5.1":
|
||||||
version: 27.5.1
|
version: 27.5.1
|
||||||
resolution: "diff-sequences@npm:27.5.1"
|
resolution: "diff-sequences@npm:27.5.1"
|
||||||
|
@ -15551,6 +15614,15 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"envinfo@npm:~7.8.1":
|
||||||
|
version: 7.8.1
|
||||||
|
resolution: "envinfo@npm:7.8.1"
|
||||||
|
bin:
|
||||||
|
envinfo: dist/cli.js
|
||||||
|
checksum: 10/e7a2d71c7dfe398a4ffda0e844e242d2183ef2627f98e74e4cd71edd2af691c8707a2b34aacef92538c27b3daf9a360d32202f33c0a9f27f767c4e1c6ba8b522
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"environment@npm:^1.0.0":
|
"environment@npm:^1.0.0":
|
||||||
version: 1.1.0
|
version: 1.1.0
|
||||||
resolution: "environment@npm:1.1.0"
|
resolution: "environment@npm:1.1.0"
|
||||||
|
@ -16647,7 +16719,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"extract-zip@npm:2.0.1":
|
"extract-zip@npm:2.0.1, extract-zip@npm:^2.0.0":
|
||||||
version: 2.0.1
|
version: 2.0.1
|
||||||
resolution: "extract-zip@npm:2.0.1"
|
resolution: "extract-zip@npm:2.0.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -16904,6 +16976,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"file-url@npm:^3.0.0":
|
||||||
|
version: 3.0.0
|
||||||
|
resolution: "file-url@npm:3.0.0"
|
||||||
|
checksum: 10/f15c1bdd81df1a09238f3411f877274d7849703df837ec327c4d1df631314f60036cb700a59d826d8c96b79ff66429d3c758480005e1899c00961541b98d5bfe
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"filelist@npm:^1.0.1":
|
"filelist@npm:^1.0.1":
|
||||||
version: 1.0.4
|
version: 1.0.4
|
||||||
resolution: "filelist@npm:1.0.4"
|
resolution: "filelist@npm:1.0.4"
|
||||||
|
@ -17814,7 +17893,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"glob@npm:^7.1.2, glob@npm:^7.1.3, glob@npm:^7.1.4":
|
"glob@npm:^7.0.3, glob@npm:^7.1.2, glob@npm:^7.1.3, glob@npm:^7.1.4":
|
||||||
version: 7.2.3
|
version: 7.2.3
|
||||||
resolution: "glob@npm:7.2.3"
|
resolution: "glob@npm:7.2.3"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -17981,6 +18060,19 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"globby@npm:~6.1.0":
|
||||||
|
version: 6.1.0
|
||||||
|
resolution: "globby@npm:6.1.0"
|
||||||
|
dependencies:
|
||||||
|
array-union: "npm:^1.0.1"
|
||||||
|
glob: "npm:^7.0.3"
|
||||||
|
object-assign: "npm:^4.0.1"
|
||||||
|
pify: "npm:^2.0.0"
|
||||||
|
pinkie-promise: "npm:^2.0.0"
|
||||||
|
checksum: 10/18109d6b9d55643d2b98b59c3cfae7073ccfe39829632f353d516cc124d836c2ddebe48a23f04af63d66a621b6d86dd4cbd7e6af906f2458a7fe510ffc4bd424
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"globjoin@npm:^0.1.4":
|
"globjoin@npm:^0.1.4":
|
||||||
version: 0.1.4
|
version: 0.1.4
|
||||||
resolution: "globjoin@npm:0.1.4"
|
resolution: "globjoin@npm:0.1.4"
|
||||||
|
@ -18262,6 +18354,7 @@ __metadata:
|
||||||
ol: "npm:7.4.0"
|
ol: "npm:7.4.0"
|
||||||
ol-ext: "npm:4.0.33"
|
ol-ext: "npm:4.0.33"
|
||||||
openapi-types: "npm:^12.1.3"
|
openapi-types: "npm:^12.1.3"
|
||||||
|
pa11y-ci: "npm:^3.1.0"
|
||||||
pdf-parse: "npm:^1.1.1"
|
pdf-parse: "npm:^1.1.1"
|
||||||
plop: "npm:^4.0.1"
|
plop: "npm:^4.0.1"
|
||||||
pluralize: "npm:^8.0.0"
|
pluralize: "npm:^8.0.0"
|
||||||
|
@ -18655,6 +18748,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"hoopy@npm:^0.1.4":
|
||||||
|
version: 0.1.4
|
||||||
|
resolution: "hoopy@npm:0.1.4"
|
||||||
|
checksum: 10/7a73f1839a7fd6b953356770dff2c3cff813d97d899cddd75b348926c4df36059d987c06bedb57b1b7711504dba83d3b7b986f979a08b1e415da73a51fefa767
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"hosted-git-info@npm:^2.1.4":
|
"hosted-git-info@npm:^2.1.4":
|
||||||
version: 2.8.9
|
version: 2.8.9
|
||||||
resolution: "hosted-git-info@npm:2.8.9"
|
resolution: "hosted-git-info@npm:2.8.9"
|
||||||
|
@ -18818,6 +18918,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"html_codesniffer@npm:~2.5.1":
|
||||||
|
version: 2.5.1
|
||||||
|
resolution: "html_codesniffer@npm:2.5.1"
|
||||||
|
checksum: 10/baeb07f54f7a514f7c0abb68318f6f1216266ef853059dbe6fc182d9c49fcc610e331de76599d51d10b2415cd1c0a137a22d656047e002cf6aa8815b9a8434cc
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"htmlparser2@npm:^6.1.0":
|
"htmlparser2@npm:^6.1.0":
|
||||||
version: 6.1.0
|
version: 6.1.0
|
||||||
resolution: "htmlparser2@npm:6.1.0"
|
resolution: "htmlparser2@npm:6.1.0"
|
||||||
|
@ -20161,6 +20268,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"is@npm:^3.3.0":
|
||||||
|
version: 3.3.0
|
||||||
|
resolution: "is@npm:3.3.0"
|
||||||
|
checksum: 10/f77dc5a05a1e8fd1f1de282add9bb01c44dae27af72b883bf0ce342151dec48f125b0b8923efa78c1e93c4fb866095629b2c7de3e5e3853aea4ed17c82c5cd8d
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"isarray@npm:0.0.1":
|
"isarray@npm:0.0.1":
|
||||||
version: 0.0.1
|
version: 0.0.1
|
||||||
resolution: "isarray@npm:0.0.1"
|
resolution: "isarray@npm:0.0.1"
|
||||||
|
@ -21382,6 +21496,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"kleur@npm:~4.1.4":
|
||||||
|
version: 4.1.5
|
||||||
|
resolution: "kleur@npm:4.1.5"
|
||||||
|
checksum: 10/44d84cc4eedd4311099402ef6d4acd9b2d16e08e499d6ef3bb92389bd4692d7ef09e35248c26e27f98acac532122acb12a1bfee645994ae3af4f0a37996da7df
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"known-css-properties@npm:^0.29.0":
|
"known-css-properties@npm:^0.29.0":
|
||||||
version: 0.29.0
|
version: 0.29.0
|
||||||
resolution: "known-css-properties@npm:0.29.0"
|
resolution: "known-css-properties@npm:0.29.0"
|
||||||
|
@ -21937,7 +22058,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"lodash@npm:4.17.21, lodash@npm:^4, lodash@npm:^4.1.1, lodash@npm:^4.15.0, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.20, lodash@npm:^4.17.21, lodash@npm:^4.17.4":
|
"lodash@npm:4.17.21, lodash@npm:^4, lodash@npm:^4.1.1, lodash@npm:^4.15.0, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.20, lodash@npm:^4.17.21, lodash@npm:^4.17.4, lodash@npm:~4.17.21":
|
||||||
version: 4.17.21
|
version: 4.17.21
|
||||||
resolution: "lodash@npm:4.17.21"
|
resolution: "lodash@npm:4.17.21"
|
||||||
checksum: 10/c08619c038846ea6ac754abd6dd29d2568aa705feb69339e836dfa8d8b09abbb2f859371e86863eda41848221f9af43714491467b5b0299122431e202bb0c532
|
checksum: 10/c08619c038846ea6ac754abd6dd29d2568aa705feb69339e836dfa8d8b09abbb2f859371e86863eda41848221f9af43714491467b5b0299122431e202bb0c532
|
||||||
|
@ -22806,6 +22927,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"mkdirp-classic@npm:^0.5.2":
|
||||||
|
version: 0.5.3
|
||||||
|
resolution: "mkdirp-classic@npm:0.5.3"
|
||||||
|
checksum: 10/3f4e088208270bbcc148d53b73e9a5bd9eef05ad2cbf3b3d0ff8795278d50dd1d11a8ef1875ff5aea3fa888931f95bfcb2ad5b7c1061cfefd6284d199e6776ac
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"mkdirp@npm:^0.5.6":
|
"mkdirp@npm:^0.5.6":
|
||||||
version: 0.5.6
|
version: 0.5.6
|
||||||
resolution: "mkdirp@npm:0.5.6"
|
resolution: "mkdirp@npm:0.5.6"
|
||||||
|
@ -23072,6 +23200,15 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"mustache@npm:~4.2.0":
|
||||||
|
version: 4.2.0
|
||||||
|
resolution: "mustache@npm:4.2.0"
|
||||||
|
bin:
|
||||||
|
mustache: bin/mustache
|
||||||
|
checksum: 10/6e668bd5803255ab0779c3983b9412b5c4f4f90e822230e0e8f414f5449ed7a137eed29430e835aa689886f663385cfe05f808eb34b16e1f3a95525889b05cd3
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"mutationobserver-shim@npm:0.3.7":
|
"mutationobserver-shim@npm:0.3.7":
|
||||||
version: 0.3.7
|
version: 0.3.7
|
||||||
resolution: "mutationobserver-shim@npm:0.3.7"
|
resolution: "mutationobserver-shim@npm:0.3.7"
|
||||||
|
@ -23291,6 +23428,20 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"node-fetch@npm:~2.6.1":
|
||||||
|
version: 2.6.13
|
||||||
|
resolution: "node-fetch@npm:2.6.13"
|
||||||
|
dependencies:
|
||||||
|
whatwg-url: "npm:^5.0.0"
|
||||||
|
peerDependencies:
|
||||||
|
encoding: ^0.1.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
encoding:
|
||||||
|
optional: true
|
||||||
|
checksum: 10/72f94498d547e322207575b2778e7b3d969b0d73f35a19f258c7fb982bf0ae96e5a3a518477300ba1dd2bd22e6b05be074648ed88448c5cf1a9b7d23c6529d1a
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"node-forge@npm:^1, node-forge@npm:^1.3.1":
|
"node-forge@npm:^1, node-forge@npm:^1.3.1":
|
||||||
version: 1.3.1
|
version: 1.3.1
|
||||||
resolution: "node-forge@npm:1.3.1"
|
resolution: "node-forge@npm:1.3.1"
|
||||||
|
@ -23414,6 +23565,16 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"node.extend@npm:~2.0.2":
|
||||||
|
version: 2.0.3
|
||||||
|
resolution: "node.extend@npm:2.0.3"
|
||||||
|
dependencies:
|
||||||
|
hasown: "npm:^2.0.0"
|
||||||
|
is: "npm:^3.3.0"
|
||||||
|
checksum: 10/f500ace16d0b90e9db3919676de593eb37e7b82d8d9b67d95a40e5856ef5842592df3364b4d01fc2c3f4c0dea6dd9d627444dd85fe18581b7a22caad5ffab249
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"nodemailer@npm:6.9.13":
|
"nodemailer@npm:6.9.13":
|
||||||
version: 6.9.13
|
version: 6.9.13
|
||||||
resolution: "nodemailer@npm:6.9.13"
|
resolution: "nodemailer@npm:6.9.13"
|
||||||
|
@ -24333,6 +24494,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"p-timeout@npm:~4.1.0":
|
||||||
|
version: 4.1.0
|
||||||
|
resolution: "p-timeout@npm:4.1.0"
|
||||||
|
checksum: 10/321fec524c23a754e3f1487f2b0a5516fd32aba960d5610490eac56f8a0114b549a93f9919ffc05aa68956dc52e8330e0519f3ddf951d208d19c845f9cd778de
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"p-try@npm:^1.0.0":
|
"p-try@npm:^1.0.0":
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
resolution: "p-try@npm:1.0.0"
|
resolution: "p-try@npm:1.0.0"
|
||||||
|
@ -24356,6 +24524,48 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"pa11y-ci@npm:^3.1.0":
|
||||||
|
version: 3.1.0
|
||||||
|
resolution: "pa11y-ci@npm:3.1.0"
|
||||||
|
dependencies:
|
||||||
|
async: "npm:~2.6.4"
|
||||||
|
cheerio: "npm:~1.0.0-rc.10"
|
||||||
|
commander: "npm:~6.2.1"
|
||||||
|
globby: "npm:~6.1.0"
|
||||||
|
kleur: "npm:~4.1.4"
|
||||||
|
lodash: "npm:~4.17.21"
|
||||||
|
node-fetch: "npm:~2.6.1"
|
||||||
|
pa11y: "npm:^6.2.3"
|
||||||
|
protocolify: "npm:~3.0.0"
|
||||||
|
puppeteer: "npm:~9.1.1"
|
||||||
|
wordwrap: "npm:~1.0.0"
|
||||||
|
bin:
|
||||||
|
pa11y-ci: bin/pa11y-ci.js
|
||||||
|
checksum: 10/26f8a9e5aa2a7e1114090f4d2ff9392b2c0fa52cf7282343ce81816a7c0c017e2860d546623b6a869b86f1e597ac2f36415056ae9ccd783e8fc4bc91d76c0e5d
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"pa11y@npm:^6.2.3":
|
||||||
|
version: 6.2.3
|
||||||
|
resolution: "pa11y@npm:6.2.3"
|
||||||
|
dependencies:
|
||||||
|
axe-core: "npm:~4.2.1"
|
||||||
|
bfj: "npm:~7.0.2"
|
||||||
|
commander: "npm:~8.0.0"
|
||||||
|
envinfo: "npm:~7.8.1"
|
||||||
|
html_codesniffer: "npm:~2.5.1"
|
||||||
|
kleur: "npm:~4.1.4"
|
||||||
|
mustache: "npm:~4.2.0"
|
||||||
|
node.extend: "npm:~2.0.2"
|
||||||
|
p-timeout: "npm:~4.1.0"
|
||||||
|
puppeteer: "npm:~9.1.1"
|
||||||
|
semver: "npm:~7.3.5"
|
||||||
|
bin:
|
||||||
|
pa11y: bin/pa11y.js
|
||||||
|
checksum: 10/3903f10475aa6132279c8af21862dbcc3133e78d3c3ab6273094964093d73f60e312e9bc6eebcdcdc5c733d9229c1e63e3890103f0e860897ffd4ec2bf0f62b3
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"package-json-from-dist@npm:^1.0.0":
|
"package-json-from-dist@npm:^1.0.0":
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
resolution: "package-json-from-dist@npm:1.0.0"
|
resolution: "package-json-from-dist@npm:1.0.0"
|
||||||
|
@ -24895,7 +25105,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"pify@npm:^2.2.0, pify@npm:^2.3.0":
|
"pify@npm:^2.0.0, pify@npm:^2.2.0, pify@npm:^2.3.0":
|
||||||
version: 2.3.0
|
version: 2.3.0
|
||||||
resolution: "pify@npm:2.3.0"
|
resolution: "pify@npm:2.3.0"
|
||||||
checksum: 10/9503aaeaf4577acc58642ad1d25c45c6d90288596238fb68f82811c08104c800e5a7870398e9f015d82b44ecbcbef3dc3d4251a1cbb582f6e5959fe09884b2ba
|
checksum: 10/9503aaeaf4577acc58642ad1d25c45c6d90288596238fb68f82811c08104c800e5a7870398e9f015d82b44ecbcbef3dc3d4251a1cbb582f6e5959fe09884b2ba
|
||||||
|
@ -24916,6 +25126,22 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"pinkie-promise@npm:^2.0.0":
|
||||||
|
version: 2.0.1
|
||||||
|
resolution: "pinkie-promise@npm:2.0.1"
|
||||||
|
dependencies:
|
||||||
|
pinkie: "npm:^2.0.0"
|
||||||
|
checksum: 10/b53a4a2e73bf56b6f421eef711e7bdcb693d6abb474d57c5c413b809f654ba5ee750c6a96dd7225052d4b96c4d053cdcb34b708a86fceed4663303abee52fcca
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"pinkie@npm:^2.0.0":
|
||||||
|
version: 2.0.4
|
||||||
|
resolution: "pinkie@npm:2.0.4"
|
||||||
|
checksum: 10/11d207257a044d1047c3755374d36d84dda883a44d030fe98216bf0ea97da05a5c9d64e82495387edeb9ee4f52c455bca97cdb97629932be65e6f54b29f5aec8
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"pirates@npm:^4.0.4":
|
"pirates@npm:^4.0.4":
|
||||||
version: 4.0.6
|
version: 4.0.6
|
||||||
resolution: "pirates@npm:4.0.6"
|
resolution: "pirates@npm:4.0.6"
|
||||||
|
@ -25516,6 +25742,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"prepend-http@npm:^3.0.0":
|
||||||
|
version: 3.0.1
|
||||||
|
resolution: "prepend-http@npm:3.0.1"
|
||||||
|
checksum: 10/8f4ea0c73e7fc9d42b33a0487a458504dd1098b64ac7832ed4b0c401d292f1cf312c631efe078d9d92b0aa898be57f63459206793882061a8f507a52f0045cc7
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"prettier@npm:3.4.2, prettier@npm:^3.1.1, prettier@npm:^3.2.5":
|
"prettier@npm:3.4.2, prettier@npm:^3.1.1, prettier@npm:^3.2.5":
|
||||||
version: 3.4.2
|
version: 3.4.2
|
||||||
resolution: "prettier@npm:3.4.2"
|
resolution: "prettier@npm:3.4.2"
|
||||||
|
@ -25622,6 +25855,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"progress@npm:^2.0.1":
|
||||||
|
version: 2.0.3
|
||||||
|
resolution: "progress@npm:2.0.3"
|
||||||
|
checksum: 10/e6f0bcb71f716eee9dfac0fe8a2606e3704d6a64dd93baaf49fbadbc8499989a610fe14cf1bc6f61b6d6653c49408d94f4a94e124538084efd8e4cf525e0293d
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"promise-all-reject-late@npm:^1.0.0":
|
"promise-all-reject-late@npm:^1.0.0":
|
||||||
version: 1.0.1
|
version: 1.0.1
|
||||||
resolution: "promise-all-reject-late@npm:1.0.1"
|
resolution: "promise-all-reject-late@npm:1.0.1"
|
||||||
|
@ -25735,6 +25975,16 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"protocolify@npm:~3.0.0":
|
||||||
|
version: 3.0.0
|
||||||
|
resolution: "protocolify@npm:3.0.0"
|
||||||
|
dependencies:
|
||||||
|
file-url: "npm:^3.0.0"
|
||||||
|
prepend-http: "npm:^3.0.0"
|
||||||
|
checksum: 10/6517361b577d42ef80b975e6ad03673f1f3ea5aedae003bed7a1b6fffb06bc9c7542302f36c3517c82fb3271ba0c7b592e7b80830fa96f397ee261cba258c396
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"protocols@npm:^2.0.0, protocols@npm:^2.0.1":
|
"protocols@npm:^2.0.0, protocols@npm:^2.0.1":
|
||||||
version: 2.0.1
|
version: 2.0.1
|
||||||
resolution: "protocols@npm:2.0.1"
|
resolution: "protocols@npm:2.0.1"
|
||||||
|
@ -25818,6 +26068,26 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"puppeteer@npm:~9.1.1":
|
||||||
|
version: 9.1.1
|
||||||
|
resolution: "puppeteer@npm:9.1.1"
|
||||||
|
dependencies:
|
||||||
|
debug: "npm:^4.1.0"
|
||||||
|
devtools-protocol: "npm:0.0.869402"
|
||||||
|
extract-zip: "npm:^2.0.0"
|
||||||
|
https-proxy-agent: "npm:^5.0.0"
|
||||||
|
node-fetch: "npm:^2.6.1"
|
||||||
|
pkg-dir: "npm:^4.2.0"
|
||||||
|
progress: "npm:^2.0.1"
|
||||||
|
proxy-from-env: "npm:^1.1.0"
|
||||||
|
rimraf: "npm:^3.0.2"
|
||||||
|
tar-fs: "npm:^2.0.0"
|
||||||
|
unbzip2-stream: "npm:^1.3.3"
|
||||||
|
ws: "npm:^7.2.3"
|
||||||
|
checksum: 10/eab8e4982ea2e6007adbe7b1028504fe55dac39476e5f6f4d93b1b5abc5276ee0b398149e1824510e51c8b9a2a15048b31518563bdbe10135e2c6ced915b8018
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"pure-rand@npm:^6.0.0":
|
"pure-rand@npm:^6.0.0":
|
||||||
version: 6.0.3
|
version: 6.0.3
|
||||||
resolution: "pure-rand@npm:6.0.3"
|
resolution: "pure-rand@npm:6.0.3"
|
||||||
|
@ -28283,6 +28553,17 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"semver@npm:~7.3.5":
|
||||||
|
version: 7.3.8
|
||||||
|
resolution: "semver@npm:7.3.8"
|
||||||
|
dependencies:
|
||||||
|
lru-cache: "npm:^6.0.0"
|
||||||
|
bin:
|
||||||
|
semver: bin/semver.js
|
||||||
|
checksum: 10/c8c04a4d41d30cffa7277904e0ad6998623dd61e36bca9578b0128d8c683b705a3924beada55eae7fa004fb30a9359a53a4ead2b68468d778b602f3b1a28f8e3
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"send@npm:0.19.0":
|
"send@npm:0.19.0":
|
||||||
version: 0.19.0
|
version: 0.19.0
|
||||||
resolution: "send@npm:0.19.0"
|
resolution: "send@npm:0.19.0"
|
||||||
|
@ -30079,7 +30360,19 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"tar-stream@npm:~2.2.0":
|
"tar-fs@npm:^2.0.0":
|
||||||
|
version: 2.1.3
|
||||||
|
resolution: "tar-fs@npm:2.1.3"
|
||||||
|
dependencies:
|
||||||
|
chownr: "npm:^1.1.1"
|
||||||
|
mkdirp-classic: "npm:^0.5.2"
|
||||||
|
pump: "npm:^3.0.0"
|
||||||
|
tar-stream: "npm:^2.1.4"
|
||||||
|
checksum: 10/37fdfd3aa73f4f49c0821ef75f67647ecafd5370d2e311d9ace6ff3825ff4355014055c3d43407c6a655adf6c5bfb0cbcf93412161dad5af7110eb7d7a0c2eae
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"tar-stream@npm:^2.1.4, tar-stream@npm:~2.2.0":
|
||||||
version: 2.2.0
|
version: 2.2.0
|
||||||
resolution: "tar-stream@npm:2.2.0"
|
resolution: "tar-stream@npm:2.2.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -30547,6 +30840,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"tryer@npm:^1.0.1":
|
||||||
|
version: 1.0.1
|
||||||
|
resolution: "tryer@npm:1.0.1"
|
||||||
|
checksum: 10/4d869d187bd715136903b349f39d1cc3e5c19f742689a348190aff92408ee8dd3d7d9adc26dc9265c35d722731184c979ed316109b6c1239249a8707bb92cc49
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"ts-api-utils@npm:^2.0.0, ts-api-utils@npm:^2.1.0":
|
"ts-api-utils@npm:^2.0.0, ts-api-utils@npm:^2.1.0":
|
||||||
version: 2.1.0
|
version: 2.1.0
|
||||||
resolution: "ts-api-utils@npm:2.1.0"
|
resolution: "ts-api-utils@npm:2.1.0"
|
||||||
|
@ -31062,6 +31362,16 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"unbzip2-stream@npm:^1.3.3":
|
||||||
|
version: 1.4.3
|
||||||
|
resolution: "unbzip2-stream@npm:1.4.3"
|
||||||
|
dependencies:
|
||||||
|
buffer: "npm:^5.2.1"
|
||||||
|
through: "npm:^2.3.8"
|
||||||
|
checksum: 10/4ffc0e14f4af97400ed0f37be83b112b25309af21dd08fa55c4513e7cb4367333f63712aec010925dbe491ef6e92db1248e1e306e589f9f6a8da8b3a9c4db90b
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"unc-path-regex@npm:^0.1.2":
|
"unc-path-regex@npm:^0.1.2":
|
||||||
version: 0.1.2
|
version: 0.1.2
|
||||||
resolution: "unc-path-regex@npm:0.1.2"
|
resolution: "unc-path-regex@npm:0.1.2"
|
||||||
|
@ -32280,7 +32590,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"wordwrap@npm:^1.0.0":
|
"wordwrap@npm:^1.0.0, wordwrap@npm:~1.0.0":
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
resolution: "wordwrap@npm:1.0.0"
|
resolution: "wordwrap@npm:1.0.0"
|
||||||
checksum: 10/497d40beb2bdb08e6d38754faa17ce20b0bf1306327f80cb777927edb23f461ee1f6bc659b3c3c93f26b08e1cf4b46acc5bae8fda1f0be3b5ab9a1a0211034cd
|
checksum: 10/497d40beb2bdb08e6d38754faa17ce20b0bf1306327f80cb777927edb23f461ee1f6bc659b3c3c93f26b08e1cf4b46acc5bae8fda1f0be3b5ab9a1a0211034cd
|
||||||
|
@ -32383,7 +32693,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"ws@npm:^7.2.0, ws@npm:^7.3.1":
|
"ws@npm:^7.2.0, ws@npm:^7.2.3, ws@npm:^7.3.1":
|
||||||
version: 7.5.10
|
version: 7.5.10
|
||||||
resolution: "ws@npm:7.5.10"
|
resolution: "ws@npm:7.5.10"
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
|
Loading…
Reference in New Issue