Skip to content

Commit f0cb0c1

Browse files
committed
init commit
0 parents  commit f0cb0c1

File tree

14 files changed

+377
-0
lines changed

14 files changed

+377
-0
lines changed

.github/workflows/go_pr.yml

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# This workflow will build a golang project
2+
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go
3+
4+
name: Go PR
5+
6+
on:
7+
pull_request:
8+
branches-ignore:
9+
- main
10+
jobs:
11+
build:
12+
runs-on: ubuntu-latest
13+
steps:
14+
- uses: actions/checkout@v4
15+
- name: Set up Go
16+
uses: actions/setup-go@v4
17+
with:
18+
go-version: '1.22'
19+
- name: Test
20+
run: SKIPTEST=optional go test -v -bench=. -race ./...

.gitignore

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# If you prefer the allow list template instead of the deny list, see community template:
2+
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
3+
#
4+
# Binaries for programs and plugins
5+
*.exe
6+
*.exe~
7+
*.dll
8+
*.so
9+
*.dylib
10+
11+
# Test binary, built with `go test -c`
12+
*.test
13+
14+
# Output of the go coverage tool, specifically when used with LiteIDE
15+
*.out
16+
17+
# Dependency directories (remove the comment below to include it)
18+
# vendor/
19+
20+
# Go workspace file
21+
go.work
22+
23+
.idea
24+
.DS_Store*
25+
26+
# Students
27+
students.txt

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2024 Talgat Sarybaev
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# exercises-go
2+
3+
This is exercises repo.
4+
5+
## Prerequisites
6+
7+
You will need:
8+
9+
- [git](https://git-scm.com/)
10+
- [go](https://go.dev/)
11+
12+
## Start
13+
14+
1. Fork repo.
15+
16+
![fork](./assets/fork.png "Fork button")
17+
18+
2. Clone forked repo. Use ssh because you will need to push.
19+
20+
3. Solve problems and test if they are valid.
21+
22+
```shell
23+
go test -v -bench=. -race ./...
24+
```
25+
26+
## Update
27+
28+
First need setup remote repo for update. You need to do that **once**:
29+
30+
```shell
31+
git remote add upstream [email protected]:talgat-ruby/exercises-go.git
32+
git remote set-url --push upstream DISABLE
33+
```
34+
35+
Now any time you need to update you can do:
36+
37+
```shell
38+
git pull upstream main
39+
```
40+
41+
## Test
42+
43+
In order to run specific exercise (for example `exercise2`):
44+
45+
```shell
46+
go test -v -bench -race ./exercise2/...
47+
```
48+
49+
Or specific problem (for example `exercise3/problem5`):
50+
51+
```shell
52+
go test -v -bench=. -race ./exercise3/problem5/...
53+
```
54+
55+
Skip optional tests:
56+
57+
```shell
58+
SKIPTEST=optional go test -v -bench=. -race ./exercise1/...
59+
```
60+
61+
## PR
62+
63+
create PR from your repo to this one from branch `{firstname}-{lastname}` for example `talgat-saribayev`.

assets/fork.png

430 KB
Loading

go.mod

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module github.com/talgat-ruby/exercises-go
2+
3+
go 1.22.3
+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package main
2+
3+
const cmdNameCreateBranches = "create-branches"
4+
const cmdNameMergeMain = "merge-main"

internal/cli/studentsBranch/main.go

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package main
2+
3+
import (
4+
_ "embed"
5+
"flag"
6+
"fmt"
7+
"os"
8+
)
9+
10+
//go:embed students.txt
11+
var studentsData string
12+
13+
func main() {
14+
cmdCreateBranches := newSubcmdCreateBranches()
15+
cmdMergeMain := newSubcmdMergeMain()
16+
17+
// Verify that a subcommand has been provided
18+
// os.Arg[0] is the main command
19+
// os.Arg[1] will be the subcommand
20+
if len(os.Args) < 2 {
21+
fmt.Printf(
22+
"one of subcommands: %v is required\n",
23+
[]string{
24+
cmdCreateBranches.getCmdName(),
25+
cmdMergeMain.getCmdName(),
26+
},
27+
)
28+
os.Exit(1)
29+
}
30+
31+
// Switch on the subcommand
32+
// Parse the flags for appropriate FlagSet
33+
// FlagSet.Parse() requires a set of arguments to parse as input
34+
// os.Args[2:] will be all arguments starting after the subcommand at os.Args[1]
35+
switch os.Args[1] {
36+
case cmdCreateBranches.getCmdName():
37+
if err := cmdCreateBranches.parse(os.Args[2:]); err != nil {
38+
fmt.Printf("error in cmd %s: %+v", cmdCreateBranches.getCmdName(), err)
39+
cmdCreateBranches.printDefaults()
40+
os.Exit(1)
41+
}
42+
case cmdMergeMain.getCmdName():
43+
if err := cmdMergeMain.parse(os.Args[2:]); err != nil {
44+
fmt.Printf("error in cmd %s: %+v", cmdMergeMain.getCmdName(), err)
45+
cmdMergeMain.printDefaults()
46+
os.Exit(1)
47+
}
48+
default:
49+
flag.PrintDefaults()
50+
os.Exit(1)
51+
}
52+
}

internal/cli/studentsBranch/subcmd.go

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package main
2+
3+
type subcmd interface {
4+
getCmdName() string
5+
printDefaults()
6+
parse([]string) error
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package main
2+
3+
import (
4+
"flag"
5+
"fmt"
6+
"sort"
7+
"strings"
8+
)
9+
10+
type subcmdCreateBranches struct {
11+
cmd *flag.FlagSet
12+
students []string
13+
}
14+
15+
func newSubcmdCreateBranches() *subcmdCreateBranches {
16+
cmd := flag.NewFlagSet(cmdNameCreateBranches, flag.ExitOnError)
17+
18+
students := strings.Split(strings.TrimSpace(studentsData), "\n")
19+
sort.Strings(students)
20+
21+
return &subcmdCreateBranches{
22+
cmd: cmd,
23+
students: students,
24+
}
25+
}
26+
27+
func (s *subcmdCreateBranches) getCmdName() string {
28+
return s.cmd.Name()
29+
}
30+
31+
func (s *subcmdCreateBranches) printDefaults() {
32+
s.cmd.PrintDefaults()
33+
}
34+
35+
func (s *subcmdCreateBranches) parse(args []string) error {
36+
if err := s.cmd.Parse(args); err != nil {
37+
return err
38+
}
39+
40+
// Check which subcommand was Parsed using the FlagSet.Parsed() function. Handle each case accordingly.
41+
// FlagSet.Parse() will evaluate to false if no flags were parsed (i.e. the user did not provide any flags)
42+
if !s.cmd.Parsed() {
43+
return fmt.Errorf("please provide correct arguments to %s command", s.cmd.Name())
44+
}
45+
46+
if err := switchToBranch("main"); err != nil {
47+
return fmt.Errorf("could not switch to main branch: %w", err)
48+
}
49+
50+
for _, student := range s.students {
51+
if err := createRemoteBranch(student); err != nil {
52+
return fmt.Errorf("could not create remote branch: %w", err)
53+
}
54+
fmt.Printf("created remote branch %s\n", student)
55+
}
56+
57+
if err := switchToBranch("main"); err != nil {
58+
return fmt.Errorf("could not switch to main branch: %w", err)
59+
}
60+
61+
return nil
62+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package main
2+
3+
import (
4+
"flag"
5+
"fmt"
6+
"sort"
7+
"strings"
8+
)
9+
10+
type subcmdMergeMain struct {
11+
cmd *flag.FlagSet
12+
students []string
13+
}
14+
15+
func newSubcmdMergeMain() *subcmdMergeMain {
16+
cmd := flag.NewFlagSet(cmdNameMergeMain, flag.ExitOnError)
17+
18+
students := strings.Split(strings.TrimSpace(studentsData), "\n")
19+
sort.Strings(students)
20+
21+
return &subcmdMergeMain{
22+
cmd: cmd,
23+
students: students,
24+
}
25+
}
26+
27+
func (s *subcmdMergeMain) getCmdName() string {
28+
return s.cmd.Name()
29+
}
30+
31+
func (s *subcmdMergeMain) printDefaults() {
32+
s.cmd.PrintDefaults()
33+
}
34+
35+
func (s *subcmdMergeMain) parse(args []string) error {
36+
if err := s.cmd.Parse(args); err != nil {
37+
return err
38+
}
39+
40+
// Check which subcommand was Parsed using the FlagSet.Parsed() function. Handle each case accordingly.
41+
// FlagSet.Parse() will evaluate to false if no flags were parsed (i.e. the user did not provide any flags)
42+
if !s.cmd.Parsed() {
43+
return fmt.Errorf("please provide correct arguments to %s command", s.cmd.Name())
44+
}
45+
46+
if err := switchToBranch("main"); err != nil {
47+
return fmt.Errorf("could not switch to main branch: %w", err)
48+
}
49+
50+
for _, student := range s.students {
51+
if err := switchToBranch(student); err != nil {
52+
return fmt.Errorf("could not switch to %s branch: %w", student, err)
53+
}
54+
if err := mergeFromLocal("main"); err != nil {
55+
return fmt.Errorf("could not merge main to %s branch: %w", student, err)
56+
}
57+
if err := pushRemoteBranch(student); err != nil {
58+
return fmt.Errorf("could not push to %s branch: %w", student, err)
59+
}
60+
fmt.Printf("merged main to %s\n", student)
61+
}
62+
63+
if err := switchToBranch("main"); err != nil {
64+
return fmt.Errorf("could not switch to main branch: %w", err)
65+
}
66+
67+
return nil
68+
}

internal/cli/studentsBranch/utils.go

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"os/exec"
6+
)
7+
8+
func createRemoteBranch(branch string) error {
9+
if err := switchToBranch(branch); err != nil {
10+
return fmt.Errorf("could not switch to branch %s: %w", branch, err)
11+
}
12+
13+
if err := pushRemoteBranch(branch); err != nil {
14+
return fmt.Errorf("could not push remote branch %s: %w", branch, err)
15+
}
16+
17+
if err := switchToBranch("main"); err != nil {
18+
return fmt.Errorf("could not switch to main branch: %w", err)
19+
}
20+
21+
return nil
22+
}
23+
24+
func switchToBranch(branch string) error {
25+
cmd := exec.Command("git", "switch", "-C", branch)
26+
return cmd.Run()
27+
}
28+
29+
func mergeFromLocal(branch string) error {
30+
cmd := exec.Command("git", "merge", branch)
31+
return cmd.Run()
32+
}
33+
34+
func pushRemoteBranch(branch string) error {
35+
cmd := exec.Command("git", "push", "--set-upstream", "origin", branch)
36+
return cmd.Run()
37+
}

main.go

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package main

pkg/util/skip.go

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package util
2+
3+
import (
4+
"os"
5+
"testing"
6+
)
7+
8+
func SkipTestOptional(t *testing.T) {
9+
if os.Getenv("SKIPTEST") == "optional" {
10+
t.Skip("Skipping testing in CI environment")
11+
}
12+
}

0 commit comments

Comments
 (0)