14 Commits
Author SHA1 Message Date
Billy Keyes 08f3e635d6 Run 'go fix' to modernize code (#69)
This only updates to Go 1.21 baseline, which is what the module still
specifies as the minimum version. I'll need to run this again when
moving to Go 1.25 or 1.26 as minimum.
2026-05-25 09:11:07 -07:00
Billy Keyes 6d3702d6db Run tests with Go 1.25 (#68) 2026-05-25 08:39:49 -07:00
Billy Keyes c4be319555 Pin GitHub actions to SHAs and enable Dependabot (#67) 2026-05-25 08:36:51 -07:00
Billy Keyes 17bd72f0e2 Report short sources as conflicts during apply (#63)
Previously, this returned an io.ErrUnexpectedEOF. This is not wrong, in
that we did unexpectedly hit the end of the input file, but it is vague
and implies a possible library bug rather than a problem with the patch
or the input. This condition is really a conflict, as the changes
described by the patch are not compatible with the state of the input.
2025-09-03 17:26:05 -07:00
Billy Keyes 7413262a18 Update golangci-lint to v2 (#61) 2025-03-31 18:37:50 -07:00
Billy Keyes 0896f01926 Clarify that we only support GNU diff
In issue #57, it was reported that the library could not apply some
patches generated by BSD `diff` because of the way that variant reports
changes in files without trailing newlines. Since the library behavior
matches Git, I don't consider this a bug, but update the README to
mention that the support for standard unified diffs is only for the GNU
variant of the `diff` tool.
2025-03-29 13:27:19 -07:00
Billy Keyes 823d31db22 Add a test for removing the last newline in a file (#59)
This worked, but completes the test coverage in combination with the
test that adds a final newline and one that leaves the missing newline
in place.
2025-03-04 20:14:23 -08:00
Billy Keyes fffa3cca9b Fix binary headers in formatted patches (#56)
Include file names in the header (now that we can actually parse them)
and fix a bad find-and-replace that changed "differ" to "fmer". Add a
new test to verify that binary files without data format correctly.
2025-01-07 19:35:14 -08:00
Billy Keyes 14da3d30f7 Parse binary headers with file paths (#55)
Some patches may include one or more file paths as part of the binary
header when there is no binary data. Git accounts for this by only
checking the prefix and suffix of the line, but I missed that logic when
implementing this originally.
2025-01-07 19:27:03 -08:00
Billy Keyes 8584cd59af Add String() methods to parsed types (#48)
This enables clients to move back and forth between parsed objects and
text patches. The generated patches are semantically equal to the parsed
object and should re-parse to the same object, but may not be
byte-for-byte identical to the original input.

In my testing, formatted text patches are usually identical to the
input, but there may be cases where this is not true. Binary patches
always differ. This is because Go's 'compress/flate' package ends
streams with an empty block instead of adding the end-of-stream flag to
the last non-empty block, like Git's C implementation. Since the streams
will always be different for this reason, I chose to also enable default
compression (the test patches I generated with Git used no compression.)

The main tests for this feature involve parsing, formatting, and then
re-parsing a patch to make sure we get equal objects.

Formatting is handled by a new internal formatter type, which allows
writing all data to the same stream. This isn't exposed publicly right
now, but will be useful if there's a need for more flexible formatting
functions in the future, like formatting to a user-provided io.Writer.
2024-08-11 11:57:07 -07:00
Billy Keyes 9e0997ef65 Update Go and golangci-lint versions (#49)
The minimum Go version for the package is now Go 1.21. This is because a
future change will use the 'slices' package in test code. Note that non-test
code in the package should still be compatible with older versions of Go.

As part of this, also update the golangci-lint version to one that works
with Go 1.21, which required replacing some deprecated linters.
2024-08-11 11:39:23 -07:00
Billy Keyes 0a4e55f9a1 Return preamble when a patch has no files (#46)
While empty patches with only a header were parsable, the parser
discarded the preamble content. This meant callers had to handle this
case specially. Now, if we reach the end of the input without finding a
file, Parse() returns the full content of the patch as the preamble.
2024-07-14 20:44:16 -07:00
Billy Keyes a00d2ccaf7 Follow git logic when parsing patch identities (#44)
When GitHub creates patches for Dependabot PRs, it generates a "From:"
line that is not valid according to RFC 5322: the address spec contains
unquoted special characters (the "[bot]" in "dependabot[bot]"). While
the 'net/mail' parser makes some exceptions to the spec, this is not one
of them, so parsing these patch headers fails.

Git's 'mailinfo' command avoids this by only implementing the unquoting
part of RFC 5322 and then applying a heuristic to separate the string in
to name and email values that seem reasonable.

This commit does two things:

1. Reimplements ParsePatchIdentity to follow Git's logic, so that it can
   accept a wider range of inputs, including quoted strings.  Strings
   accepted by the previous implementation parse in the same way with
   one exception: inputs that contain whitespace inside the angle
   brackets for an email address now use the email address as the name
   and drop any separate name component.

2. When parsing mail-formatted patches, use ParsePatchIdentity to parse
   the "From:" line instead of the 'net/mail' function.
2024-05-05 20:16:19 -07:00
Billy Keyes 3f2ea5c16e Accept empty emails in ParsePatchIdentity (#42)
Git is actually more lenient here than I thought. As long as the
identity contains the "<>" delimiters, Git will allow an empty email, so
we should accept the same thing. I also discovered that an identity with
only an email set will use the email as the name, so I've implemented
that behavior as well.
2024-03-06 21:32:38 -08:00