Skip to content

Commit 1a36513

Browse files
committed
Merge remote-tracking branch 'origin/main'
2 parents 71b31ac + 8641937 commit 1a36513

File tree

8 files changed

+207
-9
lines changed

8 files changed

+207
-9
lines changed

.github/workflows/test.yml

+11-4
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
1-
name: Test Install Script
1+
name: Test
22

33
on:
44
pull_request:
55
push:
66
branches: [main]
77

88
jobs:
9-
test:
9+
run-tests:
1010
runs-on: ubuntu-latest
11-
1211
steps:
13-
- uses: actions/checkout@v3
12+
- uses: actions/checkout@v4
13+
- uses: actions/setup-go@v5
14+
with:
15+
go-version: "1.23"
16+
- run: make test
1417

18+
install-cli:
19+
runs-on: ubuntu-latest
20+
steps:
21+
- uses: actions/checkout@v4
1522
- run: dash -x install.sh
1623
- run: codecrafters --version

.goreleaser.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ brews:
1717
commit_author:
1818
name: Paul Kuruvilla
1919
20-
homepage: https://codecrafters.io.io
20+
homepage: https://codecrafters.io
2121
description: CodeCrafters CLI
2222
license: MIT
2323
# TODO: Add completions

go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ require (
1313
github.com/mitchellh/go-wordwrap v1.0.1
1414
github.com/otiai10/copy v1.7.0
1515
github.com/rs/zerolog v1.28.0
16+
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06
1617
github.com/stretchr/testify v1.8.1
1718
)
1819

go.sum

+3
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,12 @@ github.com/rohitpaulk/asyncwriter v0.0.2/go.mod h1:y3Ja8mupuzm26lOnNtZ2TpELfHsGV
6868
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
6969
github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY=
7070
github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0=
71+
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 h1:OkMGxebDjyw0ULyrTYWeN0UNCCkmCWfjPnIA2W6oviI=
72+
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06/go.mod h1:+ePHsJ1keEjQtpvf9HHw0f4ZeJ0TLRsxhunSI2hYJSs=
7173
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
7274
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
7375
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
76+
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
7477
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
7578
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
7679
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=

install.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
set -eu
44

55
# allow overriding the version
6-
VERSION=${CODECRAFTERS_CLI_VERSION:-v34}
6+
VERSION=${CODECRAFTERS_CLI_VERSION:-v35}
77

88
PLATFORM=$(uname -s)
99
ARCH=$(uname -m)

internal/commands/test.go

+7-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"context"
55
"errors"
66
"fmt"
7-
"io/ioutil"
87
"os"
98
"os/exec"
109
"strconv"
@@ -122,12 +121,17 @@ func TestCommand(ctx context.Context, shouldTestPrevious bool) (err error) {
122121
}
123122

