Skip to content

Commit

Permalink
feature: delete test runs
Browse files Browse the repository at this point in the history
Add `delete` command to test run. It helps to delete specified test runs or all test runs from the project.
  • Loading branch information
gibiw committed Sep 24, 2024
1 parent 51e14af commit a5002ab
Show file tree
Hide file tree
Showing 8 changed files with 437 additions and 0 deletions.
79 changes: 79 additions & 0 deletions cmd/testops/run/delete/delete.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package delete

import (
"fmt"
"github.com/qase-tms/qasectl/cmd/flags"
"github.com/qase-tms/qasectl/internal/client"
"github.com/qase-tms/qasectl/internal/service/run"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"log/slog"
"time"
)

const (
idsFlag = "ids"
allFlag = "all"
startTimeFlag = "start"
endTimeFlag = "end"
)

// Command returns a new cobra command for delete runs
func Command() *cobra.Command {
var (
ids []int64
all bool
startTime string
endTime string
)

cmd := &cobra.Command{
Use: "delete",
Short: "Delete test runs",
Example: "qli testops run delete --ids 1,2,3 --start 2024-01-02 --end 2024-12-31 --project 'PRJ' --token 'TOKEN'",
RunE: func(cmd *cobra.Command, args []string) error {
token := viper.GetString(flags.TokenFlag)
project := viper.GetString(flags.ProjectFlag)

var start, end int64 = 0, 0

if startTime != "" {
t, err := time.Parse(time.DateOnly, startTime)
if err != nil {
return fmt.Errorf("failed to parse start time: %w", err)
}
start = t.Unix()
}

if endTime != "" {
t, err := time.Parse(time.DateOnly, endTime)
if err != nil {
return fmt.Errorf("failed to parse end time: %w", err)
}
end = t.Unix()
}

c := client.NewClientV1(token)
s := run.NewService(c)

err := s.DeleteRun(cmd.Context(), project, ids, all, start, end)
if err != nil {
return fmt.Errorf("failed to delete test runs: %w", err)
}

slog.Info("Test runs deleted")

return nil
},
}

cmd.Flags().Int64SliceVar(&ids, idsFlag, []int64{}, "IDs of test runs to delete. format: --ids 1,2,3")
cmd.Flags().BoolVar(&all, allFlag, false, "delete all test runs in the project")
cmd.MarkFlagsOneRequired(idsFlag, allFlag)
cmd.MarkFlagsMutuallyExclusive(idsFlag, allFlag)

cmd.Flags().StringVarP(&startTime, startTimeFlag, "s", "", "start date of the test runs. Format: YYYY-MM-DD")
cmd.Flags().StringVarP(&endTime, endTimeFlag, "e", "", "end date of the test runs. Format: YYYY-MM-DD")

return cmd
}
2 changes: 2 additions & 0 deletions cmd/testops/run/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package run
import (
"github.com/qase-tms/qasectl/cmd/testops/run/complete"
"github.com/qase-tms/qasectl/cmd/testops/run/create"
"github.com/qase-tms/qasectl/cmd/testops/run/delete"
"github.com/spf13/cobra"
)

