<commit_before>package cmd

import (
	"fmt"
	"log"
	"time"

	"github.com/spf13/cobra"
	"github.com/stormforger/cli/api/testrun"
)

var (
	// testRunWatchCmd represents the test run watch command
	testRunWatchCmd = &cobra.Command{
		Use:   "watch <test-run-id>",
		Short: "Wait and watch for a active test run",
		Long: `Wait and watch for a active test run

watch will continue to look for the active test run until it reaches
a final state (like "done" or "aborted").

It will exit with 0 on success; 1 on test run errors (like "aborted")
and 2 if the given timeout was exceeded.`,
		Run: testRunWatch,
		PersistentPreRun: func(cmd *cobra.Command, args []string) {
			if len(args) != 1 {
				log.Fatal("Expect exactly one argument: test run reference!")
			}
		},
	}

	testRunWatchOpts struct {
		MaxWatchTime time.Duration
	}
)

var successStates = []string{
	"launching",
	"deploying",
	"starting",
	"running",
	"fetching_logs",
	"log_fetched",
	"analysing",
	"done",
}

func init() {
	TestRunCmd.AddCommand(testRunWatchCmd)

	testRunWatchCmd.Flags().DurationVar(&testRunWatchOpts.MaxWatchTime, "timeout", 0, "Maximum duration in seconds to watch")
}

func testRunWatch(cmd *cobra.Command, args []string) {
	client := NewClient()

	testRunUID := getTestRunUID(*client, args[0])

	watchTestRun(testRunUID, testRunWatchOpts.MaxWatchTime.Round(time.Second).Seconds(), rootOpts.OutputFormat)

	result := fetchTestRun(*client, testRunUID)

	if rootOpts.OutputFormat == "json" {
		fmt.Println(string(result))
	}
}

func testRunOkay(testRun *testrun.TestRun) bool {
	return stringInSlice(testRun.State, successStates)
}

func testRunSuccess(testRun *testrun.TestRun) bool {
	successStates := []string{
		"done",
	}

	return stringInSlice(testRun.State, successStates)
}
<commit_msg>feat: treat finished as a successful test-run outcome and do not fail the cli<commit_after>package cmd

import (
	"fmt"
	"log"
	"time"

	"github.com/spf13/cobra"
	"github.com/stormforger/cli/api/testrun"
)

var (
	// testRunWatchCmd represents the test run watch command
	testRunWatchCmd = &cobra.Command{
		Use:   "watch <test-run-id>",
		Short: "Wait and watch for a active test run",
		Long: `Wait and watch for a active test run

watch will continue to look for the active test run until it reaches
a final state (like "done" or "aborted").

It will exit with 0 on success; 1 on test run errors (like "aborted")
and 2 if the given timeout was exceeded.`,
		Run: testRunWatch,
		PersistentPreRun: func(cmd *cobra.Command, args []string) {
			if len(args) != 1 {
				log.Fatal("Expect exactly one argument: test run reference!")
			}
		},
	}

	testRunWatchOpts struct {
		MaxWatchTime time.Duration
	}
)

var successStates = []string{
	"analysing",
	"deploying",
	"done",
	"fetching_logs",
	"finished",
	"launching",
	"log_fetched",
	"running",
	"starting",
}

func init() {
	TestRunCmd.AddCommand(testRunWatchCmd)

	testRunWatchCmd.Flags().DurationVar(&testRunWatchOpts.MaxWatchTime, "timeout", 0, "Maximum duration in seconds to watch")
}

func testRunWatch(cmd *cobra.Command, args []string) {
	client := NewClient()

	testRunUID := getTestRunUID(*client, args[0])

	watchTestRun(testRunUID, testRunWatchOpts.MaxWatchTime.Round(time.Second).Seconds(), rootOpts.OutputFormat)

	result := fetchTestRun(*client, testRunUID)

	if rootOpts.OutputFormat == "json" {
		fmt.Println(string(result))
	}
}

func testRunOkay(testRun *testrun.TestRun) bool {
	return stringInSlice(testRun.State, successStates)
}

func testRunSuccess(testRun *testrun.TestRun) bool {
	successStates := []string{
		"done",
	}

	return stringInSlice(testRun.State, successStates)
}

{'fraction_non_alphanumeric': 0.12358932012111203, 'fraction_numerical': 0.004404073768235618, 'mean_word_length': 4.7958532695374805, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5859613', 'n_tokens_mistral': 1311, 'n_tokens_neox': 1246, 'n_words': 338}