go.fuchsia.dev/jiri@v0.0.0-20240502161911-b66513b29486/cmd/jiri/check_clean.go (about)

     1  // Copyright 2022 The Fuchsia Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package main
     6  
     7  import (
     8  	"fmt"
     9  	"os"
    10  	"path/filepath"
    11  	"sort"
    12  
    13  	"go.fuchsia.dev/jiri"
    14  	"go.fuchsia.dev/jiri/cmdline"
    15  	"go.fuchsia.dev/jiri/gitutil"
    16  	"go.fuchsia.dev/jiri/project"
    17  )
    18  
    19  var cmdCheckClean = &cmdline.Command{
    20  	Runner: jiri.RunnerFunc(runCheckClean),
    21  	Name:   "check-clean",
    22  	Short:  "Checks if the checkout is clean",
    23  	Long: `
    24  Exits non-zero and prints repositories (and their status) if they contain
    25  uncommitted changes.
    26  `,
    27  }
    28  
    29  func runCheckClean(jirix *jiri.X, args []string) error {
    30  	localProjects, err := project.LocalProjects(jirix, project.FastScan)
    31  	if err != nil {
    32  		return err
    33  	}
    34  	cDir, err := os.Getwd()
    35  	if err != nil {
    36  		return err
    37  	}
    38  	states, err := project.GetProjectStates(jirix, localProjects, false)
    39  	if err != nil {
    40  		return err
    41  	}
    42  	var keys project.ProjectKeys
    43  	for key := range localProjects {
    44  		keys = append(keys, key)
    45  	}
    46  	sort.Sort(keys)
    47  	dirtyProjects := make(map[string]string)
    48  	for _, key := range keys {
    49  		localProject := localProjects[key]
    50  		state, ok := states[key]
    51  		if !ok {
    52  			// this should not happen
    53  			panic(fmt.Sprintf("State not found for project %q", localProject.Name))
    54  		}
    55  		if statusFlags.branch != "" && (statusFlags.branch != state.CurrentBranch.Name) {
    56  			continue
    57  		}
    58  		relativePath, err := filepath.Rel(cDir, localProject.Path)
    59  		if err != nil {
    60  			return err
    61  		}
    62  		scm := gitutil.New(jirix, gitutil.RootDirOpt(localProject.Path))
    63  		changes, err := scm.ShortStatus()
    64  		if err != nil {
    65  			jirix.Logger.Errorf("%s :%s\n\n", fmt.Sprintf("getting changes for project %s(%s)", localProject.Name, relativePath), err)
    66  			jirix.IncrementFailures()
    67  			continue
    68  		}
    69  		if changes != "" {
    70  			dirtyProjects[relativePath] = changes
    71  		}
    72  	}
    73  	var finalErr error
    74  	if jirix.Failures() != 0 {
    75  		finalErr = fmt.Errorf("completed with non-fatal errors")
    76  	} else if len(dirtyProjects) > 0 {
    77  		finalErr = fmt.Errorf("Checkout is not clean!")
    78  	}
    79  
    80  	if len(dirtyProjects) > 0 {
    81  		fmt.Println("Dirty projects:")
    82  		for relativePath, changes := range dirtyProjects {
    83  			fmt.Printf("%s\n%s\n\n", relativePath, changes)
    84  		}
    85  	}
    86  
    87  	return finalErr
    88  }