{"id":13895030,"url":"https://github.com/migueleliasweb/go-github-mock","last_synced_at":"2026-01-24T15:08:42.478Z","repository":{"id":41108314,"uuid":"388007565","full_name":"migueleliasweb/go-github-mock","owner":"migueleliasweb","description":"A library to aid unittesting code that uses Golang's Github SDK","archived":false,"fork":false,"pushed_at":"2025-06-26T12:07:20.000Z","size":129,"stargazers_count":121,"open_issues_count":3,"forks_count":29,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-06-26T13:21:27.332Z","etag":null,"topics":["github","go","go-github","golang","mock","mocking","sdk","testing"],"latest_commit_sha":null,"homepage":"","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/migueleliasweb.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-07-21T05:45:43.000Z","updated_at":"2025-06-26T12:06:36.000Z","dependencies_parsed_at":"2025-07-17T15:29:23.748Z","dependency_job_id":"b1fc9cc0-7363-44e0-9a19-96ad40841bef","html_url":"https://github.com/migueleliasweb/go-github-mock","commit_stats":null,"previous_names":[],"tags_count":31,"template":false,"template_full_name":null,"purl":"pkg:github/migueleliasweb/go-github-mock","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/migueleliasweb%2Fgo-github-mock","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/migueleliasweb%2Fgo-github-mock/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/migueleliasweb%2Fgo-github-mock/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/migueleliasweb%2Fgo-github-mock/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/migueleliasweb","download_url":"https://codeload.github.com/migueleliasweb/go-github-mock/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/migueleliasweb%2Fgo-github-mock/sbom","scorecard":{"id":644221,"data":{"date":"2025-08-11","repo":{"name":"github.com/migueleliasweb/go-github-mock","commit":"de485e30faa6342a552e3ad9dfcc98ebda83be38"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4,"checks":[{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Code-Review","score":4,"reason":"Found 8/20 approved changesets -- score normalized to 4","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":3,"reason":"2 commit(s) and 2 issue activity found in the last 90 days -- score normalized to 3","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 26 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-21T11:40:09.928Z","repository_id":41108314,"created_at":"2025-08-21T11:40:09.928Z","updated_at":"2025-08-21T11:40:09.928Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28730311,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-24T10:24:43.181Z","status":"ssl_error","status_checked_at":"2026-01-24T10:24:36.112Z","response_time":89,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["github","go","go-github","golang","mock","mocking","sdk","testing"],"created_at":"2024-08-06T18:01:56.733Z","updated_at":"2026-01-24T15:08:42.458Z","avatar_url":"https://github.com/migueleliasweb.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"# go-github-mock\n[![Go Reference](https://pkg.go.dev/badge/github.com/migueleliasweb/go-github-mock.svg)](https://pkg.go.dev/github.com/migueleliasweb/go-github-mock) [![Go Report Card](https://goreportcard.com/badge/github.com/migueleliasweb/go-github-mock)](https://goreportcard.com/report/github.com/migueleliasweb/go-github-mock)\n\nA library to aid unittesting code that uses Golang's Github SDK\n\n## Installation\n\n```bash\ngo get github.com/migueleliasweb/go-github-mock\n```\n\n## Features\n\n- Create mocks for successive calls for the same endpoint\n- Pagination support (see `mock.WithRequestMatchPages`)\n- Mock error returns\n- High level abstraction helps writing readabe unittests (see `mock.WithRequestMatch`)\n- Lower level abstraction for advanced uses (see `mock.WithRequestMatchHandler`)\n- Mock rate limiting errors from the api (see `mock.WithRateLimit`)\n\n## Examples\n\n```go\nimport \"github.com/migueleliasweb/go-github-mock/src/mock\"\n```\n\n### Multiple requests\n\n```golang\nmockedHTTPClient := mock.NewMockedHTTPClient(\n    mock.WithRequestMatch(\n        mock.GetUsersByUsername,\n        github.User{\n            Name: github.Ptr(\"foobar\"),\n        },\n    ),\n    mock.WithRequestMatch(\n        mock.GetUsersOrgsByUsername,\n        []github.Organization{\n            {\n                Name: github.Ptr(\"foobar123thisorgwasmocked\"),\n            },\n        },\n    ),\n    mock.WithRequestMatchHandler(\n        mock.GetOrgsProjectsByOrg,\n        http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n            w.Write(mock.MustMarshal([]github.Project{\n                {\n                    Name: github.Ptr(\"mocked-proj-1\"),\n                },\n                {\n                    Name: github.Ptr(\"mocked-proj-2\"),\n                },\n            }))\n        }),\n    ),\n)\nc := github.NewClient(mockedHTTPClient)\n\nctx := context.Background()\n\nuser, _, userErr := c.Users.Get(ctx, \"myuser\")\n\n// user.Name == \"foobar\"\n\norgs, _, orgsErr := c.Organizations.List(\n    ctx,\n    *(user.Name),\n    nil,\n)\n\n// orgs[0].Name == \"foobar123thisorgwasmocked\"\n\nprojs, _, projsErr := c.Organizations.ListProjects(\n    ctx,\n    *orgs[0].Name,\n    \u0026github.ProjectListOptions{},\n)\n\n// projs[0].Name == \"mocked-proj-1\"\n// projs[1].Name == \"mocked-proj-2\"\n\n```\n\n### Returning empty results\n\n```golang\nmockedHTTPClient := NewMockedHTTPClient(\n    WithRequestMatch(\n        GetReposIssuesByOwnerByRepo,\n        []github.Issue{\n            {\n                ID:    github.Int64(123),\n                Title: github.Ptr(\"Issue 1\"),\n            },\n            {\n                ID:    github.Int64(456),\n                Title: github.Ptr(\"Issue 2\"),\n            },\n        },\n        []github.Issue{},\n    ),\n)\n\nc := github.NewClient(mockedHTTPClient)\n\nctx := context.Background()\n\nissues1, _, repo1Err := c.Issues.ListByRepo(ctx, \"owner1\", \"repo1\", \u0026github.IssueListByRepoOptions{})\n\n// len(issues1) == 2\n// repo1Err == nil\n\nissues2, _, repo2Err := c.Issues.ListByRepo(ctx, \"owner1\", \"repo2\", \u0026github.IssueListByRepoOptions{})\n\n// len(issues2) == 0\n// repo2Err == nil\n```\n\n### Mocking errors from the API\n\n```golang\nmockedHTTPClient := mock.NewMockedHTTPClient(\n    mock.WithRequestMatchHandler(\n        mock.GetUsersByUsername,\n        http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n            mock.WriteError(\n                w,\n                http.StatusInternalServerError,\n                \"github went belly up or something\",\n            )\n        }),\n    ),\n)\nc := github.NewClient(mockedHTTPClient)\n\nctx := context.Background()\n\nuser, _, userErr := c.Users.Get(ctx, \"someUser\")\n\n// user == nil\n\nif userErr == nil {\n    if ghErr, ok := userErr.(*github.ErrorResponse); ok {\n        fmt.Println(ghErr.Message) // == \"github went belly up or something\"\n    }\n}\n\n```\n\n### Mocking with pagination\n\n```golang\nmockedHTTPClient := NewMockedHTTPClient(\n    WithRequestMatchPages(\n        GetOrgsReposByOrg,\n        []github.Repository{\n            {\n                Name: github.Ptr(\"repo-A-on-first-page\"),\n            },\n            {\n                Name: github.Ptr(\"repo-B-on-first-page\"),\n            },\n        },\n        []github.Repository{\n            {\n                Name: github.Ptr(\"repo-C-on-second-page\"),\n            },\n            {\n                Name: github.Ptr(\"repo-D-on-second-page\"),\n            },\n        },\n    ),\n)\n\nc := github.NewClient(mockedHTTPClient)\n\nctx := context.Background()\n\nopt := \u0026github.RepositoryListByOrgOptions{\n    ListOptions: github.ListOptions{\n        // in fact, the perPage option is ignored my the mocks\n        // but this would be present in production code\n        PerPage: 2,\n    },\n}\n\nvar allRepos []*github.Repository\n\nfor {\n    repos, resp, listErr := c.Repositories.ListByOrg(ctx, \"foobar\", opt)\n\n    if listErr != nil {\n        t.Errorf(\"error listing repositories: %s\", listErr.Error())\n    }\n\n    // len(repos) == 2\n\n    allRepos = append(allRepos, repos...)\n\n    if resp.NextPage == 0 {\n        break\n    }\n\n    opt.Page = resp.NextPage\n}\n\n// matches the mock definitions len(page[0]) + len(page[1])\n// len(allRepos) == 4\n```\n\n### Mocking for GitHub Enterprise\n\nGithub Enterprise uses a different prefix for its endpoints. In order to use the correct endpoints, please use the different set of `*Enterprise` options:\n\n- WithRequestMatchEnterprise\n- WithRequestMatchPagesEnterprise\n\n```golang\nmockedHTTPClient := mock.NewMockedHTTPClient(\n    mock.WithRequestMatchEnterprise( // uses enterprise endpoints instead\n        mock.GetUsersByUsername,\n        github.User{\n            Name: github.Ptr(\"foobar\"),\n        },\n    ),\n)\n\nc := githubEnterprise.NewClient(mockedHTTPClient)\n\nctx := context.Background()\n\nuser, _, userErr := c.Users.Get(ctx, \"myuser\")\n\n// user.Name == \"foobar\"\n```\n\n### Mocking with rate limits\n\n`WithRateLimit` uses a single rate-limiting middleware across all endpoints on the mock router.\n\n**NOTE:** This is an alpha feature. Future changes might break compatibility, until a stable version is released.\n\n```go\nmockedHTTPClient := mock.NewMockedHTTPClient(\n    mock.WithRequestMatchPages(\n        mock.GetOrgsReposByOrg,\n        []github.Repository{{Name: github.Ptr(repoOne)}},\n        []github.Repository{{Name: github.Ptr(repoTwo)}},\n    ),\n\n    // The rate limiter will allow 10 requests per second, and a burst size of 1.\n    // These two options together mean that the rate of requests will be strictly enforced, so if any two requests are\n    // made less than 1/10th of a second apart, the latter will be refused and come back with a rate limit error.\n    mock.WithRateLimit(10, 1),\n)\n```\n\n## Why\n\nSome conversations got started on [go-github#1800](https://github.com/google/go-github/issues/1800) since `go-github` didn't provide an interface that could be easily reimplemented for unittests. After lots of conversations from the folks from [go-github](https://github.com/google/go-github) and quite a few PR ideas later, this style of testing was deemed not suitable to be part of the core SDK as it's not a feature of the API itself. Nonetheless, the ability of writing unittests for code that uses the `go-github` package is critical.\n\nA reuseable, and not overly verbose, way of writing the tests was reached after some more interactions (months down the line) and here we are.\n\n## Thanks\n\nThanks for all ideas and feedback from the folks in [go-github](https://github.com/google/go-github/).\n\n## License\n\nThis library is distributed under the MIT License found in LICENSE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmigueleliasweb%2Fgo-github-mock","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmigueleliasweb%2Fgo-github-mock","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmigueleliasweb%2Fgo-github-mock/lists"}