124123
func copyRepositoryDirToTempDir(repoDir string) (string, error) {
125-
tmpDir, err := ioutil.TempDir("", "codecrafters")
124+
tmpDir, err := os.MkdirTemp("", "codecrafters")
125+
126126
if err != nil {
127127
return "", fmt.Errorf("create temp dir: %w", err)
128128
}
129129

130-
err = cp.Copy(repoDir, tmpDir)
130+
gitIgnore := utils.NewGitIgnore(repoDir)
131+
132+
err = cp.Copy(repoDir, tmpDir, cp.Options{
133+
Skip: gitIgnore.SkipFile,
134+
})
131135
if err != nil {
132136
return "", fmt.Errorf("copy files: %w", err)
133137
}

internal/utils/git_ignore.go

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Package utils
2+
package utils
3+
4+
import (
5+
"os"
6+
"os/exec"
7+
"path/filepath"
8+
"strings"
9+
10+
ignore "github.com/sabhiram/go-gitignore"
11+
)
12+
13+
type GitIgnore struct {
14+
baseDir string
15+
localGitIgnore *ignore.GitIgnore
16+
globalGitIgnore *ignore.GitIgnore
17+
gitInfoExclude *ignore.GitIgnore
18+
}
19+
20+
func NewGitIgnore(baseDir string) GitIgnore {
21+
return GitIgnore{
22+
baseDir: baseDir,
23+
localGitIgnore: compileIgnorer(filepath.Join(baseDir, ".gitignore")),
24+
globalGitIgnore: compileIgnorer(getGlobalGitIgnorePath()),
25+
gitInfoExclude: compileIgnorer(filepath.Join(baseDir, ".git", "info", "exclude")),
26+
}
27+
}
28+
29+
func (i GitIgnore) SkipFile(path string) (bool, error) {
30+
for _, ignorer := range []*ignore.GitIgnore{i.localGitIgnore, i.globalGitIgnore, i.gitInfoExclude} {
31+
if ignorer != nil && ignorer.MatchesPath(path) {
32+
return true, nil
33+
}
34+
}
35+
36+
return false, nil
37+
}
38+
39+
func compileIgnorer(path string) *ignore.GitIgnore {
40+
ignorer, err := ignore.CompileIgnoreFile(path)
41+
if err != nil {
42+
return nil
43+
}
44+
45+
return ignorer
46+
}
47+
48+
func getGlobalGitIgnorePath() string {
49+
output, err := exec.Command("git", "config", "--get", "core.excludesfile").Output()
50+
if err != nil {
51+
return ""
52+
}
53+
54+
path := strings.TrimSpace(string(output))
55+
if strings.HasPrefix(path, "~") {
56+
homeDir, err := os.UserHomeDir()
57+
if err != nil {
58+
return ""
59+
}
60+
path = filepath.Join(homeDir, path[2:])
61+
}
62+
63+
return path
64+
}

internal/utils/git_ignore_test.go

+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
package utils
2+
3+
import (
4+
"os"
5+
"os/exec"
6+
"path/filepath"
7+
"testing"
8+
9+
"github.com/stretchr/testify/assert"
10+
)
11+
12+
func TestGitIgnore(t *testing.T) {
13+
t.Run("without gitignore files", func(t *testing.T) {
14+
gitIgnore := NewGitIgnore(t.TempDir())
15+
assertFileNotSkipped(t, &gitIgnore, "some/random/file.txt")
16+
})
17+
18+
t.Run("with local gitignore", func(t *testing.T) {
19+
tmpRepoDir := t.TempDir()
20+
writeFile(t, filepath.Join(tmpRepoDir, ".gitignore"), "ignore/this/file.txt")
21+
22+
gitIgnore := NewGitIgnore(tmpRepoDir)
23+
assertFileSkipped(t, &gitIgnore, "ignore/this/file.txt")
24+
assertFileNotSkipped(t, &gitIgnore, "some/other/file.txt")
25+
})
26+
27+
t.Run("with global gitignore", func(t *testing.T) {
28+
backup := setupGlobalGitIgnore(t, "ignore/this/file.txt")
29+
defer func() {
30+
if backup.originalPath == "" {
31+
unsetGlobalGitIgnoreConfig(t)
32+
}
33+
backup.Restore(t)
34+
}()
35+
36+
gitIgnore := NewGitIgnore(t.TempDir())
37+
assertFileSkipped(t, &gitIgnore, "ignore/this/file.txt")
38+
assertFileNotSkipped(t, &gitIgnore, "some/other/file.txt")
39+
})
40+
41+
t.Run("with git info exclude", func(t *testing.T) {
42+
tmpRepoDir := createEmptyRepository(t)
43+
backup := setupGitInfoExclude(t, tmpRepoDir, "ignore/this/file.txt")
44+
defer backup.Restore(t)
45+
46+
gitIgnore := NewGitIgnore(tmpRepoDir)
47+
assertFileSkipped(t, &gitIgnore, "ignore/this/file.txt")
48+
assertFileNotSkipped(t, &gitIgnore, "some/other/file.txt")
49+
})
50+
}
51+
52+
func assertFileSkipped(t *testing.T, gitIgnore *GitIgnore, path string) {
53+
skip, err := gitIgnore.SkipFile(path)
54+
assert.NoError(t, err)
55+
assert.True(t, skip)
56+
}
57+
58+
func assertFileNotSkipped(t *testing.T, gitIgnore *GitIgnore, path string) {
59+
skip, err := gitIgnore.SkipFile(path)
60+
assert.NoError(t, err)
61+
assert.False(t, skip)
62+
}
63+
64+
type FileBackup struct {
65+
originalPath string
66+
backupPath string
67+
}
68+
69+
func (b *FileBackup) Restore(t *testing.T) {
70+
if b.originalPath != "" {
71+
moveFile(t, b.backupPath, b.originalPath)
72+
}
73+
}
74+
75+
func setupGlobalGitIgnore(t *testing.T, content string) *FileBackup {
76+
globalGitIgnorePath := getGlobalGitIgnorePath()
77+
backupPath := filepath.Join(t.TempDir(), ".gitignore_global")
78+
79+
if globalGitIgnorePath == "" {
80+
writeFile(t, backupPath, content)
81+
setGlobalGitIgnoreConfig(t, backupPath)
82+
return &FileBackup{originalPath: "", backupPath: backupPath}
83+
}
84+
85+
moveFile(t, globalGitIgnorePath, backupPath)
86+
writeFile(t, globalGitIgnorePath, content)
87+
return &FileBackup{originalPath: globalGitIgnorePath, backupPath: backupPath}
88+
}
89+
90+
func setupGitInfoExclude(t *testing.T, baseDir string, content string) *FileBackup {
91+
gitInfoExcludePath := filepath.Join(baseDir, ".git", "info", "exclude")
92+
_, err := os.Stat(gitInfoExcludePath)
93+
assert.NoError(t, err)
94+
95+
backupPath := filepath.Join(t.TempDir(), ".git_info_exclude_backup")
96+
moveFile(t, gitInfoExcludePath, backupPath)
97+
writeFile(t, gitInfoExcludePath, content)
98+
return &FileBackup{originalPath: gitInfoExcludePath, backupPath: backupPath}
99+
}
100+
101+
func setGlobalGitIgnoreConfig(t *testing.T, path string) {
102+
_, err := exec.Command("git", "config", "--global", "core.excludesfile", path).Output()
103+
assert.NoError(t, err)
104+
}
105+
106+
func unsetGlobalGitIgnoreConfig(t *testing.T) {
107+
_, err := exec.Command("git", "config", "--global", "--unset", "core.excludesfile").Output()
108+
assert.NoError(t, err)
109+
}
110+
111+
func moveFile(t *testing.T, srcPath string, dstPath string) {
112+
err := os.Rename(srcPath, dstPath)
113+
assert.NoError(t, err)
114+
}
115+
116+
func writeFile(t *testing.T, path string, content string) {
117+
err := os.WriteFile(path, []byte(content), 0644)
118+
assert.NoError(t, err)
119+
}

0 commit comments

Comments
 (0)