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