Resolve "add text/template task"
This commit is contained in:
parent
b55e0f2df8
commit
fc1ac9aa48
5 changed files with 339 additions and 0 deletions
62
ciletters/README.md
Normal file
62
ciletters/README.md
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
## ciletters
|
||||||
|
|
||||||
|
В этой задаче вам предстоит познакомиться со стандартным пакетом [text/template](https://golang.org/pkg/text/template/),
|
||||||
|
позволяющим генерировать текст в определенном формате.
|
||||||
|
|
||||||
|
### Легенда
|
||||||
|
|
||||||
|
В gitlab можно подписаться на различные события: успешный build, новый комментарий, решённое issue и др.
|
||||||
|
Вот так, например, выглядит нотификация о сломанном pipeline'е:
|
||||||
|
|
||||||
|
![Image description](assets/notification.png)
|
||||||
|
|
||||||
|
В задаче предлагается сгенерировать письмо подобного содержания в текстовом виде.
|
||||||
|
|
||||||
|
Для генерации HTML в языке также имеется стандартный пакет [html/template](https://golang.org/pkg/html/template/).
|
||||||
|
Работа с ним аналогична работа с `text/template`, поэтому для простоты в задаче был выбран тестовый формат.
|
||||||
|
|
||||||
|
### Что нужно сделать?
|
||||||
|
|
||||||
|
Нужно реализовать функцию `MakeLetter` из файла [letter.go](./letter.go),
|
||||||
|
которая по go объекту нотификации генерирует её текстовое представление.
|
||||||
|
|
||||||
|
#### Прокомментированный пример из теста
|
||||||
|
```
|
||||||
|
Your pipeline #194613 has failed! // 194613 -- это ID pipeline'а
|
||||||
|
Project: go-spring-2021/gopher // Project состоит из ID группы и ID проекта
|
||||||
|
Branch: 🌿 master
|
||||||
|
Commit: 8967153e Solve urlfetch. // Первые 8 байт хэша коммита.
|
||||||
|
CommitAuthor: gopher
|
||||||
|
// Здесь происходит цикл по всем сломанным job'ам
|
||||||
|
Stage: test, Job grade // test -- это имя stage'а, а grade -- имя job'а
|
||||||
|
// Далее идут последние 10 строк лога gitlab runner'а
|
||||||
|
testtool: copying go.mod, go.sum and .golangci.yml
|
||||||
|
testtool: running tests
|
||||||
|
testtool: > go test -mod readonly -tags private -c -o /tmp/bincache730817117/5d83984f885e61c1 gitlab.com/slon/shad-go/sum
|
||||||
|
--- FAIL: TestSum (0.00s)
|
||||||
|
sum_test.go:19: 2 + 2 == 0 != 4
|
||||||
|
sum_test.go:19: 9223372036854775807 + 1 == 0 != -9223372036854775808
|
||||||
|
FAIL
|
||||||
|
testtool: task sum failed: test failed: exit status 1
|
||||||
|
some tasks failed
|
||||||
|
ERROR: Job failed: exit code 1
|
||||||
|
```
|
||||||
|
|
||||||
|
Объект нотификации описан в [notification.go](notification.go).
|
||||||
|
Обратите внимание на `// +build !change`.
|
||||||
|
Этот файл менять не нужно, и на сервере будет использоваться оригинальный вариант.
|
||||||
|
|
||||||
|
В реализации нужно подогнать `text/template` шаблон под требуемый вывод.
|
||||||
|
|
||||||
|
Вам могут понадобиться:
|
||||||
|
* условные блоки (`if/else`)
|
||||||
|
* range'и
|
||||||
|
* кастомные функции в шаблоне: https://golang.org/pkg/text/template/#FuncMap
|
||||||
|
* `'-'` для удаления пробелов
|
||||||
|
|
||||||
|
### Проверка решения
|
||||||
|
|
||||||
|
Для запуска тестов нужно выполнить следующую команду:
|
||||||
|
```
|
||||||
|
go test -v ./ciletters/...
|
||||||
|
```
|
BIN
ciletters/assets/notification.png
Normal file
BIN
ciletters/assets/notification.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 69 KiB |
7
ciletters/letter.go
Normal file
7
ciletters/letter.go
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
// +build !solution
|
||||||
|
|
||||||
|
package ciletters
|
||||||
|
|
||||||
|
func MakeLetter(n *Notification) (string, error) {
|
||||||
|
return "", nil
|
||||||
|
}
|
227
ciletters/letter_test.go
Normal file
227
ciletters/letter_test.go
Normal file
|
@ -0,0 +1,227 @@
|
||||||
|
package ciletters
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"gitlab.com/slon/shad-go/tools/testtool"
|
||||||
|
)
|
||||||
|
|
||||||
|
type testCase struct {
|
||||||
|
name string
|
||||||
|
notification Notification
|
||||||
|
expected string
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSpell(t *testing.T) {
|
||||||
|
const (
|
||||||
|
testUser = "gopher"
|
||||||
|
gitlabGroupID = "go-spring-2021"
|
||||||
|
)
|
||||||
|
|
||||||
|
randomGitlabGroup := testtool.RandomName()
|
||||||
|
randomGitlabProject := testtool.RandomName()
|
||||||
|
randomBranch := testtool.RandomName()
|
||||||
|
randomTestUser := testtool.RandomName()
|
||||||
|
randomTriggerer := testtool.RandomName()
|
||||||
|
randomPipelineID := randomInt64(t)
|
||||||
|
randomJobIDS := []int64{randomInt64(t), randomInt64(t)}
|
||||||
|
randomJobNames := []string{testtool.RandomName(), testtool.RandomName()}
|
||||||
|
randomStages := []string{testtool.RandomName(), testtool.RandomName()}
|
||||||
|
randomHash := testtool.RandomName()[:8]
|
||||||
|
|
||||||
|
for _, tc := range []testCase{
|
||||||
|
{
|
||||||
|
name: "success",
|
||||||
|
notification: Notification{
|
||||||
|
Project: GitlabProject{
|
||||||
|
GroupID: gitlabGroupID,
|
||||||
|
ID: testUser,
|
||||||
|
},
|
||||||
|
Branch: "master",
|
||||||
|
Commit: Commit{
|
||||||
|
Hash: "2ff019bcb8f68d13d640e13351dad98edf7f1405",
|
||||||
|
Message: "Solve sum.",
|
||||||
|
Author: testUser,
|
||||||
|
},
|
||||||
|
Pipeline: Pipeline{
|
||||||
|
Status: PipelineStatusOK,
|
||||||
|
ID: 194555,
|
||||||
|
TriggeredBy: testUser,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: `Your pipeline #194555 passed!
|
||||||
|
Project: go-spring-2021/gopher
|
||||||
|
Branch: 🌿 master
|
||||||
|
Commit: 2ff019bc Solve sum.
|
||||||
|
CommitAuthor: gopher`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "job-failed",
|
||||||
|
notification: Notification{
|
||||||
|
Project: GitlabProject{
|
||||||
|
GroupID: gitlabGroupID,
|
||||||
|
ID: testUser,
|
||||||
|
},
|
||||||
|
Branch: "master",
|
||||||
|
Commit: Commit{
|
||||||
|
Hash: "8967153e8aa7b270af6447dae594eb87bdae8791",
|
||||||
|
Message: "Solve urlfetch.",
|
||||||
|
Author: testUser,
|
||||||
|
},
|
||||||
|
Pipeline: Pipeline{
|
||||||
|
Status: PipelineStatusFailed,
|
||||||
|
ID: 194613,
|
||||||
|
TriggeredBy: testUser,
|
||||||
|
FailedJobs: []Job{
|
||||||
|
{
|
||||||
|
ID: 202538,
|
||||||
|
Name: "grade",
|
||||||
|
Stage: "test",
|
||||||
|
RunnerLog: `$ testtool grade
|
||||||
|
testtool: detected change in tasks [sum]
|
||||||
|
testtool: skipping task sum: not released yet
|
||||||
|
testtool: testing task sum
|
||||||
|
testtool: testing submission in /tmp/sum-281145206
|
||||||
|
testtool: copying student repo
|
||||||
|
testtool: copying tests
|
||||||
|
testtool: copying !change files
|
||||||
|
testtool: copying testdata directory
|
||||||
|
testtool: copying go.mod, go.sum and .golangci.yml
|
||||||
|
testtool: running tests
|
||||||
|
testtool: > go test -mod readonly -tags private -c -o /tmp/bincache730817117/5d83984f885e61c1 gitlab.com/slon/shad-go/sum
|
||||||
|
--- FAIL: TestSum (0.00s)
|
||||||
|
sum_test.go:19: 2 + 2 == 0 != 4
|
||||||
|
sum_test.go:19: 9223372036854775807 + 1 == 0 != -9223372036854775808
|
||||||
|
FAIL
|
||||||
|
testtool: task sum failed: test failed: exit status 1
|
||||||
|
some tasks failed
|
||||||
|
ERROR: Job failed: exit code 1`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: `Your pipeline #194613 has failed!
|
||||||
|
Project: go-spring-2021/gopher
|
||||||
|
Branch: 🌿 master
|
||||||
|
Commit: 8967153e Solve urlfetch.
|
||||||
|
CommitAuthor: gopher
|
||||||
|
Stage: test, Job grade
|
||||||
|
testtool: copying go.mod, go.sum and .golangci.yml
|
||||||
|
testtool: running tests
|
||||||
|
testtool: > go test -mod readonly -tags private -c -o /tmp/bincache730817117/5d83984f885e61c1 gitlab.com/slon/shad-go/sum
|
||||||
|
--- FAIL: TestSum (0.00s)
|
||||||
|
sum_test.go:19: 2 + 2 == 0 != 4
|
||||||
|
sum_test.go:19: 9223372036854775807 + 1 == 0 != -9223372036854775808
|
||||||
|
FAIL
|
||||||
|
testtool: task sum failed: test failed: exit status 1
|
||||||
|
some tasks failed
|
||||||
|
ERROR: Job failed: exit code 1
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple-jobs-failed",
|
||||||
|
notification: Notification{
|
||||||
|
Project: GitlabProject{
|
||||||
|
GroupID: randomGitlabGroup,
|
||||||
|
ID: randomGitlabProject,
|
||||||
|
},
|
||||||
|
Branch: randomBranch,
|
||||||
|
Commit: Commit{
|
||||||
|
Hash: randomHash,
|
||||||
|
Message: "Solve digitalclock.",
|
||||||
|
Author: randomTestUser,
|
||||||
|
},
|
||||||
|
Pipeline: Pipeline{
|
||||||
|
Status: PipelineStatusFailed,
|
||||||
|
ID: randomPipelineID,
|
||||||
|
TriggeredBy: randomTriggerer,
|
||||||
|
FailedJobs: []Job{
|
||||||
|
{
|
||||||
|
ID: randomJobIDS[0],
|
||||||
|
Name: randomJobNames[0],
|
||||||
|
Stage: randomStages[0],
|
||||||
|
RunnerLog: `$ testtool grade
|
||||||
|
testtool: detected change in tasks [sum]
|
||||||
|
testtool: skipping task sum: not released yet
|
||||||
|
testtool: testing task sum
|
||||||
|
testtool: testing submission in /tmp/sum-281145206
|
||||||
|
testtool: copying student repo
|
||||||
|
testtool: copying tests
|
||||||
|
testtool: copying !change files
|
||||||
|
testtool: copying testdata directory
|
||||||
|
testtool: copying go.mod, go.sum and .golangci.yml
|
||||||
|
testtool: running tests
|
||||||
|
testtool: > go test -mod readonly -tags private -c -o /tmp/bincache730817117/5d83984f885e61c1 gitlab.com/slon/shad-go/sum
|
||||||
|
--- FAIL: TestSum (0.00s)
|
||||||
|
sum_test.go:19: 2 + 2 == 0 != 4
|
||||||
|
sum_test.go:19: 9223372036854775807 + 1 == 0 != -9223372036854775808
|
||||||
|
FAIL
|
||||||
|
testtool: task sum failed: test failed: exit status 1
|
||||||
|
some tasks failed
|
||||||
|
ERROR: Job failed: exit code 1`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: randomJobIDS[1],
|
||||||
|
Name: randomJobNames[1],
|
||||||
|
Stage: randomStages[1],
|
||||||
|
RunnerLog: `--- FAIL: TestSum (0.00s)
|
||||||
|
sum_test.go:19: 2 + 2 == 0 != 4
|
||||||
|
sum_test.go:19: 9223372036854775807 + 1 == 0 != -9223372036854775808
|
||||||
|
FAIL
|
||||||
|
testtool: task sum failed: test failed: exit status 1
|
||||||
|
some tasks failed
|
||||||
|
ERROR: Job failed: exit code 1`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: fmt.Sprintf(`Your pipeline #%d has failed!
|
||||||
|
Project: %v/%v
|
||||||
|
Branch: 🌿 %v
|
||||||
|
Commit: %v Solve digitalclock.
|
||||||
|
CommitAuthor: %v
|
||||||
|
Stage: %v, Job %v
|
||||||
|
testtool: copying go.mod, go.sum and .golangci.yml
|
||||||
|
testtool: running tests
|
||||||
|
testtool: > go test -mod readonly -tags private -c -o /tmp/bincache730817117/5d83984f885e61c1 gitlab.com/slon/shad-go/sum
|
||||||
|
--- FAIL: TestSum (0.00s)
|
||||||
|
sum_test.go:19: 2 + 2 == 0 != 4
|
||||||
|
sum_test.go:19: 9223372036854775807 + 1 == 0 != -9223372036854775808
|
||||||
|
FAIL
|
||||||
|
testtool: task sum failed: test failed: exit status 1
|
||||||
|
some tasks failed
|
||||||
|
ERROR: Job failed: exit code 1
|
||||||
|
|
||||||
|
Stage: %v, Job %v
|
||||||
|
--- FAIL: TestSum (0.00s)
|
||||||
|
sum_test.go:19: 2 + 2 == 0 != 4
|
||||||
|
sum_test.go:19: 9223372036854775807 + 1 == 0 != -9223372036854775808
|
||||||
|
FAIL
|
||||||
|
testtool: task sum failed: test failed: exit status 1
|
||||||
|
some tasks failed
|
||||||
|
ERROR: Job failed: exit code 1
|
||||||
|
`, randomPipelineID, randomGitlabGroup, randomGitlabProject, randomBranch, randomHash, randomTestUser,
|
||||||
|
randomStages[0], randomJobNames[0], randomStages[1], randomJobNames[1]),
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
letter, err := MakeLetter(&tc.notification)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, tc.expected, letter)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func randomInt64(t *testing.T) int64 {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
nBig, err := rand.Int(rand.Reader, big.NewInt(1e6))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
return nBig.Int64()
|
||||||
|
}
|
43
ciletters/notification.go
Normal file
43
ciletters/notification.go
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
// +build !change
|
||||||
|
|
||||||
|
package ciletters
|
||||||
|
|
||||||
|
type Notification struct {
|
||||||
|
Project GitlabProject
|
||||||
|
Branch string
|
||||||
|
Commit Commit
|
||||||
|
Pipeline Pipeline
|
||||||
|
}
|
||||||
|
|
||||||
|
type GitlabProject struct {
|
||||||
|
GroupID string
|
||||||
|
ID string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Commit struct {
|
||||||
|
// Hash is a 20-byte SHA-1 encoded in hex.
|
||||||
|
Hash string
|
||||||
|
Message string
|
||||||
|
Author string
|
||||||
|
}
|
||||||
|
|
||||||
|
type PipelineStatus string
|
||||||
|
|
||||||
|
const (
|
||||||
|
PipelineStatusOK PipelineStatus = "ok"
|
||||||
|
PipelineStatusFailed PipelineStatus = "failed"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Pipeline struct {
|
||||||
|
Status PipelineStatus
|
||||||
|
ID int64
|
||||||
|
TriggeredBy string
|
||||||
|
FailedJobs []Job
|
||||||
|
}
|
||||||
|
|
||||||
|
type Job struct {
|
||||||
|
ID int64
|
||||||
|
Name string
|
||||||
|
Stage string
|
||||||
|
RunnerLog string
|
||||||
|
}
|
Loading…
Reference in a new issue