2022-07-20 15:12:41 +00:00
|
|
|
package build
|
|
|
|
|
|
|
|
import (
|
|
|
|
"sort"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/drone/drone-go/drone"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
|
|
"github.com/thegeeklab/drone-admin/admin/client"
|
|
|
|
"github.com/thegeeklab/drone-admin/admin/util"
|
|
|
|
"github.com/urfave/cli/v2"
|
|
|
|
)
|
|
|
|
|
2023-02-08 09:16:05 +00:00
|
|
|
const DroneClientPageSize = 50
|
|
|
|
|
|
|
|
func getPruneCmd() *cli.Command {
|
|
|
|
return &cli.Command{
|
|
|
|
Name: "prune",
|
|
|
|
Usage: "prune builds",
|
|
|
|
ArgsUsage: "<repo/name>",
|
|
|
|
Action: prune,
|
|
|
|
Flags: []cli.Flag{
|
|
|
|
&cli.StringFlag{
|
|
|
|
Name: "older-than",
|
|
|
|
Usage: "remove builds older than the specified time limit",
|
|
|
|
EnvVars: []string{"DRONE_ADMIN_BUILD_PRUNE_OLDER_THAN"},
|
|
|
|
Required: true,
|
|
|
|
},
|
|
|
|
&cli.IntFlag{
|
|
|
|
Name: "keep-min",
|
|
|
|
Usage: "minimum number of builds to keep",
|
|
|
|
EnvVars: []string{"DRONE_ADMIN_BUILD_PRUNE_KEEP_MIN"},
|
|
|
|
//nolint:gomnd
|
|
|
|
Value: 10,
|
|
|
|
},
|
2022-07-20 15:12:41 +00:00
|
|
|
},
|
2023-02-08 09:16:05 +00:00
|
|
|
}
|
2022-07-20 15:12:41 +00:00
|
|
|
}
|
|
|
|
|
2023-02-08 09:16:05 +00:00
|
|
|
func prune(ctx *cli.Context) error {
|
|
|
|
client, err := client.New(ctx.StringSlice("server")[0], ctx.String("token"))
|
2022-07-20 15:12:41 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
repos, err := getRepos(client)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-02-08 09:16:05 +00:00
|
|
|
buildDuration := ctx.String("older-than")
|
|
|
|
buildMin := ctx.Int("keep-min")
|
|
|
|
dry := ctx.Bool("dry-run")
|
2022-07-20 15:12:41 +00:00
|
|
|
|
2023-02-08 09:16:05 +00:00
|
|
|
duration, err := time.ParseDuration(buildDuration)
|
2022-07-20 15:12:41 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if dry {
|
|
|
|
logrus.Info("dry-run enabled, no data will be removed")
|
|
|
|
}
|
|
|
|
|
2023-02-08 09:16:05 +00:00
|
|
|
logrus.Infof("prune builds older than %v, keep min %v", buildDuration, buildMin)
|
2022-07-20 15:12:41 +00:00
|
|
|
|
2023-02-08 09:16:05 +00:00
|
|
|
for _, repo := range repos {
|
|
|
|
builds, err := getBuilds(client, repo)
|
2022-07-20 15:12:41 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
sort.Slice(builds, func(i, j int) bool {
|
|
|
|
return builds[i].Number > builds[j].Number
|
|
|
|
})
|
|
|
|
|
2023-02-08 09:16:05 +00:00
|
|
|
if buildCount := len(builds); buildCount > 0 && buildCount > buildMin {
|
|
|
|
builds = builds[buildMin:]
|
2022-07-20 15:12:41 +00:00
|
|
|
builds = util.Filter(builds, func(b *drone.Build) bool {
|
|
|
|
return time.Since(time.Unix(b.Created, 0)) > duration
|
|
|
|
})
|
|
|
|
|
2023-02-08 09:16:05 +00:00
|
|
|
logrus.Infof("prune %v/%v builds from '%v'", len(builds), buildCount, repo.Slug)
|
2022-07-20 15:12:41 +00:00
|
|
|
|
|
|
|
if !dry && len(builds) > 0 {
|
2023-02-08 09:16:05 +00:00
|
|
|
err := client.BuildPurge(repo.Namespace, repo.Name, int(builds[0].Number+1))
|
2022-07-20 15:12:41 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2023-02-08 09:16:05 +00:00
|
|
|
logrus.Infof("skip '%v', number of %v builds lower than min value", repo.Slug, len(builds))
|
2022-07-20 15:12:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func getRepos(client drone.Client) ([]*drone.Repo, error) {
|
|
|
|
page := 1
|
|
|
|
repos := make([]*drone.Repo, 0)
|
|
|
|
|
|
|
|
for {
|
2023-02-08 09:16:05 +00:00
|
|
|
repo, err := client.RepoListAll(drone.ListOptions{Page: page, Size: DroneClientPageSize})
|
2022-07-20 15:12:41 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-02-08 09:16:05 +00:00
|
|
|
if len(repo) == 0 {
|
2022-07-20 15:12:41 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
|
2023-02-08 09:16:05 +00:00
|
|
|
repos = append(repos, repo...)
|
2022-07-20 15:12:41 +00:00
|
|
|
page++
|
|
|
|
}
|
|
|
|
|
2023-02-08 09:16:05 +00:00
|
|
|
repos = util.Filter(repos, func(repo *drone.Repo) bool {
|
|
|
|
return repo.Active
|
2022-07-20 15:12:41 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
return repos, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func getBuilds(client drone.Client, repo *drone.Repo) ([]*drone.Build, error) {
|
|
|
|
page := 1
|
|
|
|
builds := make([]*drone.Build, 0)
|
|
|
|
|
|
|
|
for {
|
2023-02-08 09:16:05 +00:00
|
|
|
build, err := client.BuildList(repo.Namespace, repo.Name, drone.ListOptions{Page: page, Size: DroneClientPageSize})
|
2022-07-20 15:12:41 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-02-08 09:16:05 +00:00
|
|
|
if len(build) == 0 {
|
2022-07-20 15:12:41 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
|
2023-02-08 09:16:05 +00:00
|
|
|
builds = append(builds, build...)
|
2022-07-20 15:12:41 +00:00
|
|
|
page++
|
|
|
|
}
|
2023-02-08 09:16:05 +00:00
|
|
|
|
2022-07-20 15:12:41 +00:00
|
|
|
return builds, nil
|
|
|
|
}
|