-
Notifications
You must be signed in to change notification settings - Fork 164
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
tools: introduce git-change-exec tool
This new tool detects if in your git tree changed files (compared to master branch and local-only changed files) and uses this information to run only the specified actions. Here it is used to run pillar's go-tests only if something changed there, same for this tool itself and the get-deps tool. Signed-off-by: Christoph Ostarek <[email protected]>
- Loading branch information
1 parent
2cdb98b
commit da15b2f
Showing
13 changed files
with
847 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
# Copyright (c) 2024 Zededa, Inc. | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
--- | ||
default: true | ||
line-length: false | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
git-change-exec |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# Copyright (c) 2024 Zededa, Inc. | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
git-change-exec: main.go actions.go | ||
go build | ||
|
||
.PHONY: clean | ||
|
||
clean: | ||
rm -fv git-change-exec |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# git-change-exec | ||
|
||
This new tool detects if in your git tree files changed | ||
compared to: | ||
|
||
* master branch | ||
* stable branches | ||
|
||
also local-only files are considered. | ||
|
||
Here it is used to run pillar's go-tests only if something | ||
changed there, same for this tool itself and the get-deps tool. | ||
|
||
## Add new Action | ||
|
||
Open `actions.go` add new implementation of `action` `interface` and | ||
add it to the `actions` array. | ||
|
||
Run `git-change-exec -d` to see if your action gets triggered without | ||
running. | ||
|
||
## Example output | ||
|
||
```bash | ||
2024/09/04 09:49:17 --- running gitChangeExecTest ... | ||
=== RUN TestId | ||
--- PASS: TestId (0.00s) | ||
PASS | ||
ok git-change-exec 0.004s | ||
2024/09/04 09:49:20 --- running gitChangeExecTest done | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,206 @@ | ||
// Copyright (c) 2024 Zededa, Inc. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package main | ||
|
||
import ( | ||
"fmt" | ||
"github.com/go-git/go-git/v5/config" | ||
"io" | ||
"log" | ||
"os" | ||
"os/exec" | ||
"path/filepath" | ||
"strings" | ||
"time" | ||
) | ||
|
||
type lintSpdx struct { | ||
extsMap map[string]func(path string) | ||
pathsToFix []string | ||
ownPath string | ||
organization string | ||
} | ||
|
||
func (s *lintSpdx) dontfix(path string) { | ||
log.Printf("Cannot fix %s ...\n", path) | ||
} | ||
|
||
func (s *lintSpdx) copyright(commentIndicator string) []string { | ||
copyrightLines := []string{ | ||
fmt.Sprintf("%s Copyright (c) %d %s, Inc.\n", commentIndicator, time.Now().Year(), s.organization), | ||
fmt.Sprintf("%s SPDX-License-Identifier: Apache-2.0\n\n", commentIndicator), | ||
} | ||
|
||
return copyrightLines | ||
} | ||
|
||
func (s *lintSpdx) yamlfix(path string) { | ||
log.Printf("Fixing %s ...\n", path) | ||
prepend(path, s.copyright("#")) | ||
} | ||
|
||
func (s *lintSpdx) gofix(path string) { | ||
log.Printf("Fixing %s ...\n", path) | ||
prepend(path, s.copyright("//")) | ||
} | ||
|
||
func (s *lintSpdx) dockerfilefix(path string) { | ||
log.Printf("Fixing %s ...\n", path) | ||
prepend(path, s.copyright("#")) | ||
} | ||
|
||
func prepend(path string, license []string) { | ||
backupFh, err := os.CreateTemp("/var/tmp", "git-change-exec-spdx-fix") | ||
if err != nil { | ||
log.Fatalf("could not create temp file: %v", err) | ||
} | ||
backupPath := backupFh.Name() | ||
defer os.Remove(backupPath) | ||
|
||
for _, line := range license { | ||
fmt.Fprint(backupFh, line) | ||
} | ||
|
||
origFh, err := os.Open(path) | ||
if err != nil { | ||
log.Fatalf("could not open original file %s: %v", path, err) | ||
} | ||
|
||
_, err = io.Copy(backupFh, origFh) | ||
if err != nil { | ||
log.Fatalf("could not copy: %v", err) | ||
} | ||
|
||
backupFh.Close() | ||
origFh.Close() | ||
|
||
err = copyFile(backupPath, path) | ||
if err != nil { | ||
log.Fatalf("could not rename %s -> %s: %v", backupPath, path, err) | ||
} | ||
|
||
} | ||
|
||
func readGitConfigOrganization() string { | ||
cfg, err := config.LoadConfig(config.GlobalScope) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
for _, sec := range cfg.Raw.Sections { | ||
if sec.Name != "user" { | ||
continue | ||
} | ||
// codespell:ignore | ||
organizations := sec.OptionAll("organization") | ||
|
||
for _, organization := range organizations { | ||
if organization != "" { | ||
return organization | ||
} | ||
} | ||
} | ||
|
||
return "" | ||
} | ||
|
||
func (s *lintSpdx) init() { | ||
var err error | ||
|
||
s.extsMap = map[string]func(path string){ | ||
".sh": s.dontfix, | ||
".go": s.gofix, | ||
".c": s.dontfix, | ||
".h": s.dontfix, | ||
".py": s.dontfix, | ||
".rs": s.dontfix, | ||
".yaml": s.yamlfix, | ||
".yml": s.yamlfix, | ||
"Dockerfile": s.dockerfilefix, | ||
} | ||
|
||
s.pathsToFix = make([]string, 0) | ||
|
||
s.ownPath, err = os.Executable() | ||
if err != nil { | ||
log.Fatalf("could not determine executable path: %v", err) | ||
} | ||
|
||
s.organization = readGitConfigOrganization() | ||
|
||
} | ||
|
||
func (s *lintSpdx) pathMatch(path string) (func(path string), bool) { | ||
f, found := s.extsMap[filepath.Ext(path)] | ||
if !found { | ||
f, found = s.extsMap[filepath.Base(path)] | ||
} | ||
|
||
return f, found | ||
} | ||
|
||
func (s *lintSpdx) hasSpdx(path string) bool { | ||
scriptPath := filepath.Join(filepath.Dir(s.ownPath), "..", "spdx-check.sh") | ||
|
||
cmd := exec.Command(scriptPath, path) | ||
err := cmd.Run() | ||
|
||
return err == nil | ||
} | ||
|
||
func (s *lintSpdx) match(path string) bool { | ||
if s.extsMap == nil { | ||
s.init() | ||
} | ||
|
||
if strings.Contains(path, "/vendor/") { | ||
return false | ||
} | ||
_, found := s.pathMatch(path) | ||
if !found { | ||
return false | ||
} | ||
if !s.hasSpdx(path) { | ||
s.pathsToFix = append(s.pathsToFix, path) | ||
return true | ||
} | ||
|
||
return false | ||
} | ||
|
||
func (s *lintSpdx) do() error { | ||
if s.organization == "" { | ||
log.Printf("could not read organization from git config, cannot fix copyrights") | ||
return nil | ||
} | ||
|
||
for _, path := range s.pathsToFix { | ||
extFixFunc, found := s.pathMatch(path) | ||
if !found { | ||
continue | ||
} | ||
|
||
extFixFunc(path) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func copyFile(srcPath, dstPath string) error { | ||
src, err := os.Open(srcPath) | ||
if err != nil { | ||
return err | ||
} | ||
defer src.Close() | ||
|
||
dst, err := os.Create(dstPath) | ||
if err != nil { | ||
return err | ||
} | ||
defer dst.Close() | ||
|
||
_, err = io.Copy(dst, src) | ||
|
||
return err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
// Copyright (c) 2024 Zededa, Inc. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package main | ||
|
||
import "strings" | ||
|
||
type pillarTestAction struct{} | ||
|
||
func (b pillarTestAction) match(path string) bool { | ||
return strings.HasPrefix(path, "pkg/pillar") | ||
} | ||
|
||
func (b pillarTestAction) do() error { | ||
return execCmdWithDefaults("make", "-C", "pkg/pillar", "test").Run() | ||
} | ||
|
||
type getDepsTestAction struct{} | ||
|
||
func (g getDepsTestAction) match(path string) bool { | ||
return strings.HasPrefix(path, "tools/get-deps") | ||
|
||
} | ||
func (g getDepsTestAction) do() error { | ||
return execCmdWithDefaults("go", "test", "-C", "tools/get-deps", "-v").Run() | ||
} | ||
|
||
type gitChangeExecTest struct{} | ||
|
||
func (g gitChangeExecTest) match(path string) bool { | ||
return strings.HasPrefix(path, "tools/git-change-exec") | ||
|
||
} | ||
func (g gitChangeExecTest) do() error { | ||
return execCmdWithDefaults("go", "test", "-C", "tools/git-change-exec", "-v").Run() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
// Copyright (c) 2024 Zededa, Inc. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package main | ||
|
||
import ( | ||
"os" | ||
"os/exec" | ||
"reflect" | ||
) | ||
|
||
type action interface { | ||
match(path string) bool | ||
do() error | ||
} | ||
|
||
func id(i any) string { | ||
ty := reflect.TypeOf(i) | ||
if ty.Name() == "" { | ||
ty = reflect.TypeOf(i).Elem() | ||
} | ||
return ty.Name() | ||
} | ||
|
||
func execCmdWithDefaults(name string, args ...string) *exec.Cmd { | ||
cmd := exec.Command(name, args...) | ||
|
||
cmd.Stdout = os.Stdout | ||
cmd.Stderr = os.Stderr | ||
cmd.Stdin = os.Stdin | ||
|
||
return cmd | ||
} | ||
|
||
// Do not forget to add your Action HERE | ||
var actions = map[string][]action{ | ||
"test": []action{ | ||
pillarTestAction{}, | ||
gitChangeExecTest{}, | ||
getDepsTestAction{}, | ||
}, | ||
"lint": []action{ | ||
&lintSpdx{}, | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// Copyright (c) 2024 Zededa, Inc. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package main | ||
|
||
import "testing" | ||
|
||
func TestId(t *testing.T) { | ||
p := pillarTestAction{} | ||
|
||
id := id(p) | ||
if id != "pillarTestAction" { | ||
t.Fatalf("wrong id: %s\n", id) | ||
} | ||
} |
Oops, something went wrong.