diff --git a/README.md b/README.md
index 5152ea3..d06a156 100644
--- a/README.md
+++ b/README.md
@@ -49,7 +49,7 @@ module "my_registry" {
| [project_id](#input_project_id) | ID of the project the namespace is associated with. Ressource will be created in the project set at the provider level if null. | `string` | `null` | no |
| [purge_dry_run](#input_purge_dry_run) | Prevent deletion of tags & images. | `bool` | `true` | no |
| [purge_log_level](#input_purge_log_level) | Log Level of the purge function. Refer to the Go [slog package documentation](https://pkg.go.dev/log/slog#Level) for accepted values | `number` | `0` | no |
-| [purge_preserve_tag_patterns](#input_purge_preserve_tag_patterns) | List of regex patterns for tags to preserve. By default, preserves semantic versioning tags. | `list(string)` | ```[ "^v(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$" ]``` | no |
+| [purge_preserve_tag_patterns](#input_purge_preserve_tag_patterns) | List of regex patterns for tags to preserve. By default, preserves semantic versioning tags and `latest` tags. | `list(string)` | ```[ "^latest((-.+)?)$", "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$" ]``` | no |
| [purge_retention_days](#input_purge_retention_days) | Number of days to keep images before deletion. | `number` | `30` | no |
| [purge_schedule](#input_purge_schedule) | Cron schedule for the cleanup function. Set to empty string to disable scheduled cleanup. | `string` | `"0 0 * * *"` | no |
| [purge_timeout](#input_purge_timeout) | Timeout for the cleanup function in seconds. | `number` | `300` | no |
diff --git a/functions.tf b/functions.tf
index 04735dd..ae125b2 100644
--- a/functions.tf
+++ b/functions.tf
@@ -62,7 +62,7 @@ resource "scaleway_function" "registry_purge" {
environment_variables = {
REGISTRY_NAMESPACE = var.name
RETENTION_DAYS = var.purge_retention_days
- PRESERVE_TAG_PATTERNS = join(",", var.purge_preserve_tag_patterns)
+ PRESERVE_TAG_PATTERNS = join("|", var.purge_preserve_tag_patterns)
DRY_RUN = var.purge_dry_run
LOG_LEVEL = var.purge_log_level
}
diff --git a/functions/purge/go.mod b/functions/purge/go.mod
index 2aee338..69b208d 100644
--- a/functions/purge/go.mod
+++ b/functions/purge/go.mod
@@ -1,6 +1,8 @@
module purge
-go 1.23.8
+go 1.23
+
+toolchain go1.23.8
require github.com/scaleway/scaleway-sdk-go v1.0.0-beta.33
diff --git a/functions/purge/handler.go b/functions/purge/handler.go
index 3fd758e..0fec8d3 100644
--- a/functions/purge/handler.go
+++ b/functions/purge/handler.go
@@ -15,7 +15,7 @@ import (
)
// Default semver pattern for tag preservation
-const DefaultTagPattern string = `^v(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$`
+const DefaultTagPattern string = `^latest((-.+)?)$|^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$`
// Config holds the configuration for the purge function
type Config struct {
@@ -62,7 +62,7 @@ var (
)
func init() {
- slog.Info("===== Init container =====")
+ slog.Info("===== Runing 'init' =====")
// Set log level based on environment variable
var logLevel slog.Level
slogLevel, err := strconv.Atoi(os.Getenv("LOG_LEVEL"))
@@ -149,7 +149,7 @@ func init() {
}
func Handle(w http.ResponseWriter, r *http.Request) {
- slog.Info("===== Starting purge =====")
+ slog.Info("===== Runing 'Handle' =====")
// Get Retention date
retentionDate := time.Now().AddDate(0, 0, -config.RetentionDays)
slog.Info(fmt.Sprintf("Purging images older than: %s", retentionDate.Format(time.RFC3339)))
@@ -196,15 +196,15 @@ func Handle(w http.ResponseWriter, r *http.Request) {
for _, tag := range tags {
// Check if tag is older than retention date
if tag.UpdatedAt.Before(retentionDate) {
- slog.Info(fmt.Sprintf("Tag %s:%s updated at %s is older than retention date %s",
+ slog.Debug(fmt.Sprintf("Tag %s:%s updated at %s is older than retention date %s",
image.Name, tag.Name, tag.UpdatedAt.Format(time.RFC3339), retentionDate.Format(time.RFC3339)))
// Check if tag is protected
if config.PreserveTagPatterns.MatchString(tag.Name) {
- slog.Info(fmt.Sprintf("Tag %s match protection pattern. Preserving", tag.Name))
+ slog.Debug(fmt.Sprintf("Tag %s match protection pattern. Preserving", tag.Name))
preservedTags++
} else {
- slog.Info(fmt.Sprintf("Tag %s doesn't match protection pattern.", tag.Name))
+ slog.Debug(fmt.Sprintf("Tag %s doesn't match protection pattern.", tag.Name))
// Delete tag if not dry run
if err := registryClient.DeleteTag(context.Background(), tag); err != nil {
slog.Error(fmt.Sprintf("Failed to delete tag %s (%s): %v", tag.Name, tag.ID, err))
@@ -214,7 +214,7 @@ func Handle(w http.ResponseWriter, r *http.Request) {
deletedTags++
}
} else {
- slog.Info(fmt.Sprintf("Tag %s updated at %s is newer than retention date %s. Skipping",
+ slog.Debug(fmt.Sprintf("Tag %s updated at %s is newer than retention date %s. Skipping",
tag.Name, tag.UpdatedAt.Format(time.RFC3339), retentionDate.Format(time.RFC3339)))
skippedTags++
}
@@ -233,7 +233,7 @@ func Handle(w http.ResponseWriter, r *http.Request) {
// DeleteTag deletes a tag
func (r *RegistryClient) DeleteTag(ctx context.Context, tag *registry.Tag) error {
if r.config.DryRun {
- slog.Info(fmt.Sprintf("[DRY RUN] Would delete tag: %s (%s)", tag.Name, tag.ID))
+ slog.Debug(fmt.Sprintf("[DRY RUN] Would delete tag: %s (%s)", tag.Name, tag.ID))
return nil
}
diff --git a/variables.tf b/variables.tf
index ae2bb37..b45ccd3 100644
--- a/variables.tf
+++ b/variables.tf
@@ -35,9 +35,12 @@ variable "purge_retention_days" {
}
variable "purge_preserve_tag_patterns" {
- description = "List of regex patterns for tags to preserve. By default, preserves semantic versioning tags."
+ description = "List of regex patterns for tags to preserve. By default, preserves semantic versioning tags and `latest` tags."
type = list(string)
- default = ["^v(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$"]
+ default = [
+ "^latest((-.+)?)$",
+ "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$"
+ ]
}
variable "purge_schedule" {