原始 JSON 报告 机器可读
{
"data": {
"repo": {
"topics": [
"golang",
"git",
"diff",
"patch",
"gitdiff"
],
"is_fork": false,
"size_kb": 4077,
"has_wiki": false,
"homepage": null,
"languages": {
"Go": 174128
},
"pushed_at": "2026-07-20T13:04:16Z",
"created_at": "2019-03-11T04:50:36Z",
"owner_type": "User",
"updated_at": "2026-07-24T03:00:41Z",
"description": "Go library for parsing and applying patches created by Git ",
"is_archived": false,
"is_disabled": false,
"license_spdx": "MIT",
"default_branch": "master",
"license_spdx_raw": "MIT",
"primary_language": "Go",
"significant_languages": [
"Go"
]
},
"owner": {
"blog": "https://billykeyes.dev/",
"name": "Billy Keyes",
"type": "User",
"login": "bluekeyes",
"company": null,
"location": "Pittsburgh, PA",
"followers": 93,
"avatar_url": "https://avatars.githubusercontent.com/u/1745813?v=4",
"created_at": "2012-05-16T13:49:06Z",
"is_verified": null,
"public_repos": 34,
"account_age_days": 5182
},
"license": {
"state": "standard",
"spdx_id": "MIT",
"raw_spdx": "MIT",
"file_present": true,
"scorecard_found": true,
"profile_has_license": true
},
"activity": {
"releases": [
{
"tag": "v0.9.0",
"kind": "minor",
"published_at": "2026-07-18T21:59:23Z"
},
{
"tag": "v0.8.1",
"kind": "patch",
"published_at": "2025-01-08T03:38:43Z"
},
{
"tag": "v0.8.0",
"kind": "minor",
"published_at": "2024-08-20T03:16:58Z"
},
{
"tag": "v0.7.4",
"kind": "patch",
"published_at": "2024-07-19T03:44:16Z"
},
{
"tag": "v0.7.3",
"kind": "patch",
"published_at": "2024-05-06T03:29:52Z"
},
{
"tag": "v0.7.2",
"kind": "patch",
"published_at": "2024-03-07T05:37:16Z"
},
{
"tag": "v0.7.1",
"kind": "patch",
"published_at": "2023-03-17T05:05:51Z"
},
{
"tag": "v0.7.0",
"kind": "minor",
"published_at": "2022-10-01T22:43:44Z"
},
{
"tag": "v0.6.1",
"kind": "patch",
"published_at": "2022-03-18T20:57:53Z"
},
{
"tag": "v0.6.0",
"kind": "minor",
"published_at": "2021-08-20T00:59:27Z"
},
{
"tag": "v0.5.2",
"kind": "patch",
"published_at": "2021-07-19T18:50:30Z"
},
{
"tag": "v0.5.1",
"kind": "patch",
"published_at": "2021-04-24T22:26:48Z"
},
{
"tag": "v0.5.0",
"kind": "minor",
"published_at": "2020-10-24T03:50:18Z"
},
{
"tag": "v0.4.0",
"kind": "minor",
"published_at": "2020-06-16T05:14:32Z"
},
{
"tag": "v0.3.0",
"kind": "minor",
"published_at": "2020-04-19T05:28:28Z"
},
{
"tag": "v0.2.1",
"kind": "patch",
"published_at": "2020-02-01T19:01:23Z"
},
{
"tag": "v0.2.0",
"kind": "minor",
"published_at": "2020-01-28T07:01:23Z"
},
{
"tag": "v0.1.0",
"kind": "minor",
"published_at": "2020-01-10T06:21:31Z"
}
],
"recent_commits": [
{
"oid": "0927b543c7730d28b21ceef164fd0ed7a6a53f93",
"body": null,
"is_bot": true,
"headline": "Bump actions/setup-go from 6.5.0 to 7.0.0 (#80)",
"author_name": "dependabot[bot]",
"author_login": "dependabot[bot]",
"committed_at": "2026-07-20T13:04:14Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "703f876c1784f15ce871acd16a5de80b660baf4f",
"body": null,
"is_bot": false,
"headline": "Add apply limits to the differences list (#79)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2026-07-18T18:51:55Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "12fda45f4844a93af9b67620e3b29961273aeac8",
"body": null,
"is_bot": false,
"headline": "Remove deprecated report card badge (#78)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2026-07-18T18:49:18Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "51e5b1f36268acb8ef30ee035c54573fa035b63d",
"body": "Applying a binary fragment can use a lot of memory in two ways:\n\n1. Inflating a large amount of literal data\n2. Processing a delta instruction stream with many copy operations\n\nClients could theoretically protect against the first by checking\nfragment sizes for all binary fragments before the apply,\n[…]\nc. This was required to\ngenerate the test patches for applies over the limit. The `.hex` files\nare not used directly by the test, but provide the source input for the\npatches as processed by `bin.go`.",
"is_bot": false,
"headline": "Limit binary fragment size during applies (#77)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2026-07-18T18:45:01Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "61f6dcbea813962a15b5fe2747ff72f8b8d9bb4e",
"body": "When parsing a binary fragment, the library attempted to decompress the\npatch data before checking the expected size and without specifying any\nlimit. This allowed a malicious patch to include an \"inflate bomb\" as a\nbinary fragment, forcing the library to allocate excessive memory during\nparsing.\n\nT\n[…]\nr.\nHowever, applying a patch can still write large amounts of data to the\nclient-provided writer in ways the client can't easily prevent. A future\ncommit will enforce limits at apply time to fix this.",
"is_bot": false,
"headline": "Fix unbounded inflate parsing binary fragments (#76)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2026-07-18T18:36:51Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "706d29dcff874458fe3b952090b089741af0b2ac",
"body": "The apply logic trusted the line counts of the incoming patch when\nallocating memory for preimages. This meant a patch could specify a very\nlarge old position in a fragment and force the library to allocate\nexcessive memory before checking if the source actually contains that\nmany lines.\n\nTo fix thi\n[…]\nocated before we reach the end of the source\nfile. Most practical patches should only require one or two reads.\n\nAlso fix a related panic that could happen with an old position close to\nmath.MaxInt64.",
"is_bot": false,
"headline": "Fix potential OOM in Apply (#75)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2026-07-18T17:28:49Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "1d1f2a6b4598e1cc4f6f1f2ead3831a7977d771b",
"body": "Signed-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
"is_bot": true,
"headline": "Bump golangci/golangci-lint-action from 9.2.1 to 9.3.0 (#73)",
"author_name": "dependabot[bot]",
"author_login": "dependabot[bot]",
"committed_at": "2026-07-06T23:40:59Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "eb5290733643ed5775c5f032146fc020d4ece19d",
"body": "Signed-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
"is_bot": true,
"headline": "Bump actions/setup-go from 6.4.0 to 6.5.0 (#72)",
"author_name": "dependabot[bot]",
"author_login": "dependabot[bot]",
"committed_at": "2026-06-30T00:54:47Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "d9b22e9ad4a118577ccc7a44da18be8abd8d52a8",
"body": "Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.3 to 7.0.0.\n- [Release notes](https://github.com/actions/checkout/releases)\n- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)\n- [Commits](https://github.com/actions/checkout/compare/df4cb1c069e1874edd31b43\n[…]\nirect:production\n update-type: version-update:semver-major\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
"is_bot": true,
"headline": "Bump actions/checkout from 6.0.3 to 7.0.0 (#71)",
"author_name": "dependabot[bot]",
"author_login": "dependabot[bot]",
"committed_at": "2026-06-22T17:10:48Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "66b40fd1c95631e1f9a4f0abacde8ff51e9d78f8",
"body": "Signed-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
"is_bot": true,
"headline": "Bump actions/checkout from 6.0.2 to 6.0.3 (#70)",
"author_name": "dependabot[bot]",
"author_login": "dependabot[bot]",
"committed_at": "2026-06-08T12:52:32Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "08f3e635d607a2a0db5178bc8f42b19832bdd6ab",
"body": "This only updates to Go 1.21 baseline, which is what the module still\nspecifies as the minimum version. I'll need to run this again when\nmoving to Go 1.25 or 1.26 as minimum.",
"is_bot": false,
"headline": "Run 'go fix' to modernize code (#69)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2026-05-25T16:11:07Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "6d3702d6db4ae46086b9a97959e736569760c92b",
"body": null,
"is_bot": false,
"headline": "Run tests with Go 1.25 (#68)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2026-05-25T15:39:49Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c4be319555b33071b5562cefd31f044414911eb5",
"body": null,
"is_bot": false,
"headline": "Pin GitHub actions to SHAs and enable Dependabot (#67)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2026-05-25T15:36:51Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "17bd72f0e2e89a2c6aa03de29fc2583a7ec07943",
"body": "Previously, this returned an io.ErrUnexpectedEOF. This is not wrong, in\nthat we did unexpectedly hit the end of the input file, but it is vague\nand implies a possible library bug rather than a problem with the patch\nor the input. This condition is really a conflict, as the changes\ndescribed by the patch are not compatible with the state of the input.",
"is_bot": false,
"headline": "Report short sources as conflicts during apply (#63)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2025-09-04T00:26:05Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "7413262a184380473b5cad4b12a2a061ecbc86c9",
"body": null,
"is_bot": false,
"headline": "Update golangci-lint to v2 (#61)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2025-04-01T01:37:50Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "0896f01926d529e4c0781f72c7957aa942e2068f",
"body": "In issue #57, it was reported that the library could not apply some\npatches generated by BSD `diff` because of the way that variant reports\nchanges in files without trailing newlines. Since the library behavior\nmatches Git, I don't consider this a bug, but update the README to\nmention that the support for standard unified diffs is only for the GNU\nvariant of the `diff` tool.",
"is_bot": false,
"headline": "Clarify that we only support GNU diff",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2025-03-29T20:27:19Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "823d31db22199232e1400cddc39f06d890380055",
"body": "This worked, but completes the test coverage in combination with the\ntest that adds a final newline and one that leaves the missing newline\nin place.",
"is_bot": false,
"headline": "Add a test for removing the last newline in a file (#59)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2025-03-05T04:14:23Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "fffa3cca9bd29785ec7f99ea6921de60e32a724a",
"body": "Include file names in the header (now that we can actually parse them)\r\nand fix a bad find-and-replace that changed \"differ\" to \"fmer\". Add a\r\nnew test to verify that binary files without data format correctly.",
"is_bot": false,
"headline": "Fix binary headers in formatted patches (#56)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2025-01-08T03:35:14Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "14da3d30f70427ec8b41b66f944f364e2e6aff83",
"body": "Some patches may include one or more file paths as part of the binary\r\nheader when there is no binary data. Git accounts for this by only\r\nchecking the prefix and suffix of the line, but I missed that logic when\r\nimplementing this originally.",
"is_bot": false,
"headline": "Parse binary headers with file paths (#55)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2025-01-08T03:27:03Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "8584cd59afe0fd5af926a98ea3ef650fa4b1f952",
"body": "This enables clients to move back and forth between parsed objects and\r\ntext patches. The generated patches are semantically equal to the parsed\r\nobject and should re-parse to the same object, but may not be\r\nbyte-for-byte identical to the original input.\r\n\r\nIn my testing, formatted text patches are\n[…]\nta to the same stream. This isn't exposed publicly right\r\nnow, but will be useful if there's a need for more flexible formatting\r\nfunctions in the future, like formatting to a user-provided io.Writer.",
"is_bot": false,
"headline": "Add String() methods to parsed types (#48)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2024-08-11T18:57:07Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "9e0997ef65150db9392595ab9f2a1df593d48d22",
"body": "The minimum Go version for the package is now Go 1.21. This is because a\r\nfuture change will use the 'slices' package in test code. Note that non-test\r\ncode in the package should still be compatible with older versions of Go.\r\n\r\nAs part of this, also update the golangci-lint version to one that works\r\nwith Go 1.21, which required replacing some deprecated linters.",
"is_bot": false,
"headline": "Update Go and golangci-lint versions (#49)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2024-08-11T18:39:23Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "0a4e55f9a190b500835e10d187ca4f88a96917e2",
"body": "While empty patches with only a header were parsable, the parser\r\ndiscarded the preamble content. This meant callers had to handle this\r\ncase specially. Now, if we reach the end of the input without finding a\r\nfile, Parse() returns the full content of the patch as the preamble.",
"is_bot": false,
"headline": "Return preamble when a patch has no files (#46)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2024-07-15T03:44:16Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "a00d2ccaf7332549eaa3af918b614ac73ee8c8e3",
"body": "When GitHub creates patches for Dependabot PRs, it generates a \"From:\"\r\nline that is not valid according to RFC 5322: the address spec contains\r\nunquoted special characters (the \"[bot]\" in \"dependabot[bot]\"). While\r\nthe 'net/mail' parser makes some exceptions to the spec, this is not one\r\nof them, s\n[…]\n email address as the name\r\n and drop any separate name component.\r\n\r\n2. When parsing mail-formatted patches, use ParsePatchIdentity to parse\r\n the \"From:\" line instead of the 'net/mail' function.",
"is_bot": false,
"headline": "Follow git logic when parsing patch identities (#44)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2024-05-06T03:16:19Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "3f2ea5c16e0a9d685e1b91b6b8bfc0fbf4cb5d6a",
"body": "Git is actually more lenient here than I thought. As long as the\r\nidentity contains the \"<>\" delimiters, Git will allow an empty email, so\r\nwe should accept the same thing. I also discovered that an identity with\r\nonly an email set will use the email as the name, so I've implemented\r\nthat behavior as well.",
"is_bot": false,
"headline": "Accept empty emails in ParsePatchIdentity (#42)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2024-03-07T05:32:38Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "13e8639a0b49cb49741b05f11ac52c530d2d38f0",
"body": null,
"is_bot": false,
"headline": "Clarify that Parse expects a single patch",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2024-02-25T20:39:09Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "981bc4b60c4490e10d9f8ca8cfd7833e303c399e",
"body": "If a patch is passed through a system that converts line endings to\r\n'\\r\\n', mode lines end up with trailing whitespace that confuses\r\nstrconv.ParseInt. In Git, this is avoided by using strtoul() for parsing,\r\nwhich stops at the first non-digit character.\r\n\r\nChanging line endings in patch content itself will cause other problems\r\nso it is best to avoid this transform, but if it does happen, it\r\nshouldn't cause a parse error.",
"is_bot": false,
"headline": "Fix parsing of mode lines with trailing space (#38)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2022-12-26T22:56:30Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1575e0c4ef9322a5685ff76bd40b53363a98799e",
"body": null,
"is_bot": false,
"headline": "Remove warning about apply API changes",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2022-10-01T21:50:12Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "03daf96518a95647d85122e6d107ee63c0bc5b58",
"body": "When processing mail-formatted patches, the default cleanup removed all\r\nleading content in square brackets, but this pattern is often used to\r\nidentify tickets or other information that should remain in the commit\r\ntitle. Git supports disabling this the the `-k` and `-b` flags, which we\r\nsimulate w\n[…]\ns that are (probably) part of\r\nthe actual commit message.\r\n\r\nNote that because of the mail parsing library, we cannot replicate the\r\n`-k` flag exactly and always clean leading and trailing whitespace.",
"is_bot": false,
"headline": "Add option to control patch subject cleaning (#36)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2022-10-01T21:47:39Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "dc43dbf8c7a47db0157e6261151531db188b3e3f",
"body": "Use standard string functions instead of removing leading whitespace in\r\na custom loop. This also makes the distinction between the two types of\r\nmail header parsing a bit clearer.",
"is_bot": false,
"headline": "Slightly simplify patch header parsing (#34)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2022-10-01T05:43:40Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "071689e91f0247ca1fbd40fec4c955d7d5bfa713",
"body": "The previous version of the golangci-lint action would install its own\r\nversion of Go, which eventually conflicted with the old pinned version\r\nof the linter I was using. Upgrade the action to avoid this, but also\r\nupdate Go and the linter while I'm here.",
"is_bot": false,
"headline": "Test with Go 1.19, upgrade golangci-lint (#35)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2022-10-01T05:41:17Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "75930390c9440405f4941e70e3897cb328afdc09",
"body": "Remove the Applier type and replace it with TextApplier and\r\nBinaryApplier, both of which operate on fragments instead of on full\r\nfiles. Move the logic that previously existed in Applier.ApplyFile to\r\nthe top-level Apply function.\r\n\r\nAlso restructure arguments and methods to make it clear that appliers\r\nare one-time-use objects. The destination is now set when creating an\r\napplier and the Reset() method was replaced by Close().",
"is_bot": false,
"headline": "Split apply logic by fragment type (#32)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2022-03-20T19:20:17Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "8764d8180fdd2a5100249b300011d61bb594c9cc",
"body": null,
"is_bot": false,
"headline": "Add note about apply API changes to README",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2022-03-18T21:13:13Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "52645c60d0415a26817e7cdf90ca66b8806f46b9",
"body": "Co-authored-by: Noah Goldstein <goldstein.w.n@gmail.com>",
"is_bot": false,
"headline": "Use ioutil for compatibility with older Go versions (#31)",
"author_name": "goldsteinn",
"author_login": "goldsteinn",
"committed_at": "2022-02-28T02:32:01Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f23f745615837c8bc9804b790f1eb24a8042069c",
"body": null,
"is_bot": false,
"headline": "Add note about fuzz testing to README",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2021-09-19T04:16:28Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "4f540371d0aa2a79f0540bf654a591c8bc7adae6",
"body": "This fixes two issues:\r\n\r\n 1. Fragments with only context lines were accepted\r\n 2. Fragments with only a \"no newline\" marker caused a panic\r\n\r\nThe panic was found by go-fuzz. While fixing that issue, I\r\ndiscovered the first problem with other types of empty fragments while\r\ncomparing behavior against 'git apply'.\r\n\r\nAlso extract some helper functions and modify the loop conditions to\r\nclean things up while making changes in this area.",
"is_bot": false,
"headline": "Return errors for empty text fragments (#29)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2021-09-12T22:51:00Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b6a90110a3bf32b68d27477c96f540a7fbfb536f",
"body": "Found by go-fuzz.",
"is_bot": false,
"headline": "Fix out-of-bounds panic parsing timestamps (#28)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2021-09-09T18:24:16Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "53bcdf7e5d94b09bf31b6e2915a7aa51d1f50b36",
"body": "If a file was an exact multiple of 1024 bytes (the size of an internal\r\nbuffer) and was missing a final newline, the LineReaderAt implementation\r\nwould drop the last line, leading to an unexpected EOF error on apply.\r\n\r\nIn addition to fixing the bug, slightly change the behavior of\r\nReadLineAt to re\n[…]\nt really\r\n serve a purpose.\r\n\r\nThis is technically a breaking change for external implementations but\r\nan implementation that exactly followed the \"spec\" was already broken in\r\ncertain edge cases.",
"is_bot": false,
"headline": "Fix EOF error for some files without final newline (#27)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2021-08-20T00:32:18Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "b5756546a116ebe3ba2be7f83d6c85803903d998",
"body": null,
"is_bot": false,
"headline": "Decode quoted-printable UTF8 in email subjects (#25)",
"author_name": "Javier Campanini",
"author_login": "jmcampanini",
"committed_at": "2021-07-19T18:45:58Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "3772c9eb6544df2bf61020b86080961a3eab6844",
"body": "Git does not quote file names containing spaces when generating header\r\nlines. However, I misread the Git implementation and thought it used\r\nspaces as a name terminator by default, implying that names with spaces\r\nwould be quoted.\r\n\r\nRewrite the the name parsing code to better match Git. Specifical\n[…]\n Also account for spaces in file\r\nnames when parsing file metadata.\r\n\r\nFinally, allow trailing spaces on file names, which seem to be allowed\r\nby Git (although this sounds like a terrible idea to me.)",
"is_bot": false,
"headline": "Fix parsing for file names with spaces (#24)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2021-04-24T22:23:31Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "b6666095cfbb3691e8fb77d597d099fc9373c08f",
"body": null,
"is_bot": false,
"headline": "Remove deprecated actions commands (#22)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2021-03-19T21:47:06Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "8cd57be48511a1fc996955051cc100e5f2de27d4",
"body": null,
"is_bot": false,
"headline": "Update development status in README",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2021-02-19T21:09:28Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b846b2cee04a0ba5f87d41a59f0595789e092682",
"body": "`git am` will accept patches which aren't fully RFC-compliant, as long\r\nas they start with `From` and have a `Subject` line. Relax\r\nParsePatchHeader() so that it will accept such patches as well.\r\n\r\nSpecifically, it will tolerate patches of the form:\r\n\r\n From: <foo@company.com>\r\n\r\nIn this case, t\n[…]\n field will contain `foo@company.com\r\n<foo@company.com>`. Duplicate this behavior.\r\n\r\nSigned-off-by: George Dunlap <george.dunlap@citrix.com>\r\nCo-authored-by: George Dunlap <george.dunlap@citrix.com>",
"is_bot": false,
"headline": "Relax email header requirements (#20)",
"author_name": "George Dunlap",
"author_login": "gwd",
"committed_at": "2020-10-31T23:00:50Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "1bd59c4f1123687f522447da120db26f61e787f2",
"body": "...when parsing emails, similar to `git am`.\r\n\r\nAdd a new field, `BodyAppendix` to PatchHeader.\r\n\r\nModify `scanMessageBody` to accept a boolean argument saying whether\r\nto separate out the appendix or not. Do this by keeping two string\r\nbuilders, and having it switch to the appendix builder when it\n[…]\n, but not a commit\r\nmessage.\r\n\r\nAdd some tests to verify that it works as expected.\r\n\r\nSigned-off-by: George Dunlap <george.dunlap@citrix.com>\r\nCo-authored-by: George Dunlap <george.dunlap@citrix.com>",
"is_bot": false,
"headline": "Remove \"appendix\" information from commit message (#19)",
"author_name": "George Dunlap",
"author_login": "gwd",
"committed_at": "2020-10-24T03:39:43Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "379b893435ec14b9317c0b3a1c8b34abc12f436e",
"body": "Primarily to get rid of [PATCH] at the front, but while we're here\r\njust be generally compatible with `git am`:\r\n\r\n * Remove `re` and variations\r\n * Remove whitespace\r\n * Remove anything in brackets\r\n\r\nBut only at the very beginning of the subject.\r\n\r\nStore anything removed in this way in PatchHeade\n[…]\n\n\r\nInspired by\r\nhttps://github.com/git/git/blob/master/mailinfo.c:cleanup_subject()\r\n\r\nSigned-off-by: George Dunlap <george.dunlap@citrix.com>\r\nCo-authored-by: George Dunlap <george.dunlap@citrix.com>",
"is_bot": false,
"headline": "Remove email decorations from patch titles (#17)",
"author_name": "George Dunlap",
"author_login": "gwd",
"committed_at": "2020-09-16T03:25:25Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "864dd3fb4f9b5ad65b19f6dfb59ca00b713f773e",
"body": null,
"is_bot": false,
"headline": "Replace godoc.org badge with pkg.go.dev badge",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-09-13T04:43:52Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "d3116e7b7ed5bb989c11f5274313853f292f88d9",
"body": "Removed the distinction between parsed and raw dates and simply return\r\nan error for unsupported date formats. Arbitrary date support was\r\nprobably a premature optimization and would be better supported by a\r\nmethod to register custom date parsing functions.\r\n\r\nSimple time.Time fields make the structure easier to use and mean that\r\na zero value always indicates the patch did not include a date.",
"is_bot": false,
"headline": "Make patch date parsing simpler and stricter (#15)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-06-16T05:07:06Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f3b83ad722ac956654c7c37906c8620ab5fc074d",
"body": "A closer look at the Git source shows that the rfc2822 and default\r\nformats do not zero-pad days, so we need to accept single-digit days\r\nwhen parsing. The single-digit pattern will also accept the padded\r\nformat, so there's no loss of functionality.\r\n\r\nChange the parsing test to use single-digit values to emphasize when\r\npadding is required and when it is not.",
"is_bot": false,
"headline": "Allow unpadded days in patch headers (#14)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-06-11T04:34:00Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "4fa98017427b0c44e6beb259671560f4da2ea512",
"body": "When applying a text fragment that deletes all content in the file, make\r\nsure there is no content left in the source after using all the lines in\r\nthe fragment. If there is is extra content, it's a conflict: something\r\nadded more lines to the file after generating the patch.",
"is_bot": false,
"headline": "Check for leftover content after a full delete (#9)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-05-03T20:39:08Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b5ae0bd4434ae4510cd57155d61e60fc946879bf",
"body": "Git usually refers to the whole thing (title + body) as the \"commit\r\nmessage\", so using different terms for the parts clarifies things. Also\r\nadd a new Message() function that returns the combined string.",
"is_bot": false,
"headline": "Rename PatchHeader.Message to .Body (#7)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-04-27T03:00:20Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "546a186b3920aef09b37078b3756e13ff8e3fd4d",
"body": null,
"is_bot": false,
"headline": "Fix minor documentation issues",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-04-19T05:39:42Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "5609b2d456190ab7c7dfb77b6245b09531001adf",
"body": null,
"is_bot": false,
"headline": "Fix typo in comment",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-04-19T05:23:12Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f0da09b10f3d63c12111490105e5af7a76a7c26e",
"body": "This function parses patch headers (the preamble returned by the\r\nexisting Parse function) to extract information about the commit that\r\ngenerated the patch. This is useful when patches are an interchange\r\nformat and this library is applying commits generated elsewhere.\r\n\r\nBecause of the variety of header formats, parsing is fairly lenient and\r\nbest-effort, although certain invalid input does cause errors.\r\n\r\nThis also extracts some test utilities from the apply tests for reuse.",
"is_bot": false,
"headline": "Add ParsePatchHeader and related types (#6)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-04-19T05:21:55Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c2035adeda6b63c67678ce0bccf1e8d0ec828a02",
"body": null,
"is_bot": false,
"headline": "Add Apply convenience function to match Parse (#5)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-04-11T22:21:23Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "34ea1730662faa6b12e10b312fce1b17101d9908",
"body": null,
"is_bot": false,
"headline": "Add apply example to README",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-02-01T21:30:59Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "bedbab3f65436ca9e85e67ee9f6229b6128c2b37",
"body": "Use golangci-lint to coordinate linting instead of installing tools\r\nindividually. The workflow installs the binary directly instead of using\r\none of the existing public actions.",
"is_bot": false,
"headline": "Use GitHub actions for testing and linting (#3)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-02-01T21:19:05Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "09f3004fce1ceb2ec686d644439c5135687d29bf",
"body": "copyFrom and copyLinesFrom did not increment the start offset after\r\nreading, so the same lines were copied over and over again.",
"is_bot": false,
"headline": "Fix flushing when data is larger than the buffer (#2)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-02-01T18:58:43Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "bb5b8f69fda3a361dd8c75dca7d3a5f7662d6dab",
"body": null,
"is_bot": false,
"headline": "Update README.md",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-01-28T06:55:33Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c979654ba5a25265fbc0189470f2b1ea78ba92d0",
"body": null,
"is_bot": false,
"headline": "Update README with apply status",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-01-28T06:42:13Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "9fc14fddb0177442728a7154b8ba10aa125ac2bc",
"body": "Also refactor the apply tests to use a common type now that there are\nthree variants that do almost the same thing for each test.",
"is_bot": false,
"headline": "Add tests for file-level application",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-01-28T06:35:13Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "19ec1a24b41791a03a9fae056a1a7eb9426a5e11",
"body": "Applying a file now rejects future text fragment applies under the\nassumption that all relevant fragments were part of the file.",
"is_bot": false,
"headline": "Improve detection of in-progress application",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-01-26T23:02:42Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "0f3872a5a4c234c851e41be371673d1d0436f1b2",
"body": null,
"is_bot": false,
"headline": "Fix panic with empty input in LineReaderAt",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-01-26T21:37:09Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "fa88623500b0f12ae6c59f0207d3dcd08899a29d",
"body": "Try to avoid confusion about whether variables refer to byte or line\ncounts/positions. It still isn't perfect, but I'm not sure how to\nfurther clarify without being overly verbose.",
"is_bot": false,
"headline": "Improve clarity of LineReaderAt implementation",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-01-26T06:27:59Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "206a57eb7a98a9e3907169f846dcf1b44c286259",
"body": "This adds minimal new coverage, since the apply tests already exercise\nthis, but it's complicated enough that dedicated tests will be helpful.",
"is_bot": false,
"headline": "Add tests for LineReaderAt implementation",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-01-26T06:26:21Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "18058d1e151e780b7617d574c037b8a4e948816c",
"body": "This removes the distinction between \"strict\" and \"fuzzy\" application\nby allowing future methods on Applier that control settings. It also\navoids state tracking in the text fragment apply signature by moving it\ninto the Applier type.\n\nWhile in practice, an Applier will be used once and discarded, the\ncapability is provided to reset it for multiple uses.",
"is_bot": false,
"headline": "Move apply methods to an Applier type",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-01-26T01:01:43Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "3d1274d16e8feeec692cd6314f970a8a0ba1fb7d",
"body": "This is no longer used for text application, so revert the parser back\nto using StringReader.",
"is_bot": false,
"headline": "Remove unused LineReader interface",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-01-26T00:57:23Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "0b7af3feaad275c6be1e7af533bbf70f474d354a",
"body": "This is functionally equivalent to the previous version (except for one\nerror case), but uses the new interface. I think the code is simpler\noverall because it removes the line tracking.",
"is_bot": false,
"headline": "Implement text application using LineReaderAt",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-01-26T00:56:33Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f3702115a63389c389b539e089b62c8115d2cdac",
"body": "This is a line-oriented parallel to io.ReaderAt, meant for text applies.\nWhile the mapping isn't quite as clean as in the binary case, a text\napply still reads a fixed chunk of lines starting at a specific line\nnumber and modifies them. This also allows a consistent interface for\nstrict and fuzzy ap\n[…]\ns data in chunks,\nindexing line boundaries as it goes. This is probably not the most\nefficient way to implement this interface, but it works and allows file\napplication to take a consistent interface.",
"is_bot": false,
"headline": "Add LineReaderAt interface and implementation",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-01-26T00:56:32Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "131a046908d88466f69c7f6c29155c41826159ae",
"body": "This better matches the actual contract of the delta patch, which reads\nfixed size chunks of the source files at arbitrary positions.",
"is_bot": false,
"headline": "Use io.ReaderAt to implement binary applies",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-01-26T00:48:07Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "a34334d6ef2a4cb27da1d6e5fd6b1e642189f368",
"body": "These cover some of the possible errors with delta fragments. Many of\nthe same tests could be implemented slightly easier by testing the\nhelper functions, but the infrastructure is already set up to test the\nfull function.\n\nThis is made easier by the bin.go CLI, which can parse and encode binary\npatch data. Once parsed, fragments were manipulated with truncate and\ndd, encoded, and placed in the patch files.",
"is_bot": false,
"headline": "Add error tests for BinaryFragment#Apply",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-01-17T06:43:56Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "194589f0011e57dcb6b07f8e7cc2abad0a05eab6",
"body": "This ensures a default size is used for large copy instructions.",
"is_bot": false,
"headline": "Add test for large binary delta application",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-01-17T05:52:41Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c50036a466abfec0293862e737ac176b58a9f991",
"body": null,
"is_bot": false,
"headline": "Abstract common file loading in apply tests",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-01-17T05:52:41Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "79aa2a9a77ed453b27e3e3f51244a2b9cba0ca4a",
"body": "Covers basic literal and delta application. Input files were created by\nusing dd and the 'conv=notrunc' option to modify sections of files\ncreated from /dev/urandom. All file start with two null bytes to\nconvince Git they are binary.",
"is_bot": false,
"headline": "Add positive tests for BinaryFragment#Apply",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-01-17T05:52:40Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "a1d21957e2c6d87b9b38290d5588ceb74a6a6335",
"body": "Currently untested, but based on code I validated against some generated\npatches. Tests comming in a future commit.",
"is_bot": false,
"headline": "Implement binary fragment application",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-01-15T06:49:14Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "32887c7120ec446889df755e8175e9ea17d51a53",
"body": "Tests now use errors.Is, a Go 1.13 feature.",
"is_bot": false,
"headline": "Update to Go 1.13 in go.mod",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-01-14T06:14:17Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "eb5f3de78cf0166f0c6cc2b5f1479667ddd6e230",
"body": "Conflict errors are now represented by an exported type that is\ncompatible with errors.Is instead of using the method defined on\nApplyError. This makes the tests slightly cleaner and should be more\nidiomatic for clients.",
"is_bot": false,
"headline": "Improve conflict error detection",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-01-13T06:09:08Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1b341e06931ea0f2dbec738d04d7f7362a8bcee0",
"body": "These cover the errors that can happen with a single fragment and no\nadditional manipulation by the caller of ApplyStrict.",
"is_bot": false,
"headline": "Add error tests for TextFragment#ApplyStrict",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-01-13T06:09:08Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "6a055aa600880e6fa43d3022e951a9b6aea29995",
"body": "This ensures the line number is used and application isn't based only on\nmatching context lines.",
"is_bot": false,
"headline": "Add exact line test for TextFragment#ApplyStrict",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-01-13T06:08:15Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "774281f01b714f03d4a951d8e8baf391d30093b2",
"body": "This matches the type used for positions in text fragments.",
"is_bot": false,
"headline": "Standardize on int64 for line numbers",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-01-10T06:11:25Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "7bd4e0bb0e868592a89659173e287c1656c0c6f1",
"body": "io.EOF was not properly accounted for when dealing with patches that are\nmissing trailing newline characters.",
"is_bot": false,
"headline": "Fix EOF handling in TextFragment#ApplyStrict",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-01-10T06:05:24Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "02f7ff4f795c073809952e5fadd64d489d304dd0",
"body": "These cover all of the cases (I think) where application should succeed.",
"is_bot": false,
"headline": "Add positive tests for TextFragment#ApplyStrict",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-01-09T07:04:44Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "ae704236bb956be9202a2b9aa514f66325638b5e",
"body": "This wraps the underlying error with optional position information and\nprovides a way to test if the error was due to a conflict. At the\nmoment, details about the conflict are not exposed outside of the\nmessage string.",
"is_bot": false,
"headline": "Return ApplyError when ApplyString fails",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-01-08T06:59:25Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "93d46e805c6e469c239d6cbb9b481b63f4a7d27e",
"body": "Text fragment application is implemented but untested and with several\nTODOs, binary fragment application is unimplemented and will panic.",
"is_bot": false,
"headline": "Add initial pass at ApplyStrict functions",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-01-06T04:37:59Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "25bee8cf2fa8310deebe6fe6ebbf16bc83236abe",
"body": "Applying a fragment requires the content to match the stored counts, so\nthere must be a way to check this. Parsed fragments should always be\nvalid, but manually created or modified fragments may be invalid.",
"is_bot": false,
"headline": "Add validation function for text fragment",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-01-06T04:36:01Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "d471b7e1a3ed7e1c3074f0ce2fac7b1ab5d5b71d",
"body": "When applying, we need to copy all data after the last fragment line.\nThis function provides a way to get back the possibly-buffered io.Reader\nthat backs the LineReader.",
"is_bot": false,
"headline": "Add internal function to unwrap LineReaders",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-01-05T07:32:16Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "3ec1c74c34ac0faed0e91f105ca6417b60be47b6",
"body": "Document the method as part of the type so it is processed by godoc.",
"is_bot": false,
"headline": "Improve docs for StringReader and LineReader",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-01-05T04:03:00Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "a1f934e8520f5a84a6e4a79fc7990c9128570666",
"body": "LineReader is a wrapper around StringReader that counts line numbers.\nThis is not currently used by the parser, but will be used by the apply\nfunctions.",
"is_bot": false,
"headline": "Add LineReader and StringReader interfaces",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2020-01-04T20:02:37Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f65047b16578b268507c17b5fcbd36516d2edcad",
"body": null,
"is_bot": false,
"headline": "Avoid buffering when reader supports ReadString",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2019-04-27T23:15:50Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1c950ee8546936cd292c3e14a83602eaa132bd6a",
"body": "The tests were already split up in this way, so it makes sense to have\nthe parsing functions split as well.",
"is_bot": false,
"headline": "Split source files by patch type (text/binary)",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2019-04-18T04:36:46Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "d42fb0e93f544fbd87cf86ddbce5dd6c173d4ede",
"body": null,
"is_bot": false,
"headline": "Fix spelling mistakes, add Go Report Card badge",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2019-04-15T02:53:39Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "ef3359a9693a9bf9f0f3b01b2cef1d4c91e79d17",
"body": null,
"is_bot": false,
"headline": "Add a package-level documentation comment",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2019-04-15T02:44:06Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "37fcc9a950fc67b28ccf2c37c0cb63e6cc3fff75",
"body": null,
"is_bot": false,
"headline": "Update status and add example in README",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2019-04-15T02:35:48Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "31777bd4b50c8c918e27a3aeac3614df9f328a8a",
"body": null,
"is_bot": false,
"headline": "Add parser advancement tests for binary parsing",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2019-04-15T02:27:34Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "16539ad031a615bb7e31a0dae0ce9cb6a38eaf60",
"body": null,
"is_bot": false,
"headline": "Add tests for parsing full binary fragments",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2019-04-15T02:18:08Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "d104a6c22ab0ec7ab96064205873094beaac2a99",
"body": null,
"is_bot": false,
"headline": "Add error case tests for binary chunk parsing",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2019-04-15T00:10:35Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "62569e0d07695333b7bc1cfe12e2bbe961ac035e",
"body": "These are fairly basic as the decoder is also exercised by the fragment\nparsing tests, but they cover some errror cases that may not be covered\notherwise.",
"is_bot": false,
"headline": "Add dedicated tests for base85 decoding",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2019-04-14T22:50:07Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "8ce8cba533b0f680f66b763fbe02836ef6557ce6",
"body": "Git uses a unique Base85 encoding with different characters than the\nascii85 encoding implemented by Go, so add a custom decoding function.\nOnce decoded, use zlib instead of the raw DEFLATE algorithm to\ndecompress the data.\n\nThese issues were caught by some basic parsing tests which are added\nhere as well.",
"is_bot": false,
"headline": "Fix binary chunk decoding and inflating",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2019-04-14T05:32:25Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "22fb5076be8429672f3d4d86bac3aad3df001455",
"body": null,
"is_bot": false,
"headline": "Add test for binary fragment header parsing",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2019-04-13T22:54:52Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "ddafbc8ba3335c4c188835f90863de055ebb1f84",
"body": "Parse the fragment header separately from the fragment chunk, which\nmakes each function a bit more understandable.",
"is_bot": false,
"headline": "Split up binary parsing to match text parsing",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2019-04-11T06:03:19Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "0cfd720d4f475df383ae7ed66377d1b9e6f14c72",
"body": null,
"is_bot": false,
"headline": "Add test for binary marker parsing",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2019-04-11T06:02:48Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "5a521ed05f62a91cac9c231deb86d8aad617f919",
"body": "Parse forward and optionally reverse fragments, decoding and inflating\nthe ascii85 encoded data in a binary patch. This is completely untested\nat the moment and probably has obvious and stupid bugs.",
"is_bot": false,
"headline": "Implement binary fragment parsing",
"author_name": "Billy Keyes",
"author_login": "bluekeyes",
"committed_at": "2019-04-10T05:54:41Z",
"body_truncated": false,
"is_coding_agent": false
}
],
"releases_count": 18,
"commits_last_year": 14,
"latest_release_at": "2026-07-18T21:59:23Z",
"latest_release_tag": "v0.9.0",
"releases_from_tags": false,
"days_since_last_push": 4,
"active_weeks_last_year": 7,
"days_since_latest_release": 6,
"mean_days_between_releases": 199.3
},
"community": {
"has_readme": true,
"has_license": true,
"has_description": true,
"has_contributing": false,
"health_percentage": 42,
"has_issue_template": false,
"has_code_of_conduct": false,
"has_pull_request_template": false
},
"ecosystem": {
"packages": [
{
"name": "github.com/bluekeyes/go-gitdiff",
"exists": true,
"license": null,
"keywords": [],
"ecosystem": "go",
"matches_repo": true,
"registry_url": "https://pkg.go.dev/github.com/bluekeyes/go-gitdiff",
"is_deprecated": false,
"latest_version": "v0.9.0",
"repository_url": "https://github.com/bluekeyes/go-gitdiff",
"versions_count": 18,
"total_downloads": null,
"dependents_count": null,
"deprecation_note": null,
"maintainers_count": null,
"monthly_downloads": null,
"first_published_at": null,
"latest_published_at": "2026-07-18T18:51:55Z",
"latest_version_yanked": null,
"days_since_latest_publish": 6
}
]
},
"popularity": {
"forks": 28,
"stars": 151,
"watchers": 1,
"fork_history": {
"days": [
{
"date": "2019-11-01",
"count": 1
},
{
"date": "2020-07-10",
"count": 1
},
{
"date": "2020-09-11",
"count": 1
},
{
"date": "2021-03-04",
"count": 1
},
{
"date": "2021-10-19",
"count": 1
},
{
"date": "2022-02-26",
"count": 1
},
{
"date": "2022-05-23",
"count": 1
},
{
"date": "2023-05-14",
"count": 1
},
{
"date": "2023-07-06",
"count": 1
},
{
"date": "2023-07-19",
"count": 1
},
{
"date": "2024-08-21",
"count": 1
},
{
"date": "2025-01-01",
"count": 1
},
{
"date": "2025-01-07",
"count": 1
},
{
"date": "2025-03-04",
"count": 1
},
{
"date": "2025-05-05",
"count": 1
},
{
"date": "2026-01-11",
"count": 1
},
{
"date": "2026-01-22",
"count": 1
},
{
"date": "2026-05-08",
"count": 1
},
{
"date": "2026-07-16",
"count": 1
}
],
"complete": true,
"collected": 19,
"total_forks": 28
},
"star_history": null,
"open_issues_and_prs": 5
},
"ai_readiness": {
"has_nix": false,
"example_dirs": [],
"has_llms_txt": false,
"has_dockerfile": false,
"has_mcp_signal": false,
"bootstrap_files": [],
"api_schema_files": [],
"has_devcontainer": false,
"typecheck_configs": [],
"toolchain_manifests": [
"go.mod"
],
"largest_source_bytes": 16904,
"source_files_sampled": 30,
"oversized_source_files": 0,
"agent_instruction_files": [],
"agent_instruction_max_bytes": null
},
"dependencies": {
"manifests": [
"go.mod"
],
"advisories": {
"error": "No resolved dependencies to assess",
"scope": "repository_graph",
"source": null,
"findings": [],
"collected": false,
"malicious": [],
"truncated": false,
"by_severity": {},
"advisory_count": 0,
"affected_count": 0,
"assessed_count": 0,
"malicious_count": 0,
"assessed_package": null,
"unassessed_count": 0,
"direct_affected_count": 0
},
"ecosystems": [
"go"
],
"dependencies": [],
"all_dependencies": {
"error": null,
"source": "github-sbom",
"packages": [],
"collected": true,
"truncated": false,
"total_count": 0,
"direct_count": 0,
"indirect_count": 0
}
},
"maintainership": {
"issues": {
"open_prs": 0,
"merged_prs": 46,
"open_issues": 5,
"closed_ratio": 0.828,
"closed_issues": 24,
"closed_unmerged_prs": 4
},
"bus_factor": 1,
"bot_contributors": 1,
"top_contributors": [
{
"type": "User",
"login": "bluekeyes",
"commits": 145,
"avatar_url": "https://avatars.githubusercontent.com/u/1745813?v=4"
},
{
"type": "User",
"login": "gwd",
"commits": 3,
"avatar_url": "https://avatars.githubusercontent.com/u/1247773?v=4"
},
{
"type": "User",
"login": "jmcampanini",
"commits": 1,
"avatar_url": "https://avatars.githubusercontent.com/u/316848?v=4"
},
{
"type": "User",
"login": "goldsteinn",
"commits": 1,
"avatar_url": "https://avatars.githubusercontent.com/u/35538541?v=4"
}
],
"contributors_sampled": 4,
"top_contributor_share": 0.967
},
"quality_signals": {
"has_ci": true,
"has_tests": true,
"ci_workflows": [
"go.yml"
],
"has_docs_dir": false,
"linter_configs": [
".golangci.yml"
],
"has_editorconfig": false,
"has_linter_config": true,
"has_precommit_config": false
},
"security_signals": {
"lockfiles": [],
"scorecard": {
"checks": [
{
"name": "Binary-Artifacts",
"score": 10,
"reason": "no binaries found in the repo",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
},
{
"name": "Branch-Protection",
"score": null,
"reason": "internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
},
{
"name": "CI-Tests",
"score": 5,
"reason": "14 out of 27 merged PRs checked by a CI test -- score normalized to 5",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
},
{
"name": "CII-Best-Practices",
"score": 0,
"reason": "no effort to earn an OpenSSF best practices badge detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
},
{
"name": "Code-Review",
"score": 0,
"reason": "Found 0/25 approved changesets -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
},
{
"name": "Contributors",
"score": 0,
"reason": "project has 0 contributing companies or organizations -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
},
{
"name": "Dangerous-Workflow",
"score": 10,
"reason": "no dangerous workflow patterns detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
},
{
"name": "Dependency-Update-Tool",
"score": 10,
"reason": "update tool detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
},
{
"name": "Fuzzing",
"score": 10,
"reason": "project is fuzzed",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
},
{
"name": "License",
"score": 10,
"reason": "license file detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
},
{
"name": "Maintained",
"score": 10,
"reason": "13 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 10",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
},
{
"name": "Packaging",
"score": null,
"reason": "packaging workflow not detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
},
{
"name": "Pinned-Dependencies",
"score": 10,
"reason": "all dependencies are pinned",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
},
{
"name": "SAST",
"score": 0,
"reason": "SAST tool is not run on all commits -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
},
{
"name": "Security-Policy",
"score": 0,
"reason": "security policy file not detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
},
{
"name": "Signed-Releases",
"score": null,
"reason": "no releases found",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
},
{
"name": "Token-Permissions",
"score": 0,
"reason": "detected GitHub workflow tokens with excessive permissions",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
},
{
"name": "Vulnerabilities",
"score": 10,
"reason": "0 existing vulnerabilities detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
}
],
"commit": "0927b543c7730d28b21ceef164fd0ed7a6a53f93",
"ran_at": "2026-07-25T04:27:11Z",
"aggregate_score": 6.3,
"scorecard_version": "v5.5.0"
},
"has_codeql_workflow": false,
"has_security_policy": false,
"has_dependabot_config": true
},
"contribution_flow": {
"collected": true,
"ci_last_run_at": "2026-07-20T13:04:38Z",
"oldest_open_prs": [],
"last_merged_pr_at": "2026-07-20T13:04:14Z",
"ci_last_conclusion": "SUCCESS",
"oldest_open_issues": [
{
"number": 10,
"created_at": "2020-05-03T20:23:58Z",
"last_comment_at": "2022-01-24T06:47:37Z",
"last_comment_author": "bluekeyes"
},
{
"number": 12,
"created_at": "2020-05-04T04:50:02Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 26,
"created_at": "2021-07-19T18:48:30Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 30,
"created_at": "2021-10-25T00:32:19Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 65,
"created_at": "2026-01-15T05:02:31Z",
"last_comment_at": "2026-01-16T00:30:04Z",
"last_comment_author": "bluekeyes"
}
]
}
},
"config": {
"disabled_metrics": [],
"disabled_categories": [],
"disabled_components": {}
},
"source": {
"url": "https://github.com/bluekeyes/go-gitdiff",
"host": "github.com",
"name": "go-gitdiff",
"owner": "bluekeyes"
},
"metrics": {
"overall": {
"key": "overall",
"band": "moderate",
"name": "Overall health",
"note": null,
"notes": [],
"value": 61,
"inputs": {
"security": 63,
"vitality": 70,
"community": 48,
"governance": 58,
"engineering": 64
},
"components": []
},
"categories": [
{
"key": "vitality",
"band": "good",
"name": "Vitality",
"value": 70,
"weight": 0.22,
"metrics": [
{
"key": "development_activity",
"band": "moderate",
"name": "Development activity",
"note": null,
"notes": [],
"value": 61,
"inputs": {
"commits_last_year": 14,
"human_commit_share": 0.95,
"days_since_last_push": 4,
"active_weeks_last_year": 7
},
"components": [
{
"key": "push_recency",
"name": "Push recency",
"detail": "last push 4 days ago",
"points": 36,
"status": "met",
"details": [
{
"code": "push_recency",
"params": {
"days": 4
}
}
],
"max_points": 36
},
{
"key": "commit_cadence",
"name": "Commit cadence",
"detail": "7/52 weeks with commits",
"points": 4.8,
"status": "partial",
"details": [
{
"code": "commit_cadence_weeks",
"params": {
"weeks": 7
}
}
],
"max_points": 36
},
{
"key": "commit_volume",
"name": "Commit volume",
"detail": "14 commits in the last year",
"points": 10.6,
"status": "partial",
"details": [
{
"code": "commits_last_year",
"params": {
"count": 14
}
}
],
"max_points": 18
},
{
"key": "openssf_scorecard_maintained",
"name": "OpenSSF Scorecard: Maintained",
"detail": "13 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 10",
"points": 10,
"status": "met",
"details": [],
"max_points": 10
}
]
},
{
"key": "release_discipline",
"band": "good",
"name": "Release discipline",
"note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"openssf_scorecard_signed_releases"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 84,
"inputs": {
"releases_count": 18,
"latest_release_tag": "v0.9.0",
"releases_from_tags": false,
"days_since_latest_release": 6,
"mean_days_between_releases": 199.3
},
"components": [
{
"key": "ships_releases",
"name": "Ships releases",
"detail": "18 releases published",
"points": 27,
"status": "met",
"details": [
{
"code": "releases_published",
"params": {
"count": 18
}
}
],
"max_points": 27
},
{
"key": "release_recency",
"name": "Release recency",
"detail": "latest release 6 days ago",
"points": 36,
"status": "met",
"details": [
{
"code": "release_recency",
"params": {
"days": 6
}
}
],
"max_points": 36
},
{
"key": "release_cadence",
"name": "Release cadence",
"detail": "a release every ~199.3 days",
"points": 12.6,
"status": "partial",
"details": [
{
"code": "release_cadence",
"params": {
"gap": 199.3
}
}
],
"max_points": 27
},
{
"key": "openssf_scorecard_signed_releases",
"name": "OpenSSF Scorecard: Signed-Releases",
"detail": "no releases found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 10
}
]
},
{
"key": "abandonment",
"band": "excellent",
"name": "Abandonment",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"cap": null,
"state": "maintained",
"guards": [],
"signals": [],
"red_flag": false,
"multiplier_pct": 100,
"declared_reason": null,
"unverified_reason": null,
"unanswered_open_prs": null,
"unanswered_open_issues": null,
"days_since_last_merged_pr": null,
"days_since_last_human_commit": 6,
"days_since_last_human_commit_is_floor": false
},
"components": [
{
"key": "project_is_still_maintained",
"name": "Project is still maintained",
"detail": "last human commit 6 days ago",
"points": 100,
"status": "met",
"details": [
{
"code": "abandonment_maintained",
"params": {
"days": 6
}
}
],
"max_points": 100
}
]
}
],
"description": "Is the project alive — is code being written and are releases shipping?"
},
{
"key": "community",
"band": "at_risk",
"name": "Community & Adoption",
"value": 48,
"weight": 0.18,
"metrics": [
{
"key": "popularity",
"band": "at_risk",
"name": "Popularity & adoption",
"note": null,
"notes": [],
"value": 47,
"inputs": {
"forks": 28,
"stars": 151,
"watchers": 1,
"growth_state": "unverified",
"growth_factor_pct": 100,
"growth_unverified_reason": "no_history"
},
"components": [
{
"key": "stars",
"name": "Stars",
"detail": "151 stars",
"points": 35.3,
"status": "partial",
"details": [
{
"code": "stars",
"params": {
"count": 151
}
}
],
"max_points": 60
},
{
"key": "forks",
"name": "Forks",
"detail": "28 forks",
"points": 11.9,
"status": "partial",
"details": [
{
"code": "forks",
"params": {
"count": 28
}
}
],
"max_points": 25
},
{
"key": "watchers",
"name": "Watchers",
"detail": "1 watchers",
"points": 0,
"status": "missed",
"details": [
{
"code": "watchers",
"params": {
"count": 1
}
}
],
"max_points": 15
}
]
},
{
"key": "community_health",
"band": "moderate",
"name": "Community health",
"note": null,
"notes": [],
"value": 50,
"inputs": {
"has_readme": true,
"has_license": true,
"has_contributing": false,
"has_issue_template": false,
"has_code_of_conduct": false,
"has_pull_request_template": false
},
"components": [
{
"key": "readme",
"name": "README",
"detail": null,
"points": 22.5,
"status": "met",
"details": [],
"max_points": 22.5
},
{
"key": "license",
"name": "License",
"detail": "recognized license (MIT)",
"points": 22.5,
"status": "met",
"details": [
{
"code": "license_standard",
"params": {}
},
{
"code": "license_spdx",
"params": {
"spdx": "MIT"
}
}
],
"max_points": 22.5
},
{
"key": "contributing_guide",
"name": "CONTRIBUTING guide",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 18
},
{
"key": "code_of_conduct",
"name": "Code of conduct",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 13.5
},
{
"key": "issue_template",
"name": "Issue template",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.2
},
{
"key": "pr_template",
"name": "PR template",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 6.3
}
]
}
],
"description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
},
{
"key": "governance",
"band": "moderate",
"name": "Sustainability & Governance",
"value": 58,
"weight": 0.24,
"metrics": [
{
"key": "maintainer_resilience",
"band": "critical",
"name": "Maintainer resilience (bus factor)",
"note": null,
"notes": [],
"value": 15,
"inputs": {
"bus_factor": 1,
"contributors_sampled": 4,
"top_contributor_share": 0.967
},
"components": [
{
"key": "bus_factor",
"name": "Bus factor",
"detail": "1 contributor(s) cover half of all commits",
"points": 9,
"status": "partial",
"details": [
{
"code": "bus_factor",
"params": {
"count": 1
}
}
],
"max_points": 54
},
{
"key": "commit_distribution",
"name": "Commit distribution",
"detail": "top contributor authored 97% of commits",
"points": 0.7,
"status": "partial",
"details": [
{
"code": "top_contributor_share",
"params": {
"share": 97
}
}
],
"max_points": 22.5
},
{
"key": "contributor_breadth",
"name": "Contributor breadth",
"detail": "4 contributors",
"points": 5.4,
"status": "partial",
"details": [
{
"code": "contributors_sampled",
"params": {
"count": 4
}
}
],
"max_points": 13.5
},
{
"key": "openssf_scorecard_contributors",
"name": "OpenSSF Scorecard: Contributors",
"detail": "project has 0 contributing companies or organizations -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
}
]
},
{
"key": "responsiveness",
"band": "good",
"name": "Issue & PR responsiveness",
"note": null,
"notes": [],
"value": 74,
"inputs": {
"merged_prs": 46,
"open_issues": 5,
"closed_issues": 24,
"issue_closed_ratio": 0.828,
"closed_unmerged_prs": 4
},
"components": [
{
"key": "issue_resolution",
"name": "Issue resolution",
"detail": "83% of issues closed",
"points": 38.7,
"status": "partial",
"details": [
{
"code": "issues_closed_share",
"params": {
"share": 83
}
}
],
"max_points": 46.75
},
{
"key": "pr_acceptance",
"name": "PR acceptance",
"detail": "46/50 decided PRs merged",
"points": 35.2,
"status": "partial",
"details": [
{
"code": "decided_prs_merged",
"params": {
"merged": 46,
"decided": 50
}
}
],
"max_points": 38.25
},
{
"key": "openssf_scorecard_code_review",
"name": "OpenSSF Scorecard: Code-Review",
"detail": "Found 0/25 approved changesets -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 15
}
]
},
{
"key": "stewardship",
"band": "moderate",
"name": "Ownership & stewardship",
"note": "Excluded from scoring (no data or not applicable): Verified domain. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"verified_domain"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 59,
"inputs": {
"followers": 93,
"owner_type": "User",
"is_verified": null,
"owner_login": "bluekeyes",
"public_repos": 34,
"account_age_days": 5182
},
"components": [
{
"key": "ownership_backing",
"name": "Ownership backing",
"detail": "personal (user) account",
"points": 10,
"status": "partial",
"details": [
{
"code": "owner_personal",
"params": {}
}
],
"max_points": 30
},
{
"key": "verified_domain",
"name": "Verified domain",
"detail": "not applicable to user accounts",
"points": 0,
"status": "excluded",
"details": [
{
"code": "not_applicable_to_user_accounts",
"params": {}
}
],
"max_points": 20
},
{
"key": "owner_reach",
"name": "Owner reach",
"detail": "93 followers of bluekeyes",
"points": 14.2,
"status": "partial",
"details": [
{
"code": "owner_followers",
"params": {
"count": 93,
"login": "bluekeyes"
}
}
],
"max_points": 25
},
{
"key": "track_record",
"name": "Track record",
"detail": "34 public repos, account ~14 yr old",
"points": 23.2,
"status": "partial",
"details": [
{
"code": "public_repos",
"params": {
"count": 34
}
},
{
"code": "account_age_years",
"params": {
"years": 14
}
}
],
"max_points": 25
}
]
},
{
"key": "package_maintenance",
"band": "excellent",
"name": "Package maintenance",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"packages": [
"github.com/bluekeyes/go-gitdiff"
],
"ecosystems": "go",
"any_deprecated": false,
"min_days_since_publish": 6
},
"components": [
{
"key": "published_resolvable",
"name": "Published & resolvable",
"detail": "1 package(s) on go",
"points": 25,
"status": "met",
"details": [
{
"code": "packages_published",
"params": {
"count": 1,
"ecosystems": "go"
}
}
],
"max_points": 25
},
{
"key": "publish_recency",
"name": "Publish recency",
"detail": "latest publish 6 days ago",
"points": 35,
"status": "met",
"details": [
{
"code": "publish_recency",
"params": {
"days": 6
}
}
],
"max_points": 35
},
{
"key": "version_history",
"name": "Version history",
"detail": "18 published versions",
"points": 20,
"status": "met",
"details": [
{
"code": "published_versions",
"params": {
"count": 18
}
}
],
"max_points": 20
},
{
"key": "not_deprecated",
"name": "Not deprecated",
"detail": "active, not deprecated or yanked",
"points": 20,
"status": "met",
"details": [
{
"code": "package_not_deprecated",
"params": {}
}
],
"max_points": 20
}
]
}
],
"description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
},
{
"key": "engineering",
"band": "moderate",
"name": "Engineering Quality",
"value": 64,
"weight": 0.2,
"metrics": [
{
"key": "engineering_practices",
"band": "good",
"name": "Engineering practices",
"note": null,
"notes": [],
"value": 74,
"inputs": {
"has_ci": true,
"has_tests": true,
"has_editorconfig": false,
"has_linter_config": true,
"has_precommit_config": false
},
"components": [
{
"key": "ci_workflows",
"name": "CI workflows",
"detail": "1 workflow(s)",
"points": 24,
"status": "met",
"details": [
{
"code": "ci_workflows",
"params": {
"count": 1
}
}
],
"max_points": 24
},
{
"key": "tests_present",
"name": "Tests present",
"detail": null,
"points": 24,
"status": "met",
"details": [],
"max_points": 24
},
{
"key": "linter_config",
"name": "Linter config",
"detail": ".golangci.yml",
"points": 16,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": ".golangci.yml"
}
}
],
"max_points": 16
},
{
"key": "pre_commit_hooks",
"name": "Pre-commit hooks",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 9.6
},
{
"key": "editorconfig",
"name": ".editorconfig",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 6.4
},
{
"key": "openssf_scorecard_ci_tests",
"name": "OpenSSF Scorecard: CI-Tests",
"detail": "14 out of 27 merged PRs checked by a CI test -- score normalized to 5",
"points": 10,
"status": "partial",
"details": [],
"max_points": 20
}
]
},
{
"key": "documentation",
"band": "moderate",
"name": "Documentation",
"note": null,
"notes": [],
"value": 50,
"inputs": {
"topics": [
"golang",
"git",
"diff",
"patch",
"gitdiff"
],
"has_wiki": false,
"homepage": null,
"has_readme": true,
"has_docs_dir": false,
"has_description": true
},
"components": [
{
"key": "readme",
"name": "README",
"detail": null,
"points": 30,
"status": "met",
"details": [],
"max_points": 30
},
{
"key": "documentation_directory",
"name": "Documentation directory",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 25
},
{
"key": "documentation_homepage_site",
"name": "Documentation / homepage site",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 15
},
{
"key": "repository_description",
"name": "Repository description",
"detail": null,
"points": 10,
"status": "met",
"details": [],
"max_points": 10
},
{
"key": "topics",
"name": "Topics",
"detail": "5 topics",
"points": 10,
"status": "met",
"details": [
{
"code": "topics_count",
"params": {
"count": 5
}
}
],
"max_points": 10
},
{
"key": "wiki",
"name": "Wiki",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
}
]
}
],
"description": "Are baseline engineering and documentation practices in place?"
},
{
"key": "security",
"band": "moderate",
"name": "Security",
"value": 63,
"weight": 0.16,
"metrics": [
{
"key": "security_posture",
"band": "moderate",
"name": "Security posture",
"note": "Excluded from scoring (no data or not applicable): Branch-Protection, Packaging, Signed-Releases. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"branch_protection",
"packaging",
"signed_releases"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 63,
"inputs": {
"source": "openssf_scorecard",
"checks_evaluated": 15,
"scorecard_version": "v5.5.0",
"checks_inconclusive": 3,
"scorecard_aggregate": 6.3
},
"components": [
{
"key": "binary_artifacts",
"name": "Binary-Artifacts",
"detail": "no binaries found in the repo",
"points": 7.5,
"status": "met",
"details": [],
"max_points": 7.5
},
{
"key": "branch_protection",
"name": "Branch-Protection",
"detail": "internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 7.5
},
{
"key": "ci_tests",
"name": "CI-Tests",
"detail": "14 out of 27 merged PRs checked by a CI test -- score normalized to 5",
"points": 1.2,
"status": "partial",
"details": [],
"max_points": 2.5
},
{
"key": "cii_best_practices",
"name": "CII-Best-Practices",
"detail": "no effort to earn an OpenSSF best practices badge detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 2.5
},
{
"key": "code_review",
"name": "Code-Review",
"detail": "Found 0/25 approved changesets -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "contributors",
"name": "Contributors",
"detail": "project has 0 contributing companies or organizations -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 2.5
},
{
"key": "dangerous_workflow",
"name": "Dangerous-Workflow",
"detail": "no dangerous workflow patterns detected",
"points": 10,
"status": "met",
"details": [],
"max_points": 10
},
{
"key": "dependency_update_tool",
"name": "Dependency-Update-Tool",
"detail": "update tool detected",
"points": 7.5,
"status": "met",
"details": [],
"max_points": 7.5
},
{
"key": "fuzzing",
"name": "Fuzzing",
"detail": "project is fuzzed",
"points": 5,
"status": "met",
"details": [],
"max_points": 5
},
{
"key": "license",
"name": "License",
"detail": "license file detected",
"points": 2.5,
"status": "met",
"details": [],
"max_points": 2.5
},
{
"key": "maintained",
"name": "Maintained",
"detail": "13 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 10",
"points": 7.5,
"status": "met",
"details": [],
"max_points": 7.5
},
{
"key": "packaging",
"name": "Packaging",
"detail": "packaging workflow not detected",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 5
},
{
"key": "pinned_dependencies",
"name": "Pinned-Dependencies",
"detail": "all dependencies are pinned",
"points": 5,
"status": "met",
"details": [],
"max_points": 5
},
{
"key": "sast",
"name": "SAST",
"detail": "SAST tool is not run on all commits -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "security_policy",
"name": "Security-Policy",
"detail": "security policy file not detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "signed_releases",
"name": "Signed-Releases",
"detail": "no releases found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 7.5
},
{
"key": "token_permissions",
"name": "Token-Permissions",
"detail": "detected GitHub workflow tokens with excessive permissions",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "vulnerabilities",
"name": "Vulnerabilities",
"detail": "0 existing vulnerabilities detected",
"points": 7.5,
"status": "met",
"details": [],
"max_points": 7.5
}
]
},
{
"key": "high_risk_jurisdiction_exposure",
"band": "excellent",
"name": "High-Risk Jurisdiction Exposure",
"note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
"notes": [
{
"code": "jurisdiction_evidence_limits",
"params": {}
}
],
"value": 100,
"inputs": {
"meaning": "self-published location evidence; not nationality or citizenship",
"red_flag": false,
"exposures": [],
"policy_countries": [
"Russia",
"Iran",
"North Korea"
],
"review_only_matches": 0,
"assessed_self_published_locations": 3
},
"components": [
{
"key": "policy_exposure_multiplier",
"name": "Policy exposure multiplier",
"detail": "no confirmed policy-scope location match",
"points": 100,
"status": "met",
"details": [
{
"code": "jurisdiction_no_match",
"params": {}
}
],
"max_points": 100
}
]
}
],
"description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
},
{
"key": "ai_readiness",
"band": "moderate",
"name": "AI Readiness",
"value": 66,
"weight": 0,
"metrics": [
{
"key": "ai_agent_context",
"band": "at_risk",
"name": "Agent context & guidance",
"note": null,
"notes": [],
"value": 38,
"inputs": {
"has_llms_txt": false,
"legible_history_share": 0.716,
"agent_instruction_files": [],
"agent_instruction_max_bytes": null
},
"components": [
{
"key": "agent_instructions",
"name": "Agent instructions",
"detail": "no CLAUDE.md / AGENTS.md / editor rules",
"points": 0,
"status": "missed",
"details": [
{
"code": "no_agent_instructions",
"params": {}
}
],
"max_points": 45
},
{
"key": "machine_readable_docs_llms_txt",
"name": "Machine-readable docs (llms.txt)",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 15
},
{
"key": "legible_commit_history",
"name": "Legible commit history",
"detail": "68 of 95 human commits state their intent (structured subject or explanatory body)",
"points": 38.2,
"status": "partial",
"details": [
{
"code": "legible_history",
"params": {
"legible": 68,
"sampled": 95
}
}
],
"max_points": 40
}
]
},
{
"key": "ai_verify_loop",
"band": "good",
"name": "Verify loop (build / test / typecheck)",
"note": null,
"notes": [],
"value": 75,
"inputs": {
"has_nix": false,
"has_tests": true,
"lockfiles": [],
"has_dockerfile": false,
"typed_language": true,
"bootstrap_files": [],
"has_devcontainer": false,
"has_linter_config": true,
"typecheck_configs": [],
"agent_commit_share": 0,
"toolchain_manifests": [
"go.mod"
],
"dependency_bot_commit_share": 0.05
},
"components": [
{
"key": "one_command_bootstrap",
"name": "One-command bootstrap",
"detail": "go.mod (toolchain convention, no task runner)",
"points": 12.6,
"status": "partial",
"details": [
{
"code": "toolchain_convention",
"params": {
"files": "go.mod"
}
}
],
"max_points": 18
},
{
"key": "automated_tests",
"name": "Automated tests",
"detail": null,
"points": 22,
"status": "met",
"details": [],
"max_points": 22
},
{
"key": "lint_format_config",
"name": "Lint / format config",
"detail": ".golangci.yml",
"points": 11,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": ".golangci.yml"
}
}
],
"max_points": 11
},
{
"key": "static_type_checking",
"name": "Static type checking",
"detail": "Go (statically typed)",
"points": 11,
"status": "met",
"details": [
{
"code": "statically_typed_language",
"params": {
"language": "Go"
}
}
],
"max_points": 11
},
{
"key": "reproducible_environment",
"name": "Reproducible environment",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
},
{
"key": "demonstrated_agent_practice",
"name": "Demonstrated agent practice",
"detail": "no agent-authored commits among the last 100",
"points": 0,
"status": "missed",
"details": [
{
"code": "no_agent_authored_commits",
"params": {
"sampled": 100
}
}
],
"max_points": 10
},
{
"key": "automated_maintenance",
"name": "Automated maintenance",
"detail": "5 of the last 100 commits are automated dependency updates",
"points": 8,
"status": "met",
"details": [
{
"code": "dependency_bot_commits",
"params": {
"count": 5,
"sampled": 100
}
}
],
"max_points": 8
},
{
"key": "openssf_scorecard_pinned_dependencies",
"name": "OpenSSF Scorecard: Pinned-Dependencies",
"detail": "all dependencies are pinned",
"points": 10,
"status": "met",
"details": [],
"max_points": 10
}
]
},
{
"key": "ai_code_legibility",
"band": "excellent",
"name": "Code legibility for models",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"primary_language": "Go",
"largest_source_bytes": 16904,
"source_files_sampled": 30,
"oversized_source_files": 0
},
"components": [
{
"key": "type_checkable_code",
"name": "Type-checkable code",
"detail": "Go (statically typed)",
"points": 45,
"status": "met",
"details": [
{
"code": "statically_typed_language",
"params": {
"language": "Go"
}
}
],
"max_points": 45
},
{
"key": "manageable_file_sizes",
"name": "Manageable file sizes",
"detail": "0/30 source files over 60KB",
"points": 55,
"status": "met",
"details": [
{
"code": "oversized_source_files",
"params": {
"kb": 60,
"sampled": 30,
"oversized": 0
}
}
],
"max_points": 55
}
]
}
],
"description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
}
],
"metrics_version": "1.13.0"
},
"warnings": [
"Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token"
],
"report_type": "repository",
"generated_at": "2026-07-25T04:27:26.138221Z",
"schema_version": "0.27.0",
"badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/b/bluekeyes/go-gitdiff.svg",
"full_name": "bluekeyes/go-gitdiff",
"license_state": "standard",
"license_spdx": "MIT"
}