Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,26 @@ jobs:
name: unit_coverage
path: tests_coverage

unit_client:
name: Client unit tests
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@v6

- name: Set up Go
uses: actions/setup-go@v6
with:
go-version-file: client/go.mod

- name: Install Task
uses: go-task/setup-task@v2
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}

- name: Test
run: task --yes client:test:unit

e2e_tests:
name: End-to-end tests
runs-on: ubuntu-22.04
Expand Down Expand Up @@ -136,6 +156,7 @@ jobs:
if: always()
needs:
- unit_server
- unit_client
- e2e_tests
- upload_coverage
uses: werf/common-ci/.github/workflows/notification.yml@main
Expand Down
4 changes: 4 additions & 0 deletions client/Taskfile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ tasks:
outputBin: ../bin/coverage/trdl
extraGoBuildArgs: '-ldflags="-s -w" -tags "test_coverage" -cover -covermode=atomic -coverpkg=./... -c cmd/trdl/*.go'

test:unit:
desc: "Run client unit tests."
cmd: go test ./...

verify:dist:binaries:
desc: "Verify that the distributable binaries are built and have correct platform/arch."
cmds:
Expand Down
28 changes: 20 additions & 8 deletions client/cmd/trdl/bin_path.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,40 @@ import (

func binPathCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "bin-path REPO GROUP [CHANNEL]",
Use: "bin-path REPO GROUP [CHANNEL] | REPO VERSION",
Short: "Get the directory with software binaries",
DisableFlagsInUseLine: true,
RunE: func(cmd *cobra.Command, args []string) error {
if err := cobra.RangeArgs(2, 3)(cmd, args); err != nil {
if err := validateVersionArgs(cmd, args); err != nil {
PrintHelp(cmd)
return err
}

repoName := args[0]
group := args[1]

if repoName == trdl.SelfUpdateDefaultRepo {
PrintHelp(cmd)
return fmt.Errorf("reserved repository name %q cannot be used", trdl.SelfUpdateDefaultRepo)
}

c, err := trdlClient.NewClient(homeDir)
if err != nil {
return fmt.Errorf("unable to initialize trdl client: %w", err)
}

if isVersionArg(args[1]) {
dir, err := c.GetRepoReleaseBinDir(repoName, args[1])
if err != nil {
return err
}

fmt.Println(dir)

return nil
}

group := args[1]

var optionalChannel string
if len(args) == 3 {
optionalChannel = args[2]
Expand All @@ -37,11 +54,6 @@ func binPathCmd() *cobra.Command {
}
}

c, err := trdlClient.NewClient(homeDir)
if err != nil {
return fmt.Errorf("unable to initialize trdl client: %w", err)
}

dir, err := c.GetRepoChannelReleaseBinDir(repoName, group, optionalChannel)
if err != nil {
return err
Expand Down
5 changes: 5 additions & 0 deletions client/cmd/trdl/command/md_docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ func GenMarkdownCustom(cmd *cobra.Command, w io.Writer) error {
buf.WriteString(fmt.Sprintf("```shell\n%s\n```\n\n", UsageLine(cmd)))
}

if len(cmd.Aliases) > 0 {
buf.WriteString("## Aliases\n\n")
buf.WriteString(fmt.Sprintf("```shell\n%s\n```\n\n", cmd.NameAndAliases()))
}

if len(cmd.Example) > 0 {
buf.WriteString("## Examples\n\n")
buf.WriteString(fmt.Sprintf("```shell\n%s\n```\n\n", cmd.Example))
Expand Down
2 changes: 1 addition & 1 deletion client/cmd/trdl/command/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const (
`{{$versionLine := versionLine .}}`

// SectionAliases is the help template section that displays command aliases.
SectionAliases = `{{if gt .Aliases 0}}Aliases:
SectionAliases = `{{if gt (len .Aliases) 0}}Aliases:
{{.NameAndAliases}}

{{end}}`
Expand Down
33 changes: 33 additions & 0 deletions client/cmd/trdl/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package main

import (
"fmt"
"regexp"
"strings"

"github.com/Masterminds/semver/v3"
"github.com/asaskevich/govalidator"
"github.com/spf13/cobra"

Expand All @@ -21,6 +23,37 @@ func ValidateChannel(channel string) error {
return nil
}

// isVersionArg reports whether the given positional argument is an explicit
// release version. Versions are distinguished from a GROUP (a plain version
// number, e.g. "2") by the leading "v" prefix (e.g. "v2.72.0").
func isVersionArg(arg string) bool {
if len(arg) < 2 || !regexp.MustCompile(`^[<>=~^v]`).MatchString(arg) {
return false
}

return true
}

// validateVersionArgs enforces that an explicit VERSION argument is mutually
// exclusive with the positional GROUP/CHANNEL arguments. When VERSION is given
// (args[1] has a "v" prefix), only REPO and VERSION are allowed; otherwise the
// default RangeArgs(2,3) behavior applies.
func validateVersionArgs(cmd *cobra.Command, args []string) error {
if len(args) >= 2 && isVersionArg(args[1]) {
if len(args) > 2 {
return fmt.Errorf("VERSION is mutually exclusive with GROUP and CHANNEL arguments")
}

if _, err := semver.NewConstraint(args[1]); err != nil {
return fmt.Errorf("validate version: %w", err)
}

return nil
}

return cobra.RangeArgs(2, 3)(cmd, args)
}

func SetupNoSelfUpdate(cmd *cobra.Command, noSelfUpdate *bool) {
envKey := "TRDL_NO_SELF_UPDATE"

Expand Down
28 changes: 20 additions & 8 deletions client/cmd/trdl/dir_path.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,40 @@ import (

func dirPathCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "dir-path REPO GROUP [CHANNEL]",
Use: "dir-path REPO GROUP [CHANNEL] | REPO VERSION",
Short: "Get the directory with software artifacts",
DisableFlagsInUseLine: true,
RunE: func(cmd *cobra.Command, args []string) error {
if err := cobra.RangeArgs(2, 3)(cmd, args); err != nil {
if err := validateVersionArgs(cmd, args); err != nil {
PrintHelp(cmd)
return err
}

repoName := args[0]
group := args[1]

if repoName == trdl.SelfUpdateDefaultRepo {
PrintHelp(cmd)
return fmt.Errorf("reserved repository name %q cannot be used", trdl.SelfUpdateDefaultRepo)
}

c, err := trdlClient.NewClient(homeDir)
if err != nil {
return fmt.Errorf("unable to initialize trdl client: %w", err)
}

if isVersionArg(args[1]) {
dir, err := c.GetRepoReleaseDir(repoName, args[1])
if err != nil {
return err
}

fmt.Println(dir)

return nil
}

group := args[1]

var optionalChannel string
if len(args) == 3 {
optionalChannel = args[2]
Expand All @@ -37,11 +54,6 @@ func dirPathCmd() *cobra.Command {
}
}

c, err := trdlClient.NewClient(homeDir)
if err != nil {
return fmt.Errorf("unable to initialize trdl client: %w", err)
}

dir, err := c.GetRepoChannelReleaseDir(repoName, group, optionalChannel)
if err != nil {
return err
Expand Down
42 changes: 40 additions & 2 deletions client/cmd/trdl/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"fmt"

"github.com/Masterminds/semver/v3"
"github.com/spf13/cobra"

trdlClient "github.com/werf/trdl/client/pkg/client"
Expand All @@ -11,6 +12,7 @@ import (

type execCmdData struct {
repoName string
version string
group string
optionalChannel string
optionalBinaryName string
Expand All @@ -19,7 +21,7 @@ type execCmdData struct {

func execCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "exec REPO GROUP [CHANNEL] [BINARY_NAME] [--] [ARGS]",
Use: "exec REPO GROUP [CHANNEL] [BINARY_NAME] [--] [ARGS] | REPO VERSION [BINARY_NAME] [--] [ARGS]",
Short: "Exec a software binary",
DisableFlagsInUseLine: true,
RunE: func(cmd *cobra.Command, args []string) error {
Expand All @@ -39,6 +41,17 @@ func execCmd() *cobra.Command {
return fmt.Errorf("unable to initialize trdl client: %w", err)
}

if cmdData.version != "" {
if err := c.ExecRepoReleaseBin(
cmdData.repoName, cmdData.version,
cmdData.optionalBinaryName, cmdData.optionalBinaryArgs,
); err != nil {
return err
}

return nil
}

if err := c.ExecRepoChannelReleaseBin(
cmdData.repoName, cmdData.group, cmdData.optionalChannel,
cmdData.optionalBinaryName, cmdData.optionalBinaryArgs,
Expand All @@ -57,7 +70,6 @@ func processExecArgs(cmd *cobra.Command, args []string) (*execCmdData, error) {
data := &execCmdData{}

data.repoName = args[0]
data.group = args[1]

if data.repoName == trdl.SelfUpdateDefaultRepo {
return nil, fmt.Errorf("reserved repository name %q cannot be used", trdl.SelfUpdateDefaultRepo)
Expand All @@ -66,6 +78,32 @@ func processExecArgs(cmd *cobra.Command, args []string) (*execCmdData, error) {
doubleDashInd := cmd.ArgsLenAtDash()
doubleDashExist := cmd.ArgsLenAtDash() != -1

if isVersionArg(args[1]) {
if _, err := semver.NewConstraint(args[1]); err != nil {
return nil, fmt.Errorf("validate version: %w", err)
}

data.version = args[1]

restArgs := args[2:]
if doubleDashExist {
data.optionalBinaryArgs = args[doubleDashInd:]
restArgs = args[2:doubleDashInd]
}

switch len(restArgs) {
case 0:
return data, nil
case 1:
data.optionalBinaryName = restArgs[0]
return data, nil
default:
return nil, fmt.Errorf("VERSION is mutually exclusive with GROUP and CHANNEL arguments")
}
}

data.group = args[1]

restArgs := args[2:]
if doubleDashExist {
data.optionalBinaryArgs = args[doubleDashInd:]
Expand Down
30 changes: 22 additions & 8 deletions client/cmd/trdl/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,29 +21,35 @@ func updateCmd() *cobra.Command {
var backgroundStderrFile string

cmd := &cobra.Command{
Use: "update REPO GROUP [CHANNEL]",
Use: "update REPO GROUP [CHANNEL] | REPO VERSION",
Aliases: []string{"download"},
Short: "Update the software",
DisableFlagsInUseLine: true,
RunE: func(cmd *cobra.Command, args []string) error {
if err := cobra.RangeArgs(2, 3)(cmd, args); err != nil {
if err := validateVersionArgs(cmd, args); err != nil {
PrintHelp(cmd)
return err
}

repoName := args[0]
group := args[1]

if repoName == trdl.SelfUpdateDefaultRepo {
PrintHelp(cmd)
return fmt.Errorf("reserved repository name %q cannot be used", trdl.SelfUpdateDefaultRepo)
}

isVersion := isVersionArg(args[1])

var group string
var optionalChannel string
if len(args) == 3 {
optionalChannel = args[2]
if err := ValidateChannel(optionalChannel); err != nil {
PrintHelp(cmd)
return err
if !isVersion {
group = args[1]
if len(args) == 3 {
optionalChannel = args[2]
if err := ValidateChannel(optionalChannel); err != nil {
PrintHelp(cmd)
return err
}
}
}

Expand Down Expand Up @@ -80,6 +86,14 @@ func updateCmd() *cobra.Command {
}
}

if isVersion {
if err := c.UpdateRepoToVersion(repoName, args[1], autoclean); err != nil {
return err
}

return nil
}

if err := c.UpdateRepoChannel(repoName, group, optionalChannel, autoclean); err != nil {
return err
}
Expand Down
Loading
Loading