这是indexloc提供的服务,不要输入任何密码
Skip to content

fix(cli): cache with correct file perms #1429

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jun 27, 2022
Merged

fix(cli): cache with correct file perms #1429

merged 10 commits into from
Jun 27, 2022

Conversation

tknickman
Copy link
Member

Fixes #156

Issue Summary

There were two main issues causing this:

  1. We're using generic filesystem function for the cache operations. These functions require a file mode for the source file, and a file mode for the destination file. We were setting the incorrect bit here causing all files to be restored from cache with one file mode.

  2. When recursively walking files, the walk function we use seems to be calling the callback with the incorrect file mode (it's always 0)

The Fix

To fix this, I've made the file copying functions a bit less generalized (they no longer require a source mode, or a destination mode). Instead, they always use the mode of the source file for the destination file. I also pushed the logic of sourcing the source files mode into the Copy function, below where the incorrect mode was being returned from godirwalk.

This makes these functions slightly less reusable, but for our purposes, this is what we need. We can always add back generalized versions in the future.

@vercel
Copy link

vercel bot commented Jun 22, 2022

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Updated
turborepo ❌ Failed (Inspect) Jun 27, 2022 at 2:21PM (UTC)
1 Ignored Deployment
Name Status Preview Updated
turbo-site ⬜️ Ignored (Inspect) Jun 27, 2022 at 2:21PM (UTC)

@@ -61,10 +65,10 @@ func RecursiveCopyOrLinkFile(from string, to string, mode os.FileMode, link, fal
} else if isSame {
return nil
}
return CopyOrLinkFile(name, dest, fileMode, mode, link, fallback)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fileMode, passed to the WalkMode callback is what I found to be incorrect (always 0)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, this is "correct", but it's not what anybody might expect:

https://github.com/karrick/godirwalk/blob/9a7752c108e7ea76255201b9f47bd4d4d2df868e/modeType.go#L19

It's explicitly not a complete FileMode, it's masked to only include only os.ModeType.

Anyway, I didn't go looking for why that is until you made this note, this is definitely an API footgun and I believe it's likely why we had this bug to begin with.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah interesting, yea this wasn't what I was expecting at all. Thanks for digging into this.

Copy link
Contributor

@nathanhammond nathanhammond left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tests need a change, and I think it's worth spending a bit more time on trying to reduce the number of times we stat.

Copy link
Contributor

@jaredpalmer jaredpalmer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lots of stat calls. Is this something we can avoid or cache?

@@ -60,12 +68,33 @@ func FileExists(filename string) bool {
return err == nil && !info.IsDir()
}

// StatFile adds FileInfo to the given StatedFile if it doesn't already exist
func StatFile(file StatedFile) (StatedFile, error) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ensures we only call os.Lstat one time if the fs.FileInfo doesn't exist.

I verified that we only stat once per file during a cache write / restore cycle.

Copy link
Contributor

@nathanhammond nathanhammond left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking:
Path string => Path AbsolutePath
Stat and Lstat method name matching.

@@ -61,10 +65,10 @@ func RecursiveCopyOrLinkFile(from string, to string, mode os.FileMode, link, fal
} else if isSame {
return nil
}
return CopyOrLinkFile(name, dest, fileMode, mode, link, fallback)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, this is "correct", but it's not what anybody might expect:

https://github.com/karrick/godirwalk/blob/9a7752c108e7ea76255201b9f47bd4d4d2df868e/modeType.go#L19

It's explicitly not a complete FileMode, it's masked to only include only os.ModeType.

Anyway, I didn't go looking for why that is until you made this note, this is definitely an API footgun and I believe it's likely why we had this bug to begin with.

@@ -89,7 +89,7 @@ func (f *fsCache) Put(target, hash string, duration int, files []string) error {
return fmt.Errorf("error ensuring directory file from cache: %w", err)
}

if err := fs.CopyOrLinkFile(file, filepath.Join(f.cacheDirectory, hash, file), fromInfo.Mode(), fs.DirPermissions, false, false); err != nil {
if err := fs.CopyOrLinkFile(&fs.LstatCachedFile{Path: fs.AbsolutePath(file), Info: fromInfo}, filepath.Join(f.cacheDirectory, hash, file), false, false); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re: fs.AbsolutePath, please don't cast to it. Use one of CheckedToAbsolutePath if you don't know if it's an absolute path, UnsafeToAbsolutePath if you are certain that it's an absolute path but we haven't migrated the calling code to use AbsolutePath yet, and AbsolutePathFromUpstream if the value is coming from some library function that you are certain is providing absolute paths.

This helps us find all the places that need to be migrated, as well as communicates what APIs have been investigated already. I expect this applies to anything from turbopath as well.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, the turbopath stuff is following the same rules. (Good catch on this cast, I noticed a different one.)

Some notes on turbopath:

  • AbsoluteSystemPath models the same thing as turbofs.AbsolutePath. There will be a migration PR which should hopefully "just work." I just tried to do it in an automated fashion and everything broke terribly so I need to figure out what I did wrong.
  • At some point there may be a bonus migration where we make a AnchoredXxxxPath type that is io/fs-friendly, but that's not today.

Ordering for things:

  1. Land the daemon code which extensively uses AbsolutePath so that we don't have to do it twice. (Friday US?)
  2. Migrate turbofs.AbsolutePath to turbopath.AbsoluteSystemPath. (Monday HK/US?)
  3. Delete anything unused that remains. (Tuesday HK/US?)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gsoltis I want to make sure we're on the same page with terminology.

I interpret absolute path as a path from system root. For our purposes, is that valid here? Or is our notion of an absolute path (fs.AbsolutePath) a path from the monorepo root.

I'm asking because If the former, most (if not all) of the paths in this PR are relative and will need to be converted before using one of CheckedToAbsolutePath, UnsafeToAbsolutePath, or AbsolutePathFromUpstream

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fs.AbsolutePath is semantically equivalent to turbopath.AbsoluteSystemPath and represents an absolute path in the native format of the particular OS. So <Volume>:\some\path or /some/path as appropriate.

The motivation for all this work separating out different kinds of paths is that they show up in our user input as strings, and all of the APIs for interacting with the filesystem and for interacting with potentially-shared cache artifacts also operate on strings, and it is tempting to naively assume one can be passed to the other. This has been a source of bugs, as well as my suspicion that the --cwd flag doesn't really work as intended.

The solution we've landed on is attempting to identify the specific kinds of paths we care about internally and being strict about what we're working with at any given point. The two important ones are fs.AbsolutePath/turbopath.AbsoluteSystemPath for anything that touches the filesystem, and turbopath.AnchoredUnixPath for anything that is potentially shared.

We've been migrating gradually, so some parts of the code are already using fs.AbsolutePath for filesystem access. The turbopath stuff is new, and should help us further clarify paths especially around the cache.

There's a judgement call in how much to migrate at any one point. You will likely at some point end up doing UnsafeTo<SomePathType> with a comment explaining that you've verified that the string is of the correct type. Likewise, if you need to interact with some part of the system that hasn't migrated yet, you can do ToStringDuringMigration (you may need to add this, depending what kind of type you already have). This lets us easily find the boundaries of what has and hasn't been migrated.

If it's not there already, you should feel free to thread Cofing.Cwd into whatever code you're working with. It is the fs.AbsolutePath to the root of the monorepo. You can then use your relative paths to get absolute paths for filesystem interactions.

Since it sounds like the transition from fs.AbsolutePath to turbopath.AbsoluteSystemPath is going to be an automated one, I would go with the fs.AbsolutePath for now, since it has the filesystem operations mostly implemented already. But I would except the migration to happen in short order.

Copy link
Contributor

@nathanhammond nathanhammond left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm moving out of the way on this; but still a few more idiosyncrasies left. I suspect @gsoltis can get you another review on this today.

Copy link
Contributor

@gsoltis gsoltis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a heads up, I referenced fs.AbsolutePath, but I mean whichever of fs.AbsolutePath and turbopath.AbsoluteSystemPath has the filesystem integrations implemented in main at the time of merge.

@gsoltis gsoltis added the pr: fixship A PR which is approved with notes and does not require re-review. label Jun 24, 2022
Copy link
Contributor

@gsoltis gsoltis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a couple minor things I noticed on another readthrough, then ship it!

Thanks for tackling this!

@tknickman tknickman dismissed nathanhammond’s stale review June 27, 2022 14:22

Changes addressed, feel free to review if you have time!

@tknickman tknickman added pr: automerge Kodiak will merge these automatically after checks pass and removed pr: fixship A PR which is approved with notes and does not require re-review. labels Jun 27, 2022
@kodiakhq kodiakhq bot merged commit e655e44 into main Jun 27, 2022
@kodiakhq kodiakhq bot deleted the file_perms branch June 27, 2022 15:38
@@ -145,7 +145,7 @@ func (ap AbsolutePath) RelativePathString(path string) (string, error) {
return filepath.Rel(ap.asString(), path)
}

// Symlink implements os.Symlink(target, ap) for absolute path
// Symlink implements os.Symlink(target) for absolute path
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this was correct before. The underlying call is in fact os.Symlink(target, ap.asString()), so os.Symlink(target, ap) where ap is the AbsolutePath matches.

Copy link
Contributor

@nathanhammond nathanhammond left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two things:

  • There is definitely one bug that landed with this which we need to sort out.
  • We apparently don't have any tests that would catch it. Can you get us a red/green pair of commits for this?

if err != nil {
return fmt.Errorf("error stat'ing cache source %v: %v", file, err)
}
if !fromInfo.IsDir() {
if fromType != os.ModeDir {
Copy link
Contributor

@nathanhammond nathanhammond Jun 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an extremely subtle bug. os.ModeDir is part of a bitmask. To test if fromType is not a directory you need to do something like:

fromType & os.ModeDir != os.ModeDir

https://go.dev/play/p/2ZNJ_-cvDx-

if err != nil {
return err
}

if fromInfo.IsDir() {
if fromType == os.ModeDir {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fromType & os.ModeDir == os.ModeDir

fromMode, err := from.GetMode()
isSymlink := err == nil && fromMode&os.ModeSymlink == os.ModeSymlink
fromType, err := from.GetType()
isSymlink := err == nil && fromType == os.ModeSymlink
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change was the thing that tipped me off. Thank you for being so consistent! If you weren't I wouldn't have noted this.

fromType & os.ModeSymlink == os.ModeSymlink

if err != nil {
return err
}
// chrometracing.Path() is absolute by default, but can still be relative if overriden via $CHROMETRACING_DIR
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change seems fine. That's some wild spooky action at a distance from pushing types through the system.

kodiakhq bot pushed a commit that referenced this pull request Jun 28, 2022
kodiakhq bot referenced this pull request in singlestone/sugar Jul 25, 2022
[![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [turbo](https://turborepo.org) ([source](https://togithub.com/vercel/turborepo)) | [`1.3.1` -> `1.3.4`](https://renovatebot.com/diffs/npm/turbo/1.3.1/1.3.4) | [![age](https://badges.renovateapi.com/packages/npm/turbo/1.3.4/age-slim)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://badges.renovateapi.com/packages/npm/turbo/1.3.4/adoption-slim)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://badges.renovateapi.com/packages/npm/turbo/1.3.4/compatibility-slim/1.3.1)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://badges.renovateapi.com/packages/npm/turbo/1.3.4/confidence-slim/1.3.1)](https://docs.renovatebot.com/merge-confidence/) |

---

### Release Notes

<details>
<summary>vercel/turborepo</summary>

### [`v1.3.4`](https://togithub.com/vercel/turborepo/releases/tag/v1.3.4)

[Compare Source](https://togithub.com/vercel/turborepo/compare/v1.3.3...v1.3.4)

#### What's Changed

-   fix(deps): update dependency [@&#8203;react-types/radio](https://togithub.com/react-types/radio) to v3.2.1 by [@&#8203;renovate](https://togithub.com/renovate) in [https://github.com/vercel/turborepo/pull/1553](https://togithub.com/vercel/turborepo/pull/1553)
-   Move fixtures to correct directory. by [@&#8203;nathanhammond](https://togithub.com/nathanhammond) in [https://github.com/vercel/turborepo/pull/1561](https://togithub.com/vercel/turborepo/pull/1561)
-   fix(cli): don’t exit when no tasks are found by [@&#8203;tknickman](https://togithub.com/tknickman) in [https://github.com/vercel/turborepo/pull/1564](https://togithub.com/vercel/turborepo/pull/1564)

**Full Changelog**: vercel/turborepo@v1.3.3...v1.3.4

### [`v1.3.3`](https://togithub.com/vercel/turborepo/releases/tag/v1.3.3)

[Compare Source](https://togithub.com/vercel/turborepo/compare/v1.3.2...v1.3.3)

#### What's Changed

-   fix(create-turbo): pnpm peer deps error by [@&#8203;tknickman](https://togithub.com/tknickman) in [https://github.com/vercel/turborepo/pull/1559](https://togithub.com/vercel/turborepo/pull/1559)

**Full Changelog**: vercel/turborepo@v1.3.2...v1.3.3

### [`v1.3.2`](https://togithub.com/vercel/turborepo/releases/tag/v1.3.2)

[Compare Source](https://togithub.com/vercel/turborepo/compare/v1.3.1...v1.3.2)

#### Core

-   Update schema generation script invocation. by [@&#8203;nathanhammond](https://togithub.com/nathanhammond) in [https://github.com/vercel/turborepo/pull/1436](https://togithub.com/vercel/turborepo/pull/1436)
-   fix(cli): cache with correct file perms by [@&#8203;tknickman](https://togithub.com/tknickman) in [https://github.com/vercel/turborepo/pull/1429](https://togithub.com/vercel/turborepo/pull/1429)
-   Watch task outputs to avoid cache restorations by [@&#8203;gsoltis](https://togithub.com/gsoltis) in [https://github.com/vercel/turborepo/pull/1269](https://togithub.com/vercel/turborepo/pull/1269)
-   Vendor chrometracing, add Close method by [@&#8203;gsoltis](https://togithub.com/gsoltis) in [https://github.com/vercel/turborepo/pull/1443](https://togithub.com/vercel/turborepo/pull/1443)
-   Fix symlink mode check. by [@&#8203;nathanhammond](https://togithub.com/nathanhammond) in [https://github.com/vercel/turborepo/pull/1447](https://togithub.com/vercel/turborepo/pull/1447)
-   Fix hashing uncommitted changes by [@&#8203;gsoltis](https://togithub.com/gsoltis) in [https://github.com/vercel/turborepo/pull/1448](https://togithub.com/vercel/turborepo/pull/1448)
-   Cross-compile amd64. by [@&#8203;nathanhammond](https://togithub.com/nathanhammond) in [https://github.com/vercel/turborepo/pull/1452](https://togithub.com/vercel/turborepo/pull/1452)
-   fix(cli): prefer IsDir() over explicit type check by [@&#8203;tknickman](https://togithub.com/tknickman) in [https://github.com/vercel/turborepo/pull/1445](https://togithub.com/vercel/turborepo/pull/1445)
-   Add test to confirm that file copying works as expected. by [@&#8203;nathanhammond](https://togithub.com/nathanhammond) in [https://github.com/vercel/turborepo/pull/1450](https://togithub.com/vercel/turborepo/pull/1450)
-   fix: remove suggestion of using fetch-depth by [@&#8203;harshcut](https://togithub.com/harshcut) in [https://github.com/vercel/turborepo/pull/1438](https://togithub.com/vercel/turborepo/pull/1438)
-   Chip away at path migration by [@&#8203;gsoltis](https://togithub.com/gsoltis) in [https://github.com/vercel/turborepo/pull/1459](https://togithub.com/vercel/turborepo/pull/1459)
-   Implement allowing both sides of git comparison by [@&#8203;gsoltis](https://togithub.com/gsoltis) in [https://github.com/vercel/turborepo/pull/1442](https://togithub.com/vercel/turborepo/pull/1442)
-   Move some fields out of Config by [@&#8203;gsoltis](https://togithub.com/gsoltis) in [https://github.com/vercel/turborepo/pull/1460](https://togithub.com/vercel/turborepo/pull/1460)
-   chore: remove redundant `.turbo` by [@&#8203;shayc](https://togithub.com/shayc) in [https://github.com/vercel/turborepo/pull/1475](https://togithub.com/vercel/turborepo/pull/1475)
-   Depending on root tasks should work by [@&#8203;gsoltis](https://togithub.com/gsoltis) in [https://github.com/vercel/turborepo/pull/1485](https://togithub.com/vercel/turborepo/pull/1485)
-   Implement filesystem cookies for filewatch ordering by [@&#8203;gsoltis](https://togithub.com/gsoltis) in [https://github.com/vercel/turborepo/pull/1410](https://togithub.com/vercel/turborepo/pull/1410)
-   Label root package in dependency graph by [@&#8203;gsoltis](https://togithub.com/gsoltis) in [https://github.com/vercel/turborepo/pull/1491](https://togithub.com/vercel/turborepo/pull/1491)
-   Implement fsevents by [@&#8203;gsoltis](https://togithub.com/gsoltis) in [https://github.com/vercel/turborepo/pull/1419](https://togithub.com/vercel/turborepo/pull/1419)
-   Bug: Fix logic that wipes out part of the config by [@&#8203;StevenMatchett](https://togithub.com/StevenMatchett) in [https://github.com/vercel/turborepo/pull/1527](https://togithub.com/vercel/turborepo/pull/1527)
-   Add schema.json to create-turbo templates by [@&#8203;jaredpalmer](https://togithub.com/jaredpalmer) in [https://github.com/vercel/turborepo/pull/1537](https://togithub.com/vercel/turborepo/pull/1537)
-   Filter in package by [@&#8203;nathanhammond](https://togithub.com/nathanhammond) in [https://github.com/vercel/turborepo/pull/1538](https://togithub.com/vercel/turborepo/pull/1538)

#### Internal

-   Ensure we fail if no examples are run by [@&#8203;gsoltis](https://togithub.com/gsoltis) in [https://github.com/vercel/turborepo/pull/1441](https://togithub.com/vercel/turborepo/pull/1441)
-   Bump e2e pnpm to 7 by [@&#8203;gsoltis](https://togithub.com/gsoltis) in [https://github.com/vercel/turborepo/pull/1444](https://togithub.com/vercel/turborepo/pull/1444)
-   Add missing dependencies to OSX setup by [@&#8203;trevorr](https://togithub.com/trevorr) in [https://github.com/vercel/turborepo/pull/1487](https://togithub.com/vercel/turborepo/pull/1487)
-   Add golang to OSX setup by [@&#8203;neolivz](https://togithub.com/neolivz) in [https://github.com/vercel/turborepo/pull/1492](https://togithub.com/vercel/turborepo/pull/1492)
-   Configure Renovate by [@&#8203;renovate](https://togithub.com/renovate) in [https://github.com/vercel/turborepo/pull/1499](https://togithub.com/vercel/turborepo/pull/1499)
-   chore(deps): update dependency [@&#8203;types/react](https://togithub.com/types/react) to v17.0.47 by [@&#8203;renovate](https://togithub.com/renovate) in [https://github.com/vercel/turborepo/pull/1514](https://togithub.com/vercel/turborepo/pull/1514)
-   chore(deps): update dependency ts-json-schema-generator to v0.98.0 by [@&#8203;renovate](https://togithub.com/renovate) in [https://github.com/vercel/turborepo/pull/1516](https://togithub.com/vercel/turborepo/pull/1516)
-   chore(renovate): support go mod tidy by [@&#8203;tknickman](https://togithub.com/tknickman) in [https://github.com/vercel/turborepo/pull/1515](https://togithub.com/vercel/turborepo/pull/1515)
-   fix(deps): update dependency [@&#8203;heroicons/react](https://togithub.com/heroicons/react) to v1.0.6 by [@&#8203;renovate](https://togithub.com/renovate) in [https://github.com/vercel/turborepo/pull/1520](https://togithub.com/vercel/turborepo/pull/1520)
-   chore(deps): update dependency [@&#8203;babel/core](https://togithub.com/babel/core) to v7.18.6 by [@&#8203;renovate](https://togithub.com/renovate) in [https://github.com/vercel/turborepo/pull/1523](https://togithub.com/vercel/turborepo/pull/1523)
-   chore(deps): update dependency tailwindcss to v3.1.6 by [@&#8203;renovate](https://togithub.com/renovate) in [https://github.com/vercel/turborepo/pull/1529](https://togithub.com/vercel/turborepo/pull/1529)
-   chore(deps): update dependency autoprefixer to v10.4.7 by [@&#8203;renovate](https://togithub.com/renovate) in [https://github.com/vercel/turborepo/pull/1530](https://togithub.com/vercel/turborepo/pull/1530)
-   chore(deps): update dependency eslint-config-prettier to v8.5.0 by [@&#8203;renovate](https://togithub.com/renovate) in [https://github.com/vercel/turborepo/pull/1531](https://togithub.com/vercel/turborepo/pull/1531)
-   chore(deps): update pnpm/action-setup action to v2.2.2 by [@&#8203;renovate](https://togithub.com/renovate) in [https://github.com/vercel/turborepo/pull/1546](https://togithub.com/vercel/turborepo/pull/1546)
-   chore(deps): update dependency postcss to v8.4.14 by [@&#8203;renovate](https://togithub.com/renovate) in [https://github.com/vercel/turborepo/pull/1542](https://togithub.com/vercel/turborepo/pull/1542)
-   Makefile works for turbobot by [@&#8203;nathanhammond](https://togithub.com/nathanhammond) in [https://github.com/vercel/turborepo/pull/1550](https://togithub.com/vercel/turborepo/pull/1550)

#### Examples

-   feat(examples): add svelte by [@&#8203;tknickman](https://togithub.com/tknickman) in [https://github.com/vercel/turborepo/pull/1458](https://togithub.com/vercel/turborepo/pull/1458)
-   Fix `yarn start` not working by [@&#8203;elis](https://togithub.com/elis) in [https://github.com/vercel/turborepo/pull/1468](https://togithub.com/vercel/turborepo/pull/1468)
-   feat(examples): add tailwind by [@&#8203;tknickman](https://togithub.com/tknickman) in [https://github.com/vercel/turborepo/pull/1464](https://togithub.com/vercel/turborepo/pull/1464)
-   fix: added vite.config and fixes for svelte-next.358 by [@&#8203;oneezy](https://togithub.com/oneezy) in [https://github.com/vercel/turborepo/pull/1496](https://togithub.com/vercel/turborepo/pull/1496)
-   chore(examples): update tsconfig declaration val by [@&#8203;tknickman](https://togithub.com/tknickman) in [https://github.com/vercel/turborepo/pull/1483](https://togithub.com/vercel/turborepo/pull/1483)
-   feat(examples): add react-native-web by [@&#8203;tknickman](https://togithub.com/tknickman) in [https://github.com/vercel/turborepo/pull/1486](https://togithub.com/vercel/turborepo/pull/1486)
-   Fix tailwind example by [@&#8203;kocisov](https://togithub.com/kocisov) in [https://github.com/vercel/turborepo/pull/1500](https://togithub.com/vercel/turborepo/pull/1500)
-   feat(examples): add nextjs by [@&#8203;tknickman](https://togithub.com/tknickman) in [https://github.com/vercel/turborepo/pull/1506](https://togithub.com/vercel/turborepo/pull/1506)

#### Documentation

-   docs(cli): update contributing.md with new deps by [@&#8203;tknickman](https://togithub.com/tknickman) in [https://github.com/vercel/turborepo/pull/1449](https://togithub.com/vercel/turborepo/pull/1449)
-   Update caching.mdx by [@&#8203;chitchu](https://togithub.com/chitchu) in [https://github.com/vercel/turborepo/pull/1482](https://togithub.com/vercel/turborepo/pull/1482)
-   fix(docs): update prune compatibility by [@&#8203;tknickman](https://togithub.com/tknickman) in [https://github.com/vercel/turborepo/pull/1505](https://togithub.com/vercel/turborepo/pull/1505)
-   Typo: verifcation --> verification by [@&#8203;samouri](https://togithub.com/samouri) in [https://github.com/vercel/turborepo/pull/1517](https://togithub.com/vercel/turborepo/pull/1517)
-   Add `with-prisma` example by [@&#8203;NuroDev](https://togithub.com/NuroDev) in [https://github.com/vercel/turborepo/pull/979](https://togithub.com/vercel/turborepo/pull/979)
-   feat(examples): add cra by [@&#8203;tknickman](https://togithub.com/tknickman) in [https://github.com/vercel/turborepo/pull/1504](https://togithub.com/vercel/turborepo/pull/1504)
-   Examples fast follows by [@&#8203;tknickman](https://togithub.com/tknickman) in [https://github.com/vercel/turborepo/pull/1526](https://togithub.com/vercel/turborepo/pull/1526)
-   feat(examples): add docker by [@&#8203;tknickman](https://togithub.com/tknickman) in [https://github.com/vercel/turborepo/pull/1522](https://togithub.com/vercel/turborepo/pull/1522)
-   chore(examples): clean the kitchen (sink) by [@&#8203;tknickman](https://togithub.com/tknickman) in [https://github.com/vercel/turborepo/pull/1534](https://togithub.com/vercel/turborepo/pull/1534)
-   \[example/kitchensink] allow accessing vite on any ip/hostname  by [@&#8203;zsoldosp](https://togithub.com/zsoldosp) in [https://github.com/vercel/turborepo/pull/1532](https://togithub.com/vercel/turborepo/pull/1532)
-   chore(docs): improvements by [@&#8203;tknickman](https://togithub.com/tknickman) in [https://github.com/vercel/turborepo/pull/1540](https://togithub.com/vercel/turborepo/pull/1540)

#### New Contributors

-   [@&#8203;harshcut](https://togithub.com/harshcut) made their first contribution in [https://github.com/vercel/turborepo/pull/1438](https://togithub.com/vercel/turborepo/pull/1438)
-   [@&#8203;shayc](https://togithub.com/shayc) made their first contribution in [https://github.com/vercel/turborepo/pull/1475](https://togithub.com/vercel/turborepo/pull/1475)
-   [@&#8203;elis](https://togithub.com/elis) made their first contribution in [https://github.com/vercel/turborepo/pull/1468](https://togithub.com/vercel/turborepo/pull/1468)
-   [@&#8203;chitchu](https://togithub.com/chitchu) made their first contribution in [https://github.com/vercel/turborepo/pull/1482](https://togithub.com/vercel/turborepo/pull/1482)
-   [@&#8203;trevorr](https://togithub.com/trevorr) made their first contribution in [https://github.com/vercel/turborepo/pull/1487](https://togithub.com/vercel/turborepo/pull/1487)
-   [@&#8203;oneezy](https://togithub.com/oneezy) made their first contribution in [https://github.com/vercel/turborepo/pull/1496](https://togithub.com/vercel/turborepo/pull/1496)
-   [@&#8203;neolivz](https://togithub.com/neolivz) made their first contribution in [https://github.com/vercel/turborepo/pull/1492](https://togithub.com/vercel/turborepo/pull/1492)
-   [@&#8203;kocisov](https://togithub.com/kocisov) made their first contribution in [https://github.com/vercel/turborepo/pull/1500](https://togithub.com/vercel/turborepo/pull/1500)
-   [@&#8203;renovate](https://togithub.com/renovate) made their first contribution in [https://github.com/vercel/turborepo/pull/1499](https://togithub.com/vercel/turborepo/pull/1499)
-   [@&#8203;samouri](https://togithub.com/samouri) made their first contribution in [https://github.com/vercel/turborepo/pull/1517](https://togithub.com/vercel/turborepo/pull/1517)
-   [@&#8203;NuroDev](https://togithub.com/NuroDev) made their first contribution in [https://github.com/vercel/turborepo/pull/979](https://togithub.com/vercel/turborepo/pull/979)
-   [@&#8203;zsoldosp](https://togithub.com/zsoldosp) made their first contribution in [https://github.com/vercel/turborepo/pull/1532](https://togithub.com/vercel/turborepo/pull/1532)
-   [@&#8203;StevenMatchett](https://togithub.com/StevenMatchett) made their first contribution in [https://github.com/vercel/turborepo/pull/1527](https://togithub.com/vercel/turborepo/pull/1527)

**Full Changelog**: vercel/turborepo@v1.3.1...v1.3.2

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, click this checkbox.

---

This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://app.renovatebot.com/dashboard#github/singlestone/sugar).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzMi4xMjIuMSIsInVwZGF0ZWRJblZlciI6IjMyLjEyMi4xIn0=-->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pr: automerge Kodiak will merge these automatically after checks pass
Projects
None yet
Development

Successfully merging this pull request may close these issues.

File Permissions not Preserved from Cache
4 participants