Skip to content
Merged
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
53 changes: 53 additions & 0 deletions cmd/root_cmd/push.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package root_cmd

import (
"bufio"
"context"
"fmt"
"os"
"strconv"
"strings"

Expand All @@ -16,6 +18,7 @@ import (
"github.com/tensorleap/leap-cli/pkg/secret"
"github.com/tensorleap/leap-cli/pkg/tensorleapapi"
"github.com/tensorleap/leap-cli/pkg/workspace"
"golang.org/x/term"
)

type pushInputs struct {
Expand All @@ -36,6 +39,9 @@ type pushInputs struct {
// when evaluating. Only meaningful alongside --eval / -u, since those
// are the paths that dispatch an evaluate job.
noVisualization bool
// yes acknowledges pre-push warnings (e.g. the latest version having
// insight-settings overrides) without prompting.
yes bool
}

type pushState struct {
Expand Down Expand Up @@ -102,6 +108,7 @@ Examples:
_ = cmd.Flags().MarkDeprecated("overwrite-version", "use --overwrite (-o) instead")
cmd.Flags().StringSliceVarP(&in.updateParts, "update", "u", nil, "What changed in the code on overwrite (repeatable; implies --eval; skips the prompt). Values: metadata, metric, metric_direction, insights, visualization (viz). metadata+metric trigger a full re-evaluation.")
cmd.Flags().BoolVar(&in.noVisualization, "novis", false, "Skip the visualize_samples step on the subsequent evaluate (requires --eval / -u)")
cmd.Flags().BoolVar(&in.yes, "yes", false, "Acknowledge pre-push warnings and proceed without prompting")
return cmd
}

Expand All @@ -122,6 +129,10 @@ func runPush(cmdCtx context.Context, in *pushInputs) error {

analytics.SendEvent(analytics.EventCliProjectsPushStarted, s.properties)

if err := s.confirmInsightsSettingsOverrides(); err != nil {
return err
}

if err := s.resolveOverwriteTarget(); err != nil {
return err
}
Expand Down Expand Up @@ -337,6 +348,48 @@ func (s *pushState) resolveOverwriteTarget() error {
return nil
}

// confirmInsightsSettingsOverrides warns when the project's latest version has
// insight-settings overrides — these are per-version and won't carry over to
// the version being pushed — and requires the user to acknowledge before the
// push proceeds (interactively, or via --yes).
func (s *pushState) confirmInsightsSettingsOverrides() error {
latest, err := model.GetLatestProjectVersion(s.ctx, s.projectId())
if err != nil {
return s.fail("check_insights_overrides", err)
}
if latest == nil {
return nil
}

overrides, err := model.GetInsightsSettingsOverrides(s.ctx, s.projectId(), latest.Cid)
if err != nil {
return s.fail("check_insights_overrides", err)
}
if !model.HasAnyInsightsOverride(overrides) {
return nil
}

versionLabel := latest.Notes
if versionLabel == "" {
versionLabel = latest.Cid
}

log.Warnf("The latest version %q has customized insight settings which will not be applied to the version you're about to push.\nIf you wish to carry over these settings, please apply them to the code integration first and then re-run `leap push`.", versionLabel)
if s.inputs.yes {
log.Info("Proceeding — insight-settings override warning acknowledged via --yes.")
return nil
}
if !term.IsTerminal(int(os.Stdin.Fd())) {
return fmt.Errorf("the latest version has insight settings overrides that won't carry over to the new version; re-run with --yes to acknowledge and proceed")
}

fmt.Print("\nPress enter to continue with the push, or Ctrl+C to cancel: ")
if _, err := bufio.NewReader(os.Stdin).ReadString('\n'); err != nil {
return err
}
return nil
}

func (s *pushState) needsNewModel() bool {
if !s.isOverwrite {
return true
Expand Down
52 changes: 52 additions & 0 deletions pkg/model/insights.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package model

import (
"context"
"fmt"

"github.com/tensorleap/leap-cli/pkg/api"
"github.com/tensorleap/leap-cli/pkg/tensorleapapi"
)

// GetLatestProjectVersion returns the most recently created version of the
// project (by CreatedAt), or nil if the project has no versions yet.
func GetLatestProjectVersion(ctx context.Context, projectId string) (*tensorleapapi.SlimVersion, error) {
versions, err := GetVersions(ctx, projectId)
if err != nil {
return nil, err
}
var latest *tensorleapapi.SlimVersion
for i := range versions {
v := &versions[i]
if latest == nil || v.CreatedAt.After(latest.CreatedAt) {
latest = v
}
}
return latest, nil
}

// GetInsightsSettingsOverrides fetches the per-version insight-settings
// overrides for a version. An error (including a missing endpoint) is returned
// to the caller rather than swallowed.
func GetInsightsSettingsOverrides(ctx context.Context, projectId, versionId string) (*tensorleapapi.InsightsSettingsOverrides, error) {
resp, httpRes, err := api.ApiClient.GetInsightsSettings(ctx).
GetInsightsSettingsParams(*tensorleapapi.NewGetInsightsSettingsParams(projectId, versionId)).
Execute()
if err := api.CheckRes(httpRes, err); err != nil {
return nil, fmt.Errorf("failed to fetch insight settings: %w", err)
}
return &resp.Overrides, nil
}

// HasAnyInsightsOverride reports whether any insight setting has been
// customized away from its default.
func HasAnyInsightsOverride(o *tensorleapapi.InsightsSettingsOverrides) bool {
if o == nil {
return false
}
return len(o.MetricActiveOverrides) > 0 ||
len(o.MetricDirectionOverrides) > 0 ||
len(o.IgnoredDomains) > 0 ||
len(o.AddedDomains) > 0 ||
len(o.LatentSpaceIgnoreOverrides) > 0
}
50 changes: 50 additions & 0 deletions pkg/model/insights_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package model

import (
"testing"

"github.com/tensorleap/leap-cli/pkg/tensorleapapi"
)

func TestHasAnyInsightsOverride(t *testing.T) {
cases := []struct {
name string
o *tensorleapapi.InsightsSettingsOverrides
want bool
}{
{"nil", nil, false},
{"empty", &tensorleapapi.InsightsSettingsOverrides{}, false},
{
"metric active",
&tensorleapapi.InsightsSettingsOverrides{MetricActiveOverrides: map[string]interface{}{"m": false}},
true,
},
{
"metric direction",
&tensorleapapi.InsightsSettingsOverrides{MetricDirectionOverrides: map[string]interface{}{"m": "Upward"}},
true,
},
{
"ignored domains",
&tensorleapapi.InsightsSettingsOverrides{IgnoredDomains: []string{"metadata.x"}},
true,
},
{
"added domains",
&tensorleapapi.InsightsSettingsOverrides{AddedDomains: []string{"metadata.y"}},
true,
},
{
"latent space ignore",
&tensorleapapi.InsightsSettingsOverrides{LatentSpaceIgnoreOverrides: map[string]interface{}{"balanced": false}},
true,
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
if got := HasAnyInsightsOverride(c.o); got != c.want {
t.Fatalf("HasAnyInsightsOverride(%s) = %v, want %v", c.name, got, c.want)
}
})
}
}
16 changes: 16 additions & 0 deletions pkg/tensorleapapi/.openapi-generator/FILES
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ docs/GetGenericBaseImageTypesResponse.md
docs/GetImportModelUploadUrlParams.md
docs/GetInsightsParams.md
docs/GetInsightsResponse.md
docs/GetInsightsSettingsParams.md
docs/GetInsightsSettingsResponse.md
docs/GetIssueFileUploadSignedUrl.md
docs/GetJobLogsParams.md
docs/GetJobLogsResponse.md
Expand Down Expand Up @@ -286,6 +288,8 @@ docs/InsightMetricInfo.md
docs/InsightStatus.md
docs/InsightType.md
docs/InsightsJobParams.md
docs/InsightsSettingsDefaults.md
docs/InsightsSettingsOverrides.md
docs/Issue.md
docs/IssueAction.md
docs/IssueActionType.md
Expand All @@ -311,6 +315,7 @@ docs/JobType.md
docs/JobTypeEnum.md
docs/LabelingAlgorithm.md
docs/LabelingJobParams.md
docs/LatentSpaceDefault.md
docs/LatestExportedProject.md
docs/LatestExportedProjectItem.md
docs/Layout.md
Expand All @@ -334,6 +339,8 @@ docs/MaskTextData.md
docs/MessageLevel.md
docs/MetadataField.md
docs/MetadataFieldValue.md
docs/MetricDefault.md
docs/MetricDirection.md
docs/MetricInstance.md
docs/MetricMessageParams.md
docs/MetricStatisticElement.md
Expand Down Expand Up @@ -408,6 +415,7 @@ docs/SampleSelectionInfo.md
docs/SampleVisualizationInfo.md
docs/SamplesVisualizationsRefreshParams.md
docs/SaveAnalyzerLayoutParams.md
docs/SaveInsightsSettingsParams.md
docs/ScatterFilter.md
docs/ScatterFilterValue.md
docs/ScatterInsightBase.md
Expand Down Expand Up @@ -710,6 +718,8 @@ model_get_generic_base_image_types_response.go
model_get_import_model_upload_url_params.go
model_get_insights_params.go
model_get_insights_response.go
model_get_insights_settings_params.go
model_get_insights_settings_response.go
model_get_issue_file_upload_signed_url.go
model_get_job_logs_params.go
model_get_job_logs_response.go
Expand Down Expand Up @@ -799,6 +809,8 @@ model_insight_metric_info.go
model_insight_status.go
model_insight_type.go
model_insights_job_params.go
model_insights_settings_defaults.go
model_insights_settings_overrides.go
model_issue.go
model_issue_action.go
model_issue_action_type.go
Expand All @@ -824,6 +836,7 @@ model_job_type.go
model_job_type_enum.go
model_labeling_algorithm.go
model_labeling_job_params.go
model_latent_space_default.go
model_latest_exported_project.go
model_latest_exported_project_item.go
model_layout.go
Expand All @@ -847,6 +860,8 @@ model_mask_text_data.go
model_message_level.go
model_metadata_field.go
model_metadata_field_value.go
model_metric_default.go
model_metric_direction.go
model_metric_instance.go
model_metric_message_params.go
model_metric_statistic_element.go
Expand Down Expand Up @@ -921,6 +936,7 @@ model_sample_selection_info.go
model_sample_visualization_info.go
model_samples_visualizations_refresh_params.go
model_save_analyzer_layout_params.go
model_save_insights_settings_params.go
model_scatter_filter.go
model_scatter_filter_value.go
model_scatter_insight_base.go
Expand Down
12 changes: 11 additions & 1 deletion pkg/tensorleapapi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ No description provided (generated by Openapi Generator https://github.com/opena
## Overview
This API client was generated by the [OpenAPI Generator](https://openapi-generator.tech) project. By using the [OpenAPI-spec](https://www.openapis.org/) from a remote server, you can easily generate an API client.

- API version: 11.0.94
- API version: 11.0.95
- Package version: 1.0.0
- Generator version: 7.14.0
- Build package: org.openapitools.codegen.languages.GoClientCodegen
Expand Down Expand Up @@ -152,6 +152,7 @@ Class | Method | HTTP request | Description
*DefaultAPI* | [**GetHeatmapChart**](docs/DefaultAPI.md#getheatmapchart) | **Post** /sessionmetrics/getHeatmapChart |
*DefaultAPI* | [**GetImportModelUploadUrl**](docs/DefaultAPI.md#getimportmodeluploadurl) | **Post** /versions/getImportModelUploadUrl |
*DefaultAPI* | [**GetInsights**](docs/DefaultAPI.md#getinsights) | **Post** /insights/getInsights |
*DefaultAPI* | [**GetInsightsSettings**](docs/DefaultAPI.md#getinsightssettings) | **Post** /insightsSettings/getInsightsSettings |
*DefaultAPI* | [**GetIssueFileUploadSignedUrl**](docs/DefaultAPI.md#getissuefileuploadsignedurl) | **Post** /issues/getIssueFileUploadSignedUrl |
*DefaultAPI* | [**GetJobLogs**](docs/DefaultAPI.md#getjoblogs) | **Post** /jobs/getJobLogs |
*DefaultAPI* | [**GetLatestExportedProject**](docs/DefaultAPI.md#getlatestexportedproject) | **Post** /projects/getLatestExportedProject |
Expand Down Expand Up @@ -221,6 +222,7 @@ Class | Method | HTTP request | Description
*DefaultAPI* | [**SampleAnalysis**](docs/DefaultAPI.md#sampleanalysis) | **Post** /visualizations/sampleAnalysis |
*DefaultAPI* | [**SamplesVisualizationsRefresh**](docs/DefaultAPI.md#samplesvisualizationsrefresh) | **Post** /visualizations/samplesVisualizationsRefresh |
*DefaultAPI* | [**SaveAnalyzerLayout**](docs/DefaultAPI.md#saveanalyzerlayout) | **Post** /visualizations/saveAnalyzerLayout |
*DefaultAPI* | [**SaveInsightsSettings**](docs/DefaultAPI.md#saveinsightssettings) | **Post** /insightsSettings/saveInsightsSettings |
*DefaultAPI* | [**SendUserMessage**](docs/DefaultAPI.md#sendusermessage) | **Post** /users/sendUserMessage |
*DefaultAPI* | [**SetActiveVersion**](docs/DefaultAPI.md#setactiveversion) | **Post** /versions/setActiveVersion |
*DefaultAPI* | [**SetCodeChallenge**](docs/DefaultAPI.md#setcodechallenge) | **Post** /auth/setCodeChallenge |
Expand Down Expand Up @@ -450,6 +452,8 @@ Class | Method | HTTP request | Description
- [GetImportModelUploadUrlParams](docs/GetImportModelUploadUrlParams.md)
- [GetInsightsParams](docs/GetInsightsParams.md)
- [GetInsightsResponse](docs/GetInsightsResponse.md)
- [GetInsightsSettingsParams](docs/GetInsightsSettingsParams.md)
- [GetInsightsSettingsResponse](docs/GetInsightsSettingsResponse.md)
- [GetIssueFileUploadSignedUrl](docs/GetIssueFileUploadSignedUrl.md)
- [GetJobLogsParams](docs/GetJobLogsParams.md)
- [GetJobLogsResponse](docs/GetJobLogsResponse.md)
Expand Down Expand Up @@ -539,6 +543,8 @@ Class | Method | HTTP request | Description
- [InsightStatus](docs/InsightStatus.md)
- [InsightType](docs/InsightType.md)
- [InsightsJobParams](docs/InsightsJobParams.md)
- [InsightsSettingsDefaults](docs/InsightsSettingsDefaults.md)
- [InsightsSettingsOverrides](docs/InsightsSettingsOverrides.md)
- [Issue](docs/Issue.md)
- [IssueAction](docs/IssueAction.md)
- [IssueActionType](docs/IssueActionType.md)
Expand All @@ -564,6 +570,7 @@ Class | Method | HTTP request | Description
- [JobTypeEnum](docs/JobTypeEnum.md)
- [LabelingAlgorithm](docs/LabelingAlgorithm.md)
- [LabelingJobParams](docs/LabelingJobParams.md)
- [LatentSpaceDefault](docs/LatentSpaceDefault.md)
- [LatestExportedProject](docs/LatestExportedProject.md)
- [LatestExportedProjectItem](docs/LatestExportedProjectItem.md)
- [Layout](docs/Layout.md)
Expand All @@ -587,6 +594,8 @@ Class | Method | HTTP request | Description
- [MessageLevel](docs/MessageLevel.md)
- [MetadataField](docs/MetadataField.md)
- [MetadataFieldValue](docs/MetadataFieldValue.md)
- [MetricDefault](docs/MetricDefault.md)
- [MetricDirection](docs/MetricDirection.md)
- [MetricInstance](docs/MetricInstance.md)
- [MetricMessageParams](docs/MetricMessageParams.md)
- [MetricStatisticElement](docs/MetricStatisticElement.md)
Expand Down Expand Up @@ -661,6 +670,7 @@ Class | Method | HTTP request | Description
- [SampleVisualizationInfo](docs/SampleVisualizationInfo.md)
- [SamplesVisualizationsRefreshParams](docs/SamplesVisualizationsRefreshParams.md)
- [SaveAnalyzerLayoutParams](docs/SaveAnalyzerLayoutParams.md)
- [SaveInsightsSettingsParams](docs/SaveInsightsSettingsParams.md)
- [ScatterFilter](docs/ScatterFilter.md)
- [ScatterFilterValue](docs/ScatterFilterValue.md)
- [ScatterInsightBase](docs/ScatterInsightBase.md)
Expand Down
Loading
Loading