diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d7ff4aac..f2f926c1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -32,6 +32,11 @@ jobs: npm install --global bower bower -v + - name: Install Dart SDK + uses: dart-lang/setup-dart@v1 + with: + sdk: stable + - name: Install PHP & Composer (macOS) if: runner.os == 'macOS' shell: bash diff --git a/build/docker/debian.Dockerfile b/build/docker/debian.Dockerfile index edf8efa3..983ad27d 100644 --- a/build/docker/debian.Dockerfile +++ b/build/docker/debian.Dockerfile @@ -50,7 +50,7 @@ RUN echo "deb http://deb.debian.org/debian unstable main" >> /etc/apt/sources.li # echo "Pin: release a=testing" >> /etc/apt/preferences && \ # echo "Pin-Priority: -3" >> /etc/apt/preferences -RUN apt -y update && apt -y upgrade && apt -y install curl gnupg unzip && \ +RUN apt -y update && apt -y install curl gnupg unzip && \ apt -y clean && rm -rf /var/lib/apt/lists/* RUN mkdir -p /etc/apt/keyrings @@ -73,7 +73,7 @@ RUN curl -fsSLO https://services.gradle.org/distributions/gradle-$GRADLE_VERSION ENV NODE_MAJOR="20" RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg RUN echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list -RUN apt -y update && apt -y upgrade && apt -y install nodejs && \ +RUN apt -y update && apt -y install nodejs && \ apt -y clean && rm -rf /var/lib/apt/lists/* RUN npm install --global npm@latest && \ npm install --global yarn && \ @@ -96,26 +96,20 @@ RUN curl -fsSLO https://dot.net/v1/dotnet-install.sh \ && rm ./dotnet-install.sh \ && dotnet help -# Prevent systemd from being configured to avoid QEMU segfaults on arm64 +#Prevent systemd from being configured to avoid QEMU segfaults on arm64 RUN echo 'exit 101' > /usr/sbin/policy-rc.d && chmod +x /usr/sbin/policy-rc.d RUN apt -y update && apt -y install ca-certificates && \ - apt-mark hold systemd && \ - apt -y -o Dpkg::Options::="--force-overwrite" \ - -o Dpkg::Options::="--force-confold" \ - -o Dpkg::Options::="--force-confdef" \ - install -t unstable --no-install-recommends \ - python3.13 \ - python3.13-venv \ + apt -y install --no-install-recommends \ + python3 \ + python3-venv \ python3-pip \ - openjdk-21-jdk && \ - apt -y clean && rm -rf /var/lib/apt/lists/* && \ - ln -s /usr/bin/python3.13 /usr/bin/python + openjdk-17-jdk RUN dotnet --version && go version RUN apt update -y && \ - apt install -t unstable lsb-release apt-transport-https ca-certificates software-properties-common -y && \ + apt install lsb-release apt-transport-https ca-certificates software-properties-common -y && \ curl -o /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg && \ sh -c 'echo "deb https://packages.sury.org/php/ bookworm main" > /etc/apt/sources.list.d/php.list' && \ apt -y clean && rm -rf /var/lib/apt/lists/* @@ -141,7 +135,7 @@ RUN apt -y update && apt -y install \ RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin --filename=composer -RUN ln -sf /usr/bin/python3.13 /usr/bin/python3 && php -v && composer --version && python3 --version +RUN php -v && composer --version && python3 --version # Install Poetry for Python resolution (pyproject.toml) RUN curl -sSL https://install.python-poetry.org | python3 - && \ @@ -157,4 +151,4 @@ ENV PATH="/root/.local/bin:$PATH" CMD [ "debricked", "scan" ] # Put copy at the end to speedup Docker build by caching previous RUNs and run those concurrently -COPY --from=dev /cli/debricked /usr/bin/debricked +COPY --from=dev /cli/debricked /usr/bin/debricked \ No newline at end of file diff --git a/internal/resolution/pm/pm.go b/internal/resolution/pm/pm.go index 3cbe2170..f298a751 100644 --- a/internal/resolution/pm/pm.go +++ b/internal/resolution/pm/pm.go @@ -11,6 +11,7 @@ import ( "github.com/debricked/cli/internal/resolution/pm/pip" "github.com/debricked/cli/internal/resolution/pm/pnpm" "github.com/debricked/cli/internal/resolution/pm/poetry" + "github.com/debricked/cli/internal/resolution/pm/pub" "github.com/debricked/cli/internal/resolution/pm/sbt" "github.com/debricked/cli/internal/resolution/pm/uv" "github.com/debricked/cli/internal/resolution/pm/yarn" @@ -36,5 +37,6 @@ func Pms() []IPm { nuget.NewPm(), composer.NewPm(), sbt.NewPm(), + pub.NewPm(), } } diff --git a/internal/resolution/pm/pm_test.go b/internal/resolution/pm/pm_test.go index aabd4f55..9e9a76c2 100644 --- a/internal/resolution/pm/pm_test.go +++ b/internal/resolution/pm/pm_test.go @@ -13,6 +13,7 @@ func TestPms(t *testing.T) { "go", "gradle", "composer", + "pub", } for _, pmName := range pmNames { diff --git a/internal/resolution/pm/pub/cmd_factory.go b/internal/resolution/pm/pub/cmd_factory.go new file mode 100644 index 00000000..129c286a --- /dev/null +++ b/internal/resolution/pm/pub/cmd_factory.go @@ -0,0 +1,65 @@ +package pub + +import ( + "os" + "os/exec" + "path/filepath" +) + +type ICmdFactory interface { + MakeLockCmd(manifestFile string) (*exec.Cmd, error) + MakeDepsCmd(manifestFile string) (*exec.Cmd, error) +} + +type IExecPath interface { + LookPath(file string) (string, error) +} + +type ExecPath struct{} + +func (_ ExecPath) LookPath(file string) (string, error) { + return exec.LookPath(file) +} + +type CmdFactory struct { + execPath IExecPath +} + +// MakeLockCmd creates an exec.Cmd that runs `dart pub get` in the directory +// of the given manifest file. This resolves all dependencies and writes a +// pubspec.lock file that can be used for SCA scanning. +func (cmdf CmdFactory) MakeLockCmd(manifestFile string) (*exec.Cmd, error) { + dartPath, err := cmdf.execPath.LookPath("dart") + if err != nil { + return nil, err + } + + workingDir := filepath.Dir(filepath.Clean(manifestFile)) + + return &exec.Cmd{ + Path: dartPath, + Args: []string{"dart", "pub", "get"}, + Dir: workingDir, + Env: os.Environ(), + }, nil +} + +// MakeDepsCmd creates an exec.Cmd that runs `dart pub deps --json` in the +// directory of the given manifest file. This outputs explicit parent-child +// dependency relationships used to reconstruct the transitive dependency tree. +func (cmdf CmdFactory) MakeDepsCmd(manifestFile string) (*exec.Cmd, error) { + dartPath, err := cmdf.execPath.LookPath("dart") + if err != nil { + return nil, err + } + + workingDir := filepath.Dir(filepath.Clean(manifestFile)) + + return &exec.Cmd{ + + Path: dartPath, + Args: []string{"dart", "pub", "deps", "--json"}, + Dir: workingDir, + Env: os.Environ(), + }, nil +} diff --git a/internal/resolution/pm/pub/cmd_factory_test.go b/internal/resolution/pm/pub/cmd_factory_test.go new file mode 100644 index 00000000..b4210069 --- /dev/null +++ b/internal/resolution/pm/pub/cmd_factory_test.go @@ -0,0 +1,43 @@ +package pub + +import ( + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" +) + +type execPathMock struct{} + +func (execPathMock) LookPath(file string) (string, error) { + return "/usr/bin/" + file, nil +} + +func TestMakeLockCmd(t *testing.T) { + factory := CmdFactory{execPath: execPathMock{}} + manifest := filepath.Join("some", "path", "pubspec.yaml") + + cmd, err := factory.MakeLockCmd(manifest) + assert.NoError(t, err) + assert.NotNil(t, cmd) + assert.Equal(t, "/usr/bin/dart", cmd.Path) + assert.Contains(t, cmd.Args, "dart") + assert.Contains(t, cmd.Args, "pub") + assert.Contains(t, cmd.Args, "get") + assert.Equal(t, filepath.Dir(manifest), cmd.Dir) +} + +func TestMakeDepsCmd(t *testing.T) { + factory := CmdFactory{execPath: execPathMock{}} + manifest := filepath.Join("some", "path", "pubspec.yaml") + + cmd, err := factory.MakeDepsCmd(manifest) + assert.NoError(t, err) + assert.NotNil(t, cmd) + assert.Equal(t, "/usr/bin/dart", cmd.Path) + assert.Contains(t, cmd.Args, "dart") + assert.Contains(t, cmd.Args, "pub") + assert.Contains(t, cmd.Args, "deps") + assert.Contains(t, cmd.Args, "--json") + assert.Equal(t, filepath.Dir(manifest), cmd.Dir) +} diff --git a/internal/resolution/pm/pub/job.go b/internal/resolution/pm/pub/job.go new file mode 100644 index 00000000..0398f1e5 --- /dev/null +++ b/internal/resolution/pm/pub/job.go @@ -0,0 +1,120 @@ +package pub + +import ( + "os" + "regexp" + "strings" + + "github.com/debricked/cli/internal/resolution/job" + "github.com/debricked/cli/internal/resolution/pm/util" +) + +const ( + executableNotFoundErrRegex = `executable file not found` + depsFileName = "pubspec.deps.json" +) + +// Job runs `dart pub get` and `dart pub deps --json` for a given pubspec.yaml. +// It produces pubspec.lock and pubspec.deps.json, where the latter contains +// explicit parent-child relationships for full transitive tree reconstruction. +type Job struct { + job.BaseJob + cmdFactory ICmdFactory +} + +func NewJob(file string, cmdFactory ICmdFactory) *Job { + return &Job{ + BaseJob: job.NewBaseJob(file), + cmdFactory: cmdFactory, + } +} + +func (j *Job) Run() { + status := "generating pubspec.lock" + j.SendStatus(status) + + lockCmd, err := j.cmdFactory.MakeLockCmd(j.GetFile()) + if err != nil { + j.handleError(j.createError(err.Error(), "", status)) + + return + } + + if output, err := lockCmd.Output(); err != nil { + exitErr := j.GetExitError(err, string(output)) + errorMessage := strings.Join([]string{string(output), exitErr.Error()}, "") + j.handleError(j.createError(errorMessage, lockCmd.String(), status)) + + return + } + + status = "generating pubspec.deps.json" + j.SendStatus(status) + + depsCmd, err := j.cmdFactory.MakeDepsCmd(j.GetFile()) + if err != nil { + j.handleError(j.createError(err.Error(), "", status)) + + return + } + + depsOutput, err := depsCmd.Output() + if err != nil { + exitErr := j.GetExitError(err, string(depsOutput)) + errorMessage := strings.Join([]string{string(depsOutput), exitErr.Error()}, "") + j.handleError(j.createError(errorMessage, depsCmd.String(), status)) + + return + } + + status = "writing pubspec.deps.json" + j.SendStatus(status) + + err = os.WriteFile(util.MakePathFromManifestFile(j.GetFile(), depsFileName), depsOutput, 0600) + if err != nil { + j.handleError(j.createError(err.Error(), "", status)) + + return + } +} + +func (j *Job) createError(errorStr string, cmd string, status string) job.IError { + cmdError := util.NewPMJobError(errorStr) + cmdError.SetCommand(cmd) + cmdError.SetStatus(status) + + return cmdError +} + +func (j *Job) handleError(cmdError job.IError) { + expressions := []string{ + executableNotFoundErrRegex, + } + + for _, expression := range expressions { + regex := regexp.MustCompile(expression) + matches := regex.FindAllStringSubmatch(cmdError.Error(), -1) + + if len(matches) > 0 { + cmdError = j.addDocumentation(expression, matches, cmdError) + j.Errors().Append(cmdError) + + return + } + } + + j.Errors().Append(cmdError) +} + +func (j *Job) addDocumentation(expr string, _ [][]string, cmdError job.IError) job.IError { + documentation := cmdError.Documentation() + + switch expr { + case executableNotFoundErrRegex: + documentation = j.GetExecutableNotFoundErrorDocumentation("Dart") + } + + cmdError.SetDocumentation(documentation) + + return cmdError +} diff --git a/internal/resolution/pm/pub/job_test.go b/internal/resolution/pm/pub/job_test.go new file mode 100644 index 00000000..b3d28569 --- /dev/null +++ b/internal/resolution/pm/pub/job_test.go @@ -0,0 +1,66 @@ +package pub + +import ( + "errors" + "os" + "path/filepath" + "testing" + + jobTestdata "github.com/debricked/cli/internal/resolution/job/testdata" + "github.com/debricked/cli/internal/resolution/pm/pub/testdata" + "github.com/stretchr/testify/assert" +) + +func TestNewJob(t *testing.T) { + j := NewJob("file", testdata.CmdFactoryMock{}) + assert.Equal(t, "file", j.GetFile()) + assert.False(t, j.Errors().HasError()) +} + +func TestRunCmdErrExecutableNotFound(t *testing.T) { + execErr := errors.New("exec: \"dart\": executable file not found in $PATH") + j := NewJob("file", testdata.CmdFactoryMock{LockErr: execErr}) + + go jobTestdata.WaitStatus(j) + + j.Run() + + errs := j.Errors().GetAll() + assert.Len(t, errs, 1) + assert.Contains(t, errs[0].Error(), "executable file not found") + assert.Contains(t, errs[0].Documentation(), "Dart wasn't found") +} + +func TestRunDepsCmdErrExecutableNotFound(t *testing.T) { + execErr := errors.New("exec: \"dart\": executable file not found in $PATH") + j := NewJob("file", testdata.CmdFactoryMock{Name: "echo", Arg: "ok", DepsErr: execErr}) + + go jobTestdata.WaitStatus(j) + + j.Run() + + errs := j.Errors().GetAll() + assert.Len(t, errs, 1) + assert.Contains(t, errs[0].Error(), "executable file not found") + assert.Contains(t, errs[0].Documentation(), "Dart wasn't found") +} + +func TestRunSuccess(t *testing.T) { + tmpDir := t.TempDir() + manifest := filepath.Join(tmpDir, "pubspec.yaml") + + err := os.WriteFile(manifest, []byte("name: test"), 0600) + assert.NoError(t, err) + + j := NewJob(manifest, testdata.CmdFactoryMock{Name: "echo", Arg: "ok"}) + + go jobTestdata.WaitStatus(j) + + j.Run() + + assert.False(t, j.Errors().HasError()) + assert.Len(t, j.Errors().GetAll(), 0) + + _, statErr := os.Stat(filepath.Join(tmpDir, "pubspec.deps.json")) + assert.NoError(t, statErr) +} diff --git a/internal/resolution/pm/pub/pm.go b/internal/resolution/pm/pub/pm.go new file mode 100644 index 00000000..e69bbffe --- /dev/null +++ b/internal/resolution/pm/pub/pm.go @@ -0,0 +1,23 @@ +package pub + +const Name = "pub" + +type Pm struct { + name string +} + +func NewPm() Pm { + return Pm{ + name: Name, + } +} + +func (pm Pm) Name() string { + return pm.name +} + +func (_ Pm) Manifests() []string { + return []string{ + `pubspec\.yaml$`, + } +} diff --git a/internal/resolution/pm/pub/pm_test.go b/internal/resolution/pm/pub/pm_test.go new file mode 100644 index 00000000..b32ed0e2 --- /dev/null +++ b/internal/resolution/pm/pub/pm_test.go @@ -0,0 +1,24 @@ +package pub + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNewPm(t *testing.T) { + pm := NewPm() + assert.Equal(t, Name, pm.name) +} + +func TestName(t *testing.T) { + pm := NewPm() + assert.Equal(t, Name, pm.Name()) +} + +func TestManifests(t *testing.T) { + pm := Pm{} + manifests := pm.Manifests() + assert.Len(t, manifests, 1) + assert.Equal(t, `pubspec\.yaml$`, manifests[0]) +} diff --git a/internal/resolution/pm/pub/strategy.go b/internal/resolution/pm/pub/strategy.go new file mode 100644 index 00000000..c6bd6c6b --- /dev/null +++ b/internal/resolution/pm/pub/strategy.go @@ -0,0 +1,23 @@ +package pub + +import "github.com/debricked/cli/internal/resolution/job" + +type Strategy struct { + files []string +} + +func NewStrategy(files []string) Strategy { + return Strategy{files: files} +} + +func (s Strategy) Invoke() ([]job.IJob, error) { + var jobs []job.IJob + for _, file := range s.files { + jobs = append(jobs, NewJob( + file, + CmdFactory{execPath: ExecPath{}}, + )) + } + + return jobs, nil +} diff --git a/internal/resolution/pm/pub/strategy_test.go b/internal/resolution/pm/pub/strategy_test.go new file mode 100644 index 00000000..3a3a8d9f --- /dev/null +++ b/internal/resolution/pm/pub/strategy_test.go @@ -0,0 +1,35 @@ +package pub + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNewStrategy(t *testing.T) { + s := NewStrategy(nil) + assert.NotNil(t, s) + assert.Len(t, s.files, 0) + + s = NewStrategy([]string{"file"}) + assert.Len(t, s.files, 1) +} + +func TestStrategyInvoke(t *testing.T) { + cases := [][]string{ + {}, + {"pubspec.yaml"}, + {"a/pubspec.yaml", "b/pubspec.yaml"}, + } + + for _, files := range cases { + filesCopy := append([]string{}, files...) + name := "len=" + string(rune(len(filesCopy))) + t.Run(name, func(t *testing.T) { + s := NewStrategy(filesCopy) + jobs, err := s.Invoke() + assert.NoError(t, err) + assert.Len(t, jobs, len(filesCopy)) + }) + } +} diff --git a/internal/resolution/pm/pub/testdata/cmd_factory_mock.go b/internal/resolution/pm/pub/testdata/cmd_factory_mock.go new file mode 100644 index 00000000..543cf6b7 --- /dev/null +++ b/internal/resolution/pm/pub/testdata/cmd_factory_mock.go @@ -0,0 +1,37 @@ +package testdata + +import ( + "os/exec" + "runtime" +) + +type CmdFactoryMock struct { + LockErr error + DepsErr error + Name string + Arg string +} + +func (f CmdFactoryMock) MakeLockCmd(_ string) (*exec.Cmd, error) { + if len(f.Arg) == 0 { + f.Arg = `"MakeLockCmd"` + } + + if runtime.GOOS == "windows" && f.Name == "echo" { + return exec.Command("cmd", "/C", f.Name, f.Arg), f.LockErr + } + + return exec.Command(f.Name, f.Arg), f.LockErr +} + +func (f CmdFactoryMock) MakeDepsCmd(_ string) (*exec.Cmd, error) { + if len(f.Arg) == 0 { + f.Arg = `"MakeDepsCmd"` + } + + if runtime.GOOS == "windows" && f.Name == "echo" { + return exec.Command("cmd", "/C", f.Name, f.Arg), f.DepsErr + } + + return exec.Command(f.Name, f.Arg), f.DepsErr +} diff --git a/internal/resolution/resolver.go b/internal/resolution/resolver.go index e824d9d3..cc96084f 100644 --- a/internal/resolution/resolver.go +++ b/internal/resolution/resolver.go @@ -5,7 +5,9 @@ import ( "fmt" "os" "path" + "path/filepath" "regexp" + "strings" "github.com/debricked/cli/internal/cmd/cmderror" "github.com/debricked/cli/internal/file" @@ -271,9 +273,9 @@ func shouldGenerateLock(fileGroup file.Group, regenerate int) bool { } switch regenerate { case 0: - return !fileGroup.HasLockFiles() + return !fileGroup.HasLockFiles() || shouldGeneratePubDepsFile(fileGroup) case 1: - return onlyNonNativeLockFiles(fileGroup.LockFiles) + return onlyNonNativeLockFiles(fileGroup.LockFiles) || shouldGeneratePubDepsFile(fileGroup) case 2: return true } @@ -292,3 +294,14 @@ func onlyNonNativeLockFiles(lockFiles []string) bool { return true } + +func shouldGeneratePubDepsFile(fileGroup file.Group) bool { + if !strings.EqualFold(filepath.Base(fileGroup.ManifestFile), "pubspec.yaml") { + return false + } + + depsFile := filepath.Join(filepath.Dir(fileGroup.ManifestFile), "pubspec.deps.json") + _, err := os.Stat(depsFile) + + return os.IsNotExist(err) +} diff --git a/internal/resolution/resolver_test.go b/internal/resolution/resolver_test.go index 8f55be47..8f4584a8 100644 --- a/internal/resolution/resolver_test.go +++ b/internal/resolution/resolver_test.go @@ -3,6 +3,8 @@ package resolution import ( "errors" "fmt" + "os" + "path/filepath" "testing" "github.com/debricked/cli/internal/file" @@ -378,3 +380,38 @@ func TestGetStrictnessLevel(t *testing.T) { }) } } + +func TestShouldGenerateLockPubDepsMissing(t *testing.T) { + tmpDir := t.TempDir() + manifest := filepath.Join(tmpDir, "pubspec.yaml") + lock := filepath.Join(tmpDir, "pubspec.lock") + + err := os.WriteFile(manifest, []byte("name: app"), 0600) + assert.NoError(t, err) + err = os.WriteFile(lock, []byte("packages:"), 0600) + assert.NoError(t, err) + + group := file.Group{ManifestFile: manifest, LockFiles: []string{lock}} + + assert.True(t, shouldGenerateLock(group, 0)) + assert.True(t, shouldGenerateLock(group, 1)) +} + +func TestShouldGenerateLockPubDepsExists(t *testing.T) { + tmpDir := t.TempDir() + manifest := filepath.Join(tmpDir, "pubspec.yaml") + lock := filepath.Join(tmpDir, "pubspec.lock") + deps := filepath.Join(tmpDir, "pubspec.deps.json") + + err := os.WriteFile(manifest, []byte("name: app"), 0600) + assert.NoError(t, err) + err = os.WriteFile(lock, []byte("packages:"), 0600) + assert.NoError(t, err) + err = os.WriteFile(deps, []byte("{}"), 0600) + assert.NoError(t, err) + + group := file.Group{ManifestFile: manifest, LockFiles: []string{lock}} + + assert.False(t, shouldGenerateLock(group, 0)) + assert.False(t, shouldGenerateLock(group, 1)) +} diff --git a/internal/resolution/strategy/strategy_factory.go b/internal/resolution/strategy/strategy_factory.go index 75565a43..1e2b30be 100644 --- a/internal/resolution/strategy/strategy_factory.go +++ b/internal/resolution/strategy/strategy_factory.go @@ -14,6 +14,7 @@ import ( "github.com/debricked/cli/internal/resolution/pm/pip" "github.com/debricked/cli/internal/resolution/pm/pnpm" "github.com/debricked/cli/internal/resolution/pm/poetry" + "github.com/debricked/cli/internal/resolution/pm/pub" "github.com/debricked/cli/internal/resolution/pm/sbt" "github.com/debricked/cli/internal/resolution/pm/uv" "github.com/debricked/cli/internal/resolution/pm/yarn" @@ -59,6 +60,8 @@ func (sf Factory) Make(pmFileBatch file.IBatch, paths []string) (IStrategy, erro return composer.NewStrategy(pmFileBatch.Files()), nil case sbt.Name: return sbt.NewStrategy(pmFileBatch.Files()), nil + case pub.Name: + return pub.NewStrategy(pmFileBatch.Files()), nil default: return nil, fmt.Errorf("failed to make strategy from %s", name) } diff --git a/internal/resolution/strategy/strategy_factory_test.go b/internal/resolution/strategy/strategy_factory_test.go index 1b82db6b..7c2f8b90 100644 --- a/internal/resolution/strategy/strategy_factory_test.go +++ b/internal/resolution/strategy/strategy_factory_test.go @@ -11,6 +11,7 @@ import ( "github.com/debricked/cli/internal/resolution/pm/nuget" "github.com/debricked/cli/internal/resolution/pm/pip" "github.com/debricked/cli/internal/resolution/pm/poetry" + "github.com/debricked/cli/internal/resolution/pm/pub" "github.com/debricked/cli/internal/resolution/pm/sbt" "github.com/debricked/cli/internal/resolution/pm/testdata" "github.com/debricked/cli/internal/resolution/pm/yarn" @@ -41,6 +42,7 @@ func TestMake(t *testing.T) { nuget.Name: nuget.NewStrategy(nil), composer.Name: composer.NewStrategy(nil), sbt.Name: sbt.NewStrategy(nil), + pub.Name: pub.NewStrategy(nil), } f := NewStrategyFactory() var batch file.IBatch diff --git a/test/resolve/resolver_test.go b/test/resolve/resolver_test.go index f332e53d..0098040d 100644 --- a/test/resolve/resolver_test.go +++ b/test/resolve/resolver_test.go @@ -18,6 +18,9 @@ func TestResolves(t *testing.T) { manifestFile string lockFileName string packageManager string + preserveLock bool + extraFileName string + removeExtra bool }{ { name: "basic composer.json", @@ -79,6 +82,23 @@ func TestResolves(t *testing.T) { lockFileName: "gradle.debricked.lock", packageManager: "gradle", }, + { + name: "basic pubspec.yaml", + manifestFile: "testdata/pub/pubspec.yaml", + lockFileName: "pubspec.lock", + packageManager: "pub", + extraFileName: "pubspec.deps.json", + removeExtra: true, + }, + { + name: "pubspec.lock exists but deps is missing", + manifestFile: "testdata/pub/pubspec.yaml", + lockFileName: "pubspec.lock", + packageManager: "pub", + preserveLock: true, + extraFileName: "pubspec.deps.json", + removeExtra: true, + }, } for _, cT := range cases { @@ -91,8 +111,15 @@ func TestResolves(t *testing.T) { resolveCmd := resolve.NewResolveCmd(wire.GetCliContainer().Resolver()) lockFileDir := filepath.Dir(c.manifestFile) lockFile := filepath.Join(lockFileDir, c.lockFileName) - // Remove the lock file if it exists - os.Remove(lockFile) + if !c.preserveLock { + // Remove the lock file if it exists. + os.Remove(lockFile) + } + + if c.removeExtra && c.extraFileName != "" { + extraFile := filepath.Join(lockFileDir, c.extraFileName) + os.Remove(extraFile) + } err := resolveCmd.RunE(resolveCmd, []string{c.manifestFile}) assert.NoError(t, err) @@ -104,6 +131,13 @@ func TestResolves(t *testing.T) { assert.Greater(t, len(actualString), 0) + if c.extraFileName != "" { + extraFile := filepath.Join(lockFileDir, c.extraFileName) + extraContents, extraErr := os.ReadFile(extraFile) + assert.NoError(t, extraErr) + assert.Greater(t, len(extraContents), 0) + } + }) } } diff --git a/test/resolve/testdata/pub/pubspec.deps.json b/test/resolve/testdata/pub/pubspec.deps.json new file mode 100644 index 00000000..3e77eedd --- /dev/null +++ b/test/resolve/testdata/pub/pubspec.deps.json @@ -0,0 +1,818 @@ +{ + "root": "my_dart_app", + "packages": [ + { + "name": "my_dart_app", + "version": "1.0.0", + "kind": "root", + "source": "root", + "dependencies": [ + "http", + "collection", + "path", + "test", + "lints" + ], + "directDependencies": [ + "http", + "collection", + "path" + ], + "devDependencies": [ + "test", + "lints" + ] + }, + { + "name": "lints", + "version": "3.0.0", + "kind": "dev", + "source": "hosted", + "dependencies": [], + "directDependencies": [] + }, + { + "name": "test", + "version": "1.31.1", + "kind": "dev", + "source": "hosted", + "dependencies": [ + "analyzer", + "async", + "boolean_selector", + "collection", + "coverage", + "http_multi_server", + "io", + "matcher", + "node_preamble", + "package_config", + "path", + "pool", + "shelf", + "shelf_packages_handler", + "shelf_static", + "shelf_web_socket", + "source_span", + "stack_trace", + "stream_channel", + "test_api", + "test_core", + "typed_data", + "web_socket_channel", + "webkit_inspection_protocol", + "yaml" + ], + "directDependencies": [ + "analyzer", + "async", + "boolean_selector", + "collection", + "coverage", + "http_multi_server", + "io", + "matcher", + "node_preamble", + "package_config", + "path", + "pool", + "shelf", + "shelf_packages_handler", + "shelf_static", + "shelf_web_socket", + "source_span", + "stack_trace", + "stream_channel", + "test_api", + "test_core", + "typed_data", + "web_socket_channel", + "webkit_inspection_protocol", + "yaml" + ] + }, + { + "name": "yaml", + "version": "3.1.3", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "collection", + "source_span", + "string_scanner" + ], + "directDependencies": [ + "collection", + "source_span", + "string_scanner" + ] + }, + { + "name": "string_scanner", + "version": "1.4.1", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "source_span" + ], + "directDependencies": [ + "source_span" + ] + }, + { + "name": "source_span", + "version": "1.10.2", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "collection", + "path", + "term_glyph" + ], + "directDependencies": [ + "collection", + "path", + "term_glyph" + ] + }, + { + "name": "term_glyph", + "version": "1.2.2", + "kind": "transitive", + "source": "hosted", + "dependencies": [], + "directDependencies": [] + }, + { + "name": "path", + "version": "1.9.1", + "kind": "direct", + "source": "hosted", + "dependencies": [], + "directDependencies": [] + }, + { + "name": "collection", + "version": "1.19.1", + "kind": "direct", + "source": "hosted", + "dependencies": [], + "directDependencies": [] + }, + { + "name": "webkit_inspection_protocol", + "version": "1.2.1", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "logging" + ], + "directDependencies": [ + "logging" + ] + }, + { + "name": "logging", + "version": "1.3.0", + "kind": "transitive", + "source": "hosted", + "dependencies": [], + "directDependencies": [] + }, + { + "name": "web_socket_channel", + "version": "3.0.3", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "async", + "crypto", + "stream_channel", + "web", + "web_socket" + ], + "directDependencies": [ + "async", + "crypto", + "stream_channel", + "web", + "web_socket" + ] + }, + { + "name": "web_socket", + "version": "1.0.1", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "web" + ], + "directDependencies": [ + "web" + ] + }, + { + "name": "web", + "version": "1.1.1", + "kind": "transitive", + "source": "hosted", + "dependencies": [], + "directDependencies": [] + }, + { + "name": "stream_channel", + "version": "2.1.4", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "async" + ], + "directDependencies": [ + "async" + ] + }, + { + "name": "async", + "version": "2.13.1", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "collection", + "meta" + ], + "directDependencies": [ + "collection", + "meta" + ] + }, + { + "name": "meta", + "version": "1.18.3", + "kind": "transitive", + "source": "hosted", + "dependencies": [], + "directDependencies": [] + }, + { + "name": "crypto", + "version": "3.0.7", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "typed_data" + ], + "directDependencies": [ + "typed_data" + ] + }, + { + "name": "typed_data", + "version": "1.4.0", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "collection" + ], + "directDependencies": [ + "collection" + ] + }, + { + "name": "test_core", + "version": "0.6.18", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "analyzer", + "args", + "async", + "boolean_selector", + "collection", + "coverage", + "frontend_server_client", + "glob", + "io", + "meta", + "package_config", + "path", + "pool", + "source_map_stack_trace", + "source_maps", + "source_span", + "stack_trace", + "stream_channel", + "test_api", + "vm_service", + "yaml" + ], + "directDependencies": [ + "analyzer", + "args", + "async", + "boolean_selector", + "collection", + "coverage", + "frontend_server_client", + "glob", + "io", + "meta", + "package_config", + "path", + "pool", + "source_map_stack_trace", + "source_maps", + "source_span", + "stack_trace", + "stream_channel", + "test_api", + "vm_service", + "yaml" + ] + }, + { + "name": "vm_service", + "version": "15.2.0", + "kind": "transitive", + "source": "hosted", + "dependencies": [], + "directDependencies": [] + }, + { + "name": "test_api", + "version": "0.7.12", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "async", + "boolean_selector", + "collection", + "meta", + "source_span", + "stack_trace", + "stream_channel", + "string_scanner", + "term_glyph" + ], + "directDependencies": [ + "async", + "boolean_selector", + "collection", + "meta", + "source_span", + "stack_trace", + "stream_channel", + "string_scanner", + "term_glyph" + ] + }, + { + "name": "stack_trace", + "version": "1.12.1", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "path" + ], + "directDependencies": [ + "path" + ] + }, + { + "name": "boolean_selector", + "version": "2.1.2", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "source_span", + "string_scanner" + ], + "directDependencies": [ + "source_span", + "string_scanner" + ] + }, + { + "name": "source_maps", + "version": "0.10.13", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "source_span" + ], + "directDependencies": [ + "source_span" + ] + }, + { + "name": "source_map_stack_trace", + "version": "2.1.2", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "path", + "source_maps", + "stack_trace" + ], + "directDependencies": [ + "path", + "source_maps", + "stack_trace" + ] + }, + { + "name": "pool", + "version": "1.5.2", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "async", + "stack_trace" + ], + "directDependencies": [ + "async", + "stack_trace" + ] + }, + { + "name": "package_config", + "version": "2.2.0", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "path" + ], + "directDependencies": [ + "path" + ] + }, + { + "name": "io", + "version": "1.0.5", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "meta", + "path", + "string_scanner" + ], + "directDependencies": [ + "meta", + "path", + "string_scanner" + ] + }, + { + "name": "glob", + "version": "2.1.3", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "async", + "collection", + "file", + "path", + "string_scanner" + ], + "directDependencies": [ + "async", + "collection", + "file", + "path", + "string_scanner" + ] + }, + { + "name": "file", + "version": "7.0.1", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "meta", + "path" + ], + "directDependencies": [ + "meta", + "path" + ] + }, + { + "name": "frontend_server_client", + "version": "4.0.0", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "async", + "path" + ], + "directDependencies": [ + "async", + "path" + ] + }, + { + "name": "coverage", + "version": "1.15.1", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "args", + "cli_config", + "glob", + "logging", + "meta", + "package_config", + "path", + "source_maps", + "stack_trace", + "vm_service", + "yaml" + ], + "directDependencies": [ + "args", + "cli_config", + "glob", + "logging", + "meta", + "package_config", + "path", + "source_maps", + "stack_trace", + "vm_service", + "yaml" + ] + }, + { + "name": "cli_config", + "version": "0.2.0", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "args", + "yaml" + ], + "directDependencies": [ + "args", + "yaml" + ] + }, + { + "name": "args", + "version": "2.7.0", + "kind": "transitive", + "source": "hosted", + "dependencies": [], + "directDependencies": [] + }, + { + "name": "analyzer", + "version": "13.3.0", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "_fe_analyzer_shared", + "collection", + "convert", + "crypto", + "glob", + "meta", + "package_config", + "path", + "pub_semver", + "source_span", + "watcher", + "yaml" + ], + "directDependencies": [ + "_fe_analyzer_shared", + "collection", + "convert", + "crypto", + "glob", + "meta", + "package_config", + "path", + "pub_semver", + "source_span", + "watcher", + "yaml" + ] + }, + { + "name": "watcher", + "version": "1.2.1", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "async", + "path" + ], + "directDependencies": [ + "async", + "path" + ] + }, + { + "name": "pub_semver", + "version": "2.2.0", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "collection" + ], + "directDependencies": [ + "collection" + ] + }, + { + "name": "convert", + "version": "3.1.2", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "typed_data" + ], + "directDependencies": [ + "typed_data" + ] + }, + { + "name": "_fe_analyzer_shared", + "version": "103.0.0", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "meta" + ], + "directDependencies": [ + "meta" + ] + }, + { + "name": "shelf_web_socket", + "version": "3.0.0", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "shelf", + "stream_channel", + "web_socket_channel" + ], + "directDependencies": [ + "shelf", + "stream_channel", + "web_socket_channel" + ] + }, + { + "name": "shelf", + "version": "1.4.2", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "async", + "collection", + "http_parser", + "path", + "stack_trace", + "stream_channel" + ], + "directDependencies": [ + "async", + "collection", + "http_parser", + "path", + "stack_trace", + "stream_channel" + ] + }, + { + "name": "http_parser", + "version": "4.1.2", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "collection", + "source_span", + "string_scanner", + "typed_data" + ], + "directDependencies": [ + "collection", + "source_span", + "string_scanner", + "typed_data" + ] + }, + { + "name": "shelf_static", + "version": "1.1.3", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "convert", + "http_parser", + "mime", + "path", + "shelf" + ], + "directDependencies": [ + "convert", + "http_parser", + "mime", + "path", + "shelf" + ] + }, + { + "name": "mime", + "version": "2.0.0", + "kind": "transitive", + "source": "hosted", + "dependencies": [], + "directDependencies": [] + }, + { + "name": "shelf_packages_handler", + "version": "3.0.2", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "path", + "shelf", + "shelf_static" + ], + "directDependencies": [ + "path", + "shelf", + "shelf_static" + ] + }, + { + "name": "node_preamble", + "version": "2.0.2", + "kind": "transitive", + "source": "hosted", + "dependencies": [], + "directDependencies": [] + }, + { + "name": "matcher", + "version": "0.12.20", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "async", + "meta", + "stack_trace", + "term_glyph", + "test_api" + ], + "directDependencies": [ + "async", + "meta", + "stack_trace", + "term_glyph", + "test_api" + ] + }, + { + "name": "http_multi_server", + "version": "3.2.2", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "async" + ], + "directDependencies": [ + "async" + ] + }, + { + "name": "http", + "version": "1.6.0", + "kind": "direct", + "source": "hosted", + "dependencies": [ + "async", + "http_parser", + "meta", + "web" + ], + "directDependencies": [ + "async", + "http_parser", + "meta", + "web" + ] + } + ], + "sdks": [ + { + "name": "Dart", + "version": "3.12.2" + } + ], + "executables": [ + "test" + ] +} diff --git a/test/resolve/testdata/pub/pubspec.lock b/test/resolve/testdata/pub/pubspec.lock new file mode 100644 index 00000000..3ba07bda --- /dev/null +++ b/test/resolve/testdata/pub/pubspec.lock @@ -0,0 +1,397 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: "1b0e6a07425a3e460666e88bf1c949ccc7bb0116ad562ce94a1eca60fe820725" + url: "https://pub.dev" + source: hosted + version: "103.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: "61c04d0c1bfed555c681ea079519933f071a5a026578ff73c4ff0df2d3462e5e" + url: "https://pub.dev" + source: hosted + version: "13.3.0" + args: + dependency: transitive + description: + name: args + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 + url: "https://pub.dev" + source: hosted + version: "2.7.0" + async: + dependency: transitive + description: + name: async + sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37 + url: "https://pub.dev" + source: hosted + version: "2.13.1" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + cli_config: + dependency: transitive + description: + name: cli_config + sha256: ac20a183a07002b700f0c25e61b7ee46b23c309d76ab7b7640a028f18e4d99ec + url: "https://pub.dev" + source: hosted + version: "0.2.0" + collection: + dependency: "direct main" + description: + name: collection + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" + source: hosted + version: "1.19.1" + convert: + dependency: transitive + description: + name: convert + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 + url: "https://pub.dev" + source: hosted + version: "3.1.2" + coverage: + dependency: transitive + description: + name: coverage + sha256: "956a3de0725ca232ad353565a8290d3357592bf4250f6f298a185e2d949c5d3d" + url: "https://pub.dev" + source: hosted + version: "1.15.1" + crypto: + dependency: transitive + description: + name: crypto + sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf + url: "https://pub.dev" + source: hosted + version: "3.0.7" + file: + dependency: transitive + description: + name: file + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" + source: hosted + version: "7.0.1" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 + url: "https://pub.dev" + source: hosted + version: "4.0.0" + glob: + dependency: transitive + description: + name: glob + sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de + url: "https://pub.dev" + source: hosted + version: "2.1.3" + http: + dependency: "direct main" + description: + name: http + sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" + url: "https://pub.dev" + source: hosted + version: "1.6.0" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8 + url: "https://pub.dev" + source: hosted + version: "3.2.2" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + url: "https://pub.dev" + source: hosted + version: "4.1.2" + io: + dependency: transitive + description: + name: io + sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b + url: "https://pub.dev" + source: hosted + version: "1.0.5" + lints: + dependency: "direct dev" + description: + name: lints + sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 + url: "https://pub.dev" + source: hosted + version: "3.0.0" + logging: + dependency: transitive + description: + name: logging + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" + source: hosted + version: "1.3.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: "31bd099b47c10cd1aeb55146a2d46ce0277630ecef3f7dae54ad7873f36696cd" + url: "https://pub.dev" + source: hosted + version: "0.12.20" + meta: + dependency: transitive + description: + name: meta + sha256: c82594181e3312f3d0695fc95aaaf7758d75b8d4ae2bbecf223b9fd5109a059d + url: "https://pub.dev" + source: hosted + version: "1.18.3" + mime: + dependency: transitive + description: + name: mime + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + node_preamble: + dependency: transitive + description: + name: node_preamble + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + package_config: + dependency: transitive + description: + name: package_config + sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc + url: "https://pub.dev" + source: hosted + version: "2.2.0" + path: + dependency: "direct main" + description: + name: path + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + pool: + dependency: transitive + description: + name: pool + sha256: "978783255c543aa3586a1b3c21f6e9d720eb315376a915872c61ef8b5c20177d" + url: "https://pub.dev" + source: hosted + version: "1.5.2" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + shelf: + dependency: transitive + description: + name: shelf + sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 + url: "https://pub.dev" + source: hosted + version: "1.4.2" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + shelf_static: + dependency: transitive + description: + name: shelf_static + sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3 + url: "https://pub.dev" + source: hosted + version: "1.1.3" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b + url: "https://pub.dev" + source: hosted + version: "2.1.2" + source_maps: + dependency: transitive + description: + name: source_maps + sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812" + url: "https://pub.dev" + source: hosted + version: "0.10.13" + source_span: + dependency: transitive + description: + name: source_span + sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab" + url: "https://pub.dev" + source: hosted + version: "1.10.2" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" + source: hosted + version: "1.12.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.dev" + source: hosted + version: "1.4.1" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.dev" + source: hosted + version: "1.2.2" + test: + dependency: "direct dev" + description: + name: test + sha256: ca578dc12bb8b2f40b67b7d3bd2fac4f31c01a6ff7130a14e2597b919934507f + url: "https://pub.dev" + source: hosted + version: "1.31.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: "2a122cbe059f8b610d3a5415f42e255b6c17b1f21eee1d960f31080237fb4f11" + url: "https://pub.dev" + source: hosted + version: "0.7.12" + test_core: + dependency: transitive + description: + name: test_core + sha256: d2e98ec12998368dc59ddd47ab709f2cd55acd6b66dc7db764455a44082f4bc5 + url: "https://pub.dev" + source: hosted + version: "0.6.18" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "0016aef94fc66495ac78af5859181e3f3bf2026bd8eecc72b9565601e19ab360" + url: "https://pub.dev" + source: hosted + version: "15.2.0" + watcher: + dependency: transitive + description: + name: watcher + sha256: "1398c9f081a753f9226febe8900fce8f7d0a67163334e1c94a2438339d79d635" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + web: + dependency: transitive + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8 + url: "https://pub.dev" + source: hosted + version: "3.0.3" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + yaml: + dependency: transitive + description: + name: yaml + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce + url: "https://pub.dev" + source: hosted + version: "3.1.3" +sdks: + dart: ">=3.11.0 <4.0.0" diff --git a/test/resolve/testdata/pub/pubspec.yaml b/test/resolve/testdata/pub/pubspec.yaml new file mode 100644 index 00000000..267adfd1 --- /dev/null +++ b/test/resolve/testdata/pub/pubspec.yaml @@ -0,0 +1,15 @@ +name: my_dart_app +description: A sample Dart application for testing Debricked resolution. +version: 1.0.0 + +environment: + sdk: ">=3.0.0 <4.0.0" + +dependencies: + http: ^1.2.0 + collection: ^1.18.0 + path: ^1.9.0 + +dev_dependencies: + test: ^1.24.0 + lints: ^3.0.0