diff --git a/README.md b/README.md index 13e8e14..57c18ca 100644 --- a/README.md +++ b/README.md @@ -44,26 +44,34 @@ Application config is specified with a yaml configuration file, with an example ```yaml access_token: myaccesstoken url: https://gitlab.privateinstance.com -repositories: -- project: 123 - image: myproject/somerepository +policies: +- name: nonsemverpolicy filter: include: .* exclude: ^v.+ keep: 5 age: 30 +repositories: +- project: 123 + image: myproject/somerepository + policies: + - nonsemverpolicy ``` * `access_token`: Private access token with `api` read/write scope * `url`: Gitlab instance URL -* `repositories` __array__ - * `project`: Project ID to target - * `image`: Path of repository/image +* `policies`: __array__ + * `name`: Name of policy * `filter`: __object__ * `include`: Regex specifying image tags to include - no tags will be matched if this isn't specified * `exclude`: (Optional) Regex specifying image tags to exclude * `keep`: (Optional) Specifies amount of tags to keep * `age`: (Optional) Specifies amount of days to keep tags +* `repositories` __array__ + * `project`: Project ID to target + * `image`: Path of repository/image + * `policies` __array__ + * Name of policies ## Docker diff --git a/cmd/execute.go b/cmd/execute.go index cde4787..29c5214 100644 --- a/cmd/execute.go +++ b/cmd/execute.go @@ -39,30 +39,7 @@ func executeCleanup(cmd *cobra.Command, args []string) error { return fmt.Errorf("Failed initialising Gitlab client: %s", err) } - for _, repositoryCfg := range cfg.Repositories { - log.WithFields(log.Fields{ - "include": repositoryCfg.Filter.Include, - "exclude": repositoryCfg.Filter.Exclude, - "keep": repositoryCfg.Filter.Keep, - "age": repositoryCfg.Filter.Age, - }).Infof("Processing repository %s", repositoryCfg.Image) - repositories, err := getAllRepositories(client, repositoryCfg) - if err != nil { - return fmt.Errorf("Error retrieving all Gitlab registry repositories for project %d: %s", repositoryCfg.Project, err) - } - - for _, repository := range repositories { - if repositoryCfg.Image == repository.Path { - err := processRepository(cmd, client, repository, repositoryCfg) - if err != nil { - return fmt.Errorf("Failed processing repository %s: %s", repositoryCfg.Image, err) - } - } - } - log.Infof("Finished processing repository %s", repositoryCfg.Image) - } - - return nil + return processRepositories(cmd, client, cfg) } func getAllRepositories(client *gitlab.Client, repositoryCfg config.RepositoryConfig) ([]*gitlab.RegistryRepository, error) { @@ -105,7 +82,52 @@ func getAllTags(client *gitlab.Client, repository *gitlab.RegistryRepository, re return allTags, nil } -func processRepository(cmd *cobra.Command, client *gitlab.Client, repository *gitlab.RegistryRepository, repositoryCfg config.RepositoryConfig) error { +func processRepositories(cmd *cobra.Command, client *gitlab.Client, cfg *config.Config) error { + for _, repositoryCfg := range cfg.Repositories { + log.WithFields(log.Fields{ + "project_id": repositoryCfg.Project, + "image": repositoryCfg.Image, + }).Infof("Processing repository %s", repositoryCfg.Image) + + repositories, err := getAllRepositories(client, repositoryCfg) + if err != nil { + return fmt.Errorf("Error retrieving all Gitlab registry repositories for project %d: %s", repositoryCfg.Project, err) + } + + for _, repository := range repositories { + if repositoryCfg.Image == repository.Path { + err := processRepository(cmd, client, cfg, repository, repositoryCfg) + if err != nil { + return err + } + } + } + log.Infof("Finished processing repository %s", repositoryCfg.Image) + } + + return nil +} + +func processRepository(cmd *cobra.Command, client *gitlab.Client, cfg *config.Config, repository *gitlab.RegistryRepository, repositoryCfg config.RepositoryConfig) error { + for _, policyName := range repositoryCfg.Policies { + log.Infof("Processing repository policy %s", policyName) + policyCfg, err := cfg.GetPolicyConfig(policyName) + if err != nil { + return err + } + + err = processRepositoryPolicy(cmd, client, repository, repositoryCfg, policyCfg) + if err != nil { + return err + } + + log.Infof("Finished processing repository policy %s", policyName) + } + + return nil +} + +func processRepositoryPolicy(cmd *cobra.Command, client *gitlab.Client, repository *gitlab.RegistryRepository, repositoryCfg config.RepositoryConfig, policyCfg config.PolicyConfig) error { log.Debug("Retrieving tag metadata") tagsMeta, err := getAllTags(client, repository, repositoryCfg) if err != nil { @@ -131,9 +153,14 @@ func processRepository(cmd *cobra.Command, client *gitlab.Client, repository *gi } bar.Finish() - log.Debug("Executing filters") + log.WithFields(log.Fields{ + "include": policyCfg.Filter.Include, + "exclude": policyCfg.Filter.Exclude, + "keep": policyCfg.Filter.Keep, + "age": policyCfg.Filter.Age, + }).Debug("Executing filter pipeline") - f := filter.NewFilterPipeline(tags, repositoryCfg.Filter) + f := filter.NewFilterPipeline(tags, policyCfg.Filter) filteredTags, err := f.Execute( filter.ExcludeLatestFilter, filter.IncludeFilter, @@ -143,7 +170,7 @@ func processRepository(cmd *cobra.Command, client *gitlab.Client, repository *gi filter.ExcludeFilter, ) if err != nil { - return fmt.Errorf("Failed to execute filters: %w", err) + return fmt.Errorf("Failed to execute filter pipeline: %w", err) } log.Infof("Found %d tags for removal", len(filteredTags)) diff --git a/config.example.yml b/config.example.yml index 92524bf..1216e50 100644 --- a/config.example.yml +++ b/config.example.yml @@ -2,11 +2,15 @@ access_token: myaccesstoken url: https://gitlab.privateinstance.com -repositories: -- project: 123 - image: myproject/somerepository +policies: +- name: nonsemverpolicy filter: include: .* exclude: ^v.+ keep: 5 - age: 30 \ No newline at end of file + age: 30 +repositories: +- project: 123 + image: myproject/somerepository + policies: + - nonsemverpolicy diff --git a/pkg/config/config.go b/pkg/config/config.go index 0d3d607..4d14b5b 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -10,13 +10,29 @@ import ( type Config struct { AccessToken string `yaml:"access_token"` URL string `yaml:"url"` + Policies []PolicyConfig `yaml:"policies"` Repositories []RepositoryConfig `yaml:"repositories"` } +func (c *Config) GetPolicyConfig(name string) (PolicyConfig, error) { + for _, cfg := range c.Policies { + if cfg.Name == name { + return cfg, nil + } + } + + return PolicyConfig{}, fmt.Errorf("Cannot find policy %s", name) +} + +type PolicyConfig struct { + Name string `yaml:"name"` + Filter FilterConfig `yaml:"filter"` +} + type RepositoryConfig struct { - Project int `yaml:"project"` - Image string `yaml:"image"` - Filter FilterConfig `yaml:"filter"` + Project int `yaml:"project"` + Image string `yaml:"image"` + Policies []string `yaml:"policies"` } type FilterConfig struct {