Sfoglia il codice sorgente

Add the defense against huge renames

Signed-off-by: Vadim Markovtsev <vadim@sourced.tech>
Vadim Markovtsev 6 anni fa
parent
commit
06ba0c3c77

+ 1 - 1
internal/core/pipeline.go

@@ -636,7 +636,7 @@ func (pipeline *Pipeline) Initialize(facts map[string]interface{}) error {
 			log.Panicf("failed to list the commits: %v", err)
 		}
 	}
-	pipeline.PrintActions = facts[ConfigPipelinePrintActions].(bool)
+	pipeline.PrintActions, _ = facts[ConfigPipelinePrintActions].(bool)
 	if val, exists := facts[ConfigPipelineHibernationDistance].(int); exists {
 		if val < 0 {
 			log.Panicf("--hibernation-distance cannot be negative (got %d)", val)

+ 2 - 1
internal/core/registry_test.go

@@ -138,7 +138,7 @@ func TestRegistryAddFlags(t *testing.T) {
 		Run:   func(cmd *cobra.Command, args []string) {},
 	}
 	facts, deployed := reg.AddFlags(testCmd.Flags())
-	assert.Len(t, facts, 6)
+	assert.Len(t, facts, 7)
 	assert.IsType(t, 0, facts[(&testPipelineItem{}).ListConfigurationOptions()[0].Name])
 	assert.IsType(t, true, facts[(&dummyPipelineItem{}).ListConfigurationOptions()[0].Name])
 	assert.Contains(t, facts, ConfigPipelineDryRun)
@@ -153,6 +153,7 @@ func TestRegistryAddFlags(t *testing.T) {
 	assert.NotNil(t, testCmd.Flags().Lookup("dump-plan"))
 	assert.NotNil(t, testCmd.Flags().Lookup("dry-run"))
 	assert.NotNil(t, testCmd.Flags().Lookup("hibernation-distance"))
+	assert.NotNil(t, testCmd.Flags().Lookup("print-actions"))
 	assert.NotNil(t, testCmd.Flags().Lookup(
 		(&testPipelineItem{}).ListConfigurationOptions()[0].Flag))
 	assert.NotNil(t, testCmd.Flags().Lookup(

+ 10 - 2
internal/plumbing/renames.go

@@ -44,6 +44,10 @@ const (
 
 	// RenameAnalysisMaxCandidates is the maximum number of rename candidates to consider per file.
 	RenameAnalysisMaxCandidates = 50
+
+	// RenameAnalysisSetSizeLimit is the maximum number of added + removed files for
+	// RenameAnalysisMaxCandidates to be active; the bigger numbers set it to 1.
+	RenameAnalysisSetSizeLimit = 1000
 )
 
 // Name of this PipelineItem. Uniquely identifies the type, used for mapping keys, etc.
@@ -163,6 +167,10 @@ func (ra *RenameAnalysis) Consume(deps map[string]interface{}) (map[string]inter
 	// Stage 2 - apply the similarity threshold
 	// n^2 but actually linear
 	// We sort the blobs by size and do the single linear scan.
+	maxCandidates := RenameAnalysisMaxCandidates
+	if len(stillAdded)+len(stillDeleted) > RenameAnalysisSetSizeLimit {
+		maxCandidates = 1
+	}
 	addedBlobs := make(sortableBlobs, 0, stillAdded.Len())
 	deletedBlobs := make(sortableBlobs, 0, stillDeleted.Len())
 	var smallChanges []*object.Change
@@ -226,7 +234,7 @@ func (ra *RenameAnalysis) Consume(deps map[string]interface{}) (map[string]inter
 				if finished {
 					return nil
 				}
-				if ci > RenameAnalysisMaxCandidates {
+				if ci > maxCandidates {
 					break
 				}
 				blobsAreClose, err := ra.blobsAreClose(
@@ -281,7 +289,7 @@ func (ra *RenameAnalysis) Consume(deps map[string]interface{}) (map[string]inter
 				if finished {
 					return nil
 				}
-				if ci > RenameAnalysisMaxCandidates {
+				if ci > maxCandidates {
 					break
 				}
 				blobsAreClose, err := ra.blobsAreClose(