From f14a9e751f15c3a7e5f86242dca421ce8075f1ae Mon Sep 17 00:00:00 2001 From: Sypher845 Date: Tue, 5 May 2026 10:58:49 +0530 Subject: [PATCH 01/15] feat(preheat): preheat policy list command Signed-off-by: Sypher845 --- cmd/harbor/root/project/cmd.go | 1 + cmd/harbor/root/project/preheat.go | 34 +++++++ cmd/harbor/root/project/preheat/policy.go | 34 +++++++ .../root/project/preheat/policy/list.go | 89 +++++++++++++++++++ pkg/api/preheat_handler.go | 51 +++++++++++ pkg/views/preheat/policy/list/view.go | 71 +++++++++++++++ 6 files changed, 280 insertions(+) create mode 100644 cmd/harbor/root/project/preheat.go create mode 100644 cmd/harbor/root/project/preheat/policy.go create mode 100644 cmd/harbor/root/project/preheat/policy/list.go create mode 100644 pkg/api/preheat_handler.go create mode 100644 pkg/views/preheat/policy/list/view.go diff --git a/cmd/harbor/root/project/cmd.go b/cmd/harbor/root/project/cmd.go index 5942e2b69..a64d802fc 100644 --- a/cmd/harbor/root/project/cmd.go +++ b/cmd/harbor/root/project/cmd.go @@ -35,6 +35,7 @@ func Project() *cobra.Command { SearchProjectCommand(), Robot(), Member(), + Preheat(), ) return cmd diff --git a/cmd/harbor/root/project/preheat.go b/cmd/harbor/root/project/preheat.go new file mode 100644 index 000000000..f65e1c536 --- /dev/null +++ b/cmd/harbor/root/project/preheat.go @@ -0,0 +1,34 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package project + +import ( + "github.com/goharbor/harbor-cli/cmd/harbor/root/project/preheat" + "github.com/spf13/cobra" +) + +func Preheat() *cobra.Command { + cmd := &cobra.Command{ + Use: "preheat", + Aliases: []string{"p2p"}, + Short: "Manage project preheat resources", + Long: "Manage project-scoped P2P preheat policies, executions, and tasks in Harbor", + Example: ` harbor project preheat policy list`, + } + cmd.AddCommand( + preheat.PolicyCommand(), + ) + + return cmd +} diff --git a/cmd/harbor/root/project/preheat/policy.go b/cmd/harbor/root/project/preheat/policy.go new file mode 100644 index 000000000..6186b6b5f --- /dev/null +++ b/cmd/harbor/root/project/preheat/policy.go @@ -0,0 +1,34 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package preheat + +import ( + "github.com/goharbor/harbor-cli/cmd/harbor/root/project/preheat/policy" + "github.com/spf13/cobra" +) + +func PolicyCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "policy", + Aliases: []string{"pol"}, + Short: "Manage preheat policies", + Long: "Manage P2P preheat policies under a project", + } + + cmd.AddCommand( + policy.ListPolicyCommand(), + ) + + return cmd +} diff --git a/cmd/harbor/root/project/preheat/policy/list.go b/cmd/harbor/root/project/preheat/policy/list.go new file mode 100644 index 000000000..f9c9cb948 --- /dev/null +++ b/cmd/harbor/root/project/preheat/policy/list.go @@ -0,0 +1,89 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package policy + +import ( + "fmt" + + "github.com/goharbor/harbor-cli/pkg/api" + "github.com/goharbor/harbor-cli/pkg/prompt" + "github.com/goharbor/harbor-cli/pkg/utils" + "github.com/goharbor/harbor-cli/pkg/views/preheat/policy/list" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +func ListPolicyCommand() *cobra.Command { + var opts api.ListFlags + var isID bool + + cmd := &cobra.Command{ + Use: "list [NAME|ID]", + Short: "List preheat policies under a project by name or id", + Long: "List project-scoped P2P preheat policies in Harbor", + Args: cobra.MaximumNArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + var err error + var projectName string + + if opts.Page < 1 { + return fmt.Errorf("page number must be greater than or equal to 1") + } + if opts.PageSize <= 0 || opts.PageSize > 100 { + return fmt.Errorf("page size must be greater than 0 and less than or equal to 100") + } + + if len(args) > 0 { + log.Debugf("Project name provided: %s", args[0]) + projectName = args[0] + } else { + log.Debug("No project name provided, prompting user") + projectName, err = prompt.GetProjectNameFromUser() + if err != nil { + return fmt.Errorf("failed to get project name: %v", utils.ParseHarborErrorMsg(err)) + } + } + + log.Debug("Fetching preheat policies...") + resp, err := api.ListPreheatPolicies(projectName, isID, opts) + if err != nil { + if utils.ParseHarborErrorCode(err) == "404" { + return fmt.Errorf("project %s does not exist", projectName) + } + return fmt.Errorf("failed to list preheat policies: %v", utils.ParseHarborErrorMsg(err)) + } + + FormatFlag := viper.GetString("output-format") + if FormatFlag != "" { + err = utils.PrintFormat(resp, FormatFlag) + if err != nil { + return err + } + } else { + list.ListPolicies(resp.Payload) + } + return nil + }, + } + + flags := cmd.Flags() + flags.BoolVar(&isID, "id", false, "Get preheat policies by project id") + flags.Int64VarP(&opts.Page, "page", "", 1, "Page number") + flags.Int64VarP(&opts.PageSize, "page-size", "", 10, "Size of per page") + flags.StringVarP(&opts.Q, "query", "q", "", "Query string to query resources") + flags.StringVarP(&opts.Sort, "sort", "", "", "Sort the resource list in ascending or descending order") + + return cmd +} diff --git a/pkg/api/preheat_handler.go b/pkg/api/preheat_handler.go new file mode 100644 index 000000000..0d6e922e4 --- /dev/null +++ b/pkg/api/preheat_handler.go @@ -0,0 +1,51 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package api + +import ( + "github.com/goharbor/go-client/pkg/sdk/v2.0/client/preheat" + "github.com/goharbor/harbor-cli/pkg/utils" +) + +func ListPreheatPolicies(projectName string, isID bool, opts ...ListFlags) (*preheat.ListPoliciesOK, error) { + ctx, client, err := utils.ContextWithClient() + if err != nil { + return nil, err + } + + var listFlags ListFlags + if len(opts) > 0 { + listFlags = opts[0] + } + + if isID { + project, err := GetProject(projectName, true) + if err != nil { + return nil, err + } + projectName = project.Payload.Name + } + + response, err := client.Preheat.ListPolicies(ctx, &preheat.ListPoliciesParams{ + ProjectName: projectName, + Page: &listFlags.Page, + PageSize: &listFlags.PageSize, + Q: &listFlags.Q, + Sort: &listFlags.Sort, + }) + if err != nil { + return nil, err + } + return response, nil +} diff --git a/pkg/views/preheat/policy/list/view.go b/pkg/views/preheat/policy/list/view.go new file mode 100644 index 000000000..3075ac624 --- /dev/null +++ b/pkg/views/preheat/policy/list/view.go @@ -0,0 +1,71 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package list + +import ( + "encoding/json" + "fmt" + "os" + + "github.com/charmbracelet/bubbles/table" + tea "github.com/charmbracelet/bubbletea" + "github.com/goharbor/go-client/pkg/sdk/v2.0/models" + "github.com/goharbor/harbor-cli/pkg/utils" + "github.com/goharbor/harbor-cli/pkg/views/base/tablelist" +) + +var columns = []table.Column{ + {Title: "Name", Width: tablelist.WidthM}, + {Title: "Enabled", Width: tablelist.WidthXS}, + {Title: "Provider Name", Width: tablelist.WidthXL}, + {Title: "Filters", Width: tablelist.WidthXL}, + {Title: "Trigger", Width: tablelist.WidthM}, + {Title: "Creation Time", Width: tablelist.WidthL}, + {Title: "Description", Width: tablelist.WidthXL}, +} + +func ListPolicies(policies []*models.PreheatPolicy) { + var rows []table.Row + for _, policy := range policies { + enabled := "No" + if policy.Enabled { + enabled = "Yes" + } + + createdTime, _ := utils.FormatCreatedTime(policy.CreationTime.String()) + + var trigger struct { + Type string `json:"type"` + } + if err := json.Unmarshal([]byte(policy.Trigger), &trigger); err != nil { + trigger.Type = policy.Trigger + } + + rows = append(rows, table.Row{ + policy.Name, + enabled, + policy.ProviderName, + policy.Filters, + trigger.Type, + createdTime, + policy.Description, + }) + } + + m := tablelist.NewModel(columns, rows, len(rows)) + if _, err := tea.NewProgram(m).Run(); err != nil { + fmt.Println("Error running program:", err) + os.Exit(1) + } +} From f10eca2da0cbfee8fc34e514077fa810aa2a08ca Mon Sep 17 00:00:00 2001 From: Sypher845 Date: Tue, 5 May 2026 11:45:59 +0530 Subject: [PATCH 02/15] docs(preheat): docs for preheat policy list command Signed-off-by: Sypher845 --- .../harbor-project-preheat-policy-list.md | 41 ++++++++++++++ doc/cli-docs/harbor-project-preheat-policy.md | 33 +++++++++++ doc/cli-docs/harbor-project-preheat.md | 39 +++++++++++++ doc/cli-docs/harbor-project.md | 1 + .../man1/harbor-project-preheat-policy-list.1 | 55 +++++++++++++++++++ .../man1/harbor-project-preheat-policy.1 | 35 ++++++++++++ doc/man-docs/man1/harbor-project-preheat.1 | 41 ++++++++++++++ doc/man-docs/man1/harbor-project.1 | 2 +- 8 files changed, 246 insertions(+), 1 deletion(-) create mode 100644 doc/cli-docs/harbor-project-preheat-policy-list.md create mode 100644 doc/cli-docs/harbor-project-preheat-policy.md create mode 100644 doc/cli-docs/harbor-project-preheat.md create mode 100644 doc/man-docs/man1/harbor-project-preheat-policy-list.1 create mode 100644 doc/man-docs/man1/harbor-project-preheat-policy.1 create mode 100644 doc/man-docs/man1/harbor-project-preheat.1 diff --git a/doc/cli-docs/harbor-project-preheat-policy-list.md b/doc/cli-docs/harbor-project-preheat-policy-list.md new file mode 100644 index 000000000..62cabfebc --- /dev/null +++ b/doc/cli-docs/harbor-project-preheat-policy-list.md @@ -0,0 +1,41 @@ +--- +title: harbor project preheat policy list +weight: 20 +--- +## harbor project preheat policy list + +### Description + +##### List preheat policies under a project by name or id + +### Synopsis + +List project-scoped P2P preheat policies in Harbor + +```sh +harbor project preheat policy list [NAME|ID] [flags] +``` + +### Options + +```sh + -h, --help help for list + --id Get preheat policies by project id + --page int Page number (default 1) + --page-size int Size of per page (default 10) + -q, --query string Query string to query resources + --sort string Sort the resource list in ascending or descending order +``` + +### Options inherited from parent commands + +```sh + -c, --config string config file (default is $HOME/.config/harbor-cli/config.yaml) + -o, --output-format string Output format. One of: json|yaml|csv + -v, --verbose verbose output +``` + +### SEE ALSO + +* [harbor project preheat policy](harbor-project-preheat-policy.md) - Manage preheat policies + diff --git a/doc/cli-docs/harbor-project-preheat-policy.md b/doc/cli-docs/harbor-project-preheat-policy.md new file mode 100644 index 000000000..5914fc13b --- /dev/null +++ b/doc/cli-docs/harbor-project-preheat-policy.md @@ -0,0 +1,33 @@ +--- +title: harbor project preheat policy +weight: 90 +--- +## harbor project preheat policy + +### Description + +##### Manage preheat policies + +### Synopsis + +Manage P2P preheat policies under a project + +### Options + +```sh + -h, --help help for policy +``` + +### Options inherited from parent commands + +```sh + -c, --config string config file (default is $HOME/.config/harbor-cli/config.yaml) + -o, --output-format string Output format. One of: json|yaml|csv + -v, --verbose verbose output +``` + +### SEE ALSO + +* [harbor project preheat](harbor-project-preheat.md) - Manage project preheat resources +* [harbor project preheat policy list](harbor-project-preheat-policy-list.md) - List preheat policies under a project by name or id + diff --git a/doc/cli-docs/harbor-project-preheat.md b/doc/cli-docs/harbor-project-preheat.md new file mode 100644 index 000000000..e847c8b53 --- /dev/null +++ b/doc/cli-docs/harbor-project-preheat.md @@ -0,0 +1,39 @@ +--- +title: harbor project preheat +weight: 15 +--- +## harbor project preheat + +### Description + +##### Manage project preheat resources + +### Synopsis + +Manage project-scoped P2P preheat policies, executions, and tasks in Harbor + +### Examples + +```sh + harbor project preheat policy list +``` + +### Options + +```sh + -h, --help help for preheat +``` + +### Options inherited from parent commands + +```sh + -c, --config string config file (default is $HOME/.config/harbor-cli/config.yaml) + -o, --output-format string Output format. One of: json|yaml|csv + -v, --verbose verbose output +``` + +### SEE ALSO + +* [harbor project](harbor-project.md) - Manage projects and assign resources to them +* [harbor project preheat policy](harbor-project-preheat-policy.md) - Manage preheat policies + diff --git a/doc/cli-docs/harbor-project.md b/doc/cli-docs/harbor-project.md index 70a414107..1fcfaaef5 100644 --- a/doc/cli-docs/harbor-project.md +++ b/doc/cli-docs/harbor-project.md @@ -41,6 +41,7 @@ Manage projects in Harbor * [harbor project list](harbor-project-list.md) - List projects * [harbor project logs](harbor-project-logs.md) - get project logs * [harbor project member](harbor-project-member.md) - Manage members in a Project +* [harbor project preheat](harbor-project-preheat.md) - Manage project preheat resources * [harbor project robot](harbor-project-robot.md) - Manage robot accounts * [harbor project search](harbor-project-search.md) - search project based on their names * [harbor project view](harbor-project-view.md) - get project by name or id diff --git a/doc/man-docs/man1/harbor-project-preheat-policy-list.1 b/doc/man-docs/man1/harbor-project-preheat-policy-list.1 new file mode 100644 index 000000000..8eadea270 --- /dev/null +++ b/doc/man-docs/man1/harbor-project-preheat-policy-list.1 @@ -0,0 +1,55 @@ +.nh +.TH "HARBOR" "1" "Harbor Community" "Harbor User Manuals" + +.SH NAME +harbor-project-preheat-policy-list - List preheat policies under a project by name or id + + +.SH SYNOPSIS +\fBharbor project preheat policy list [NAME|ID] [flags]\fP + + +.SH DESCRIPTION +List project-scoped P2P preheat policies in Harbor + + +.SH OPTIONS +\fB-h\fP, \fB--help\fP[=false] + help for list + +.PP +\fB--id\fP[=false] + Get preheat policies by project id + +.PP +\fB--page\fP=1 + Page number + +.PP +\fB--page-size\fP=10 + Size of per page + +.PP +\fB-q\fP, \fB--query\fP="" + Query string to query resources + +.PP +\fB--sort\fP="" + Sort the resource list in ascending or descending order + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +\fB-c\fP, \fB--config\fP="" + config file (default is $HOME/.config/harbor-cli/config.yaml) + +.PP +\fB-o\fP, \fB--output-format\fP="" + Output format. One of: json|yaml|csv + +.PP +\fB-v\fP, \fB--verbose\fP[=false] + verbose output + + +.SH SEE ALSO +\fBharbor-project-preheat-policy(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-project-preheat-policy.1 b/doc/man-docs/man1/harbor-project-preheat-policy.1 new file mode 100644 index 000000000..bb9581820 --- /dev/null +++ b/doc/man-docs/man1/harbor-project-preheat-policy.1 @@ -0,0 +1,35 @@ +.nh +.TH "HARBOR" "1" "Harbor Community" "Harbor User Manuals" + +.SH NAME +harbor-project-preheat-policy - Manage preheat policies + + +.SH SYNOPSIS +\fBharbor project preheat policy [flags]\fP + + +.SH DESCRIPTION +Manage P2P preheat policies under a project + + +.SH OPTIONS +\fB-h\fP, \fB--help\fP[=false] + help for policy + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +\fB-c\fP, \fB--config\fP="" + config file (default is $HOME/.config/harbor-cli/config.yaml) + +.PP +\fB-o\fP, \fB--output-format\fP="" + Output format. One of: json|yaml|csv + +.PP +\fB-v\fP, \fB--verbose\fP[=false] + verbose output + + +.SH SEE ALSO +\fBharbor-project-preheat(1)\fP, \fBharbor-project-preheat-policy-list(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-project-preheat.1 b/doc/man-docs/man1/harbor-project-preheat.1 new file mode 100644 index 000000000..f5b24d21e --- /dev/null +++ b/doc/man-docs/man1/harbor-project-preheat.1 @@ -0,0 +1,41 @@ +.nh +.TH "HARBOR" "1" "Harbor Community" "Harbor User Manuals" + +.SH NAME +harbor-project-preheat - Manage project preheat resources + + +.SH SYNOPSIS +\fBharbor project preheat [flags]\fP + + +.SH DESCRIPTION +Manage project-scoped P2P preheat policies, executions, and tasks in Harbor + + +.SH OPTIONS +\fB-h\fP, \fB--help\fP[=false] + help for preheat + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +\fB-c\fP, \fB--config\fP="" + config file (default is $HOME/.config/harbor-cli/config.yaml) + +.PP +\fB-o\fP, \fB--output-format\fP="" + Output format. One of: json|yaml|csv + +.PP +\fB-v\fP, \fB--verbose\fP[=false] + verbose output + + +.SH EXAMPLE +.EX + harbor project preheat policy list +.EE + + +.SH SEE ALSO +\fBharbor-project(1)\fP, \fBharbor-project-preheat-policy(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-project.1 b/doc/man-docs/man1/harbor-project.1 index 0ad3d4256..42ef05b1f 100644 --- a/doc/man-docs/man1/harbor-project.1 +++ b/doc/man-docs/man1/harbor-project.1 @@ -38,4 +38,4 @@ Manage projects in Harbor .SH SEE ALSO -\fBharbor(1)\fP, \fBharbor-project-config(1)\fP, \fBharbor-project-create(1)\fP, \fBharbor-project-delete(1)\fP, \fBharbor-project-list(1)\fP, \fBharbor-project-logs(1)\fP, \fBharbor-project-member(1)\fP, \fBharbor-project-robot(1)\fP, \fBharbor-project-search(1)\fP, \fBharbor-project-view(1)\fP \ No newline at end of file +\fBharbor(1)\fP, \fBharbor-project-config(1)\fP, \fBharbor-project-create(1)\fP, \fBharbor-project-delete(1)\fP, \fBharbor-project-list(1)\fP, \fBharbor-project-logs(1)\fP, \fBharbor-project-member(1)\fP, \fBharbor-project-preheat(1)\fP, \fBharbor-project-robot(1)\fP, \fBharbor-project-search(1)\fP, \fBharbor-project-view(1)\fP \ No newline at end of file From 64126cd70012b34828e5d20191ef55ec91b8c6b8 Mon Sep 17 00:00:00 2001 From: Sypher845 Date: Thu, 7 May 2026 17:25:07 +0530 Subject: [PATCH 03/15] feat(preheat): preheat policy view command Signed-off-by: Sypher845 --- cmd/harbor/root/project/preheat/policy.go | 1 + .../root/project/preheat/policy/view.go | 88 +++++++++++++++++++ pkg/api/preheat_handler.go | 24 +++++ pkg/prompt/prompt.go | 38 ++++++++ pkg/views/preheat/policy/list/view.go | 22 +++-- pkg/views/preheat/policy/select/view.go | 54 ++++++++++++ pkg/views/preheat/policy/view/view.go | 85 ++++++++++++++++++ 7 files changed, 307 insertions(+), 5 deletions(-) create mode 100644 cmd/harbor/root/project/preheat/policy/view.go create mode 100644 pkg/views/preheat/policy/select/view.go create mode 100644 pkg/views/preheat/policy/view/view.go diff --git a/cmd/harbor/root/project/preheat/policy.go b/cmd/harbor/root/project/preheat/policy.go index 6186b6b5f..50ff5e4ff 100644 --- a/cmd/harbor/root/project/preheat/policy.go +++ b/cmd/harbor/root/project/preheat/policy.go @@ -28,6 +28,7 @@ func PolicyCommand() *cobra.Command { cmd.AddCommand( policy.ListPolicyCommand(), + policy.ViewPolicyCommand(), ) return cmd diff --git a/cmd/harbor/root/project/preheat/policy/view.go b/cmd/harbor/root/project/preheat/policy/view.go new file mode 100644 index 000000000..8fbaa4cea --- /dev/null +++ b/cmd/harbor/root/project/preheat/policy/view.go @@ -0,0 +1,88 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package policy + +import ( + "fmt" + + "github.com/goharbor/harbor-cli/pkg/api" + "github.com/goharbor/harbor-cli/pkg/prompt" + "github.com/goharbor/harbor-cli/pkg/utils" + view "github.com/goharbor/harbor-cli/pkg/views/preheat/policy/view" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +func ViewPolicyCommand() *cobra.Command { + var isID bool + + cmd := &cobra.Command{ + Use: "view [NAME|ID] [POLICY_NAME]", + Short: "View details of a preheat policy", + Long: "Get details of a specific P2P preheat policy under a project", + Args: cobra.MaximumNArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + var err error + var projectName, policyName string + + if len(args) >= 1 { + log.Debugf("Project name provided: %s", args[0]) + projectName = args[0] + } else { + log.Debug("No project name provided, prompting user") + projectName, err = prompt.GetProjectNameFromUser() + if err != nil { + return fmt.Errorf("failed to get project name: %v", utils.ParseHarborErrorMsg(err)) + } + } + + if len(args) >= 2 { + log.Debugf("Policy name provided: %s", args[1]) + policyName = args[1] + } else { + log.Debug("No policy name provided, prompting user") + policyName, err = prompt.GetPreheatPolicyNameFromUser(projectName) + if err != nil { + return fmt.Errorf("failed to get policy name: %v", utils.ParseHarborErrorMsg(err)) + } + } + + log.Debug("Fetching preheat policy...") + resp, err := api.GetPreheatPolicy(projectName, policyName, isID) + if err != nil { + if utils.ParseHarborErrorCode(err) == "404" { + return fmt.Errorf("preheat policy %s not found in project %s", policyName, projectName) + } + return fmt.Errorf("failed to get preheat policy: %v", utils.ParseHarborErrorMsg(err)) + } + + FormatFlag := viper.GetString("output-format") + if FormatFlag != "" { + err = utils.PrintFormat(resp.Payload, FormatFlag) + if err != nil { + return err + } + } else { + view.ViewPolicy(resp.Payload) + } + return nil + }, + } + + flags := cmd.Flags() + flags.BoolVar(&isID, "id", false, "Get preheat policy by project id") + + return cmd +} diff --git a/pkg/api/preheat_handler.go b/pkg/api/preheat_handler.go index 0d6e922e4..4f58f5078 100644 --- a/pkg/api/preheat_handler.go +++ b/pkg/api/preheat_handler.go @@ -49,3 +49,27 @@ func ListPreheatPolicies(projectName string, isID bool, opts ...ListFlags) (*pre } return response, nil } + +func GetPreheatPolicy(projectName, policyName string, isID bool) (*preheat.GetPolicyOK, error) { + ctx, client, err := utils.ContextWithClient() + if err != nil { + return nil, err + } + + if isID { + project, err := GetProject(projectName, true) + if err != nil { + return nil, err + } + projectName = project.Payload.Name + } + + response, err := client.Preheat.GetPolicy(ctx, &preheat.GetPolicyParams{ + ProjectName: projectName, + PreheatPolicyName: policyName, + }) + if err != nil { + return nil, err + } + return response, nil +} diff --git a/pkg/prompt/prompt.go b/pkg/prompt/prompt.go index f21932e5f..68aede286 100644 --- a/pkg/prompt/prompt.go +++ b/pkg/prompt/prompt.go @@ -37,6 +37,8 @@ import ( rpolicies "github.com/goharbor/harbor-cli/pkg/views/replication/policies/select" rtasks "github.com/goharbor/harbor-cli/pkg/views/replication/task/select" + phpolicies "github.com/goharbor/harbor-cli/pkg/views/preheat/policy/select" + repoView "github.com/goharbor/harbor-cli/pkg/views/repository/select" retview "github.com/goharbor/harbor-cli/pkg/views/retention/select" robotView "github.com/goharbor/harbor-cli/pkg/views/robot/select" @@ -467,3 +469,39 @@ func GetRetentionTagRule(retentionID string) int64 { }() return <-retentionIndex } + +func GetPreheatPolicyNameFromUser(projectName string) (string, error) { + type result struct { + name string + err error + } + resultChan := make(chan result) + + go func() { + response, err := api.ListPreheatPolicies(projectName, false) + if err != nil { + resultChan <- result{"", err} + return + } + + if len(response.Payload) == 0 { + resultChan <- result{"", errors.New("no preheat policies found")} + return + } + + name, err := phpolicies.PreheatPolicyList(response.Payload) + if err != nil { + if err == phpolicies.ErrUserAborted { + resultChan <- result{"", errors.New("user aborted policy selection")} + } else { + resultChan <- result{"", fmt.Errorf("error during policy selection: %w", err)} + } + return + } + + resultChan <- result{name, nil} + }() + + res := <-resultChan + return res.name, res.err +} diff --git a/pkg/views/preheat/policy/list/view.go b/pkg/views/preheat/policy/list/view.go index 3075ac624..a98910aa7 100644 --- a/pkg/views/preheat/policy/list/view.go +++ b/pkg/views/preheat/policy/list/view.go @@ -17,6 +17,7 @@ import ( "encoding/json" "fmt" "os" + "strings" "github.com/charmbracelet/bubbles/table" tea "github.com/charmbracelet/bubbletea" @@ -27,12 +28,12 @@ import ( var columns = []table.Column{ {Title: "Name", Width: tablelist.WidthM}, - {Title: "Enabled", Width: tablelist.WidthXS}, - {Title: "Provider Name", Width: tablelist.WidthXL}, - {Title: "Filters", Width: tablelist.WidthXL}, + {Title: "Enabled", Width: tablelist.WidthS}, + {Title: "Provider", Width: tablelist.WidthXL}, + {Title: "Filters", Width: tablelist.Width3XL}, {Title: "Trigger", Width: tablelist.WidthM}, {Title: "Creation Time", Width: tablelist.WidthL}, - {Title: "Description", Width: tablelist.WidthXL}, + {Title: "Description", Width: tablelist.WidthM}, } func ListPolicies(policies []*models.PreheatPolicy) { @@ -45,6 +46,17 @@ func ListPolicies(policies []*models.PreheatPolicy) { createdTime, _ := utils.FormatCreatedTime(policy.CreationTime.String()) + var filters []struct { + Type string `json:"type"` + Value string `json:"value"` + } + var filterParts []string + if err := json.Unmarshal([]byte(policy.Filters), &filters); err == nil { + for _, f := range filters { + filterParts = append(filterParts, fmt.Sprintf("%s: %s", f.Type, f.Value)) + } + } + var trigger struct { Type string `json:"type"` } @@ -56,7 +68,7 @@ func ListPolicies(policies []*models.PreheatPolicy) { policy.Name, enabled, policy.ProviderName, - policy.Filters, + strings.Join(filterParts, " "), trigger.Type, createdTime, policy.Description, diff --git a/pkg/views/preheat/policy/select/view.go b/pkg/views/preheat/policy/select/view.go new file mode 100644 index 000000000..21d584006 --- /dev/null +++ b/pkg/views/preheat/policy/select/view.go @@ -0,0 +1,54 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package policy + +import ( + "errors" + "fmt" + "os" + + "github.com/charmbracelet/bubbles/list" + tea "github.com/charmbracelet/bubbletea" + "github.com/goharbor/go-client/pkg/sdk/v2.0/models" + "github.com/goharbor/harbor-cli/pkg/views/base/selection" +) + +var ErrUserAborted = errors.New("user aborted selection") + +func PreheatPolicyList(policies []*models.PreheatPolicy) (string, error) { + items := make([]list.Item, len(policies)) + for i, p := range policies { + items[i] = selection.Item(p.Name) + } + + m := selection.NewModel(items, "Preheat Policy") + + p, err := tea.NewProgram(m, tea.WithAltScreen()).Run() + if err != nil { + fmt.Println("Error running program:", err) + os.Exit(1) + } + + if model, ok := p.(selection.Model); ok { + if model.Aborted { + return "", ErrUserAborted + } + if model.Choice == "" { + return "", errors.New("no policy selected") + } + return model.Choice, nil + } + + return "", errors.New("unexpected program result") +} diff --git a/pkg/views/preheat/policy/view/view.go b/pkg/views/preheat/policy/view/view.go new file mode 100644 index 000000000..e13704b21 --- /dev/null +++ b/pkg/views/preheat/policy/view/view.go @@ -0,0 +1,85 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package view + +import ( + "encoding/json" + "fmt" + "os" + "strings" + + "github.com/charmbracelet/bubbles/table" + tea "github.com/charmbracelet/bubbletea" + "github.com/goharbor/go-client/pkg/sdk/v2.0/models" + "github.com/goharbor/harbor-cli/pkg/utils" + "github.com/goharbor/harbor-cli/pkg/views/base/tablelist" +) + +var columns = []table.Column{ + {Title: "Name", Width: tablelist.WidthM}, + {Title: "Enabled", Width: tablelist.WidthS}, + {Title: "Provider", Width: tablelist.WidthXL}, + {Title: "Filters", Width: tablelist.Width3XL}, + {Title: "Trigger", Width: tablelist.WidthM}, + {Title: "Creation Time", Width: tablelist.WidthL}, + {Title: "Updated", Width: tablelist.WidthL}, + {Title: "Description", Width: tablelist.WidthM}, +} + +func ViewPolicy(policy *models.PreheatPolicy) { + var rows []table.Row + + enabled := "No" + if policy.Enabled { + enabled = "Yes" + } + + createdTime, _ := utils.FormatCreatedTime(policy.CreationTime.String()) + updatedTime, _ := utils.FormatCreatedTime(policy.UpdateTime.String()) + + var filters []struct { + Type string `json:"type"` + Value string `json:"value"` + } + var filterParts []string + if err := json.Unmarshal([]byte(policy.Filters), &filters); err == nil { + for _, f := range filters { + filterParts = append(filterParts, fmt.Sprintf("%s: %s", f.Type, f.Value)) + } + } + + var trigger struct { + Type string `json:"type"` + } + if err := json.Unmarshal([]byte(policy.Trigger), &trigger); err != nil { + trigger.Type = policy.Trigger + } + + rows = append(rows, table.Row{ + policy.Name, + enabled, + policy.ProviderName, + strings.Join(filterParts, " "), + trigger.Type, + createdTime, + updatedTime, + policy.Description, + }) + + m := tablelist.NewModel(columns, rows, len(rows)) + if _, err := tea.NewProgram(m).Run(); err != nil { + fmt.Println("Error running program:", err) + os.Exit(1) + } +} From bab12ea35afc07c3cd5a0254f3b5d8d665e20722 Mon Sep 17 00:00:00 2001 From: Sypher845 Date: Thu, 7 May 2026 17:28:20 +0530 Subject: [PATCH 04/15] docs(preheat): docs for preheat policy view command Signed-off-by: Sypher845 --- .../harbor-project-preheat-policy-view.md | 37 ++++++++++++++++++ doc/cli-docs/harbor-project-preheat-policy.md | 1 + .../man1/harbor-project-preheat-policy-view.1 | 39 +++++++++++++++++++ .../man1/harbor-project-preheat-policy.1 | 2 +- 4 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 doc/cli-docs/harbor-project-preheat-policy-view.md create mode 100644 doc/man-docs/man1/harbor-project-preheat-policy-view.1 diff --git a/doc/cli-docs/harbor-project-preheat-policy-view.md b/doc/cli-docs/harbor-project-preheat-policy-view.md new file mode 100644 index 000000000..3c33cf09d --- /dev/null +++ b/doc/cli-docs/harbor-project-preheat-policy-view.md @@ -0,0 +1,37 @@ +--- +title: harbor project preheat policy view +weight: 30 +--- +## harbor project preheat policy view + +### Description + +##### View details of a preheat policy + +### Synopsis + +Get details of a specific P2P preheat policy under a project + +```sh +harbor project preheat policy view [NAME|ID] [POLICY_NAME] [flags] +``` + +### Options + +```sh + -h, --help help for view + --id Get preheat policy by project id +``` + +### Options inherited from parent commands + +```sh + -c, --config string config file (default is $HOME/.config/harbor-cli/config.yaml) + -o, --output-format string Output format. One of: json|yaml|csv + -v, --verbose verbose output +``` + +### SEE ALSO + +* [harbor project preheat policy](harbor-project-preheat-policy.md) - Manage preheat policies + diff --git a/doc/cli-docs/harbor-project-preheat-policy.md b/doc/cli-docs/harbor-project-preheat-policy.md index 5914fc13b..f27546f37 100644 --- a/doc/cli-docs/harbor-project-preheat-policy.md +++ b/doc/cli-docs/harbor-project-preheat-policy.md @@ -30,4 +30,5 @@ Manage P2P preheat policies under a project * [harbor project preheat](harbor-project-preheat.md) - Manage project preheat resources * [harbor project preheat policy list](harbor-project-preheat-policy-list.md) - List preheat policies under a project by name or id +* [harbor project preheat policy view](harbor-project-preheat-policy-view.md) - View details of a preheat policy diff --git a/doc/man-docs/man1/harbor-project-preheat-policy-view.1 b/doc/man-docs/man1/harbor-project-preheat-policy-view.1 new file mode 100644 index 000000000..8a724e406 --- /dev/null +++ b/doc/man-docs/man1/harbor-project-preheat-policy-view.1 @@ -0,0 +1,39 @@ +.nh +.TH "HARBOR" "1" "Harbor Community" "Harbor User Manuals" + +.SH NAME +harbor-project-preheat-policy-view - View details of a preheat policy + + +.SH SYNOPSIS +\fBharbor project preheat policy view [NAME|ID] [POLICY_NAME] [flags]\fP + + +.SH DESCRIPTION +Get details of a specific P2P preheat policy under a project + + +.SH OPTIONS +\fB-h\fP, \fB--help\fP[=false] + help for view + +.PP +\fB--id\fP[=false] + Get preheat policy by project id + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +\fB-c\fP, \fB--config\fP="" + config file (default is $HOME/.config/harbor-cli/config.yaml) + +.PP +\fB-o\fP, \fB--output-format\fP="" + Output format. One of: json|yaml|csv + +.PP +\fB-v\fP, \fB--verbose\fP[=false] + verbose output + + +.SH SEE ALSO +\fBharbor-project-preheat-policy(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-project-preheat-policy.1 b/doc/man-docs/man1/harbor-project-preheat-policy.1 index bb9581820..d403fb169 100644 --- a/doc/man-docs/man1/harbor-project-preheat-policy.1 +++ b/doc/man-docs/man1/harbor-project-preheat-policy.1 @@ -32,4 +32,4 @@ Manage P2P preheat policies under a project .SH SEE ALSO -\fBharbor-project-preheat(1)\fP, \fBharbor-project-preheat-policy-list(1)\fP \ No newline at end of file +\fBharbor-project-preheat(1)\fP, \fBharbor-project-preheat-policy-list(1)\fP, \fBharbor-project-preheat-policy-view(1)\fP \ No newline at end of file From a0df09b08d400b32b0822a5d11c0240d2d17f934 Mon Sep 17 00:00:00 2001 From: Sypher845 Date: Fri, 8 May 2026 08:42:26 +0530 Subject: [PATCH 05/15] feat(preheat): preheat policy delete command Signed-off-by: Sypher845 --- cmd/harbor/root/project/preheat/policy.go | 1 + .../root/project/preheat/policy/delete.go | 78 +++++++++++++++++++ pkg/api/preheat_handler.go | 24 ++++++ 3 files changed, 103 insertions(+) create mode 100644 cmd/harbor/root/project/preheat/policy/delete.go diff --git a/cmd/harbor/root/project/preheat/policy.go b/cmd/harbor/root/project/preheat/policy.go index 50ff5e4ff..a362e6216 100644 --- a/cmd/harbor/root/project/preheat/policy.go +++ b/cmd/harbor/root/project/preheat/policy.go @@ -29,6 +29,7 @@ func PolicyCommand() *cobra.Command { cmd.AddCommand( policy.ListPolicyCommand(), policy.ViewPolicyCommand(), + policy.DeletePolicyCommand(), ) return cmd diff --git a/cmd/harbor/root/project/preheat/policy/delete.go b/cmd/harbor/root/project/preheat/policy/delete.go new file mode 100644 index 000000000..ecb281fca --- /dev/null +++ b/cmd/harbor/root/project/preheat/policy/delete.go @@ -0,0 +1,78 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package policy + +import ( + "fmt" + + "github.com/goharbor/harbor-cli/pkg/api" + "github.com/goharbor/harbor-cli/pkg/prompt" + "github.com/goharbor/harbor-cli/pkg/utils" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +func DeletePolicyCommand() *cobra.Command { + var isID bool + + cmd := &cobra.Command{ + Use: "delete [NAME|ID] [POLICY_NAME]", + Short: "Delete a preheat policy", + Long: "Delete a specific P2P preheat policy under a project", + Args: cobra.MaximumNArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + var err error + var projectName, policyName string + + if len(args) >= 1 { + log.Debugf("Project name provided: %s", args[0]) + projectName = args[0] + } else { + log.Debug("No project name provided, prompting user") + projectName, err = prompt.GetProjectNameFromUser() + if err != nil { + return fmt.Errorf("failed to get project name: %v", utils.ParseHarborErrorMsg(err)) + } + } + + if len(args) >= 2 { + log.Debugf("Policy name provided: %s", args[1]) + policyName = args[1] + } else { + log.Debug("No policy name provided, prompting user") + policyName, err = prompt.GetPreheatPolicyNameFromUser(projectName) + if err != nil { + return fmt.Errorf("failed to get policy name: %v", utils.ParseHarborErrorMsg(err)) + } + } + + log.Debug("Deleting preheat policy...") + err = api.DeletePreheatPolicy(projectName, policyName, isID) + if err != nil { + if utils.ParseHarborErrorCode(err) == "404" { + return fmt.Errorf("preheat policy %s not found in project %s", policyName, projectName) + } + return fmt.Errorf("failed to delete preheat policy: %v", utils.ParseHarborErrorMsg(err)) + } + + fmt.Printf("Preheat policy '%s' deleted successfully from project '%s'\n", policyName, projectName) + return nil + }, + } + + flags := cmd.Flags() + flags.BoolVar(&isID, "id", false, "Delete preheat policy by project id") + + return cmd +} diff --git a/pkg/api/preheat_handler.go b/pkg/api/preheat_handler.go index 4f58f5078..130059de5 100644 --- a/pkg/api/preheat_handler.go +++ b/pkg/api/preheat_handler.go @@ -73,3 +73,27 @@ func GetPreheatPolicy(projectName, policyName string, isID bool) (*preheat.GetPo } return response, nil } + +func DeletePreheatPolicy(projectName, policyName string, isID bool) error { + ctx, client, err := utils.ContextWithClient() + if err != nil { + return err + } + + if isID { + project, err := GetProject(projectName, true) + if err != nil { + return err + } + projectName = project.Payload.Name + } + + _, err = client.Preheat.DeletePolicy(ctx, &preheat.DeletePolicyParams{ + ProjectName: projectName, + PreheatPolicyName: policyName, + }) + if err != nil { + return err + } + return nil +} From 3595e4a53501babaa698acbdd2d4dd5ac7926a42 Mon Sep 17 00:00:00 2001 From: Sypher845 Date: Fri, 8 May 2026 08:44:04 +0530 Subject: [PATCH 06/15] docs(preheat): docs for preheat policy delete command Signed-off-by: Sypher845 --- .../harbor-project-preheat-policy-delete.md | 37 ++++++++++++++++++ doc/cli-docs/harbor-project-preheat-policy.md | 1 + .../harbor-project-preheat-policy-delete.1 | 39 +++++++++++++++++++ .../man1/harbor-project-preheat-policy.1 | 2 +- 4 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 doc/cli-docs/harbor-project-preheat-policy-delete.md create mode 100644 doc/man-docs/man1/harbor-project-preheat-policy-delete.1 diff --git a/doc/cli-docs/harbor-project-preheat-policy-delete.md b/doc/cli-docs/harbor-project-preheat-policy-delete.md new file mode 100644 index 000000000..9ad9a0abe --- /dev/null +++ b/doc/cli-docs/harbor-project-preheat-policy-delete.md @@ -0,0 +1,37 @@ +--- +title: harbor project preheat policy delete +weight: 20 +--- +## harbor project preheat policy delete + +### Description + +##### Delete a preheat policy + +### Synopsis + +Delete a specific P2P preheat policy under a project + +```sh +harbor project preheat policy delete [NAME|ID] [POLICY_NAME] [flags] +``` + +### Options + +```sh + -h, --help help for delete + --id Delete preheat policy by project id +``` + +### Options inherited from parent commands + +```sh + -c, --config string config file (default is $HOME/.config/harbor-cli/config.yaml) + -o, --output-format string Output format. One of: json|yaml|csv + -v, --verbose verbose output +``` + +### SEE ALSO + +* [harbor project preheat policy](harbor-project-preheat-policy.md) - Manage preheat policies + diff --git a/doc/cli-docs/harbor-project-preheat-policy.md b/doc/cli-docs/harbor-project-preheat-policy.md index f27546f37..4c428bd56 100644 --- a/doc/cli-docs/harbor-project-preheat-policy.md +++ b/doc/cli-docs/harbor-project-preheat-policy.md @@ -29,6 +29,7 @@ Manage P2P preheat policies under a project ### SEE ALSO * [harbor project preheat](harbor-project-preheat.md) - Manage project preheat resources +* [harbor project preheat policy delete](harbor-project-preheat-policy-delete.md) - Delete a preheat policy * [harbor project preheat policy list](harbor-project-preheat-policy-list.md) - List preheat policies under a project by name or id * [harbor project preheat policy view](harbor-project-preheat-policy-view.md) - View details of a preheat policy diff --git a/doc/man-docs/man1/harbor-project-preheat-policy-delete.1 b/doc/man-docs/man1/harbor-project-preheat-policy-delete.1 new file mode 100644 index 000000000..e7f036fff --- /dev/null +++ b/doc/man-docs/man1/harbor-project-preheat-policy-delete.1 @@ -0,0 +1,39 @@ +.nh +.TH "HARBOR" "1" "Harbor Community" "Harbor User Manuals" + +.SH NAME +harbor-project-preheat-policy-delete - Delete a preheat policy + + +.SH SYNOPSIS +\fBharbor project preheat policy delete [NAME|ID] [POLICY_NAME] [flags]\fP + + +.SH DESCRIPTION +Delete a specific P2P preheat policy under a project + + +.SH OPTIONS +\fB-h\fP, \fB--help\fP[=false] + help for delete + +.PP +\fB--id\fP[=false] + Delete preheat policy by project id + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +\fB-c\fP, \fB--config\fP="" + config file (default is $HOME/.config/harbor-cli/config.yaml) + +.PP +\fB-o\fP, \fB--output-format\fP="" + Output format. One of: json|yaml|csv + +.PP +\fB-v\fP, \fB--verbose\fP[=false] + verbose output + + +.SH SEE ALSO +\fBharbor-project-preheat-policy(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-project-preheat-policy.1 b/doc/man-docs/man1/harbor-project-preheat-policy.1 index d403fb169..b304e8389 100644 --- a/doc/man-docs/man1/harbor-project-preheat-policy.1 +++ b/doc/man-docs/man1/harbor-project-preheat-policy.1 @@ -32,4 +32,4 @@ Manage P2P preheat policies under a project .SH SEE ALSO -\fBharbor-project-preheat(1)\fP, \fBharbor-project-preheat-policy-list(1)\fP, \fBharbor-project-preheat-policy-view(1)\fP \ No newline at end of file +\fBharbor-project-preheat(1)\fP, \fBharbor-project-preheat-policy-delete(1)\fP, \fBharbor-project-preheat-policy-list(1)\fP, \fBharbor-project-preheat-policy-view(1)\fP \ No newline at end of file From 4969354d8d48541fce3b4e35dfb95323a5f93d5f Mon Sep 17 00:00:00 2001 From: Sypher845 Date: Fri, 8 May 2026 16:14:37 +0530 Subject: [PATCH 07/15] feat(preheat): preheat policy start command Signed-off-by: Sypher845 --- cmd/harbor/root/project/preheat/policy.go | 1 + .../root/project/preheat/policy/start.go | 78 +++++++++++++++++++ pkg/api/preheat_handler.go | 30 +++++++ 3 files changed, 109 insertions(+) create mode 100644 cmd/harbor/root/project/preheat/policy/start.go diff --git a/cmd/harbor/root/project/preheat/policy.go b/cmd/harbor/root/project/preheat/policy.go index a362e6216..98ff2dbab 100644 --- a/cmd/harbor/root/project/preheat/policy.go +++ b/cmd/harbor/root/project/preheat/policy.go @@ -30,6 +30,7 @@ func PolicyCommand() *cobra.Command { policy.ListPolicyCommand(), policy.ViewPolicyCommand(), policy.DeletePolicyCommand(), + policy.StartPolicyCommand(), ) return cmd diff --git a/cmd/harbor/root/project/preheat/policy/start.go b/cmd/harbor/root/project/preheat/policy/start.go new file mode 100644 index 000000000..1ce2c15bb --- /dev/null +++ b/cmd/harbor/root/project/preheat/policy/start.go @@ -0,0 +1,78 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package policy + +import ( + "fmt" + + "github.com/goharbor/harbor-cli/pkg/api" + "github.com/goharbor/harbor-cli/pkg/prompt" + "github.com/goharbor/harbor-cli/pkg/utils" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +func StartPolicyCommand() *cobra.Command { + var isID bool + + cmd := &cobra.Command{ + Use: "start [NAME|ID] [POLICY_NAME]", + Short: "Manually trigger a preheat policy", + Long: "Manually trigger a specific P2P preheat policy under a project", + Args: cobra.MaximumNArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + var err error + var projectName, policyName string + + if len(args) >= 1 { + log.Debugf("Project name provided: %s", args[0]) + projectName = args[0] + } else { + log.Debug("No project name provided, prompting user") + projectName, err = prompt.GetProjectNameFromUser() + if err != nil { + return fmt.Errorf("failed to get project name: %v", utils.ParseHarborErrorMsg(err)) + } + } + + if len(args) >= 2 { + log.Debugf("Policy name provided: %s", args[1]) + policyName = args[1] + } else { + log.Debug("No policy name provided, prompting user") + policyName, err = prompt.GetPreheatPolicyNameFromUser(projectName) + if err != nil { + return fmt.Errorf("failed to get policy name: %v", utils.ParseHarborErrorMsg(err)) + } + } + + log.Debug("Manually triggering preheat policy...") + location, err := api.StartPreheatPolicy(projectName, policyName, isID) + if err != nil { + if utils.ParseHarborErrorCode(err) == "404" { + return fmt.Errorf("preheat policy %s not found in project %s", policyName, projectName) + } + return fmt.Errorf("failed to manually trigger preheat policy: %v", utils.ParseHarborErrorMsg(err)) + } + + fmt.Printf("Preheat policy '%s' manually triggered successfully from project '%s'\nExecution location: %s\n", policyName, projectName, location) + return nil + }, + } + + flags := cmd.Flags() + flags.BoolVar(&isID, "id", false, "Manually trigger preheat policy by project id") + + return cmd +} diff --git a/pkg/api/preheat_handler.go b/pkg/api/preheat_handler.go index 130059de5..2f2f8ceae 100644 --- a/pkg/api/preheat_handler.go +++ b/pkg/api/preheat_handler.go @@ -97,3 +97,33 @@ func DeletePreheatPolicy(projectName, policyName string, isID bool) error { } return nil } + +func StartPreheatPolicy(projectName, policyName string, isID bool) (string, error) { + ctx, client, err := utils.ContextWithClient() + if err != nil { + return "", err + } + + if isID { + project, err := GetProject(projectName, true) + if err != nil { + return "", err + } + projectName = project.Payload.Name + } + + policy, err := GetPreheatPolicy(projectName, policyName, false) + if err != nil { + return "", err + } + + resp, err := client.Preheat.ManualPreheat(ctx, &preheat.ManualPreheatParams{ + ProjectName: projectName, + PreheatPolicyName: policyName, + Policy: policy.Payload, + }) + if err != nil { + return "", err + } + return resp.Location, nil +} From 604d6e2f459b8196c7e2eaaa27f2ec5077ea0e38 Mon Sep 17 00:00:00 2001 From: Sypher845 Date: Fri, 8 May 2026 16:15:58 +0530 Subject: [PATCH 08/15] docs(preheat): docs for preheat policy start command Signed-off-by: Sypher845 --- .../harbor-project-preheat-policy-start.md | 37 ++++++++++++++++++ doc/cli-docs/harbor-project-preheat-policy.md | 1 + .../harbor-project-preheat-policy-start.1 | 39 +++++++++++++++++++ .../man1/harbor-project-preheat-policy.1 | 2 +- 4 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 doc/cli-docs/harbor-project-preheat-policy-start.md create mode 100644 doc/man-docs/man1/harbor-project-preheat-policy-start.1 diff --git a/doc/cli-docs/harbor-project-preheat-policy-start.md b/doc/cli-docs/harbor-project-preheat-policy-start.md new file mode 100644 index 000000000..57bd3b1e1 --- /dev/null +++ b/doc/cli-docs/harbor-project-preheat-policy-start.md @@ -0,0 +1,37 @@ +--- +title: harbor project preheat policy start +weight: 55 +--- +## harbor project preheat policy start + +### Description + +##### Manually trigger a preheat policy + +### Synopsis + +Manually trigger a specific P2P preheat policy under a project + +```sh +harbor project preheat policy start [NAME|ID] [POLICY_NAME] [flags] +``` + +### Options + +```sh + -h, --help help for start + --id Manually trigger preheat policy by project id +``` + +### Options inherited from parent commands + +```sh + -c, --config string config file (default is $HOME/.config/harbor-cli/config.yaml) + -o, --output-format string Output format. One of: json|yaml|csv + -v, --verbose verbose output +``` + +### SEE ALSO + +* [harbor project preheat policy](harbor-project-preheat-policy.md) - Manage preheat policies + diff --git a/doc/cli-docs/harbor-project-preheat-policy.md b/doc/cli-docs/harbor-project-preheat-policy.md index 4c428bd56..5995c8e49 100644 --- a/doc/cli-docs/harbor-project-preheat-policy.md +++ b/doc/cli-docs/harbor-project-preheat-policy.md @@ -31,5 +31,6 @@ Manage P2P preheat policies under a project * [harbor project preheat](harbor-project-preheat.md) - Manage project preheat resources * [harbor project preheat policy delete](harbor-project-preheat-policy-delete.md) - Delete a preheat policy * [harbor project preheat policy list](harbor-project-preheat-policy-list.md) - List preheat policies under a project by name or id +* [harbor project preheat policy start](harbor-project-preheat-policy-start.md) - Manually trigger a preheat policy * [harbor project preheat policy view](harbor-project-preheat-policy-view.md) - View details of a preheat policy diff --git a/doc/man-docs/man1/harbor-project-preheat-policy-start.1 b/doc/man-docs/man1/harbor-project-preheat-policy-start.1 new file mode 100644 index 000000000..573c85092 --- /dev/null +++ b/doc/man-docs/man1/harbor-project-preheat-policy-start.1 @@ -0,0 +1,39 @@ +.nh +.TH "HARBOR" "1" "Harbor Community" "Harbor User Manuals" + +.SH NAME +harbor-project-preheat-policy-start - Manually trigger a preheat policy + + +.SH SYNOPSIS +\fBharbor project preheat policy start [NAME|ID] [POLICY_NAME] [flags]\fP + + +.SH DESCRIPTION +Manually trigger a specific P2P preheat policy under a project + + +.SH OPTIONS +\fB-h\fP, \fB--help\fP[=false] + help for start + +.PP +\fB--id\fP[=false] + Manually trigger preheat policy by project id + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +\fB-c\fP, \fB--config\fP="" + config file (default is $HOME/.config/harbor-cli/config.yaml) + +.PP +\fB-o\fP, \fB--output-format\fP="" + Output format. One of: json|yaml|csv + +.PP +\fB-v\fP, \fB--verbose\fP[=false] + verbose output + + +.SH SEE ALSO +\fBharbor-project-preheat-policy(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-project-preheat-policy.1 b/doc/man-docs/man1/harbor-project-preheat-policy.1 index b304e8389..c21a715ee 100644 --- a/doc/man-docs/man1/harbor-project-preheat-policy.1 +++ b/doc/man-docs/man1/harbor-project-preheat-policy.1 @@ -32,4 +32,4 @@ Manage P2P preheat policies under a project .SH SEE ALSO -\fBharbor-project-preheat(1)\fP, \fBharbor-project-preheat-policy-delete(1)\fP, \fBharbor-project-preheat-policy-list(1)\fP, \fBharbor-project-preheat-policy-view(1)\fP \ No newline at end of file +\fBharbor-project-preheat(1)\fP, \fBharbor-project-preheat-policy-delete(1)\fP, \fBharbor-project-preheat-policy-list(1)\fP, \fBharbor-project-preheat-policy-start(1)\fP, \fBharbor-project-preheat-policy-view(1)\fP \ No newline at end of file From 162da4eec018f01654df41398ba816aff6733dd8 Mon Sep 17 00:00:00 2001 From: Sypher845 Date: Sun, 10 May 2026 21:19:33 +0530 Subject: [PATCH 09/15] feat(preheat): preheat policy create command Signed-off-by: Sypher845 --- cmd/harbor/root/project/preheat/policy.go | 1 + .../root/project/preheat/policy/create.go | 173 ++++++++++++ pkg/api/preheat_handler.go | 32 +++ pkg/config/preheat/policies.go | 262 ++++++++++++++++++ pkg/views/preheat/policy/create/view.go | 208 ++++++++++++++ 5 files changed, 676 insertions(+) create mode 100644 cmd/harbor/root/project/preheat/policy/create.go create mode 100644 pkg/config/preheat/policies.go create mode 100644 pkg/views/preheat/policy/create/view.go diff --git a/cmd/harbor/root/project/preheat/policy.go b/cmd/harbor/root/project/preheat/policy.go index 98ff2dbab..0efb565cc 100644 --- a/cmd/harbor/root/project/preheat/policy.go +++ b/cmd/harbor/root/project/preheat/policy.go @@ -29,6 +29,7 @@ func PolicyCommand() *cobra.Command { cmd.AddCommand( policy.ListPolicyCommand(), policy.ViewPolicyCommand(), + policy.CreatePolicyCommand(), policy.DeletePolicyCommand(), policy.StartPolicyCommand(), ) diff --git a/cmd/harbor/root/project/preheat/policy/create.go b/cmd/harbor/root/project/preheat/policy/create.go new file mode 100644 index 000000000..e9adc7a65 --- /dev/null +++ b/cmd/harbor/root/project/preheat/policy/create.go @@ -0,0 +1,173 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package policy + +import ( + "encoding/json" + "fmt" + + "github.com/goharbor/go-client/pkg/sdk/v2.0/models" + "github.com/goharbor/harbor-cli/pkg/api" + config "github.com/goharbor/harbor-cli/pkg/config/preheat" + "github.com/goharbor/harbor-cli/pkg/prompt" + "github.com/goharbor/harbor-cli/pkg/utils" + "github.com/goharbor/harbor-cli/pkg/views/preheat/policy/create" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +func CreatePolicyCommand() *cobra.Command { + var isID bool + var configFile string + + cmd := &cobra.Command{ + Use: "create [NAME|ID]", + Short: "Create a preheat policy", + Long: "Create a new P2P preheat policy under a project", + Args: cobra.MaximumNArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + var err error + var projectName string + + if len(args) > 0 { + log.Debugf("Project name provided: %s", args[0]) + projectName = args[0] + } else { + log.Debug("No project name provided, prompting user") + projectName, err = prompt.GetProjectNameFromUser() + if err != nil { + return fmt.Errorf("failed to get project name: %v", utils.ParseHarborErrorMsg(err)) + } + } + + if isID { + project, err := api.GetProject(projectName, true) + if err != nil { + return fmt.Errorf("failed to get project: %v", utils.ParseHarborErrorMsg(err)) + } + projectName = project.Payload.Name + } + + var opts *create.CreateView + + if configFile != "" { + log.Debugf("Loading preheat policy configuration from file: %s", configFile) + opts, err = config.LoadConfigFromFile(configFile) + if err != nil { + return fmt.Errorf("failed to load preheat policy configuration: %v", err) + } + } else { + opts = &create.CreateView{ + Enabled: true, + } + } + + log.Debug("Fetching available providers...") + providers, err := api.ListProvidersUnderProject(projectName) + if err != nil { + return fmt.Errorf("failed to list providers: %v", utils.ParseHarborErrorMsg(err)) + } + + if len(providers) == 0 { + return fmt.Errorf("no P2P provider instances available for project '%s'. Please create a provider instance first", projectName) + } + + if configFile == "" { + create.CreatePreheatPolicyView(opts, providers) + } + + providerID, err := resolveProviderID(providers, opts.ProviderName, projectName) + if err != nil { + return err + } + + policy, err := ConvertToPolicy(opts, providerID) + if err != nil { + return err + } + + log.Debug("Creating preheat policy...") + response, err := api.CreatePreheatPolicy(projectName, policy) + if err != nil { + if utils.ParseHarborErrorCode(err) == "409" { + return fmt.Errorf("preheat policy '%s' already exists in project '%s'", opts.Name, projectName) + } + return fmt.Errorf("failed to create preheat policy: %v", utils.ParseHarborErrorMsg(err)) + } + + fmt.Println("Preheat policy created successfully with ID:", response.Location) + return nil + }, + } + + flags := cmd.Flags() + flags.BoolVar(&isID, "id", false, "Use project id instead of name") + flags.StringVarP(&configFile, "policy-config-file", "f", "", "YAML/JSON file with preheat policy configuration") + + return cmd +} + +func resolveProviderID(providers []*models.ProviderUnderProject, providerName, projectName string) (int64, error) { + for _, provider := range providers { + if provider.Provider == providerName && provider.Enabled { + return provider.ID, nil + } + } + + return 0, fmt.Errorf("provider '%s' not found or not enabled for project '%s'", providerName, projectName) +} + +func ConvertToPolicy(view *create.CreateView, providerID int64) (*models.PreheatPolicy, error) { + type filter struct { + Type string `json:"type"` + Value string `json:"value"` + } + filters := []filter{ + {Type: "repository", Value: view.RepositoryFilter}, + {Type: "tag", Value: view.TagFilter}, + } + if view.LabelFilter != "" { + filters = append(filters, filter{Type: "label", Value: view.LabelFilter}) + } + filtersJSON, err := json.Marshal(filters) + if err != nil { + return nil, fmt.Errorf("failed to marshal filters: %v", err) + } + + type triggerSetting struct { + Cron string `json:"cron"` + } + type trigger struct { + Type string `json:"type"` + TriggerSetting *triggerSetting `json:"trigger_setting,omitempty"` + } + t := trigger{Type: view.TriggerType} + if view.TriggerType == "scheduled" { + t.TriggerSetting = &triggerSetting{Cron: view.CronString} + } + triggerJSON, err := json.Marshal(t) + if err != nil { + return nil, fmt.Errorf("failed to marshal trigger: %v", err) + } + + return &models.PreheatPolicy{ + Name: view.Name, + Description: view.Description, + ProviderID: providerID, + ProviderName: view.ProviderName, + Filters: string(filtersJSON), + Trigger: string(triggerJSON), + Enabled: view.Enabled, + }, nil +} diff --git a/pkg/api/preheat_handler.go b/pkg/api/preheat_handler.go index 2f2f8ceae..ec87423de 100644 --- a/pkg/api/preheat_handler.go +++ b/pkg/api/preheat_handler.go @@ -15,6 +15,7 @@ package api import ( "github.com/goharbor/go-client/pkg/sdk/v2.0/client/preheat" + "github.com/goharbor/go-client/pkg/sdk/v2.0/models" "github.com/goharbor/harbor-cli/pkg/utils" ) @@ -127,3 +128,34 @@ func StartPreheatPolicy(projectName, policyName string, isID bool) (string, erro } return resp.Location, nil } + +func CreatePreheatPolicy(projectName string, policy *models.PreheatPolicy) (*preheat.CreatePolicyCreated, error) { + ctx, client, err := utils.ContextWithClient() + if err != nil { + return nil, err + } + + response, err := client.Preheat.CreatePolicy(ctx, &preheat.CreatePolicyParams{ + ProjectName: projectName, + Policy: policy, + }) + if err != nil { + return nil, err + } + return response, nil +} + +func ListProvidersUnderProject(projectName string) ([]*models.ProviderUnderProject, error) { + ctx, client, err := utils.ContextWithClient() + if err != nil { + return nil, err + } + + response, err := client.Preheat.ListProvidersUnderProject(ctx, &preheat.ListProvidersUnderProjectParams{ + ProjectName: projectName, + }) + if err != nil { + return nil, err + } + return response.Payload, nil +} diff --git a/pkg/config/preheat/policies.go b/pkg/config/preheat/policies.go new file mode 100644 index 000000000..b6796a1a4 --- /dev/null +++ b/pkg/config/preheat/policies.go @@ -0,0 +1,262 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package config + +import ( + "encoding/json" + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/goharbor/harbor-cli/pkg/views/preheat/policy/create" + log "github.com/sirupsen/logrus" + "gopkg.in/yaml.v2" +) + +type PolicyConfig struct { + Name string `yaml:"name" json:"name"` + Description string `yaml:"description,omitempty" json:"description,omitempty"` + Enabled bool `yaml:"enabled,omitempty" json:"enabled,omitempty"` + Filters []*PolicyFilter `yaml:"filters" json:"filters"` + ProviderName string `yaml:"provider_name" json:"provider_name"` + Trigger *PolicyTrigger `yaml:"trigger,omitempty" json:"trigger,omitempty"` +} + +type PolicyFilter struct { + Type string `yaml:"type" json:"type"` + Value string `yaml:"value" json:"value"` +} + +type PolicyTriggerSetting struct { + SchedulePreset string `yaml:"schedule_preset,omitempty" json:"schedule_preset,omitempty"` + Cron string `yaml:"cron,omitempty" json:"cron,omitempty"` +} + +type PolicyTrigger struct { + Type string `yaml:"type" json:"type"` + TriggerSetting *PolicyTriggerSetting `yaml:"trigger_setting,omitempty" json:"trigger_setting,omitempty"` +} + +func LoadConfigFromFile(filename string) (*create.CreateView, error) { + var opts *create.CreateView + var err error + + ext := filepath.Ext(filename) + if ext == "" { + return nil, fmt.Errorf("file must have an extension (.yaml, .yml, or .json)") + } + + fileType := ext[1:] + if fileType == "yml" { + fileType = "yaml" + } + + opts, err = LoadConfigFromYAMLorJSON(filename, fileType) + if err != nil { + return nil, fmt.Errorf("failed to load configuration: %v", err) + } + return opts, nil +} + +func LoadConfigFromYAMLorJSON(filename string, fileType string) (*create.CreateView, error) { + data, err := os.ReadFile(filename) + if err != nil { + return nil, fmt.Errorf("failed to read file: %v", err) + } + log.Debug("Preheat policy config file read successfully") + + var config PolicyConfig + switch fileType { + case "yaml", "yml": + if err := yaml.Unmarshal(data, &config); err != nil { + return nil, fmt.Errorf("failed to parse YAML: %v", err) + } + log.Debugf("Parsed %s configuration successfully", fileType) + + case "json": + if err := json.Unmarshal(data, &config); err != nil { + return nil, fmt.Errorf("failed to parse JSON: %v", err) + } + log.Debugf("Parsed %s configuration successfully", fileType) + default: + return nil, fmt.Errorf("unsupported file type: %s, expected 'yaml' or 'json'", fileType) + } + + if err := validateConfig(&config); err != nil { + return nil, fmt.Errorf("configuration validation failed: %v", err) + } + log.Debug("Preheat policy configuration validated successfully") + + triggerType := "manual" + cronString := "" + if config.Trigger != nil { + triggerType = normalizeTriggerMode(config.Trigger.Type) + if triggerType == "scheduled" { + var err error + cronString, err = resolveTriggerCron(config.Trigger) + if err != nil { + return nil, err + } + } + } + + opts := &create.CreateView{ + Name: config.Name, + Description: config.Description, + ProviderName: config.ProviderName, + TriggerType: triggerType, + CronString: cronString, + Enabled: config.Enabled, + } + + for _, filter := range config.Filters { + switch filter.Type { + case "repository": + opts.RepositoryFilter = filter.Value + case "tag": + opts.TagFilter = filter.Value + case "label": + opts.LabelFilter = filter.Value + } + } + + return opts, nil +} + +func validateConfig(config *PolicyConfig) error { + if config.Name == "" { + return fmt.Errorf("name is required") + } + + if config.ProviderName == "" { + return fmt.Errorf("provider_name is required") + } + + if err := validatePolicyFilters(config.Filters); err != nil { + return err + } + + if config.Trigger == nil { + return nil + } + + if strings.TrimSpace(config.Trigger.Type) == "" { + return fmt.Errorf("trigger.type is required") + } + + triggerType := strings.ToLower(config.Trigger.Type) + switch triggerType { + case "manual", "scheduled", "event_based": + default: + return fmt.Errorf("trigger.type must be one of [manual, scheduled, event_based], got: %s", config.Trigger.Type) + } + + if triggerType != "scheduled" { + setting := config.Trigger.TriggerSetting + if setting != nil && (strings.TrimSpace(setting.SchedulePreset) != "" || strings.TrimSpace(setting.Cron) != "") { + return fmt.Errorf("trigger.trigger_setting is only supported for scheduled trigger") + } + return nil + } + + _, err := resolveTriggerCron(config.Trigger) + return err +} + +func resolveTriggerCron(trigger *PolicyTrigger) (string, error) { + if trigger == nil || trigger.TriggerSetting == nil { + return "", nil + } + + setting := trigger.TriggerSetting + preset := strings.ToLower(strings.TrimSpace(setting.SchedulePreset)) + switch preset { + case "": + return strings.TrimSpace(setting.Cron), nil + case "none": + return "", nil + case "hourly", "daily", "weekly", "custom": + cron := resolveSchedulePreset(preset, setting.Cron) + if preset == "custom" && cron == "" { + return "", fmt.Errorf("trigger.trigger_setting.cron is required for custom schedule") + } + return cron, nil + default: + return "", fmt.Errorf("trigger.trigger_setting.schedule_preset must be one of [none, hourly, daily, weekly, custom], got: %s", setting.SchedulePreset) + } +} + +func resolveSchedulePreset(preset, cron string) string { + switch preset { + case "hourly": + return "0 0 * * * *" + case "daily": + return "0 0 0 * * *" + case "weekly": + return "0 0 0 * * 0" + case "custom": + return strings.TrimSpace(cron) + default: + return "" + } +} + +func validatePolicyFilters(filters []*PolicyFilter) error { + if len(filters) < 2 || len(filters) > 3 { + return fmt.Errorf("filters must include repository and tag filters, with label optional") + } + + hasRepositoryFilter := false + hasTagFilter := false + for i, filter := range filters { + if filter == nil { + return fmt.Errorf("filters[%d] is required", i) + } + + switch filter.Type { + case "repository": + hasRepositoryFilter = true + case "tag": + hasTagFilter = true + case "label": + default: + return fmt.Errorf("filters[%d].type must be one of [repository, tag, label], got: %s", i, filter.Type) + } + + if strings.TrimSpace(filter.Value) == "" { + return fmt.Errorf("filters[%d].value is required", i) + } + } + + if !hasRepositoryFilter { + return fmt.Errorf("filters must include a repository filter") + } + if !hasTagFilter { + return fmt.Errorf("filters must include a tag filter") + } + + return nil +} + +func normalizeTriggerMode(mode string) string { + switch strings.ToLower(mode) { + case "scheduled": + return "scheduled" + case "event_based": + return "event_based" + default: + return "manual" + } +} diff --git a/pkg/views/preheat/policy/create/view.go b/pkg/views/preheat/policy/create/view.go new file mode 100644 index 000000000..b8430b621 --- /dev/null +++ b/pkg/views/preheat/policy/create/view.go @@ -0,0 +1,208 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package create + +import ( + "errors" + "fmt" + "strings" + + "github.com/charmbracelet/huh" + "github.com/charmbracelet/lipgloss" + "github.com/goharbor/go-client/pkg/sdk/v2.0/models" + log "github.com/sirupsen/logrus" +) + +type CreateView struct { + Name string `json:"name,omitempty"` + Description string `json:"description,omitempty"` + Enabled bool `json:"enabled,omitempty"` + + // Provider related fields + ProviderName string `json:"provider_name,omitempty"` + + // Filter related fields + RepositoryFilter string `json:"repository_filter,omitempty"` + TagFilter string `json:"tag_filter,omitempty"` + LabelFilter string `json:"label_filter,omitempty"` + + // Trigger related fields + TriggerType string `json:"trigger_type,omitempty"` + CronString string `json:"cron_string,omitempty"` +} + +func CreatePreheatPolicyView(createView *CreateView, providers []*models.ProviderUnderProject) { + if createView.TriggerType == "" { + createView.TriggerType = "manual" + } + + theme := huh.ThemeCharm() + + if len(providers) == 0 { + log.Fatal("No P2P provider instances available for this project. Please create a provider instance first.") + } + + providerOptions := make([]huh.Option[string], 0, len(providers)) + for _, p := range providers { + if !p.Enabled { + continue + } + label := fmt.Sprintf("%s (ID: %d)", p.Provider, p.ID) + providerOptions = append(providerOptions, huh.NewOption(label, p.Provider)) + } + + if len(providerOptions) == 0 { + log.Fatal("No enabled P2P provider instances available for this project.") + } + + basicGroup := huh.NewGroup( + huh.NewSelect[string](). + Title("Provider"). + Options(providerOptions...). + Value(&createView.ProviderName), + huh.NewInput(). + Title("Policy Name"). + Value(&createView.Name). + Validate(func(str string) error { + if strings.TrimSpace(str) == "" { + return errors.New("policy name cannot be empty") + } + return nil + }), + huh.NewInput(). + Title("Description"). + Value(&createView.Description), + huh.NewConfirm(). + Title("Enabled"). + Value(&createView.Enabled). + WithButtonAlignment(lipgloss.Left), + ) + + basicForm := huh.NewForm(basicGroup).WithTheme(theme) + if err := basicForm.Run(); err != nil { + log.Fatal(err) + } + + filterGroup := huh.NewGroup( + huh.NewInput(). + Title("Repositories"). + Description("Enter multiple comma separated repos, repo*, or **"). + Value(&createView.RepositoryFilter). + Validate(func(str string) error { + if strings.TrimSpace(str) == "" { + return errors.New("repository filter cannot be empty") + } + return nil + }), + huh.NewInput(). + Title("Tags"). + Description("Enter multiple comma separated tags, tag*, or **"). + Value(&createView.TagFilter). + Validate(func(str string) error { + if strings.TrimSpace(str) == "" { + return errors.New("tag filter cannot be empty") + } + return nil + }), + huh.NewInput(). + Title("Labels"). + Description("(optional)"). + Value(&createView.LabelFilter), + ).Title("Filters") + + triggerGroup := huh.NewGroup( + huh.NewSelect[string](). + Title("Trigger Type"). + Options( + huh.NewOption("Manual", "manual"), + huh.NewOption("Scheduled", "scheduled"), + huh.NewOption("Event Based", "event_based"), + ). + Value(&createView.TriggerType), + ) + + restForm := huh.NewForm(filterGroup, triggerGroup).WithTheme(theme) + if err := restForm.Run(); err != nil { + log.Fatal(err) + } + + if createView.TriggerType == "scheduled" { + schedulePreset := "none" + presetForm := huh.NewForm( + huh.NewGroup( + huh.NewSelect[string](). + Title("Schedule"). + Description("Choose a schedule frequency for preheating"). + Options( + huh.NewOption("None", "none"), + huh.NewOption("Hourly", "hourly"), + huh.NewOption("Daily", "daily"), + huh.NewOption("Weekly", "weekly"), + huh.NewOption("Custom", "custom"), + ). + Value(&schedulePreset), + ), + ).WithTheme(theme) + + if err := presetForm.Run(); err != nil { + log.Fatal(err) + } + + if schedulePreset == "custom" { + cronForm := huh.NewForm( + huh.NewGroup( + huh.NewInput(). + Title("Cron String"). + Description("Schedule using 6-field cron format: seconds minutes hours day-month month day-week"). + Placeholder("0 0 0 * * *"). + Value(&createView.CronString). + Validate(func(s string) error { + if strings.TrimSpace(s) == "" { + return errors.New("cron string cannot be empty for custom schedule") + } + + fields := strings.Fields(s) + if len(fields) != 6 { + return fmt.Errorf("cron must have exactly 6 fields (found %d): seconds minutes hours day-month month day-week", len(fields)) + } + + return nil + }), + ), + ).WithTheme(theme) + + if err := cronForm.Run(); err != nil { + log.Fatal(err) + } + createView.CronString = resolveSchedulePreset(schedulePreset, createView.CronString) + } else { + createView.CronString = resolveSchedulePreset(schedulePreset, "") + } + } +} + +func resolveSchedulePreset(preset, cron string) string { + switch preset { + case "hourly": + return "0 0 * * * *" + case "daily": + return "0 0 0 * * *" + case "weekly": + return "0 0 0 * * 0" + case "custom": + return strings.TrimSpace(cron) + default: + return "" + } +} From 063cfea62d13b65733de75b1a354ad6931d964c2 Mon Sep 17 00:00:00 2001 From: Sypher845 Date: Sun, 10 May 2026 21:20:39 +0530 Subject: [PATCH 10/15] docs(preheat): docs for preheat policy create command Signed-off-by: Sypher845 --- .../harbor-project-preheat-policy-create.md | 38 ++++++++++++++++ doc/cli-docs/harbor-project-preheat-policy.md | 1 + .../harbor-project-preheat-policy-create.1 | 43 +++++++++++++++++++ .../man1/harbor-project-preheat-policy.1 | 2 +- 4 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 doc/cli-docs/harbor-project-preheat-policy-create.md create mode 100644 doc/man-docs/man1/harbor-project-preheat-policy-create.1 diff --git a/doc/cli-docs/harbor-project-preheat-policy-create.md b/doc/cli-docs/harbor-project-preheat-policy-create.md new file mode 100644 index 000000000..f1189d792 --- /dev/null +++ b/doc/cli-docs/harbor-project-preheat-policy-create.md @@ -0,0 +1,38 @@ +--- +title: harbor project preheat policy create +weight: 50 +--- +## harbor project preheat policy create + +### Description + +##### Create a preheat policy + +### Synopsis + +Create a new P2P preheat policy under a project + +```sh +harbor project preheat policy create [NAME|ID] [flags] +``` + +### Options + +```sh + -h, --help help for create + --id Use project id instead of name + -f, --policy-config-file string YAML/JSON file with preheat policy configuration +``` + +### Options inherited from parent commands + +```sh + -c, --config string config file (default is $HOME/.config/harbor-cli/config.yaml) + -o, --output-format string Output format. One of: json|yaml|csv + -v, --verbose verbose output +``` + +### SEE ALSO + +* [harbor project preheat policy](harbor-project-preheat-policy.md) - Manage preheat policies + diff --git a/doc/cli-docs/harbor-project-preheat-policy.md b/doc/cli-docs/harbor-project-preheat-policy.md index 5995c8e49..abf77819c 100644 --- a/doc/cli-docs/harbor-project-preheat-policy.md +++ b/doc/cli-docs/harbor-project-preheat-policy.md @@ -29,6 +29,7 @@ Manage P2P preheat policies under a project ### SEE ALSO * [harbor project preheat](harbor-project-preheat.md) - Manage project preheat resources +* [harbor project preheat policy create](harbor-project-preheat-policy-create.md) - Create a preheat policy * [harbor project preheat policy delete](harbor-project-preheat-policy-delete.md) - Delete a preheat policy * [harbor project preheat policy list](harbor-project-preheat-policy-list.md) - List preheat policies under a project by name or id * [harbor project preheat policy start](harbor-project-preheat-policy-start.md) - Manually trigger a preheat policy diff --git a/doc/man-docs/man1/harbor-project-preheat-policy-create.1 b/doc/man-docs/man1/harbor-project-preheat-policy-create.1 new file mode 100644 index 000000000..9c4cec963 --- /dev/null +++ b/doc/man-docs/man1/harbor-project-preheat-policy-create.1 @@ -0,0 +1,43 @@ +.nh +.TH "HARBOR" "1" "Harbor Community" "Harbor User Manuals" + +.SH NAME +harbor-project-preheat-policy-create - Create a preheat policy + + +.SH SYNOPSIS +\fBharbor project preheat policy create [NAME|ID] [flags]\fP + + +.SH DESCRIPTION +Create a new P2P preheat policy under a project + + +.SH OPTIONS +\fB-h\fP, \fB--help\fP[=false] + help for create + +.PP +\fB--id\fP[=false] + Use project id instead of name + +.PP +\fB-f\fP, \fB--policy-config-file\fP="" + YAML/JSON file with preheat policy configuration + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +\fB-c\fP, \fB--config\fP="" + config file (default is $HOME/.config/harbor-cli/config.yaml) + +.PP +\fB-o\fP, \fB--output-format\fP="" + Output format. One of: json|yaml|csv + +.PP +\fB-v\fP, \fB--verbose\fP[=false] + verbose output + + +.SH SEE ALSO +\fBharbor-project-preheat-policy(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-project-preheat-policy.1 b/doc/man-docs/man1/harbor-project-preheat-policy.1 index c21a715ee..61381ddf4 100644 --- a/doc/man-docs/man1/harbor-project-preheat-policy.1 +++ b/doc/man-docs/man1/harbor-project-preheat-policy.1 @@ -32,4 +32,4 @@ Manage P2P preheat policies under a project .SH SEE ALSO -\fBharbor-project-preheat(1)\fP, \fBharbor-project-preheat-policy-delete(1)\fP, \fBharbor-project-preheat-policy-list(1)\fP, \fBharbor-project-preheat-policy-start(1)\fP, \fBharbor-project-preheat-policy-view(1)\fP \ No newline at end of file +\fBharbor-project-preheat(1)\fP, \fBharbor-project-preheat-policy-create(1)\fP, \fBharbor-project-preheat-policy-delete(1)\fP, \fBharbor-project-preheat-policy-list(1)\fP, \fBharbor-project-preheat-policy-start(1)\fP, \fBharbor-project-preheat-policy-view(1)\fP \ No newline at end of file From 8a04341490cccfee507109af604582e4de609011 Mon Sep 17 00:00:00 2001 From: Sypher845 Date: Sun, 10 May 2026 22:43:27 +0530 Subject: [PATCH 11/15] feat(preheat): preheat policy update command Signed-off-by: Sypher845 --- cmd/harbor/root/project/preheat/policy.go | 1 + .../root/project/preheat/policy/update.go | 178 ++++++++++++++++++ .../harbor-project-preheat-policy-update.md | 37 ++++ doc/cli-docs/harbor-project-preheat-policy.md | 1 + .../harbor-project-preheat-policy-update.1 | 39 ++++ .../man1/harbor-project-preheat-policy.1 | 2 +- pkg/api/preheat_handler.go | 17 ++ pkg/views/preheat/policy/create/view.go | 17 +- 8 files changed, 290 insertions(+), 2 deletions(-) create mode 100644 cmd/harbor/root/project/preheat/policy/update.go create mode 100644 doc/cli-docs/harbor-project-preheat-policy-update.md create mode 100644 doc/man-docs/man1/harbor-project-preheat-policy-update.1 diff --git a/cmd/harbor/root/project/preheat/policy.go b/cmd/harbor/root/project/preheat/policy.go index 0efb565cc..b7003f227 100644 --- a/cmd/harbor/root/project/preheat/policy.go +++ b/cmd/harbor/root/project/preheat/policy.go @@ -30,6 +30,7 @@ func PolicyCommand() *cobra.Command { policy.ListPolicyCommand(), policy.ViewPolicyCommand(), policy.CreatePolicyCommand(), + policy.UpdatePolicyCommand(), policy.DeletePolicyCommand(), policy.StartPolicyCommand(), ) diff --git a/cmd/harbor/root/project/preheat/policy/update.go b/cmd/harbor/root/project/preheat/policy/update.go new file mode 100644 index 000000000..c4a84f3b5 --- /dev/null +++ b/cmd/harbor/root/project/preheat/policy/update.go @@ -0,0 +1,178 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package policy + +import ( + "encoding/json" + "fmt" + + "github.com/goharbor/go-client/pkg/sdk/v2.0/models" + "github.com/goharbor/harbor-cli/pkg/api" + "github.com/goharbor/harbor-cli/pkg/prompt" + "github.com/goharbor/harbor-cli/pkg/utils" + "github.com/goharbor/harbor-cli/pkg/views/preheat/policy/create" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +func UpdatePolicyCommand() *cobra.Command { + var isID bool + + cmd := &cobra.Command{ + Use: "update [NAME|ID] [POLICY_NAME]", + Short: "Update a preheat policy", + Long: "Update an existing P2P preheat policy under a project", + Args: cobra.MaximumNArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + var err error + var projectName, policyName string + + if len(args) >= 1 { + log.Debugf("Project name provided: %s", args[0]) + projectName = args[0] + } else { + log.Debug("No project name provided, prompting user") + projectName, err = prompt.GetProjectNameFromUser() + if err != nil { + return fmt.Errorf("failed to get project name: %v", utils.ParseHarborErrorMsg(err)) + } + } + + if isID { + project, err := api.GetProject(projectName, true) + if err != nil { + return fmt.Errorf("failed to get project: %v", utils.ParseHarborErrorMsg(err)) + } + projectName = project.Payload.Name + } + + if len(args) >= 2 { + log.Debugf("Policy name provided: %s", args[1]) + policyName = args[1] + } else { + log.Debug("No policy name provided, prompting user") + policyName, err = prompt.GetPreheatPolicyNameFromUser(projectName) + if err != nil { + return fmt.Errorf("failed to get policy name: %v", utils.ParseHarborErrorMsg(err)) + } + } + + log.Debug("Fetching preheat policy...") + existingPolicy, err := api.GetPreheatPolicy(projectName, policyName, false) + if err != nil { + if utils.ParseHarborErrorCode(err) == "404" { + return fmt.Errorf("preheat policy %s not found in project %s", policyName, projectName) + } + return fmt.Errorf("failed to get preheat policy: %v", utils.ParseHarborErrorMsg(err)) + } + + log.Debug("Fetching available providers...") + providers, err := api.ListProvidersUnderProject(projectName) + if err != nil { + return fmt.Errorf("failed to list providers: %v", utils.ParseHarborErrorMsg(err)) + } + + if len(providers) == 0 { + return fmt.Errorf("no P2P provider instances available for project '%s'. Please create a provider instance first", projectName) + } + + opts := policyToCreateView(existingPolicy.Payload, providers) + create.CreatePreheatPolicyView(opts, providers) + + providerID, err := resolveProviderID(providers, opts.ProviderName, projectName) + if err != nil { + return err + } + + policy, err := ConvertToPolicy(opts, providerID) + if err != nil { + return err + } + policy.ID = existingPolicy.Payload.ID + policy.ProjectID = existingPolicy.Payload.ProjectID + policy.CreationTime = existingPolicy.Payload.CreationTime + policy.ExtraAttrs = existingPolicy.Payload.ExtraAttrs + + log.Debug("Updating preheat policy...") + _, err = api.UpdatePreheatPolicy(projectName, policyName, policy) + if err != nil { + if utils.ParseHarborErrorCode(err) == "409" { + return fmt.Errorf("preheat policy '%s' already exists in project '%s'", opts.Name, projectName) + } + return fmt.Errorf("failed to update preheat policy: %v", utils.ParseHarborErrorMsg(err)) + } + + fmt.Printf("Preheat policy '%s' updated successfully in project '%s'\n", opts.Name, projectName) + return nil + }, + } + + flags := cmd.Flags() + flags.BoolVar(&isID, "id", false, "Use project id instead of name") + + return cmd +} + +func policyToCreateView(policy *models.PreheatPolicy, providers []*models.ProviderUnderProject) *create.CreateView { + view := &create.CreateView{ + Name: policy.Name, + Description: policy.Description, + Enabled: policy.Enabled, + ProviderName: policy.ProviderName, + TriggerType: "manual", + } + + for _, provider := range providers { + if provider.ID == policy.ProviderID { + view.ProviderName = provider.Provider + break + } + } + + var filters []struct { + Type string `json:"type"` + Value string `json:"value"` + } + _ = json.Unmarshal([]byte(policy.Filters), &filters) + for _, filter := range filters { + switch filter.Type { + case "repository": + view.RepositoryFilter = filter.Value + case "tag": + view.TagFilter = filter.Value + case "label": + view.LabelFilter = filter.Value + } + } + + type triggerSetting struct { + Cron string `json:"cron"` + } + var trigger struct { + Type string `json:"type"` + TriggerSetting *triggerSetting `json:"trigger_setting"` + TriggerSettings *triggerSetting `json:"trigger_settings"` + } + _ = json.Unmarshal([]byte(policy.Trigger), &trigger) + if trigger.Type != "" { + view.TriggerType = trigger.Type + } + if trigger.TriggerSetting != nil { + view.CronString = trigger.TriggerSetting.Cron + } else if trigger.TriggerSettings != nil { + view.CronString = trigger.TriggerSettings.Cron + } + + return view +} diff --git a/doc/cli-docs/harbor-project-preheat-policy-update.md b/doc/cli-docs/harbor-project-preheat-policy-update.md new file mode 100644 index 000000000..c3f729b4d --- /dev/null +++ b/doc/cli-docs/harbor-project-preheat-policy-update.md @@ -0,0 +1,37 @@ +--- +title: harbor project preheat policy update +weight: 25 +--- +## harbor project preheat policy update + +### Description + +##### Update a preheat policy + +### Synopsis + +Update an existing P2P preheat policy under a project + +```sh +harbor project preheat policy update [NAME|ID] [POLICY_NAME] [flags] +``` + +### Options + +```sh + -h, --help help for update + --id Use project id instead of name +``` + +### Options inherited from parent commands + +```sh + -c, --config string config file (default is $HOME/.config/harbor-cli/config.yaml) + -o, --output-format string Output format. One of: json|yaml|csv + -v, --verbose verbose output +``` + +### SEE ALSO + +* [harbor project preheat policy](harbor-project-preheat-policy.md) - Manage preheat policies + diff --git a/doc/cli-docs/harbor-project-preheat-policy.md b/doc/cli-docs/harbor-project-preheat-policy.md index abf77819c..4ffab3547 100644 --- a/doc/cli-docs/harbor-project-preheat-policy.md +++ b/doc/cli-docs/harbor-project-preheat-policy.md @@ -33,5 +33,6 @@ Manage P2P preheat policies under a project * [harbor project preheat policy delete](harbor-project-preheat-policy-delete.md) - Delete a preheat policy * [harbor project preheat policy list](harbor-project-preheat-policy-list.md) - List preheat policies under a project by name or id * [harbor project preheat policy start](harbor-project-preheat-policy-start.md) - Manually trigger a preheat policy +* [harbor project preheat policy update](harbor-project-preheat-policy-update.md) - Update a preheat policy * [harbor project preheat policy view](harbor-project-preheat-policy-view.md) - View details of a preheat policy diff --git a/doc/man-docs/man1/harbor-project-preheat-policy-update.1 b/doc/man-docs/man1/harbor-project-preheat-policy-update.1 new file mode 100644 index 000000000..43a9effca --- /dev/null +++ b/doc/man-docs/man1/harbor-project-preheat-policy-update.1 @@ -0,0 +1,39 @@ +.nh +.TH "HARBOR" "1" "Harbor Community" "Harbor User Manuals" + +.SH NAME +harbor-project-preheat-policy-update - Update a preheat policy + + +.SH SYNOPSIS +\fBharbor project preheat policy update [NAME|ID] [POLICY_NAME] [flags]\fP + + +.SH DESCRIPTION +Update an existing P2P preheat policy under a project + + +.SH OPTIONS +\fB-h\fP, \fB--help\fP[=false] + help for update + +.PP +\fB--id\fP[=false] + Use project id instead of name + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +\fB-c\fP, \fB--config\fP="" + config file (default is $HOME/.config/harbor-cli/config.yaml) + +.PP +\fB-o\fP, \fB--output-format\fP="" + Output format. One of: json|yaml|csv + +.PP +\fB-v\fP, \fB--verbose\fP[=false] + verbose output + + +.SH SEE ALSO +\fBharbor-project-preheat-policy(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-project-preheat-policy.1 b/doc/man-docs/man1/harbor-project-preheat-policy.1 index 61381ddf4..ba7f61792 100644 --- a/doc/man-docs/man1/harbor-project-preheat-policy.1 +++ b/doc/man-docs/man1/harbor-project-preheat-policy.1 @@ -32,4 +32,4 @@ Manage P2P preheat policies under a project .SH SEE ALSO -\fBharbor-project-preheat(1)\fP, \fBharbor-project-preheat-policy-create(1)\fP, \fBharbor-project-preheat-policy-delete(1)\fP, \fBharbor-project-preheat-policy-list(1)\fP, \fBharbor-project-preheat-policy-start(1)\fP, \fBharbor-project-preheat-policy-view(1)\fP \ No newline at end of file +\fBharbor-project-preheat(1)\fP, \fBharbor-project-preheat-policy-create(1)\fP, \fBharbor-project-preheat-policy-delete(1)\fP, \fBharbor-project-preheat-policy-list(1)\fP, \fBharbor-project-preheat-policy-start(1)\fP, \fBharbor-project-preheat-policy-update(1)\fP, \fBharbor-project-preheat-policy-view(1)\fP \ No newline at end of file diff --git a/pkg/api/preheat_handler.go b/pkg/api/preheat_handler.go index ec87423de..463e2d145 100644 --- a/pkg/api/preheat_handler.go +++ b/pkg/api/preheat_handler.go @@ -145,6 +145,23 @@ func CreatePreheatPolicy(projectName string, policy *models.PreheatPolicy) (*pre return response, nil } +func UpdatePreheatPolicy(projectName, policyName string, policy *models.PreheatPolicy) (*preheat.UpdatePolicyOK, error) { + ctx, client, err := utils.ContextWithClient() + if err != nil { + return nil, err + } + + response, err := client.Preheat.UpdatePolicy(ctx, &preheat.UpdatePolicyParams{ + ProjectName: projectName, + PreheatPolicyName: policyName, + Policy: policy, + }) + if err != nil { + return nil, err + } + return response, nil +} + func ListProvidersUnderProject(projectName string) ([]*models.ProviderUnderProject, error) { ctx, client, err := utils.ContextWithClient() if err != nil { diff --git a/pkg/views/preheat/policy/create/view.go b/pkg/views/preheat/policy/create/view.go index b8430b621..5982e7bcd 100644 --- a/pkg/views/preheat/policy/create/view.go +++ b/pkg/views/preheat/policy/create/view.go @@ -138,7 +138,7 @@ func CreatePreheatPolicyView(createView *CreateView, providers []*models.Provide } if createView.TriggerType == "scheduled" { - schedulePreset := "none" + schedulePreset := schedulePresetForCron(createView.CronString) presetForm := huh.NewForm( huh.NewGroup( huh.NewSelect[string](). @@ -192,6 +192,21 @@ func CreatePreheatPolicyView(createView *CreateView, providers []*models.Provide } } +func schedulePresetForCron(cron string) string { + switch strings.TrimSpace(cron) { + case "": + return "none" + case "0 0 * * * *": + return "hourly" + case "0 0 0 * * *": + return "daily" + case "0 0 0 * * 0": + return "weekly" + default: + return "custom" + } +} + func resolveSchedulePreset(preset, cron string) string { switch preset { case "hourly": From 880f15e422a28f2cd2b307767064b5a028957115 Mon Sep 17 00:00:00 2001 From: Sypher845 Date: Sun, 10 May 2026 23:15:20 +0530 Subject: [PATCH 12/15] refac(preheat): add examples to commands Signed-off-by: Sypher845 --- cmd/harbor/root/project/preheat/policy.go | 1 + cmd/harbor/root/project/preheat/policy/create.go | 9 +++++---- cmd/harbor/root/project/preheat/policy/delete.go | 9 +++++---- cmd/harbor/root/project/preheat/policy/list.go | 9 +++++---- cmd/harbor/root/project/preheat/policy/start.go | 9 +++++---- cmd/harbor/root/project/preheat/policy/update.go | 9 +++++---- cmd/harbor/root/project/preheat/policy/view.go | 9 +++++---- doc/cli-docs/harbor-project-preheat-policy-create.md | 6 ++++++ doc/cli-docs/harbor-project-preheat-policy-delete.md | 6 ++++++ doc/cli-docs/harbor-project-preheat-policy-list.md | 8 +++++++- doc/cli-docs/harbor-project-preheat-policy-start.md | 6 ++++++ doc/cli-docs/harbor-project-preheat-policy-update.md | 6 ++++++ doc/cli-docs/harbor-project-preheat-policy-view.md | 6 ++++++ doc/cli-docs/harbor-project-preheat-policy.md | 8 +++++++- doc/man-docs/man1/harbor-project-preheat-policy-create.1 | 6 ++++++ doc/man-docs/man1/harbor-project-preheat-policy-delete.1 | 6 ++++++ doc/man-docs/man1/harbor-project-preheat-policy-list.1 | 8 +++++++- doc/man-docs/man1/harbor-project-preheat-policy-start.1 | 6 ++++++ doc/man-docs/man1/harbor-project-preheat-policy-update.1 | 6 ++++++ doc/man-docs/man1/harbor-project-preheat-policy-view.1 | 6 ++++++ doc/man-docs/man1/harbor-project-preheat-policy.1 | 6 ++++++ 21 files changed, 118 insertions(+), 27 deletions(-) diff --git a/cmd/harbor/root/project/preheat/policy.go b/cmd/harbor/root/project/preheat/policy.go index b7003f227..b2313fd60 100644 --- a/cmd/harbor/root/project/preheat/policy.go +++ b/cmd/harbor/root/project/preheat/policy.go @@ -24,6 +24,7 @@ func PolicyCommand() *cobra.Command { Aliases: []string{"pol"}, Short: "Manage preheat policies", Long: "Manage P2P preheat policies under a project", + Example: ` harbor-cli project preheat policy list [NAME|ID]`, } cmd.AddCommand( diff --git a/cmd/harbor/root/project/preheat/policy/create.go b/cmd/harbor/root/project/preheat/policy/create.go index e9adc7a65..802480427 100644 --- a/cmd/harbor/root/project/preheat/policy/create.go +++ b/cmd/harbor/root/project/preheat/policy/create.go @@ -32,10 +32,11 @@ func CreatePolicyCommand() *cobra.Command { var configFile string cmd := &cobra.Command{ - Use: "create [NAME|ID]", - Short: "Create a preheat policy", - Long: "Create a new P2P preheat policy under a project", - Args: cobra.MaximumNArgs(1), + Use: "create [NAME|ID]", + Short: "Create a preheat policy", + Long: "Create a new P2P preheat policy under a project", + Example: ` harbor-cli project preheat policy create [NAME|ID]`, + Args: cobra.MaximumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { var err error var projectName string diff --git a/cmd/harbor/root/project/preheat/policy/delete.go b/cmd/harbor/root/project/preheat/policy/delete.go index ecb281fca..e2bbdf1ce 100644 --- a/cmd/harbor/root/project/preheat/policy/delete.go +++ b/cmd/harbor/root/project/preheat/policy/delete.go @@ -27,10 +27,11 @@ func DeletePolicyCommand() *cobra.Command { var isID bool cmd := &cobra.Command{ - Use: "delete [NAME|ID] [POLICY_NAME]", - Short: "Delete a preheat policy", - Long: "Delete a specific P2P preheat policy under a project", - Args: cobra.MaximumNArgs(2), + Use: "delete [NAME|ID] [POLICY_NAME]", + Short: "Delete a preheat policy", + Long: "Delete a specific P2P preheat policy under a project", + Example: ` harbor-cli project preheat policy delete [NAME|ID] [POLICY_NAME]`, + Args: cobra.MaximumNArgs(2), RunE: func(cmd *cobra.Command, args []string) error { var err error var projectName, policyName string diff --git a/cmd/harbor/root/project/preheat/policy/list.go b/cmd/harbor/root/project/preheat/policy/list.go index f9c9cb948..0da0e010b 100644 --- a/cmd/harbor/root/project/preheat/policy/list.go +++ b/cmd/harbor/root/project/preheat/policy/list.go @@ -30,10 +30,11 @@ func ListPolicyCommand() *cobra.Command { var isID bool cmd := &cobra.Command{ - Use: "list [NAME|ID]", - Short: "List preheat policies under a project by name or id", - Long: "List project-scoped P2P preheat policies in Harbor", - Args: cobra.MaximumNArgs(1), + Use: "list [NAME|ID]", + Short: "List preheat policies under a project", + Long: "List project-scoped P2P preheat policies in Harbor", + Example: ` harbor-cli project preheat policy list [NAME|ID]`, + Args: cobra.MaximumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { var err error var projectName string diff --git a/cmd/harbor/root/project/preheat/policy/start.go b/cmd/harbor/root/project/preheat/policy/start.go index 1ce2c15bb..e2bc8c41d 100644 --- a/cmd/harbor/root/project/preheat/policy/start.go +++ b/cmd/harbor/root/project/preheat/policy/start.go @@ -27,10 +27,11 @@ func StartPolicyCommand() *cobra.Command { var isID bool cmd := &cobra.Command{ - Use: "start [NAME|ID] [POLICY_NAME]", - Short: "Manually trigger a preheat policy", - Long: "Manually trigger a specific P2P preheat policy under a project", - Args: cobra.MaximumNArgs(2), + Use: "start [NAME|ID] [POLICY_NAME]", + Short: "Manually trigger a preheat policy", + Long: "Manually trigger a specific P2P preheat policy under a project", + Example: ` harbor-cli project preheat policy start [NAME|ID] [POLICY_NAME]`, + Args: cobra.MaximumNArgs(2), RunE: func(cmd *cobra.Command, args []string) error { var err error var projectName, policyName string diff --git a/cmd/harbor/root/project/preheat/policy/update.go b/cmd/harbor/root/project/preheat/policy/update.go index c4a84f3b5..3162243a8 100644 --- a/cmd/harbor/root/project/preheat/policy/update.go +++ b/cmd/harbor/root/project/preheat/policy/update.go @@ -30,10 +30,11 @@ func UpdatePolicyCommand() *cobra.Command { var isID bool cmd := &cobra.Command{ - Use: "update [NAME|ID] [POLICY_NAME]", - Short: "Update a preheat policy", - Long: "Update an existing P2P preheat policy under a project", - Args: cobra.MaximumNArgs(2), + Use: "update [NAME|ID] [POLICY_NAME]", + Short: "Update a preheat policy", + Long: "Update an existing P2P preheat policy under a project", + Example: ` harbor-cli project preheat policy update [NAME|ID] [POLICY_NAME]`, + Args: cobra.MaximumNArgs(2), RunE: func(cmd *cobra.Command, args []string) error { var err error var projectName, policyName string diff --git a/cmd/harbor/root/project/preheat/policy/view.go b/cmd/harbor/root/project/preheat/policy/view.go index 8fbaa4cea..b9ff82801 100644 --- a/cmd/harbor/root/project/preheat/policy/view.go +++ b/cmd/harbor/root/project/preheat/policy/view.go @@ -29,10 +29,11 @@ func ViewPolicyCommand() *cobra.Command { var isID bool cmd := &cobra.Command{ - Use: "view [NAME|ID] [POLICY_NAME]", - Short: "View details of a preheat policy", - Long: "Get details of a specific P2P preheat policy under a project", - Args: cobra.MaximumNArgs(2), + Use: "view [NAME|ID] [POLICY_NAME]", + Short: "View details of a preheat policy", + Long: "Get details of a specific P2P preheat policy under a project", + Example: ` harbor-cli project preheat policy view [NAME|ID] [POLICY_NAME]`, + Args: cobra.MaximumNArgs(2), RunE: func(cmd *cobra.Command, args []string) error { var err error var projectName, policyName string diff --git a/doc/cli-docs/harbor-project-preheat-policy-create.md b/doc/cli-docs/harbor-project-preheat-policy-create.md index f1189d792..06816234b 100644 --- a/doc/cli-docs/harbor-project-preheat-policy-create.md +++ b/doc/cli-docs/harbor-project-preheat-policy-create.md @@ -16,6 +16,12 @@ Create a new P2P preheat policy under a project harbor project preheat policy create [NAME|ID] [flags] ``` +### Examples + +```sh + harbor-cli project preheat policy create [NAME|ID] +``` + ### Options ```sh diff --git a/doc/cli-docs/harbor-project-preheat-policy-delete.md b/doc/cli-docs/harbor-project-preheat-policy-delete.md index 9ad9a0abe..3bbfc86ff 100644 --- a/doc/cli-docs/harbor-project-preheat-policy-delete.md +++ b/doc/cli-docs/harbor-project-preheat-policy-delete.md @@ -16,6 +16,12 @@ Delete a specific P2P preheat policy under a project harbor project preheat policy delete [NAME|ID] [POLICY_NAME] [flags] ``` +### Examples + +```sh + harbor-cli project preheat policy delete [NAME|ID] [POLICY_NAME] +``` + ### Options ```sh diff --git a/doc/cli-docs/harbor-project-preheat-policy-list.md b/doc/cli-docs/harbor-project-preheat-policy-list.md index 62cabfebc..fffc942bf 100644 --- a/doc/cli-docs/harbor-project-preheat-policy-list.md +++ b/doc/cli-docs/harbor-project-preheat-policy-list.md @@ -6,7 +6,7 @@ weight: 20 ### Description -##### List preheat policies under a project by name or id +##### List preheat policies under a project ### Synopsis @@ -16,6 +16,12 @@ List project-scoped P2P preheat policies in Harbor harbor project preheat policy list [NAME|ID] [flags] ``` +### Examples + +```sh + harbor-cli project preheat policy list [NAME|ID] +``` + ### Options ```sh diff --git a/doc/cli-docs/harbor-project-preheat-policy-start.md b/doc/cli-docs/harbor-project-preheat-policy-start.md index 57bd3b1e1..79d73e8aa 100644 --- a/doc/cli-docs/harbor-project-preheat-policy-start.md +++ b/doc/cli-docs/harbor-project-preheat-policy-start.md @@ -16,6 +16,12 @@ Manually trigger a specific P2P preheat policy under a project harbor project preheat policy start [NAME|ID] [POLICY_NAME] [flags] ``` +### Examples + +```sh + harbor-cli project preheat policy start [NAME|ID] [POLICY_NAME] +``` + ### Options ```sh diff --git a/doc/cli-docs/harbor-project-preheat-policy-update.md b/doc/cli-docs/harbor-project-preheat-policy-update.md index c3f729b4d..87023cf67 100644 --- a/doc/cli-docs/harbor-project-preheat-policy-update.md +++ b/doc/cli-docs/harbor-project-preheat-policy-update.md @@ -16,6 +16,12 @@ Update an existing P2P preheat policy under a project harbor project preheat policy update [NAME|ID] [POLICY_NAME] [flags] ``` +### Examples + +```sh + harbor-cli project preheat policy update [NAME|ID] [POLICY_NAME] +``` + ### Options ```sh diff --git a/doc/cli-docs/harbor-project-preheat-policy-view.md b/doc/cli-docs/harbor-project-preheat-policy-view.md index 3c33cf09d..389e09989 100644 --- a/doc/cli-docs/harbor-project-preheat-policy-view.md +++ b/doc/cli-docs/harbor-project-preheat-policy-view.md @@ -16,6 +16,12 @@ Get details of a specific P2P preheat policy under a project harbor project preheat policy view [NAME|ID] [POLICY_NAME] [flags] ``` +### Examples + +```sh + harbor-cli project preheat policy view [NAME|ID] [POLICY_NAME] +``` + ### Options ```sh diff --git a/doc/cli-docs/harbor-project-preheat-policy.md b/doc/cli-docs/harbor-project-preheat-policy.md index 4ffab3547..70509492f 100644 --- a/doc/cli-docs/harbor-project-preheat-policy.md +++ b/doc/cli-docs/harbor-project-preheat-policy.md @@ -12,6 +12,12 @@ weight: 90 Manage P2P preheat policies under a project +### Examples + +```sh + harbor-cli project preheat policy list [NAME|ID] +``` + ### Options ```sh @@ -31,7 +37,7 @@ Manage P2P preheat policies under a project * [harbor project preheat](harbor-project-preheat.md) - Manage project preheat resources * [harbor project preheat policy create](harbor-project-preheat-policy-create.md) - Create a preheat policy * [harbor project preheat policy delete](harbor-project-preheat-policy-delete.md) - Delete a preheat policy -* [harbor project preheat policy list](harbor-project-preheat-policy-list.md) - List preheat policies under a project by name or id +* [harbor project preheat policy list](harbor-project-preheat-policy-list.md) - List preheat policies under a project * [harbor project preheat policy start](harbor-project-preheat-policy-start.md) - Manually trigger a preheat policy * [harbor project preheat policy update](harbor-project-preheat-policy-update.md) - Update a preheat policy * [harbor project preheat policy view](harbor-project-preheat-policy-view.md) - View details of a preheat policy diff --git a/doc/man-docs/man1/harbor-project-preheat-policy-create.1 b/doc/man-docs/man1/harbor-project-preheat-policy-create.1 index 9c4cec963..192b1f023 100644 --- a/doc/man-docs/man1/harbor-project-preheat-policy-create.1 +++ b/doc/man-docs/man1/harbor-project-preheat-policy-create.1 @@ -39,5 +39,11 @@ Create a new P2P preheat policy under a project verbose output +.SH EXAMPLE +.EX + harbor-cli project preheat policy create [NAME|ID] +.EE + + .SH SEE ALSO \fBharbor-project-preheat-policy(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-project-preheat-policy-delete.1 b/doc/man-docs/man1/harbor-project-preheat-policy-delete.1 index e7f036fff..7e484b969 100644 --- a/doc/man-docs/man1/harbor-project-preheat-policy-delete.1 +++ b/doc/man-docs/man1/harbor-project-preheat-policy-delete.1 @@ -35,5 +35,11 @@ Delete a specific P2P preheat policy under a project verbose output +.SH EXAMPLE +.EX + harbor-cli project preheat policy delete [NAME|ID] [POLICY_NAME] +.EE + + .SH SEE ALSO \fBharbor-project-preheat-policy(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-project-preheat-policy-list.1 b/doc/man-docs/man1/harbor-project-preheat-policy-list.1 index 8eadea270..b7739a02a 100644 --- a/doc/man-docs/man1/harbor-project-preheat-policy-list.1 +++ b/doc/man-docs/man1/harbor-project-preheat-policy-list.1 @@ -2,7 +2,7 @@ .TH "HARBOR" "1" "Harbor Community" "Harbor User Manuals" .SH NAME -harbor-project-preheat-policy-list - List preheat policies under a project by name or id +harbor-project-preheat-policy-list - List preheat policies under a project .SH SYNOPSIS @@ -51,5 +51,11 @@ List project-scoped P2P preheat policies in Harbor verbose output +.SH EXAMPLE +.EX + harbor-cli project preheat policy list [NAME|ID] +.EE + + .SH SEE ALSO \fBharbor-project-preheat-policy(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-project-preheat-policy-start.1 b/doc/man-docs/man1/harbor-project-preheat-policy-start.1 index 573c85092..30f077b59 100644 --- a/doc/man-docs/man1/harbor-project-preheat-policy-start.1 +++ b/doc/man-docs/man1/harbor-project-preheat-policy-start.1 @@ -35,5 +35,11 @@ Manually trigger a specific P2P preheat policy under a project verbose output +.SH EXAMPLE +.EX + harbor-cli project preheat policy start [NAME|ID] [POLICY_NAME] +.EE + + .SH SEE ALSO \fBharbor-project-preheat-policy(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-project-preheat-policy-update.1 b/doc/man-docs/man1/harbor-project-preheat-policy-update.1 index 43a9effca..769cf7907 100644 --- a/doc/man-docs/man1/harbor-project-preheat-policy-update.1 +++ b/doc/man-docs/man1/harbor-project-preheat-policy-update.1 @@ -35,5 +35,11 @@ Update an existing P2P preheat policy under a project verbose output +.SH EXAMPLE +.EX + harbor-cli project preheat policy update [NAME|ID] [POLICY_NAME] +.EE + + .SH SEE ALSO \fBharbor-project-preheat-policy(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-project-preheat-policy-view.1 b/doc/man-docs/man1/harbor-project-preheat-policy-view.1 index 8a724e406..1ae05218d 100644 --- a/doc/man-docs/man1/harbor-project-preheat-policy-view.1 +++ b/doc/man-docs/man1/harbor-project-preheat-policy-view.1 @@ -35,5 +35,11 @@ Get details of a specific P2P preheat policy under a project verbose output +.SH EXAMPLE +.EX + harbor-cli project preheat policy view [NAME|ID] [POLICY_NAME] +.EE + + .SH SEE ALSO \fBharbor-project-preheat-policy(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-project-preheat-policy.1 b/doc/man-docs/man1/harbor-project-preheat-policy.1 index ba7f61792..7cf22b8ff 100644 --- a/doc/man-docs/man1/harbor-project-preheat-policy.1 +++ b/doc/man-docs/man1/harbor-project-preheat-policy.1 @@ -31,5 +31,11 @@ Manage P2P preheat policies under a project verbose output +.SH EXAMPLE +.EX + harbor-cli project preheat policy list [NAME|ID] +.EE + + .SH SEE ALSO \fBharbor-project-preheat(1)\fP, \fBharbor-project-preheat-policy-create(1)\fP, \fBharbor-project-preheat-policy-delete(1)\fP, \fBharbor-project-preheat-policy-list(1)\fP, \fBharbor-project-preheat-policy-start(1)\fP, \fBharbor-project-preheat-policy-update(1)\fP, \fBharbor-project-preheat-policy-view(1)\fP \ No newline at end of file From 78f665933d92fe4b46a20ef0060acdc5af69f348 Mon Sep 17 00:00:00 2001 From: Sypher845 Date: Tue, 12 May 2026 21:01:56 +0530 Subject: [PATCH 13/15] refac: add more validation Signed-off-by: Sypher845 --- .../root/project/preheat/policy/create.go | 4 +++ .../root/project/preheat/policy/delete.go | 4 +++ .../root/project/preheat/policy/list.go | 4 +++ .../root/project/preheat/policy/start.go | 4 +++ .../root/project/preheat/policy/update.go | 4 +++ .../root/project/preheat/policy/view.go | 4 +++ pkg/config/preheat/policies.go | 27 +++++-------------- pkg/views/preheat/policy/create/view.go | 6 ++--- 8 files changed, 33 insertions(+), 24 deletions(-) diff --git a/cmd/harbor/root/project/preheat/policy/create.go b/cmd/harbor/root/project/preheat/policy/create.go index 802480427..72012a378 100644 --- a/cmd/harbor/root/project/preheat/policy/create.go +++ b/cmd/harbor/root/project/preheat/policy/create.go @@ -41,6 +41,10 @@ func CreatePolicyCommand() *cobra.Command { var err error var projectName string + if isID && len(args) == 0 { + return fmt.Errorf("project ID must be provided when using --id") + } + if len(args) > 0 { log.Debugf("Project name provided: %s", args[0]) projectName = args[0] diff --git a/cmd/harbor/root/project/preheat/policy/delete.go b/cmd/harbor/root/project/preheat/policy/delete.go index e2bbdf1ce..404df489c 100644 --- a/cmd/harbor/root/project/preheat/policy/delete.go +++ b/cmd/harbor/root/project/preheat/policy/delete.go @@ -36,6 +36,10 @@ func DeletePolicyCommand() *cobra.Command { var err error var projectName, policyName string + if isID && len(args) == 0 { + return fmt.Errorf("project ID must be provided when using --id") + } + if len(args) >= 1 { log.Debugf("Project name provided: %s", args[0]) projectName = args[0] diff --git a/cmd/harbor/root/project/preheat/policy/list.go b/cmd/harbor/root/project/preheat/policy/list.go index 0da0e010b..85e208274 100644 --- a/cmd/harbor/root/project/preheat/policy/list.go +++ b/cmd/harbor/root/project/preheat/policy/list.go @@ -46,6 +46,10 @@ func ListPolicyCommand() *cobra.Command { return fmt.Errorf("page size must be greater than 0 and less than or equal to 100") } + if isID && len(args) == 0 { + return fmt.Errorf("project ID must be provided when using --id") + } + if len(args) > 0 { log.Debugf("Project name provided: %s", args[0]) projectName = args[0] diff --git a/cmd/harbor/root/project/preheat/policy/start.go b/cmd/harbor/root/project/preheat/policy/start.go index e2bc8c41d..2650e5739 100644 --- a/cmd/harbor/root/project/preheat/policy/start.go +++ b/cmd/harbor/root/project/preheat/policy/start.go @@ -36,6 +36,10 @@ func StartPolicyCommand() *cobra.Command { var err error var projectName, policyName string + if isID && len(args) == 0 { + return fmt.Errorf("project ID must be provided when using --id") + } + if len(args) >= 1 { log.Debugf("Project name provided: %s", args[0]) projectName = args[0] diff --git a/cmd/harbor/root/project/preheat/policy/update.go b/cmd/harbor/root/project/preheat/policy/update.go index 3162243a8..6038acc27 100644 --- a/cmd/harbor/root/project/preheat/policy/update.go +++ b/cmd/harbor/root/project/preheat/policy/update.go @@ -39,6 +39,10 @@ func UpdatePolicyCommand() *cobra.Command { var err error var projectName, policyName string + if isID && len(args) == 0 { + return fmt.Errorf("project ID must be provided when using --id") + } + if len(args) >= 1 { log.Debugf("Project name provided: %s", args[0]) projectName = args[0] diff --git a/cmd/harbor/root/project/preheat/policy/view.go b/cmd/harbor/root/project/preheat/policy/view.go index b9ff82801..fd3866cdb 100644 --- a/cmd/harbor/root/project/preheat/policy/view.go +++ b/cmd/harbor/root/project/preheat/policy/view.go @@ -38,6 +38,10 @@ func ViewPolicyCommand() *cobra.Command { var err error var projectName, policyName string + if isID && len(args) == 0 { + return fmt.Errorf("project ID must be provided when using --id") + } + if len(args) >= 1 { log.Debugf("Project name provided: %s", args[0]) projectName = args[0] diff --git a/pkg/config/preheat/policies.go b/pkg/config/preheat/policies.go index b6796a1a4..ba7ca17ec 100644 --- a/pkg/config/preheat/policies.go +++ b/pkg/config/preheat/policies.go @@ -20,7 +20,7 @@ import ( "path/filepath" "strings" - "github.com/goharbor/harbor-cli/pkg/views/preheat/policy/create" + policycreate "github.com/goharbor/harbor-cli/pkg/views/preheat/policy/create" log "github.com/sirupsen/logrus" "gopkg.in/yaml.v2" ) @@ -49,8 +49,8 @@ type PolicyTrigger struct { TriggerSetting *PolicyTriggerSetting `yaml:"trigger_setting,omitempty" json:"trigger_setting,omitempty"` } -func LoadConfigFromFile(filename string) (*create.CreateView, error) { - var opts *create.CreateView +func LoadConfigFromFile(filename string) (*policycreate.CreateView, error) { + var opts *policycreate.CreateView var err error ext := filepath.Ext(filename) @@ -70,7 +70,7 @@ func LoadConfigFromFile(filename string) (*create.CreateView, error) { return opts, nil } -func LoadConfigFromYAMLorJSON(filename string, fileType string) (*create.CreateView, error) { +func LoadConfigFromYAMLorJSON(filename string, fileType string) (*policycreate.CreateView, error) { data, err := os.ReadFile(filename) if err != nil { return nil, fmt.Errorf("failed to read file: %v", err) @@ -112,7 +112,7 @@ func LoadConfigFromYAMLorJSON(filename string, fileType string) (*create.CreateV } } - opts := &create.CreateView{ + opts := &policycreate.CreateView{ Name: config.Name, Description: config.Description, ProviderName: config.ProviderName, @@ -188,7 +188,7 @@ func resolveTriggerCron(trigger *PolicyTrigger) (string, error) { case "none": return "", nil case "hourly", "daily", "weekly", "custom": - cron := resolveSchedulePreset(preset, setting.Cron) + cron := policycreate.ResolveSchedulePreset(preset, setting.Cron) if preset == "custom" && cron == "" { return "", fmt.Errorf("trigger.trigger_setting.cron is required for custom schedule") } @@ -198,21 +198,6 @@ func resolveTriggerCron(trigger *PolicyTrigger) (string, error) { } } -func resolveSchedulePreset(preset, cron string) string { - switch preset { - case "hourly": - return "0 0 * * * *" - case "daily": - return "0 0 0 * * *" - case "weekly": - return "0 0 0 * * 0" - case "custom": - return strings.TrimSpace(cron) - default: - return "" - } -} - func validatePolicyFilters(filters []*PolicyFilter) error { if len(filters) < 2 || len(filters) > 3 { return fmt.Errorf("filters must include repository and tag filters, with label optional") diff --git a/pkg/views/preheat/policy/create/view.go b/pkg/views/preheat/policy/create/view.go index 5982e7bcd..f8a995598 100644 --- a/pkg/views/preheat/policy/create/view.go +++ b/pkg/views/preheat/policy/create/view.go @@ -185,9 +185,9 @@ func CreatePreheatPolicyView(createView *CreateView, providers []*models.Provide if err := cronForm.Run(); err != nil { log.Fatal(err) } - createView.CronString = resolveSchedulePreset(schedulePreset, createView.CronString) + createView.CronString = ResolveSchedulePreset(schedulePreset, createView.CronString) } else { - createView.CronString = resolveSchedulePreset(schedulePreset, "") + createView.CronString = ResolveSchedulePreset(schedulePreset, "") } } } @@ -207,7 +207,7 @@ func schedulePresetForCron(cron string) string { } } -func resolveSchedulePreset(preset, cron string) string { +func ResolveSchedulePreset(preset, cron string) string { switch preset { case "hourly": return "0 0 * * * *" From bda5bbe43246a62b4e154fac93609f4b4a718c4c Mon Sep 17 00:00:00 2001 From: Sypher845 Date: Tue, 12 May 2026 21:32:01 +0530 Subject: [PATCH 14/15] refac: solve minor logic issue Signed-off-by: Sypher845 --- .../root/project/preheat/policy/delete.go | 10 +++++- .../root/project/preheat/policy/list.go | 2 +- .../root/project/preheat/policy/start.go | 10 +++++- .../root/project/preheat/policy/update.go | 2 +- .../root/project/preheat/policy/view.go | 10 +++++- pkg/api/preheat_handler.go | 32 +++---------------- 6 files changed, 33 insertions(+), 33 deletions(-) diff --git a/cmd/harbor/root/project/preheat/policy/delete.go b/cmd/harbor/root/project/preheat/policy/delete.go index 404df489c..2f64194c4 100644 --- a/cmd/harbor/root/project/preheat/policy/delete.go +++ b/cmd/harbor/root/project/preheat/policy/delete.go @@ -51,6 +51,14 @@ func DeletePolicyCommand() *cobra.Command { } } + if isID { + project, err := api.GetProject(projectName, true) + if err != nil { + return fmt.Errorf("failed to resolve project ID: %v", utils.ParseHarborErrorMsg(err)) + } + projectName = project.Payload.Name + } + if len(args) >= 2 { log.Debugf("Policy name provided: %s", args[1]) policyName = args[1] @@ -63,7 +71,7 @@ func DeletePolicyCommand() *cobra.Command { } log.Debug("Deleting preheat policy...") - err = api.DeletePreheatPolicy(projectName, policyName, isID) + err = api.DeletePreheatPolicy(projectName, policyName) if err != nil { if utils.ParseHarborErrorCode(err) == "404" { return fmt.Errorf("preheat policy %s not found in project %s", policyName, projectName) diff --git a/cmd/harbor/root/project/preheat/policy/list.go b/cmd/harbor/root/project/preheat/policy/list.go index 85e208274..46834c145 100644 --- a/cmd/harbor/root/project/preheat/policy/list.go +++ b/cmd/harbor/root/project/preheat/policy/list.go @@ -72,7 +72,7 @@ func ListPolicyCommand() *cobra.Command { FormatFlag := viper.GetString("output-format") if FormatFlag != "" { - err = utils.PrintFormat(resp, FormatFlag) + err = utils.PrintFormat(resp.Payload, FormatFlag) if err != nil { return err } diff --git a/cmd/harbor/root/project/preheat/policy/start.go b/cmd/harbor/root/project/preheat/policy/start.go index 2650e5739..ef5da06ff 100644 --- a/cmd/harbor/root/project/preheat/policy/start.go +++ b/cmd/harbor/root/project/preheat/policy/start.go @@ -51,6 +51,14 @@ func StartPolicyCommand() *cobra.Command { } } + if isID { + project, err := api.GetProject(projectName, true) + if err != nil { + return fmt.Errorf("failed to resolve project ID: %v", utils.ParseHarborErrorMsg(err)) + } + projectName = project.Payload.Name + } + if len(args) >= 2 { log.Debugf("Policy name provided: %s", args[1]) policyName = args[1] @@ -63,7 +71,7 @@ func StartPolicyCommand() *cobra.Command { } log.Debug("Manually triggering preheat policy...") - location, err := api.StartPreheatPolicy(projectName, policyName, isID) + location, err := api.StartPreheatPolicy(projectName, policyName) if err != nil { if utils.ParseHarborErrorCode(err) == "404" { return fmt.Errorf("preheat policy %s not found in project %s", policyName, projectName) diff --git a/cmd/harbor/root/project/preheat/policy/update.go b/cmd/harbor/root/project/preheat/policy/update.go index 6038acc27..4ac9af094 100644 --- a/cmd/harbor/root/project/preheat/policy/update.go +++ b/cmd/harbor/root/project/preheat/policy/update.go @@ -74,7 +74,7 @@ func UpdatePolicyCommand() *cobra.Command { } log.Debug("Fetching preheat policy...") - existingPolicy, err := api.GetPreheatPolicy(projectName, policyName, false) + existingPolicy, err := api.GetPreheatPolicy(projectName, policyName) if err != nil { if utils.ParseHarborErrorCode(err) == "404" { return fmt.Errorf("preheat policy %s not found in project %s", policyName, projectName) diff --git a/cmd/harbor/root/project/preheat/policy/view.go b/cmd/harbor/root/project/preheat/policy/view.go index fd3866cdb..633df1394 100644 --- a/cmd/harbor/root/project/preheat/policy/view.go +++ b/cmd/harbor/root/project/preheat/policy/view.go @@ -53,6 +53,14 @@ func ViewPolicyCommand() *cobra.Command { } } + if isID { + project, err := api.GetProject(projectName, true) + if err != nil { + return fmt.Errorf("failed to resolve project ID: %v", utils.ParseHarborErrorMsg(err)) + } + projectName = project.Payload.Name + } + if len(args) >= 2 { log.Debugf("Policy name provided: %s", args[1]) policyName = args[1] @@ -65,7 +73,7 @@ func ViewPolicyCommand() *cobra.Command { } log.Debug("Fetching preheat policy...") - resp, err := api.GetPreheatPolicy(projectName, policyName, isID) + resp, err := api.GetPreheatPolicy(projectName, policyName) if err != nil { if utils.ParseHarborErrorCode(err) == "404" { return fmt.Errorf("preheat policy %s not found in project %s", policyName, projectName) diff --git a/pkg/api/preheat_handler.go b/pkg/api/preheat_handler.go index 463e2d145..da52a72ce 100644 --- a/pkg/api/preheat_handler.go +++ b/pkg/api/preheat_handler.go @@ -51,20 +51,12 @@ func ListPreheatPolicies(projectName string, isID bool, opts ...ListFlags) (*pre return response, nil } -func GetPreheatPolicy(projectName, policyName string, isID bool) (*preheat.GetPolicyOK, error) { +func GetPreheatPolicy(projectName, policyName string) (*preheat.GetPolicyOK, error) { ctx, client, err := utils.ContextWithClient() if err != nil { return nil, err } - if isID { - project, err := GetProject(projectName, true) - if err != nil { - return nil, err - } - projectName = project.Payload.Name - } - response, err := client.Preheat.GetPolicy(ctx, &preheat.GetPolicyParams{ ProjectName: projectName, PreheatPolicyName: policyName, @@ -75,20 +67,12 @@ func GetPreheatPolicy(projectName, policyName string, isID bool) (*preheat.GetPo return response, nil } -func DeletePreheatPolicy(projectName, policyName string, isID bool) error { +func DeletePreheatPolicy(projectName, policyName string) error { ctx, client, err := utils.ContextWithClient() if err != nil { return err } - if isID { - project, err := GetProject(projectName, true) - if err != nil { - return err - } - projectName = project.Payload.Name - } - _, err = client.Preheat.DeletePolicy(ctx, &preheat.DeletePolicyParams{ ProjectName: projectName, PreheatPolicyName: policyName, @@ -99,21 +83,13 @@ func DeletePreheatPolicy(projectName, policyName string, isID bool) error { return nil } -func StartPreheatPolicy(projectName, policyName string, isID bool) (string, error) { +func StartPreheatPolicy(projectName, policyName string) (string, error) { ctx, client, err := utils.ContextWithClient() if err != nil { return "", err } - if isID { - project, err := GetProject(projectName, true) - if err != nil { - return "", err - } - projectName = project.Payload.Name - } - - policy, err := GetPreheatPolicy(projectName, policyName, false) + policy, err := GetPreheatPolicy(projectName, policyName) if err != nil { return "", err } From 316d12181c5e55ffd55453a280e59746bacb8cbb Mon Sep 17 00:00:00 2001 From: Sypher845 Date: Tue, 19 May 2026 01:19:56 +0530 Subject: [PATCH 15/15] refac(preheat): policy create command Signed-off-by: Sypher845 --- cmd/harbor/root/project/preheat.go | 5 +- cmd/harbor/root/project/preheat/policy.go | 6 +- .../root/project/preheat/policy/create.go | 88 +++++++++++-------- .../root/project/preheat/policy/delete.go | 11 +-- .../root/project/preheat/policy/list.go | 11 +-- .../root/project/preheat/policy/start.go | 11 +-- .../root/project/preheat/policy/update.go | 11 +-- .../root/project/preheat/policy/view.go | 11 +-- .../harbor-project-preheat-policy-create.md | 6 +- .../harbor-project-preheat-policy-delete.md | 5 +- .../harbor-project-preheat-policy-list.md | 5 +- .../harbor-project-preheat-policy-start.md | 5 +- .../harbor-project-preheat-policy-update.md | 5 +- .../harbor-project-preheat-policy-view.md | 5 +- doc/cli-docs/harbor-project-preheat-policy.md | 6 +- doc/cli-docs/harbor-project-preheat.md | 5 +- .../harbor-project-preheat-policy-create.1 | 6 +- .../harbor-project-preheat-policy-delete.1 | 5 +- .../man1/harbor-project-preheat-policy-list.1 | 5 +- .../harbor-project-preheat-policy-start.1 | 5 +- .../harbor-project-preheat-policy-update.1 | 5 +- .../man1/harbor-project-preheat-policy-view.1 | 5 +- .../man1/harbor-project-preheat-policy.1 | 6 +- doc/man-docs/man1/harbor-project-preheat.1 | 5 +- pkg/config/preheat/policies.go | 6 ++ pkg/views/preheat/policy/create/view.go | 1 + 26 files changed, 154 insertions(+), 91 deletions(-) diff --git a/cmd/harbor/root/project/preheat.go b/cmd/harbor/root/project/preheat.go index f65e1c536..4558fe0b4 100644 --- a/cmd/harbor/root/project/preheat.go +++ b/cmd/harbor/root/project/preheat.go @@ -24,7 +24,10 @@ func Preheat() *cobra.Command { Aliases: []string{"p2p"}, Short: "Manage project preheat resources", Long: "Manage project-scoped P2P preheat policies, executions, and tasks in Harbor", - Example: ` harbor project preheat policy list`, + Example: ` harbor project preheat policy list [PROJECT_NAME] + harbor project preheat policy list [PROJECT_ID] --id + harbor project preheat policy create -f [CONFIG_FILE] + harbor project preheat policy start [PROJECT_NAME] [POLICY_NAME]`, } cmd.AddCommand( preheat.PolicyCommand(), diff --git a/cmd/harbor/root/project/preheat/policy.go b/cmd/harbor/root/project/preheat/policy.go index b2313fd60..c240591b9 100644 --- a/cmd/harbor/root/project/preheat/policy.go +++ b/cmd/harbor/root/project/preheat/policy.go @@ -24,7 +24,11 @@ func PolicyCommand() *cobra.Command { Aliases: []string{"pol"}, Short: "Manage preheat policies", Long: "Manage P2P preheat policies under a project", - Example: ` harbor-cli project preheat policy list [NAME|ID]`, + Example: ` harbor project preheat policy list [PROJECT_NAME] + harbor project preheat policy list [PROJECT_ID] --id + harbor project preheat policy create -f [CONFIG_FILE] + harbor project preheat policy view [PROJECT_NAME] [POLICY_NAME] + harbor project preheat policy start [PROJECT_NAME] [POLICY_NAME]`, } cmd.AddCommand( diff --git a/cmd/harbor/root/project/preheat/policy/create.go b/cmd/harbor/root/project/preheat/policy/create.go index 72012a378..b7ea4ac01 100644 --- a/cmd/harbor/root/project/preheat/policy/create.go +++ b/cmd/harbor/root/project/preheat/policy/create.go @@ -30,43 +30,25 @@ import ( func CreatePolicyCommand() *cobra.Command { var isID bool var configFile string + var err error + var opts *create.CreateView cmd := &cobra.Command{ - Use: "create [NAME|ID]", - Short: "Create a preheat policy", - Long: "Create a new P2P preheat policy under a project", - Example: ` harbor-cli project preheat policy create [NAME|ID]`, - Args: cobra.MaximumNArgs(1), + Use: "create", + Short: "Create a preheat policy", + Long: "Create a new P2P preheat policy under a project", + Example: ` harbor project preheat policy create [PROJECT_NAME] + harbor project preheat policy create [PROJECT_ID] --id + harbor project preheat policy create -f [CONFIG_FILE]`, + Args: cobra.MaximumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - var err error - var projectName string + log.Debug("Starting preheat policy create command") - if isID && len(args) == 0 { - return fmt.Errorf("project ID must be provided when using --id") - } - - if len(args) > 0 { - log.Debugf("Project name provided: %s", args[0]) - projectName = args[0] - } else { - log.Debug("No project name provided, prompting user") - projectName, err = prompt.GetProjectNameFromUser() - if err != nil { - return fmt.Errorf("failed to get project name: %v", utils.ParseHarborErrorMsg(err)) - } - } - - if isID { - project, err := api.GetProject(projectName, true) - if err != nil { - return fmt.Errorf("failed to get project: %v", utils.ParseHarborErrorMsg(err)) + if configFile != "" { + if len(args) > 0 { + return fmt.Errorf("arguments are not supported with --policy-config-file") } - projectName = project.Payload.Name - } - - var opts *create.CreateView - if configFile != "" { log.Debugf("Loading preheat policy configuration from file: %s", configFile) opts, err = config.LoadConfigFromFile(configFile) if err != nil { @@ -76,23 +58,57 @@ func CreatePolicyCommand() *cobra.Command { opts = &create.CreateView{ Enabled: true, } + + if isID && len(args) == 0 { + return fmt.Errorf("project ID must be provided when using --id") + } + + if len(args) > 0 { + log.Debugf("Project name provided: %s", args[0]) + opts.ProjectName = args[0] + } else { + log.Debug("No project name provided, prompting user") + opts.ProjectName, err = prompt.GetProjectNameFromUser() + if err != nil { + return fmt.Errorf("failed to get project name: %v", utils.ParseHarborErrorMsg(err)) + } + } + + if isID { + project, err := api.GetProject(opts.ProjectName, true) + if err != nil { + if utils.ParseHarborErrorCode(err) == "404" { + return fmt.Errorf("project %s does not exist", opts.ProjectName) + } + return fmt.Errorf("failed to get project: %v", utils.ParseHarborErrorMsg(err)) + } + opts.ProjectName = project.Payload.Name + } + } + + _, err = api.GetProject(opts.ProjectName, false) + if err != nil { + if utils.ParseHarborErrorCode(err) == "404" { + return fmt.Errorf("project %s does not exist. If you entered a project ID, use --id", opts.ProjectName) + } + return fmt.Errorf("failed to verify project: %v", utils.ParseHarborErrorMsg(err)) } log.Debug("Fetching available providers...") - providers, err := api.ListProvidersUnderProject(projectName) + providers, err := api.ListProvidersUnderProject(opts.ProjectName) if err != nil { return fmt.Errorf("failed to list providers: %v", utils.ParseHarborErrorMsg(err)) } if len(providers) == 0 { - return fmt.Errorf("no P2P provider instances available for project '%s'. Please create a provider instance first", projectName) + return fmt.Errorf("no P2P provider instances available for project '%s'. Please create a provider instance first", opts.ProjectName) } if configFile == "" { create.CreatePreheatPolicyView(opts, providers) } - providerID, err := resolveProviderID(providers, opts.ProviderName, projectName) + providerID, err := resolveProviderID(providers, opts.ProviderName, opts.ProjectName) if err != nil { return err } @@ -103,10 +119,10 @@ func CreatePolicyCommand() *cobra.Command { } log.Debug("Creating preheat policy...") - response, err := api.CreatePreheatPolicy(projectName, policy) + response, err := api.CreatePreheatPolicy(opts.ProjectName, policy) if err != nil { if utils.ParseHarborErrorCode(err) == "409" { - return fmt.Errorf("preheat policy '%s' already exists in project '%s'", opts.Name, projectName) + return fmt.Errorf("preheat policy '%s' already exists in project '%s'", opts.Name, opts.ProjectName) } return fmt.Errorf("failed to create preheat policy: %v", utils.ParseHarborErrorMsg(err)) } diff --git a/cmd/harbor/root/project/preheat/policy/delete.go b/cmd/harbor/root/project/preheat/policy/delete.go index 2f64194c4..004826db0 100644 --- a/cmd/harbor/root/project/preheat/policy/delete.go +++ b/cmd/harbor/root/project/preheat/policy/delete.go @@ -27,11 +27,12 @@ func DeletePolicyCommand() *cobra.Command { var isID bool cmd := &cobra.Command{ - Use: "delete [NAME|ID] [POLICY_NAME]", - Short: "Delete a preheat policy", - Long: "Delete a specific P2P preheat policy under a project", - Example: ` harbor-cli project preheat policy delete [NAME|ID] [POLICY_NAME]`, - Args: cobra.MaximumNArgs(2), + Use: "delete", + Short: "Delete a preheat policy", + Long: "Delete a specific P2P preheat policy under a project", + Example: ` harbor project preheat policy delete [PROJECT_NAME] [POLICY_NAME] + harbor project preheat policy delete [PROJECT_ID] [POLICY_NAME] --id`, + Args: cobra.MaximumNArgs(2), RunE: func(cmd *cobra.Command, args []string) error { var err error var projectName, policyName string diff --git a/cmd/harbor/root/project/preheat/policy/list.go b/cmd/harbor/root/project/preheat/policy/list.go index 46834c145..1f332e957 100644 --- a/cmd/harbor/root/project/preheat/policy/list.go +++ b/cmd/harbor/root/project/preheat/policy/list.go @@ -30,11 +30,12 @@ func ListPolicyCommand() *cobra.Command { var isID bool cmd := &cobra.Command{ - Use: "list [NAME|ID]", - Short: "List preheat policies under a project", - Long: "List project-scoped P2P preheat policies in Harbor", - Example: ` harbor-cli project preheat policy list [NAME|ID]`, - Args: cobra.MaximumNArgs(1), + Use: "list", + Short: "List preheat policies under a project", + Long: "List project-scoped P2P preheat policies in Harbor", + Example: ` harbor project preheat policy list [PROJECT_NAME] + harbor project preheat policy list [PROJECT_ID] --id`, + Args: cobra.MaximumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { var err error var projectName string diff --git a/cmd/harbor/root/project/preheat/policy/start.go b/cmd/harbor/root/project/preheat/policy/start.go index ef5da06ff..224a8921a 100644 --- a/cmd/harbor/root/project/preheat/policy/start.go +++ b/cmd/harbor/root/project/preheat/policy/start.go @@ -27,11 +27,12 @@ func StartPolicyCommand() *cobra.Command { var isID bool cmd := &cobra.Command{ - Use: "start [NAME|ID] [POLICY_NAME]", - Short: "Manually trigger a preheat policy", - Long: "Manually trigger a specific P2P preheat policy under a project", - Example: ` harbor-cli project preheat policy start [NAME|ID] [POLICY_NAME]`, - Args: cobra.MaximumNArgs(2), + Use: "start", + Short: "Manually trigger a preheat policy", + Long: "Manually trigger a specific P2P preheat policy under a project", + Example: ` harbor project preheat policy start [PROJECT_NAME] [POLICY_NAME] + harbor project preheat policy start [PROJECT_ID] [POLICY_NAME] --id`, + Args: cobra.MaximumNArgs(2), RunE: func(cmd *cobra.Command, args []string) error { var err error var projectName, policyName string diff --git a/cmd/harbor/root/project/preheat/policy/update.go b/cmd/harbor/root/project/preheat/policy/update.go index 4ac9af094..abdb21da0 100644 --- a/cmd/harbor/root/project/preheat/policy/update.go +++ b/cmd/harbor/root/project/preheat/policy/update.go @@ -30,11 +30,12 @@ func UpdatePolicyCommand() *cobra.Command { var isID bool cmd := &cobra.Command{ - Use: "update [NAME|ID] [POLICY_NAME]", - Short: "Update a preheat policy", - Long: "Update an existing P2P preheat policy under a project", - Example: ` harbor-cli project preheat policy update [NAME|ID] [POLICY_NAME]`, - Args: cobra.MaximumNArgs(2), + Use: "update", + Short: "Update a preheat policy", + Long: "Update an existing P2P preheat policy under a project", + Example: ` harbor project preheat policy update [PROJECT_NAME] [POLICY_NAME] + harbor project preheat policy update [PROJECT_ID] [POLICY_NAME] --id`, + Args: cobra.MaximumNArgs(2), RunE: func(cmd *cobra.Command, args []string) error { var err error var projectName, policyName string diff --git a/cmd/harbor/root/project/preheat/policy/view.go b/cmd/harbor/root/project/preheat/policy/view.go index 633df1394..c9972bb56 100644 --- a/cmd/harbor/root/project/preheat/policy/view.go +++ b/cmd/harbor/root/project/preheat/policy/view.go @@ -29,11 +29,12 @@ func ViewPolicyCommand() *cobra.Command { var isID bool cmd := &cobra.Command{ - Use: "view [NAME|ID] [POLICY_NAME]", - Short: "View details of a preheat policy", - Long: "Get details of a specific P2P preheat policy under a project", - Example: ` harbor-cli project preheat policy view [NAME|ID] [POLICY_NAME]`, - Args: cobra.MaximumNArgs(2), + Use: "view", + Short: "View details of a preheat policy", + Long: "Get details of a specific P2P preheat policy under a project", + Example: ` harbor project preheat policy view [PROJECT_NAME] [POLICY_NAME] + harbor project preheat policy view [PROJECT_ID] [POLICY_NAME] --id`, + Args: cobra.MaximumNArgs(2), RunE: func(cmd *cobra.Command, args []string) error { var err error var projectName, policyName string diff --git a/doc/cli-docs/harbor-project-preheat-policy-create.md b/doc/cli-docs/harbor-project-preheat-policy-create.md index 06816234b..b15ed161e 100644 --- a/doc/cli-docs/harbor-project-preheat-policy-create.md +++ b/doc/cli-docs/harbor-project-preheat-policy-create.md @@ -13,13 +13,15 @@ weight: 50 Create a new P2P preheat policy under a project ```sh -harbor project preheat policy create [NAME|ID] [flags] +harbor project preheat policy create [flags] ``` ### Examples ```sh - harbor-cli project preheat policy create [NAME|ID] + harbor project preheat policy create [PROJECT_NAME] + harbor project preheat policy create [PROJECT_ID] --id + harbor project preheat policy create -f [CONFIG_FILE] ``` ### Options diff --git a/doc/cli-docs/harbor-project-preheat-policy-delete.md b/doc/cli-docs/harbor-project-preheat-policy-delete.md index 3bbfc86ff..a58b1cb94 100644 --- a/doc/cli-docs/harbor-project-preheat-policy-delete.md +++ b/doc/cli-docs/harbor-project-preheat-policy-delete.md @@ -13,13 +13,14 @@ weight: 20 Delete a specific P2P preheat policy under a project ```sh -harbor project preheat policy delete [NAME|ID] [POLICY_NAME] [flags] +harbor project preheat policy delete [flags] ``` ### Examples ```sh - harbor-cli project preheat policy delete [NAME|ID] [POLICY_NAME] + harbor project preheat policy delete [PROJECT_NAME] [POLICY_NAME] + harbor project preheat policy delete [PROJECT_ID] [POLICY_NAME] --id ``` ### Options diff --git a/doc/cli-docs/harbor-project-preheat-policy-list.md b/doc/cli-docs/harbor-project-preheat-policy-list.md index fffc942bf..78330b103 100644 --- a/doc/cli-docs/harbor-project-preheat-policy-list.md +++ b/doc/cli-docs/harbor-project-preheat-policy-list.md @@ -13,13 +13,14 @@ weight: 20 List project-scoped P2P preheat policies in Harbor ```sh -harbor project preheat policy list [NAME|ID] [flags] +harbor project preheat policy list [flags] ``` ### Examples ```sh - harbor-cli project preheat policy list [NAME|ID] + harbor project preheat policy list [PROJECT_NAME] + harbor project preheat policy list [PROJECT_ID] --id ``` ### Options diff --git a/doc/cli-docs/harbor-project-preheat-policy-start.md b/doc/cli-docs/harbor-project-preheat-policy-start.md index 79d73e8aa..0296452e0 100644 --- a/doc/cli-docs/harbor-project-preheat-policy-start.md +++ b/doc/cli-docs/harbor-project-preheat-policy-start.md @@ -13,13 +13,14 @@ weight: 55 Manually trigger a specific P2P preheat policy under a project ```sh -harbor project preheat policy start [NAME|ID] [POLICY_NAME] [flags] +harbor project preheat policy start [flags] ``` ### Examples ```sh - harbor-cli project preheat policy start [NAME|ID] [POLICY_NAME] + harbor project preheat policy start [PROJECT_NAME] [POLICY_NAME] + harbor project preheat policy start [PROJECT_ID] [POLICY_NAME] --id ``` ### Options diff --git a/doc/cli-docs/harbor-project-preheat-policy-update.md b/doc/cli-docs/harbor-project-preheat-policy-update.md index 87023cf67..ef5ef0933 100644 --- a/doc/cli-docs/harbor-project-preheat-policy-update.md +++ b/doc/cli-docs/harbor-project-preheat-policy-update.md @@ -13,13 +13,14 @@ weight: 25 Update an existing P2P preheat policy under a project ```sh -harbor project preheat policy update [NAME|ID] [POLICY_NAME] [flags] +harbor project preheat policy update [flags] ``` ### Examples ```sh - harbor-cli project preheat policy update [NAME|ID] [POLICY_NAME] + harbor project preheat policy update [PROJECT_NAME] [POLICY_NAME] + harbor project preheat policy update [PROJECT_ID] [POLICY_NAME] --id ``` ### Options diff --git a/doc/cli-docs/harbor-project-preheat-policy-view.md b/doc/cli-docs/harbor-project-preheat-policy-view.md index 389e09989..867db83b7 100644 --- a/doc/cli-docs/harbor-project-preheat-policy-view.md +++ b/doc/cli-docs/harbor-project-preheat-policy-view.md @@ -13,13 +13,14 @@ weight: 30 Get details of a specific P2P preheat policy under a project ```sh -harbor project preheat policy view [NAME|ID] [POLICY_NAME] [flags] +harbor project preheat policy view [flags] ``` ### Examples ```sh - harbor-cli project preheat policy view [NAME|ID] [POLICY_NAME] + harbor project preheat policy view [PROJECT_NAME] [POLICY_NAME] + harbor project preheat policy view [PROJECT_ID] [POLICY_NAME] --id ``` ### Options diff --git a/doc/cli-docs/harbor-project-preheat-policy.md b/doc/cli-docs/harbor-project-preheat-policy.md index 70509492f..e0c3718c0 100644 --- a/doc/cli-docs/harbor-project-preheat-policy.md +++ b/doc/cli-docs/harbor-project-preheat-policy.md @@ -15,7 +15,11 @@ Manage P2P preheat policies under a project ### Examples ```sh - harbor-cli project preheat policy list [NAME|ID] + harbor project preheat policy list [PROJECT_NAME] + harbor project preheat policy list [PROJECT_ID] --id + harbor project preheat policy create -f [CONFIG_FILE] + harbor project preheat policy view [PROJECT_NAME] [POLICY_NAME] + harbor project preheat policy start [PROJECT_NAME] [POLICY_NAME] ``` ### Options diff --git a/doc/cli-docs/harbor-project-preheat.md b/doc/cli-docs/harbor-project-preheat.md index e847c8b53..fc9d16d91 100644 --- a/doc/cli-docs/harbor-project-preheat.md +++ b/doc/cli-docs/harbor-project-preheat.md @@ -15,7 +15,10 @@ Manage project-scoped P2P preheat policies, executions, and tasks in Harbor ### Examples ```sh - harbor project preheat policy list + harbor project preheat policy list [PROJECT_NAME] + harbor project preheat policy list [PROJECT_ID] --id + harbor project preheat policy create -f [CONFIG_FILE] + harbor project preheat policy start [PROJECT_NAME] [POLICY_NAME] ``` ### Options diff --git a/doc/man-docs/man1/harbor-project-preheat-policy-create.1 b/doc/man-docs/man1/harbor-project-preheat-policy-create.1 index 192b1f023..711432dcb 100644 --- a/doc/man-docs/man1/harbor-project-preheat-policy-create.1 +++ b/doc/man-docs/man1/harbor-project-preheat-policy-create.1 @@ -6,7 +6,7 @@ harbor-project-preheat-policy-create - Create a preheat policy .SH SYNOPSIS -\fBharbor project preheat policy create [NAME|ID] [flags]\fP +\fBharbor project preheat policy create [flags]\fP .SH DESCRIPTION @@ -41,7 +41,9 @@ Create a new P2P preheat policy under a project .SH EXAMPLE .EX - harbor-cli project preheat policy create [NAME|ID] + harbor project preheat policy create [PROJECT_NAME] + harbor project preheat policy create [PROJECT_ID] --id + harbor project preheat policy create -f [CONFIG_FILE] .EE diff --git a/doc/man-docs/man1/harbor-project-preheat-policy-delete.1 b/doc/man-docs/man1/harbor-project-preheat-policy-delete.1 index 7e484b969..3df9be2c8 100644 --- a/doc/man-docs/man1/harbor-project-preheat-policy-delete.1 +++ b/doc/man-docs/man1/harbor-project-preheat-policy-delete.1 @@ -6,7 +6,7 @@ harbor-project-preheat-policy-delete - Delete a preheat policy .SH SYNOPSIS -\fBharbor project preheat policy delete [NAME|ID] [POLICY_NAME] [flags]\fP +\fBharbor project preheat policy delete [flags]\fP .SH DESCRIPTION @@ -37,7 +37,8 @@ Delete a specific P2P preheat policy under a project .SH EXAMPLE .EX - harbor-cli project preheat policy delete [NAME|ID] [POLICY_NAME] + harbor project preheat policy delete [PROJECT_NAME] [POLICY_NAME] + harbor project preheat policy delete [PROJECT_ID] [POLICY_NAME] --id .EE diff --git a/doc/man-docs/man1/harbor-project-preheat-policy-list.1 b/doc/man-docs/man1/harbor-project-preheat-policy-list.1 index b7739a02a..f1ad1f079 100644 --- a/doc/man-docs/man1/harbor-project-preheat-policy-list.1 +++ b/doc/man-docs/man1/harbor-project-preheat-policy-list.1 @@ -6,7 +6,7 @@ harbor-project-preheat-policy-list - List preheat policies under a project .SH SYNOPSIS -\fBharbor project preheat policy list [NAME|ID] [flags]\fP +\fBharbor project preheat policy list [flags]\fP .SH DESCRIPTION @@ -53,7 +53,8 @@ List project-scoped P2P preheat policies in Harbor .SH EXAMPLE .EX - harbor-cli project preheat policy list [NAME|ID] + harbor project preheat policy list [PROJECT_NAME] + harbor project preheat policy list [PROJECT_ID] --id .EE diff --git a/doc/man-docs/man1/harbor-project-preheat-policy-start.1 b/doc/man-docs/man1/harbor-project-preheat-policy-start.1 index 30f077b59..995a28b92 100644 --- a/doc/man-docs/man1/harbor-project-preheat-policy-start.1 +++ b/doc/man-docs/man1/harbor-project-preheat-policy-start.1 @@ -6,7 +6,7 @@ harbor-project-preheat-policy-start - Manually trigger a preheat policy .SH SYNOPSIS -\fBharbor project preheat policy start [NAME|ID] [POLICY_NAME] [flags]\fP +\fBharbor project preheat policy start [flags]\fP .SH DESCRIPTION @@ -37,7 +37,8 @@ Manually trigger a specific P2P preheat policy under a project .SH EXAMPLE .EX - harbor-cli project preheat policy start [NAME|ID] [POLICY_NAME] + harbor project preheat policy start [PROJECT_NAME] [POLICY_NAME] + harbor project preheat policy start [PROJECT_ID] [POLICY_NAME] --id .EE diff --git a/doc/man-docs/man1/harbor-project-preheat-policy-update.1 b/doc/man-docs/man1/harbor-project-preheat-policy-update.1 index 769cf7907..2e8f32242 100644 --- a/doc/man-docs/man1/harbor-project-preheat-policy-update.1 +++ b/doc/man-docs/man1/harbor-project-preheat-policy-update.1 @@ -6,7 +6,7 @@ harbor-project-preheat-policy-update - Update a preheat policy .SH SYNOPSIS -\fBharbor project preheat policy update [NAME|ID] [POLICY_NAME] [flags]\fP +\fBharbor project preheat policy update [flags]\fP .SH DESCRIPTION @@ -37,7 +37,8 @@ Update an existing P2P preheat policy under a project .SH EXAMPLE .EX - harbor-cli project preheat policy update [NAME|ID] [POLICY_NAME] + harbor project preheat policy update [PROJECT_NAME] [POLICY_NAME] + harbor project preheat policy update [PROJECT_ID] [POLICY_NAME] --id .EE diff --git a/doc/man-docs/man1/harbor-project-preheat-policy-view.1 b/doc/man-docs/man1/harbor-project-preheat-policy-view.1 index 1ae05218d..a07929d52 100644 --- a/doc/man-docs/man1/harbor-project-preheat-policy-view.1 +++ b/doc/man-docs/man1/harbor-project-preheat-policy-view.1 @@ -6,7 +6,7 @@ harbor-project-preheat-policy-view - View details of a preheat policy .SH SYNOPSIS -\fBharbor project preheat policy view [NAME|ID] [POLICY_NAME] [flags]\fP +\fBharbor project preheat policy view [flags]\fP .SH DESCRIPTION @@ -37,7 +37,8 @@ Get details of a specific P2P preheat policy under a project .SH EXAMPLE .EX - harbor-cli project preheat policy view [NAME|ID] [POLICY_NAME] + harbor project preheat policy view [PROJECT_NAME] [POLICY_NAME] + harbor project preheat policy view [PROJECT_ID] [POLICY_NAME] --id .EE diff --git a/doc/man-docs/man1/harbor-project-preheat-policy.1 b/doc/man-docs/man1/harbor-project-preheat-policy.1 index 7cf22b8ff..2924c2c1d 100644 --- a/doc/man-docs/man1/harbor-project-preheat-policy.1 +++ b/doc/man-docs/man1/harbor-project-preheat-policy.1 @@ -33,7 +33,11 @@ Manage P2P preheat policies under a project .SH EXAMPLE .EX - harbor-cli project preheat policy list [NAME|ID] + harbor project preheat policy list [PROJECT_NAME] + harbor project preheat policy list [PROJECT_ID] --id + harbor project preheat policy create -f [CONFIG_FILE] + harbor project preheat policy view [PROJECT_NAME] [POLICY_NAME] + harbor project preheat policy start [PROJECT_NAME] [POLICY_NAME] .EE diff --git a/doc/man-docs/man1/harbor-project-preheat.1 b/doc/man-docs/man1/harbor-project-preheat.1 index f5b24d21e..6824d1233 100644 --- a/doc/man-docs/man1/harbor-project-preheat.1 +++ b/doc/man-docs/man1/harbor-project-preheat.1 @@ -33,7 +33,10 @@ Manage project-scoped P2P preheat policies, executions, and tasks in Harbor .SH EXAMPLE .EX - harbor project preheat policy list + harbor project preheat policy list [PROJECT_NAME] + harbor project preheat policy list [PROJECT_ID] --id + harbor project preheat policy create -f [CONFIG_FILE] + harbor project preheat policy start [PROJECT_NAME] [POLICY_NAME] .EE diff --git a/pkg/config/preheat/policies.go b/pkg/config/preheat/policies.go index ba7ca17ec..7592c77ee 100644 --- a/pkg/config/preheat/policies.go +++ b/pkg/config/preheat/policies.go @@ -26,6 +26,7 @@ import ( ) type PolicyConfig struct { + ProjectName string `yaml:"project_name" json:"project_name"` Name string `yaml:"name" json:"name"` Description string `yaml:"description,omitempty" json:"description,omitempty"` Enabled bool `yaml:"enabled,omitempty" json:"enabled,omitempty"` @@ -113,6 +114,7 @@ func LoadConfigFromYAMLorJSON(filename string, fileType string) (*policycreate.C } opts := &policycreate.CreateView{ + ProjectName: config.ProjectName, Name: config.Name, Description: config.Description, ProviderName: config.ProviderName, @@ -136,6 +138,10 @@ func LoadConfigFromYAMLorJSON(filename string, fileType string) (*policycreate.C } func validateConfig(config *PolicyConfig) error { + if config.ProjectName == "" { + return fmt.Errorf("project_name is required") + } + if config.Name == "" { return fmt.Errorf("name is required") } diff --git a/pkg/views/preheat/policy/create/view.go b/pkg/views/preheat/policy/create/view.go index f8a995598..cd8f1c69a 100644 --- a/pkg/views/preheat/policy/create/view.go +++ b/pkg/views/preheat/policy/create/view.go @@ -25,6 +25,7 @@ import ( ) type CreateView struct { + ProjectName string `json:"project_name,omitempty"` Name string `json:"name,omitempty"` Description string `json:"description,omitempty"` Enabled bool `json:"enabled,omitempty"`