Open
Conversation
Signed-off-by: Trevor Taubitz <trevor.taubitz@flocksafety.com>
Signed-off-by: Trevor Taubitz <trevor.taubitz@flocksafety.com>
Signed-off-by: Trevor Taubitz <trevor.taubitz@flocksafety.com>
Signed-off-by: Trevor Taubitz <trevor.taubitz@flocksafety.com>
Signed-off-by: Trevor Taubitz <trevor.taubitz@flocksafety.com>
Signed-off-by: Trevor Taubitz <trevor.taubitz@flocksafety.com>
Signed-off-by: Trevor Taubitz <trevor.taubitz@flocksafety.com>
Signed-off-by: Trevor Taubitz <trevor.taubitz@flocksafety.com>
Signed-off-by: Trevor Taubitz <trevor.taubitz@flocksafety.com>
Signed-off-by: Trevor Taubitz <trevor.taubitz@flocksafety.com>
Signed-off-by: Trevor Taubitz <trevor.taubitz@flocksafety.com>
Signed-off-by: Trevor Taubitz <trevor.taubitz@flocksafety.com>
Signed-off-by: Trevor Taubitz <trevor.taubitz@flocksafety.com>
Signed-off-by: Trevor Taubitz <trevor.taubitz@flocksafety.com>
Signed-off-by: Trevor Taubitz <trevor.taubitz@flocksafety.com>
Signed-off-by: Trevor Taubitz <trevor.taubitz@flocksafety.com>
Signed-off-by: Trevor Taubitz <trevor.taubitz@flocksafety.com>
Signed-off-by: Trevor Taubitz <trevor.taubitz@flocksafety.com>
Signed-off-by: Trevor Taubitz <trevor.taubitz@flocksafety.com>
🦋 Changeset detectedLatest commit: f48527b The changes in this PR will be included in the next version bump. This PR includes changesets to release 16 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Signed-off-by: Trevor Taubitz <trevor.taubitz@flocksafety.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
This PR adds Git LFS support to the GitHub mode adapter. That way we can more easily add and version images to repos without cluttering up the Git history. It's enabled via a new opt-in flag.
Note
I am a bit of a noob with React sites, and did use LLM-powered tooling to assist with this PR. I have reviewed all the output and tested it to the best of my ability, but I definitely may have missed something. I feel like I have a decent understanding of all the components I touched, but I don't know what I don't know.
Background
I love Git LFS, and use it pretty much any large binaries so I don't bloat my Git history. I recently setup a Keystatic+Astro site, and was using Git LFS for some of my website image assets. But once it came to adding images via Keystatic, I started to see errors that looked like this:
Even though I had setup LFS and .gitattributes correctly, the GitHub content API that Keystatic was using didn't automatically support LFS. This lead to some images not getting LFS tracked, even though most were.
It looks like the community has been wanting cloud image assets support for a while (#491). It looks like the paid Keystatic Cloud option supports this with a nice image processing pipeline through Cloudflare. But I suspect for a lot of people, Git LFS would be a nice middle ground so that all the assets are tracked in Git via pointer files. GitHub offers a free tier of 10 GB LFS storage and more for paid users, which is probably enough for most people's purposes.
Implementation Notes
LFS support can be enabled via a new opt-in config called
lfsstorage: { kind: 'github', repo: { owner: REPO_OWNER, name: REPO_NAME, }, + lfs: true, }When enabled, Keystatic will gather information about what LFS patterns are configured in the .gitattributes. It does so via a new
LfsPatternsContext.Providerin data.tsx. It looks at a file in the target repo/commit called.gitattributes, and parses it to determine which patterns have been added vialfs track. For now, I made the behavior fairly strict, such that it'll only use patterns wherefilter,diff, andmergeare all set to LFS.Once we have these patterns, that affects the upload path: it checks for the existence of these patterns and the LFS config, and will process any matching files through a separate LFS path. Instead of directly uploading these to the GitHub API, it instead uses a new backend API called
github/lfs/uploadthat uses the LFS basic transfer API to upload to LFS and commit the pointer file.Note
We needed a new backend here because the LFS APIs in GitHub don't have any CORS headers set
The download path works slightly differently: it looks at the content of each images, and determines which ones are actually an LFS pointer file. It does so by looking at the first few bytes to see if they match
version https://git-lfs.github.com/spec/v1. If it is a pointer file, then we resolve it through thegithub/lfs/downloadendpoint. Once resolved, we override the existing cache entry to hold the resolved image bytes instead of just the pointer. That way subsequent pulls can use the image cache directly without having to re-resolve them.Design Notes
There were a few design decisions I made here:
lfsflag. That way existing sites should not be affected at all by the new code paths. Realistically we don't need a new flag, since the existence of a.gitattributesfile with LFS entries would also be a pretty good signal. But I opted to do so to stay as conservative as possible.github/lfs/downloadendpoint does single file downloads, while thegithub/lfs/uploadendpoint does all writes in one batch. The former is good to make sure the images are all downloaded at the same time, so that the initial resolution is as fast as possible. Downside is this is unbounded, so I don't know how it'll perform if we have hundreds of images, each making its own API call.lfs:trueconfig flag being set. It will always resolve LFS files regardless of this setting. This allows both forward and backwards compatibility: you can use non-LFS files in LFS mode, and vise-versa. The LFS mode only affects how files are uploaded. This makes it more robust, since you can enable and disable the LFS setting without losing any images you have previously uploaded.Testing Notes
Apart from a few small unit tests I added for some of the new parsing logic, most of my testing was manual. I also didn't see a whole lot of end-to-end testing, so I opted not to write any. I tested in both a public and private repository to confirm there weren't any differences wrt authentication.
All of this is tested through a minimal Keystatic+Astro+Cloudflare site
After enabling LFS mode, previously-uploaded non-LFS files are still resolved
Adding LFS-managed files works when
lfs: trueis set, and we have our .gitattributes setupAdding non-LFS managed files still works
After disabling LFS mode, the previously-uploaded LFS files are still resolved, while new files don't go through LFS