{"id":13490622,"url":"https://github.com/exercism/go","last_synced_at":"2025-05-14T06:09:51.151Z","repository":{"id":14557578,"uuid":"17273223","full_name":"exercism/go","owner":"exercism","description":"Exercism exercises in Go.","archived":false,"fork":false,"pushed_at":"2025-05-01T16:23:28.000Z","size":5846,"stargazers_count":1050,"open_issues_count":47,"forks_count":662,"subscribers_count":31,"default_branch":"main","last_synced_at":"2025-05-11T17:33:16.341Z","etag":null,"topics":["community-contributions-paused","exercism-track","maintained-autonomous"],"latest_commit_sha":null,"homepage":"https://exercism.org/tracks/go","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/exercism.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":"docs/ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["exercism"],"custom":["https://exercism.org/donate"]}},"created_at":"2014-02-28T02:51:19.000Z","updated_at":"2025-05-09T10:09:51.000Z","dependencies_parsed_at":"2023-12-28T18:31:30.311Z","dependency_job_id":"466799f2-9278-4dfe-82dc-d01fa649c10f","html_url":"https://github.com/exercism/go","commit_stats":{"total_commits":2127,"total_committers":391,"mean_commits":5.439897698209719,"dds":0.9313587212035731,"last_synced_commit":"c78eeb7b4b532cd020f8f1e506104b41d130ccc6"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/exercism%2Fgo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/exercism%2Fgo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/exercism%2Fgo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/exercism%2Fgo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/exercism","download_url":"https://codeload.github.com/exercism/go/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254079713,"owners_count":22011236,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["community-contributions-paused","exercism-track","maintained-autonomous"],"created_at":"2024-07-31T19:00:49.545Z","updated_at":"2025-05-14T06:09:51.103Z","avatar_url":"https://github.com/exercism.png","language":"Go","funding_links":["https://github.com/sponsors/exercism","https://exercism.org/donate"],"categories":["Go"],"sub_categories":[],"readme":"# Exercism Go Track\n\n[![Configlet Status](https://github.com/exercism/go/workflows/Configlet%20CI/badge.svg)](https://github.com/exercism/go/actions?query=workflow%3A%22Configlet+CI%22)\n[![Exercise Test Status](https://github.com/exercism/go/workflows/Exercise%20tests/badge.svg)](https://github.com/exercism/go/actions?query=workflow%3A%22Exercise+tests%22)\n\nExercism exercises in Go.\n\n## Issues/Feedback\n\n⚠️ Please be aware that this repository currently does not accept community contributions. This [blog post](https://exercism.org/blog/freeing-our-maintainers) explains the details.\n\nIf you have any feedback or experience problems, you can bring them up in the [Go section of the Exercism forum](https://forum.exercism.org/c/programming/go/19).\n\n\n## Development setup\n\nIf you work on this repository, you should follow some standard Go development practices.\nYou should have a [recent version of Go](http://golang.org/doc/install) installed, ideally either the current release or previous release.\n\nYou will need a github account and you will need to fork exercism/go to your account.\nSee [GitHub Help](https://help.github.com/articles/fork-a-repo/) if you are unfamiliar with the process.\nClone your fork with the command: `git clone https://github.com/\u003cyou\u003e/go`.\nTest your clone by cding to the go directory and typing `bin/fetch-golangci-lint` and then\n`bin/run-tests`. You should see tests pass for all exercises.\n\nNote that unlike most other Go code, it is not necessary to clone this to your GOPATH.\nThis is because this repo only imports from the standard library and isn't expected to be imported by other packages.\n\nYour Go code should be formatted using the [gofmt](https://golang.org/cmd/gofmt/) tool.\n\nThere is a [misspelling tool](https://github.com/client9/misspell). You can install and occasionally run it to\nfind low hanging typo problems. [#570](https://github.com/exercism/go/pull/570) It's not added into CI since it could give false positives.\n\n## Contributing Guide\n\nPlease be familiar with the [contributing guide](https://github.com/exercism/legacy-docs/tree/main/contributing-to-language-tracks) in the docs repository.\nThis describes some great ways to get involved.\nIn particular, please read the [Pull Request Guidelines](https://github.com/exercism/legacy-docs/blob/main/contributing/pull-request-guidelines.md) before opening a pull request.\n\n## Exercism Go style\n\nLet's walk through an example, non-existent, exercise, which we'll call\n`fizzbuzz` to see what could be included in its implementation.\n\n### Exercise configuration\n\nAn exercise is configured\nvia an entry in the exercises array in [config.json file](/config.json). If `fizzbuzz` is an optional\nexercise, it would have an entry below the core exercises that might look like:\n\n```json\n{\n  \"slug\": \"fizzbuzz\",\n  \"uuid\": \"mumblety-peg-whatever\",\n  \"core\": false,\n  \"unlocked_by\": \"two-fer\",\n  \"difficulty\": 1,\n  \"topics\": [\"conditionals\"]\n}\n```\n\nSee [Exercism Docs: config.json](https://exercism.org/docs/building/tracks/config-json)\nfor more info.\n\n### Exercise files: Overview\n\nFor any exercise you may see a number of files present in a directory under `exercises/`:\n\n```sh\n~/go/exercises/fizzbuzz\n$ tree -a\n.\n├── cases_test.go\n├── example.go\n├── fizzbuzz.go\n├── fizzbuzz_test.go\n├── .meta\n│   └── description.md\n│   └── gen.go\n│   └── hints.md\n│   └── metadata.yml\n└── README.md\n```\n\nThis list of files _can vary_ across exercises.\nNot all exercises use all of these files.\nExercises originate their test data and README text from the Exercism [problem-specification repository](https://github.com/exercism/problem-specifications/tree/master/exercises).\nThis repository collects common information for all exercises across all tracks.\nHowever, should track-specific documentation need to be included with the exercise, files in an exercise's `.meta/` directory can be used to override or augment the exercise's README.\n\nLet's briefly describe each file:\n\n- **cases_test.go** - Contains [generated test cases](#synchronizing-exercises-with-problem-specifications), using test data sourced from the problem-specifications repository.\n  Only in some exercises.\n  Automatically generated by `.meta/gen.go`.\n\n- **example.go** - An [example solution](#example-solutions) for the exercise used to verify the test suite.\n  Ignored by the `exercism fetch` command.\n  See also [ignored files](#ignored-files).\n\n- **fizzbuzz.go** - A _stub file_, in some early exercises to give users a starting point.\n\n- **fizzbuzz_test.go** - The main test file for the exercise.\n\n- **.meta/** - Contains files not to be included when a user fetches an\n  exercise: See also [ignored files](#ignored-files).\n\n- **.meta/description.md** - Use to generate a [track specific description](https://github.com/exercism/docs/blob/master/language-tracks/exercises/anatomy/readmes.md) of the exercise in the exercise's README.\n\n- **.meta/gen.go** - Generates `cases_test.go` when present.\n  See also [synchronizing exercises with problem specifications](#synchronizing-exercises-with-problem-specifications).\n\n- **.meta/hints.md** - Use to add track specific information in addition to the generic exercise's problem-specification description in the README.\n\n- **.meta/metadata.yml** - Track specific exercise metadata, overrides the exercise metadata from the problem-specifications repository.\n\nIn some exercises there can be extra files, for instance the [series](exercises/series/) exercise contains extra test files.\n\n### Ignored files\n\nWhen a user fetches an exercise, they do not need to get all the files within an exercise directory.\nFor instance; the _example.go_ files that contain an example solution, or the _gen.go_ files used to generate an exercise's test cases.\nTherefore there are certain files and directories that are ignored when an exercise is fetched.\nThese are:\n\n- The _.meta_ directory and anything within it.\n- Any file that matches the `ignore_pattern` defined in [config.json file](/config.json).\n  This currently matches any filename that contains the word `example`, _unless_ it is followed by the word `test`, with any number of characters in between.\n\n### Example solutions\n\n_example.go_ is a reference solution.\nIt is a valid solution that the CI (continuous integration) service can run tests against.\nFiles with _\"example\"_ in the file name are skipped by the `exercism fetch` command.\nBecause of this, there is less need for this code to be a model of style, expression and readability, or to use the best algorithm.\nExamples can be plain, simple, concise, even naïve, as long as they are correct.\n\n### Stub files\n\nStub files, such as _leap.go_, are a starting point for solutions.\nNot all exercises need to have a stub file, only exercises early in the syllabus.\nBy convention, the stub file for an exercise with slug `exercise-slug`\nmust be named `exercise_slug.go`. This is because CI needs to delete stub files\nto avoid conflicting definitions.\n\n### Tests\n\nThe test file is fetched for the solver and deserves\nattention for consistency and appearance.\n\nThe `leap` exercise makes use of data-driven tests.\nTest cases are defined as data, then a test function iterates over the data.\nIn this exercise, as they are generated, the test cases are defined in the _cases_test.go_ file.\nThe test function that iterates over this data is defined in the _leap_test.go_ file.\nThe _cases_test.go_ file is generated by information found in [problem-specifications](https://github.com/exercism/problem-specifications) using [generators](#synchronizing-exercises-with-problem-specifications).\nTo add additional test cases (e.g. test cases that only make sense for Go) add the test cases to `\u003cexercise\u003e_test.go`.\nAn example of using additional test cases can be found in the exercise [two-bucket](exercises/practice/two-bucket/two_bucket_test.go).\n\nIdentifiers within the test function appear in actual-expected order as described\nat [Useful Test Failures](https://github.com/golang/go/wiki/CodeReviewComments#useful-test-failures).\nHere the identifier `observed` is used instead of actual. That's fine. More\ncommon are words `got` and `want`. They are clear and short. Note [Useful Test\nFailures](https://github.com/golang/go/wiki/CodeReviewComments#useful-test-failures)\nis part of [Code Review Comments](https://github.com/golang/go/wiki/CodeReviewComments).\nReally we like most of the advice on that page.\n\nIn Go we generally have all tests enabled and do not ask the solver to edit the test program, to enable progressive tests for example.\n`t.Fatalf()`, as seen in the _leap_test.go_ file, will stop tests at the first failure encountered, so the solver is not faced with too many failures at once.\n\n### Testable examples\n\nSome exercises can contain [Example tests](https://blog.golang.org/examples)\nthat document the exercise API. These examples are run alongside the standard\nexercise tests and will verify that the exercise API is working as expected.\nThey are not required by all exercises and are not intended to replace the\ndata-driven tests. They are most useful for providing examples of how an\nexercise's API is used. Have a look at the example tests in the [clock exercise](https://github.com/exercism/go/blob/master/exercises/clock/example_clock_test.go)\nto see them in action.\n\n### Errors\n\nWe like errors in Go. It's not idiomatic Go to ignore invalid data or have undefined\nbehavior. Sometimes our Go tests require an error return where other language\ntracks don't.\n\n### Benchmarks\n\nIn most test files there will also be benchmark tests, as can be seen at the end\nof the _leap_test.go_ file. In Go, benchmarking is a first-class citizen of the\ntesting package. We throw in benchmarks because they're interesting, and because\nit is idiomatic in Go to think about performance. There is no critical use for\nthese though. Usually they will just bench the combined time to run over all\nthe test data rather than attempt precise timings on single function calls. They\nare useful if they let the solver try a change and see a performance effect.\n\n## Synchronizing exercises with problem specifications\n\nSome problems that are implemented in multiple tracks use the same inputs and\noutputs to define the test suites.\nWhere the [problem-specifications](https://github.com/exercism/problem-specifications)\nrepository contains a _canonical-data.json_ file with these inputs and outputs,\nwe can generate the test cases programmatically.\nThe problem-specifications repo also defines the instructions for the exercises, which are also shared across tracks and must also be synchronized.\n\n### Test structure\n\nSee the _gen.go_ file in the `leap` exercise for an example of how this\ncan be done.\n\nTest case generators are named _gen.go_ and are kept in a special _.meta_\ndirectory within each exercise that makes use of a test cases generator. This\n_.meta_ directory will be ignored when a user fetches an exercise.\n\nWhenever the shared JSON data changes, the test cases will need to be regenerated.\nThe generator will first look for a local copy of the **problem-specifications** repository.\nIf there isn't one it will attempt to get the relevant json data for the exercise from the **problem-specifications** repository on GitHub.\nThe generator uses the GitHub API to find some information about exercises when it cannot find a local copy of **problem-specifications**.\nThis can cause throttling issues if working with a large number of exercises.\n_We therefore recommend using a local copy of the repository when possible_ (remember to keep it current :smile:).\n\nTo use a local copy of the **problem-specifications** repository, make sure that it has been cloned into the same parent-directory as the **go** repository.\n\n```sh\n$ tree -L 1 .\n.\n├── problem-specifications\n└── go\n```\n\n#### Adding a test generator to an exercise\n\nFor some exercises, a test generator is used to generate the `cases_test.go` file with the test cases based on information from [problem-specifications](https://github.com/exercism/problem-specifications).\nTo add a new exercise generator to an exercise the following steps are needed:\n1. Create the file `gen.go` in the directory `.meta` of the exercise\n2. Add the following template to `gen.go`:\n```go\npackage main\n\nimport (\n    \"log\"\n    \"text/template\"\n  \n    \"../../../../gen\"\n)\n\nfunc main() {\n\tt, err := template.New(\"\").Parse(tmpl)\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tvar j = map[string]interface{}{\n              \"property_1\":  \u0026[]Property1Case{},\n              \"property_2\":  \u0026[]Property2Case{},\n\t}\n\tif err := gen.Gen(\"\u003cexercise-name\u003e\", j, t); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n3. Insert the name of the exercise to the call of `gen.Gen`\n4. Add all values for the field `property` in `canonical-data.json` to the map `j`. `canonical-data.json` can be found at [problem-specifications/exercises/\\\u003cexercise-name\\\u003e](https://github.com/exercism/problem-specifications)\n5. Create the needed structs for storing the test cases from `canonical-data.json` (you can for example use [JSON-to-Go](https://mholt.github.io/json-to-go/) to convert the JSON to a struct)\n\n**NOTE:** In some cases, the struct of the data in the `input`/`expected` fields is not the same for all test cases of one property. In those situations, an `interface{}` has to be used to represent the values for these fields.  These `interface{}` values then need to be handled by the test generator. A common way to handle these cases is to create methods on the test case structs that perform type assertions on the `interface{}` values and return something more meaningful. These methods can then be referenced/called in the `tmpl` template variable. Examples of this can be found in the exercises [forth](https://github.com/exercism/go/blob/main/exercises/practice/forth/.meta/gen.go) or [bowling](https://github.com/exercism/go/blob/main/exercises/practice/bowling/.meta/gen.go).\n\n6. Add the variable `tmpl` to `gen.go`. This template will be used to create the `cases_test.go` file.\n\nExample:\n```go\nvar tmpl = `package \u003cpackage of exercise\u003e\n\n{{.Header}}\n\nvar testCases = []struct {\n\tdescription    string\n\tinput          int\n\texpected       int       \n}{ {{range .J.\u003cproperty\u003e}}\n{\n\tdescription: {{printf \"%q\"  .Description}},\n\tinput: {{printf \"%d\"  .Score}},\n\texpected: {{printf \"%d\"  .Score}},\n},{{end}}\n}\n`\n```\n7. Synchronize the test case using the exercise generator (as described in [Synchronizing tests and instructions](#synchronizing-tests-and-instructions))\n8. Check the validity of `cases_test.go`\n9. Use the generated test cases in the `\u003cexercise\u003e_test.go` file\n10. Check if `.meta/example.go` passes all tests\n\n### Synchronizing tests and instructions\n\nTo keep track of which tests are implemented by the exercise the file `.meta/tests.toml` is used by [configlet](https://github.com/exercism/configlet).\n\nTo synchronize the exercise with [problem-specifications](https://github.com/exercism/problem-specifications) and to regenerate the tests, navigate into the **go** directory and perform the following steps:\n\n1. Synchronize your exercise with [`exercism/problem-specifications`](https://github.com/exercism/problem-specifications) using [configlet](https://github.com/exercism/configlet):\n\n```console\n$ configlet sync --update -e \u003cexercise\u003e\n```\n\n`configlet` synchronizes the following parts, if an updated is needed:\n\n* docs: `.docs/instructions.md`, `.docs/introduction.md`\n* metadata: `.meta/config.json`\n* tests: `.meta/tests.toml`\n* filepaths: `./meta/config.json`\n\nFor further instructions check out [configlet](https://github.com/exercism/configlet#configlet-sync).\n\n2. Run the test case generator to update `\u003cexercise\u003e/cases_test.go`:\n\n```console\n$ GO111MODULE=off go run exercises/practice/\u003cexercise\u003e/.meta/gen.go\n```\n\n**NOTE**: If you see the error `json: cannot unmarshal object into Go value of type []gen.Commit` when running the generator you probably have been rate limited by GitHub.\nTry providing a GitHub access token with the flag `-github_token=\"\u003cToken\u003e\"`.\nUsing the token will result in a higher rate limit.\nThe token does not need any specific scopes as it is only used to fetch infos about commits.\n\nYou should see that some/all of the above files have changed. Commit the changes.\n\n### Synchronizing all exercises with generators\n\n```console\n$ ./bin/run-generators \u003cGitHub Access Token\u003e\n```\n\n**NOTE**: If you see the error `json: cannot unmarshal object into Go value of type []gen.Commit` when running the generator you probably have been rate limited by GitHub.\nMake sure you provided the GitHub access token as first argument to the script as shown above.\nUsing the token will result in a higher rate limit.\nThe token does not need any specific scopes as it is only used to fetch infos about commits.\n\n## Managing the Go version\n\nFor an easy management of the Go version in the `go.mod` file in all exercises, we can use `gomod-sync`.\nThis is a tool made in Go that can be seen in the `gomod-sync/` folder.\n\nTo update all go.mod files according to the config file (`gomod-sync/config.json`) run:\n\n```console\n$ cd gomod-sync \u0026\u0026 go run main.go update\n```\n\nTo check all exercise go.mod files specify the correct Go version, run:\n\n```console\n$ cd gomod-sync \u0026\u0026 go run main.go check\n```\n\n## Pull requests\n\nPull requests are welcome.\nYou forked, cloned, coded and tested and you have something good? Awesome!\nUse git to add, commit, and push to your repository.\nCheckout your repository on the web now.\nYou should see your commit and the invitation to submit a pull request!\n\n\u003cimg src=\"img/mars1.png\"\u003e\n\nClick on that big green button.\nYou have a chance to add more explanation to your pull request here, then send it.\nLooking at the exercism/go repository now instead of your own, you see this.\n\n\u003cimg src=\"img/mars2.png\"\u003e\n\nThat inconspicuous orange dot is important!\nHover over it (no, not on this image, on a real page) and you can see it's indicating that a CI build is in progress.\nAfter a few minutes (usually) that dot will turn green indicating that tests passed.\nIf there's a problem, it comes up red:\n\n\u003cimg src=\"img/mars3.png\"\u003e\n\nThis means you've still got work to do.\nClick on \"details\" to go to the CI build details. Look over the build log for clues.\nUsually error messages will be helpful and you can correct the problem.\n\n## Direction\n\nDirections are unlimited.\nThis code is fresh and evolving.\nExplore the existing code and you will see some new directions being tried.\nYour fresh ideas and contributions are welcome. :sparkles:\n\n### Go icon\n\nThe Go logo was designed by Renée French, and has been released under the Creative Commons 3.0 Attributions license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fexercism%2Fgo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fexercism%2Fgo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fexercism%2Fgo/lists"}