feat(dev): support glob targets in apply command
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
ae3935919e
commit
93c8eef876
5 changed files with 77 additions and 28 deletions
|
|
@ -12,14 +12,14 @@ import (
|
|||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sort"
|
||||
|
||||
"forge.lthn.ai/core/cli/pkg/cli"
|
||||
core "dappco.re/go/core/log"
|
||||
"dappco.re/go/core/scm/git"
|
||||
"dappco.re/go/core/i18n"
|
||||
"dappco.re/go/core/io"
|
||||
core "dappco.re/go/core/log"
|
||||
"dappco.re/go/core/scm/git"
|
||||
"dappco.re/go/core/scm/repos"
|
||||
"forge.lthn.ai/core/cli/pkg/cli"
|
||||
)
|
||||
|
||||
// Apply command flags
|
||||
|
|
@ -235,29 +235,39 @@ func getApplyTargetRepos() ([]*repos.Repo, error) {
|
|||
return nil, core.E("dev.apply", "failed to load registry", err)
|
||||
}
|
||||
|
||||
// If --repos specified, filter to those
|
||||
if applyRepos != "" {
|
||||
repoNames := strings.Split(applyRepos, ",")
|
||||
nameSet := make(map[string]bool)
|
||||
for _, name := range repoNames {
|
||||
nameSet[strings.TrimSpace(name)] = true
|
||||
}
|
||||
return filterTargetRepos(registry, applyRepos), nil
|
||||
}
|
||||
|
||||
var matched []*repos.Repo
|
||||
for _, repo := range registry.Repos {
|
||||
if nameSet[repo.Name] {
|
||||
// filterTargetRepos selects repos by exact name/path or glob pattern.
|
||||
func filterTargetRepos(registry *repos.Registry, selection string) []*repos.Repo {
|
||||
repoNames := make([]string, 0, len(registry.Repos))
|
||||
for name := range registry.Repos {
|
||||
repoNames = append(repoNames, name)
|
||||
}
|
||||
sort.Strings(repoNames)
|
||||
|
||||
if selection == "" {
|
||||
matched := make([]*repos.Repo, 0, len(repoNames))
|
||||
for _, name := range repoNames {
|
||||
matched = append(matched, registry.Repos[name])
|
||||
}
|
||||
return matched
|
||||
}
|
||||
|
||||
patterns := splitPatterns(selection)
|
||||
var matched []*repos.Repo
|
||||
|
||||
for _, name := range repoNames {
|
||||
repo := registry.Repos[name]
|
||||
for _, candidate := range patterns {
|
||||
if matchGlob(repo.Name, candidate) || matchGlob(repo.Path, candidate) {
|
||||
matched = append(matched, repo)
|
||||
break
|
||||
}
|
||||
}
|
||||
return matched, nil
|
||||
}
|
||||
|
||||
// Return all repos as slice
|
||||
var all []*repos.Repo
|
||||
for _, repo := range registry.Repos {
|
||||
all = append(all, repo)
|
||||
}
|
||||
return all, nil
|
||||
return matched
|
||||
}
|
||||
|
||||
// runCommandInRepo runs a shell command in a repo directory
|
||||
|
|
|
|||
39
cmd/dev/cmd_apply_test.go
Normal file
39
cmd/dev/cmd_apply_test.go
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
package dev
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"dappco.re/go/core/scm/repos"
|
||||
)
|
||||
|
||||
func TestFilterTargetRepos_Good(t *testing.T) {
|
||||
registry := &repos.Registry{
|
||||
Repos: map[string]*repos.Repo{
|
||||
"core-api": &repos.Repo{Name: "core-api", Path: "packages/core-api"},
|
||||
"core-web": &repos.Repo{Name: "core-web", Path: "packages/core-web"},
|
||||
"docs-site": &repos.Repo{Name: "docs-site", Path: "sites/docs"},
|
||||
},
|
||||
}
|
||||
|
||||
t.Run("exact names", func(t *testing.T) {
|
||||
matched := filterTargetRepos(registry, "core-api,docs-site")
|
||||
require.Len(t, matched, 2)
|
||||
require.Equal(t, "core-api", matched[0].Name)
|
||||
require.Equal(t, "docs-site", matched[1].Name)
|
||||
})
|
||||
|
||||
t.Run("glob patterns", func(t *testing.T) {
|
||||
matched := filterTargetRepos(registry, "core-*,sites/*")
|
||||
require.Len(t, matched, 3)
|
||||
require.Equal(t, "core-api", matched[0].Name)
|
||||
require.Equal(t, "core-web", matched[1].Name)
|
||||
require.Equal(t, "docs-site", matched[2].Name)
|
||||
})
|
||||
|
||||
t.Run("all repos when empty", func(t *testing.T) {
|
||||
matched := filterTargetRepos(registry, "")
|
||||
require.Len(t, matched, 3)
|
||||
})
|
||||
}
|
||||
|
|
@ -59,6 +59,6 @@ func TestOutputPowershellInstall_Good(t *testing.T) {
|
|||
return outputPowershellInstall(DefaultCIConfig(), "dev")
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, out, `scoop bucket add host-uk https://forge.lthn.ai/core/scoop-bucket.git`)
|
||||
require.Contains(t, out, `scoop bucket add host-uk $ScoopBucket`)
|
||||
require.NotContains(t, out, `https://https://forge.lthn.ai/core/scoop-bucket.git`)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,9 +94,9 @@ func runPackageWizard(reg *repos.Registry, preselectedTypes []string) ([]string,
|
|||
return selected, nil
|
||||
}
|
||||
|
||||
func filterReposByTypes(repos []*repos.Repo, allowedTypes []string) []*repos.Repo {
|
||||
func filterReposByTypes(repoList []*repos.Repo, allowedTypes []string) []*repos.Repo {
|
||||
if len(allowedTypes) == 0 {
|
||||
return repos
|
||||
return repoList
|
||||
}
|
||||
|
||||
allowed := make(map[string]struct{}, len(allowedTypes))
|
||||
|
|
@ -108,11 +108,11 @@ func filterReposByTypes(repos []*repos.Repo, allowedTypes []string) []*repos.Rep
|
|||
}
|
||||
|
||||
if len(allowed) == 0 {
|
||||
return repos
|
||||
return repoList
|
||||
}
|
||||
|
||||
filtered := make([]*repos.Repo, 0, len(repos))
|
||||
for _, repo := range repos {
|
||||
filtered := make([]*repos.Repo, 0, len(repoList))
|
||||
for _, repo := range repoList {
|
||||
if _, ok := allowed[repo.Type]; ok {
|
||||
filtered = append(filtered, repo)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@
|
|||
"flag": {
|
||||
"command": "Shell command to run in each repo",
|
||||
"script": "Script file to run in each repo",
|
||||
"repos": "Comma-separated list of repo names to target",
|
||||
"repos": "Comma-separated list of repo names, paths, or glob patterns to target",
|
||||
"commit": "Commit changes after running",
|
||||
"message": "Commit message (required with --commit)",
|
||||
"push": "Push after committing",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue