github.com/GoogleContainerTools/skaffold@v1.39.18/pkg/skaffold/schema/v1beta9/upgrade.go (about)

     1  /*
     2  Copyright 2019 The Skaffold Authors
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package v1beta9
    18  
    19  import (
    20  	"context"
    21  	"regexp"
    22  	"strings"
    23  
    24  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/output/log"
    25  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/util"
    26  	next "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/v1beta10"
    27  	pkgutil "github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
    28  )
    29  
    30  const (
    31  	incompatibleSyncWarning = `The semantics of sync has changed, the folder structure is no longer flattened but preserved (see https://skaffold.dev/docs/how-tos/filesync/). The likely impacted patterns in your skaffold yaml are: %s`
    32  )
    33  
    34  var (
    35  	// compatibleSimplePattern have a directory prefix without stars and a basename with at most one star.
    36  	compatibleSimplePattern = regexp.MustCompile(`^([^*]*/)?([^*/]*\*[^*/]*|[^*/]+)$`)
    37  )
    38  
    39  // Upgrade upgrades a configuration to the next version.
    40  // Config changes from v1beta9 to v1beta10
    41  // 1. Additions:
    42  //   - DockerArtifact.NetworkMode
    43  //
    44  // 2. No removals
    45  // 3. Updates:
    46  //   - sync map becomes a list of sync rules
    47  func (c *SkaffoldConfig) Upgrade() (util.VersionedConfig, error) {
    48  	var newConfig next.SkaffoldConfig
    49  	pkgutil.CloneThroughJSON(c, &newConfig)
    50  	newConfig.APIVersion = next.Version
    51  
    52  	err := util.UpgradePipelines(c, &newConfig, upgradeOnePipeline)
    53  	return &newConfig, err
    54  }
    55  
    56  func upgradeOnePipeline(oldPipeline, newPipeline interface{}) error {
    57  	oldBuild := &oldPipeline.(*Pipeline).Build
    58  	newBuild := &newPipeline.(*next.Pipeline).Build
    59  
    60  	// set Sync in newBuild
    61  	newSyncRules := convertSyncRules(oldBuild.Artifacts)
    62  	for i, a := range newBuild.Artifacts {
    63  		if len(newSyncRules[i]) > 0 {
    64  			a.Sync = &next.Sync{
    65  				Manual: newSyncRules[i],
    66  			}
    67  		}
    68  	}
    69  	return nil
    70  }
    71  
    72  // convertSyncRules converts the old sync map into sync rules.
    73  // It also prints a warning message when some rules can not be upgraded.
    74  func convertSyncRules(artifacts []*Artifact) [][]*next.SyncRule {
    75  	var incompatiblePatterns []string
    76  	newSync := make([][]*next.SyncRule, len(artifacts))
    77  	for i, a := range artifacts {
    78  		newRules := make([]*next.SyncRule, 0, len(a.Sync))
    79  		for src, dest := range a.Sync {
    80  			var syncRule *next.SyncRule
    81  			switch {
    82  			case compatibleSimplePattern.MatchString(src):
    83  				dest, strip := simplify(dest, compatibleSimplePattern.FindStringSubmatch(src)[1])
    84  				syncRule = &next.SyncRule{
    85  					Src:   src,
    86  					Dest:  dest,
    87  					Strip: strip,
    88  				}
    89  			case strings.Contains(src, "***"):
    90  				dest, strip := simplify(dest, strings.Split(src, "***")[0])
    91  				syncRule = &next.SyncRule{
    92  					Src:   strings.ReplaceAll(src, "***", "**"),
    93  					Dest:  dest,
    94  					Strip: strip,
    95  				}
    96  			default:
    97  				// Incompatible patterns contain `**` or glob directories.
    98  				// Such patterns flatten the content at the destination which
    99  				// cannot be reproduced with the current config. For example:
   100  				// `/app/**/subdir/*.html`, `/app/*/*.html`
   101  				incompatiblePatterns = append(incompatiblePatterns, src)
   102  				syncRule = &next.SyncRule{
   103  					Src:  src,
   104  					Dest: dest,
   105  				}
   106  			}
   107  			newRules = append(newRules, syncRule)
   108  		}
   109  		newSync[i] = newRules
   110  		// blank input sync because it breaks cloning
   111  		a.Sync = nil
   112  	}
   113  	if len(incompatiblePatterns) > 0 {
   114  		log.Entry(context.TODO()).Warnf(incompatibleSyncWarning, incompatiblePatterns)
   115  	}
   116  	return newSync
   117  }
   118  
   119  // simplify dest and strip, if strip is a suffix of dest modulo a trailing `/`.
   120  func simplify(dest, strip string) (string, string) {
   121  	if strip == "" || strip == "/" || dest == "" {
   122  		return dest, strip
   123  	}
   124  
   125  	simpleStrip := strip
   126  	simpleDest := dest
   127  
   128  	if dest[len(dest)-1] != '/' {
   129  		dest += "/"
   130  	}
   131  
   132  	if strings.HasSuffix(dest, strip) {
   133  		simpleDest = strings.TrimSuffix(dest, strings.TrimPrefix(strip, "/"))
   134  		simpleStrip = ""
   135  		if simpleDest == "" {
   136  			simpleDest = "."
   137  		}
   138  	}
   139  
   140  	return simpleDest, simpleStrip
   141  }