Expand All @@ -16,6 +17,7 @@ func Command() *cobra.Command {

cmd.AddCommand(create.Command())
cmd.AddCommand(complete.Command())
cmd.AddCommand(delete.Command())

return cmd
}
40 changes: 40 additions & 0 deletions docs/command.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,46 @@ The following example shows how to complete a test run with the ID `1` in the pr
qli testops run complete --project PROJ --token <token> --id 1 --verbose
```

# Delete test runs

You can delete test runs by using the `delete` command. The `delete` command is used to delete test runs in the
specified project.

## Example usage:

```bash
qli testops run delete --project <project_code> --token <token> --ids <run_id> --verbose
```

The `delete` command has the following options:

- `--project`, `-p`: The project code where the test runs will be deleted. Required.
- `--token`, `-t`: The API token to authenticate with the TestOps API. Required.
- `--ids`: The IDs of the test runs to delete. Optional if all doesn't set.
- `--all`: Delete all test runs in the project. Optional if ids doesn't set.
- `--start`, `-s`: The start date of the test runs to delete. Optional.
- `--end`, `-e`: The end date of the test runs to delete. Optional.
- `--verbose`, `-v`: Enable verbose mode. Optional.

The following example shows how to delete a test run with the ID `1` in the project with the code `PROJ`:

```bash
qli testops run delete --project PROJ --token <token> --ids 1 --verbose
```

The following example shows how to delete all test runs in the project with the code `PROJ`:

```bash
qli testops run delete --project PROJ --token <token> --all --verbose
```

The following example shows how to delete all test runs in the project with the code `PROJ` that were created between
`2022-01-01` and `2022-12-31`:

```bash
qli testops run delete --project PROJ --token <token> --all --start "2022-01-01" --end "2022-12-31" --verbose
```

# Upload test results

You can upload test results by using the `upload` command. The `upload` command is used to upload test results for a
Expand Down
70 changes: 70 additions & 0 deletions internal/client/clientv1.go
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,76 @@ func (c *ClientV1) UploadData(ctx context.Context, project string, runID int64,
return nil
}

// GetTestRuns returns test runs
func (c *ClientV1) GetTestRuns(ctx context.Context, projectCode string, start, end int64) ([]run.Run, error) {
const op = "client.clientv1.gettestruns"
logger := slog.With("op", op)

logger.Debug("getting test runs", "projectCode", projectCode)

ctx, client := c.getApiV1Client(ctx)

testRuns := make([]run.Run, 0)

var offset int32 = 0
for {
req := client.RunsAPI.
GetRuns(ctx, projectCode).
Limit(defaultLimit).
Offset(offset)

if start != 0 {
req = req.FromStartTime(start)
}

if end != 0 {
req = req.ToStartTime(end)
}

resp, r, err := req.Execute()

if err != nil {
return nil, NewQaseApiError(err.Error(), r.Body)
}

for _, testRun := range resp.Result.Entities {
testRuns = append(testRuns, run.Run{
ID: testRun.GetId(),
})
}

if resp.Result.GetFiltered() <= offset {
break
} else {
offset += defaultLimit
}
}

logger.Debug("got test runs", "testRuns", testRuns)

return testRuns, nil
}

// DeleteTestRun deletes test run
func (c *ClientV1) DeleteTestRun(ctx context.Context, projectCode string, id int64) error {
const op = "client.clientv1.deletetestrun"
logger := slog.With("op", op)

logger.Debug("deleting test run", "projectCode", projectCode, "id", id)

ctx, client := c.getApiV1Client(ctx)

_, r, err := client.RunsAPI.
DeleteRun(ctx, projectCode, int32(id)).
Execute()

if err != nil {
return NewQaseApiError(err.Error(), r.Body)
}

return nil
}

// uploadAttachment uploads attachments to Qase
func (c *ClientV1) uploadAttachment(ctx context.Context, projectCode string, file []*os.File) (string, error) {
const op = "client.clientv1.uploadattachment"
Expand Down
4 changes: 4 additions & 0 deletions internal/models/run/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@ type Plan struct {
Title string `json:"title"`
ID int64 `json:"id"`
}

type Run struct {
ID int64 `json:"id"`
}
31 changes: 31 additions & 0 deletions internal/service/run/mocks/run.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

42 changes: 42 additions & 0 deletions internal/service/run/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package run

import (
"context"
"fmt"
"github.com/qase-tms/qasectl/internal/models/run"
)

// client is a client for run
Expand All @@ -10,6 +12,8 @@ import (
type client interface {
CreateRun(ctx context.Context, projectCode, title string, description, envSlug string, mileID, planID int64) (int64, error)
CompleteRun(ctx context.Context, projectCode string, runId int64) error
GetTestRuns(ctx context.Context, projectCode string, start, end int64) ([]run.Run, error)
DeleteTestRun(ctx context.Context, projectCode string, id int64) error
}

// Service is a Service for run
Expand All @@ -31,3 +35,41 @@ func (s *Service) CreateRun(ctx context.Context, pc, t, d, e string, m, plan int
func (s *Service) CompleteRun(ctx context.Context, projectCode string, runId int64) error {
return s.client.CompleteRun(ctx, projectCode, runId)
}

func (s *Service) DeleteRun(ctx context.Context, projectCode string, ids []int64, all bool, start, end int64) error {
if len(ids) == 0 && !all {
return fmt.Errorf("no ids provided")
}

foundIDs, err := s.client.GetTestRuns(ctx, projectCode, start, end)
if err != nil {
return fmt.Errorf("failed to get test runs: %w", err)
}

delIDs := make([]int64, 0)

if len(ids) > 0 {
for _, v := range foundIDs {
for _, id := range ids {
if v.ID == id {
delIDs = append(delIDs, id)
}
}
}
}

if all {
for _, v := range foundIDs {
delIDs = append(delIDs, v.ID)
}
}

for _, id := range delIDs {
err := s.client.DeleteTestRun(ctx, projectCode, id)
if err != nil {
return fmt.Errorf("failed to delete run with id %d: %w", id, err)
}
}

return nil
}
Loading

0 comments on commit a5002ab

Please sign in to comment.