@@ -32,11 +32,9 @@ type Config struct {
3232 // Filename to look for the root of a package.
3333 PackageFile []string `json:"package-file"`
3434
35- // Setup file, must be located in the same directory as the package file.
36- Setup struct {
37- FileName string `json:"filename"`
38- Defaults map [string ]any `json:"defaults"`
39- } `json:"setup"`
35+ // CI setup file, must be located in the same directory as the package file.
36+ CISetupFileName string `json:"ci-setup-filename"`
37+ CISetupDefaults * CISetup `json:"ci-setup-defaults"`
4038
4139 // Pattern to match filenames or directories.
4240 Match []string `json:"match"`
@@ -48,13 +46,7 @@ type Config struct {
4846 ExcludePackages []string `json:"exclude-packages"`
4947}
5048
51- type Package struct {
52- // Package directory path.
53- Path string `json:"path"`
54-
55- // Package setup configurations.
56- Setup * map [string ]any `json:"setup"`
57- }
49+ type CISetup = map [string ]any
5850
5951// Saves the config to the given file.
6052func (c * Config ) Save (file * os.File ) error {
@@ -73,7 +65,7 @@ func (c *Config) Save(file *os.File) error {
7365func LoadConfig (path string ) (* Config , error ) {
7466 // Read the config file.
7567 var config Config
76- err := ReadJsonc (path , & config )
68+ err := readJsonc (path , & config )
7769 if err != nil {
7870 return nil , err
7971 }
@@ -85,6 +77,9 @@ func LoadConfig(path string) (*Config, error) {
8577 if config .Match == nil {
8678 config .Match = []string {"*" }
8779 }
80+ if config .CISetupFileName == "" {
81+ config .CISetupFileName = "ci-setup.json"
82+ }
8883
8984 return & config , nil
9085}
@@ -111,15 +106,14 @@ func (c *Config) Matches(path string) bool {
111106// IsPackageDir returns true if the path is a package directory.
112107func (c * Config ) IsPackageDir (dir string ) bool {
113108 for _ , filename := range c .PackageFile {
114- packageFile := filepath .Join (dir , filename )
115- if fileExists (packageFile ) {
109+ if fileExists (filepath .Join (dir , filename )) {
116110 return true
117111 }
118112 }
119113 return false
120114}
121115
122- // FindPackage returns the package name for the given path .
116+ // FindPackage returns the most specific package path for the given filename .
123117func (c * Config ) FindPackage (path string ) string {
124118 dir := filepath .Dir (path )
125119 if dir == "." || c .IsPackageDir (dir ) {
@@ -128,9 +122,9 @@ func (c *Config) FindPackage(path string) string {
128122 return c .FindPackage (dir )
129123}
130124
131- // FindAllPackages finds all the packages in the given root directory.
125+ // FindAllPackages finds all the package paths in the given root directory.
132126func (c * Config ) FindAllPackages (root string ) ([]string , error ) {
133- var packages []string
127+ var paths []string
134128 err := fs .WalkDir (os .DirFS (root ), "." ,
135129 func (path string , d os.DirEntry , err error ) error {
136130 if err != nil {
@@ -143,45 +137,15 @@ func (c *Config) FindAllPackages(root string) ([]string, error) {
143137 return nil
144138 }
145139 if d .IsDir () && c .Matches (path ) && c .IsPackageDir (path ) {
146- packages = append (packages , path )
140+ paths = append (paths , path )
147141 return nil
148142 }
149143 return nil
150144 })
151145 if err != nil {
152146 return []string {}, err
153147 }
154- return packages , nil
155- }
156-
157- // Affected returns the packages that have been affected from diffs.
158- // If there are diffs on at leat one global file affecting all packages,
159- // then this returns all packages matched by the config.
160- func (c * Config ) Affected (log io.Writer , diffs []string ) ([]Package , error ) {
161- changed := c .Changed (log , diffs )
162- if slices .Contains (changed , "." ) {
163- allPackages , err := c .FindAllPackages ("." )
164- if err != nil {
165- return nil , err
166- }
167- changed = allPackages
168- }
169-
170- packages := make ([]Package , 0 , len (changed ))
171- for _ , path := range changed {
172- pkg := Package {Path : path , Setup : & c .Setup .Defaults }
173- if c .Setup .FileName != "" {
174- setup_file := filepath .Join (path , c .Setup .FileName )
175- if fileExists (setup_file ) {
176- err := ReadJsonc (setup_file , pkg .Setup )
177- if err != nil {
178- return nil , err
179- }
180- }
181- }
182- packages = append (packages , pkg )
183- }
184- return packages , nil
148+ return paths , nil
185149}
186150
187151// Changed returns the packages that have changed.
@@ -193,17 +157,54 @@ func (c *Config) Changed(log io.Writer, diffs []string) []string {
193157 if ! c .Matches (diff ) {
194158 continue
195159 }
196- pkg := c .FindPackage (diff )
197- changedUnique [pkg ] = true
160+ path := c .FindPackage (diff )
161+ if path == "." {
162+ fmt .Fprintf (log , "ℹ️ Global file changed: %q\n " , diff )
163+ }
164+ changedUnique [path ] = true
198165 }
199166
200167 changed := make ([]string , 0 , len (changedUnique ))
201- for pkg := range changedUnique {
202- if slices .Contains (c .ExcludePackages , pkg ) {
203- fmt .Fprintf (log , "ℹ️ Excluded package %q, skipping.\n " , pkg )
168+ for path := range changedUnique {
169+ if slices .Contains (c .ExcludePackages , path ) {
170+ fmt .Fprintf (log , "ℹ️ Excluded package %q, skipping.\n " , path )
204171 continue
205172 }
206- changed = append (changed , pkg )
173+ changed = append (changed , path )
207174 }
208175 return changed
209176}
177+
178+ // Affected returns the packages that have been affected from diffs.
179+ // If there are diffs on at leat one global file affecting all packages,
180+ // then this returns all packages matched by the config.
181+ func (c * Config ) Affected (log io.Writer , diffs []string ) ([]string , error ) {
182+ paths := c .Changed (log , diffs )
183+ if slices .Contains (paths , "." ) {
184+ fmt .Fprintf (log , "One or more global files were affected, all packages marked as affected." )
185+ allPackages , err := c .FindAllPackages ("." )
186+ if err != nil {
187+ return nil , err
188+ }
189+ paths = allPackages
190+ }
191+ return paths , nil
192+ }
193+
194+ func (c * Config ) FindSetupFiles (paths []string ) (* map [string ]CISetup , error ) {
195+ setups := make (map [string ]CISetup , len (paths ))
196+ for _ , path := range paths {
197+ setup := * c .CISetupDefaults
198+ setupFile := filepath .Join (path , c .CISetupFileName )
199+ if fileExists (setupFile ) {
200+ // This mutates `setup` so there's no need to reassign it.
201+ // It keeps the default values if they're not in the JSON file.
202+ err := readJsonc (setupFile , & setup )
203+ if err != nil {
204+ return nil , err
205+ }
206+ }
207+ setups [path ] = setup
208+ }
209+ return & setups , nil
210+ }
0 commit comments