Skip to content

Commit 9e85356

Browse files
authored
Merge pull request #131 from buildkite-plugins/fix/handle_emojis_SUP-5786
Fix unicode handling in git diff output
2 parents 46011f7 + e89ae36 commit 9e85356

2 files changed

Lines changed: 48 additions & 1 deletion

File tree

pipeline.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"os"
66
"reflect"
7+
"strconv"
78
"strings"
89

910
"github.com/bmatcuk/doublestar/v4"
@@ -104,7 +105,25 @@ func diff(command string) ([]string, error) {
104105
return nil, fmt.Errorf("diff command failed: %v", err)
105106
}
106107

107-
return strings.Fields(strings.TrimSpace(output)), nil
108+
fields := strings.Fields(strings.TrimSpace(output))
109+
paths := make([]string, 0, len(fields))
110+
111+
for _, field := range fields {
112+
// Git quotes paths with special characters using C-style quoting
113+
if strings.HasPrefix(field, "\"") && strings.HasSuffix(field, "\"") {
114+
// Unquote to decode escape sequences (e.g., \360\237\252\201 -> 🪁)
115+
if unquoted, err := strconv.Unquote(field); err == nil {
116+
paths = append(paths, unquoted)
117+
} else {
118+
// If unquoting fails, fall back to removing quotes
119+
paths = append(paths, strings.Trim(field, "\""))
120+
}
121+
} else {
122+
paths = append(paths, field)
123+
}
124+
}
125+
126+
return paths, nil
108127
}
109128

110129
func stepsToTrigger(files []string, watch []WatchConfig) ([]Step, error) {

pipeline_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,34 @@ func TestDiffWithSubshell(t *testing.T) {
119119
assert.Equal(t, want, got)
120120
}
121121

122+
func TestDiffWithQuotedPaths(t *testing.T) {
123+
want := []string{
124+
"projects/test/pages/17_🪁_testfile.py",
125+
"normal/file.txt",
126+
}
127+
got, err := diff(`printf '"projects/test/pages/17_\360\237\252\201_testfile.py" normal/file.txt'`)
128+
assert.NoError(t, err)
129+
assert.Equal(t, want, got)
130+
}
131+
132+
func TestStepsToTriggerWithEmojiPaths(t *testing.T) {
133+
watch := []WatchConfig{
134+
{
135+
Paths: []string{"projects/**"},
136+
Step: Step{Trigger: "test-pipeline"},
137+
},
138+
}
139+
140+
changedFiles := []string{
141+
"projects/test/pages/17_🪁_testfile.py",
142+
"other/file.txt",
143+
}
144+
145+
steps, err := stepsToTrigger(changedFiles, watch)
146+
assert.NoError(t, err)
147+
assert.Equal(t, []Step{{Trigger: "test-pipeline"}}, steps)
148+
}
149+
122150
func TestPipelinesToTriggerGetsListOfPipelines(t *testing.T) {
123151
want := []string{"service-1", "service-2", "service-4"}
124152

0 commit comments

Comments
 (0)