mirror of
https://github.com/tiktok/sparo.git
synced 2025-02-24 13:33:59 -05:00
1 line
No EOL
8.7 KiB
JavaScript
1 line
No EOL
8.7 KiB
JavaScript
"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[739],{4699:(e,s,r)=>{r.r(s),r.d(s,{assets:()=>l,contentTitle:()=>t,default:()=>d,frontMatter:()=>i,metadata:()=>a,toc:()=>c});var o=r(678),n=r(4738);const i={title:"Sparo profiles"},t=void 0,a={id:"pages/guide/sparo_profiles",title:"Sparo profiles",description:'Git\'s sparse checkout feature normally relies on a collection of glob patterns that are stored in the .git/info/sparse-checkout config file. Normal glob syntax proved to be too inefficient, so Git instead uses "cone mode" that ignores file-matching patterns and only matches directories.',source:"@site/docs/pages/guide/sparo_profiles.md",sourceDirName:"pages/guide",slug:"/pages/guide/sparo_profiles",permalink:"/sparo/pages/guide/sparo_profiles",draft:!1,unlisted:!1,editUrl:"https://github.com/tiktok/sparo/tree/main/apps/website/docs/pages/guide/sparo_profiles.md",tags:[],version:"current",frontMatter:{title:"Sparo profiles"},sidebar:"docsSidebar",previous:{title:"Getting Started",permalink:"/sparo/pages/guide/getting_started"},next:{title:"Git optimization",permalink:"/sparo/pages/reference/git_optimization"}},l={},c=[{value:"Best practices for profiles",id:"best-practices-for-profiles",level:2},{value:"Combining profiles",id:"combining-profiles",level:2},{value:"Querying profiles",id:"querying-profiles",level:2}];function p(e){const s={a:"a",code:"code",em:"em",h2:"h2",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,n.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsxs)(s.p,{children:["Git's sparse checkout feature normally relies on a collection of glob patterns that are stored in the ",(0,o.jsx)(s.code,{children:".git/info/sparse-checkout"})," config file. Normal glob syntax proved to be too inefficient, so Git instead uses ",(0,o.jsx)(s.a,{href:"https://git-scm.com/docs/git-sparse-checkout#_internalsnon_cone_problems",children:'"cone mode"'})," that ignores file-matching patterns and only matches directories."]}),"\n",(0,o.jsx)(s.p,{children:"The syntax looks something like this:"}),"\n",(0,o.jsx)(s.p,{children:(0,o.jsx)(s.strong,{children:".git/info/sparse-checkout example"})}),"\n",(0,o.jsx)(s.pre,{children:(0,o.jsx)(s.code,{children:"/*\r\n!/*/\r\n/apps/\r\n!/apps/*/\r\n/apps/my-app/\r\n!/apps/my-app/*/\r\n/apps/my-app/_/\n"})}),"\n",(0,o.jsxs)(s.p,{children:["To simplify management, the ",(0,o.jsx)(s.code,{children:"git sparse-checkout"})," command line provides convenient ways to add/remove patterns from this file. However, in a large monorepo with hundreds of projects, managing these globs can be confusing and error-prone."]}),"\n",(0,o.jsxs)(s.p,{children:["Sparo's approach is to generate the ",(0,o.jsx)(s.code,{children:".git/info/sparse-checkout"})," configuration from config files called profiles. This provides many benefits:"]}),"\n",(0,o.jsxs)(s.ul,{children:["\n",(0,o.jsxs)(s.li,{children:["\n",(0,o.jsxs)(s.p,{children:["Profiles are specified using ",(0,o.jsx)(s.a,{href:"https://rushjs.io/pages/developer/selecting_subsets/#--to",children:"project selectors"}),", for example: ",(0,o.jsxs)(s.em,{children:['"Give me ',(0,o.jsx)(s.strong,{children:"app1"}),", ",(0,o.jsx)(s.strong,{children:"app2"}),', and all the projects needed to build them."']})," This is more concise and maintainable than specifying globs."]}),"\n"]}),"\n",(0,o.jsxs)(s.li,{children:["\n",(0,o.jsx)(s.p,{children:"Profiles are stored in a config file and committed to Git. This makes it easy to share them with your teammates."}),"\n"]}),"\n",(0,o.jsxs)(s.li,{children:["\n",(0,o.jsx)(s.p,{children:"Profiles are automatically updated when switching between branches, which ensures deterministic results. For example, when checking out a very old branch, you want the old profile definition, not today's version of it."}),"\n"]}),"\n",(0,o.jsxs)(s.li,{children:["\n",(0,o.jsxs)(s.p,{children:["You combine multiple profiles at the same time (",(0,o.jsx)(s.code,{children:"sparo checkout --profile team1 --profile team2"}),"), which produces the union of their subsets. This is useful for example when modifying a library project that is consumed by projects belonging to several other teams. You could instead use a selector ",(0,o.jsx)(s.code,{children:"--from the-library"})," of course, but it's likely those other teams have included other relevant projects in their profiles."]}),"\n"]}),"\n",(0,o.jsxs)(s.li,{children:["\n",(0,o.jsxs)(s.p,{children:["Sparo avoids common mistakes by imposing additional restrictions beyond ",(0,o.jsx)(s.code,{children:"git sparse-checkout"}),"."]}),"\n"]}),"\n"]}),"\n",(0,o.jsx)(s.h2,{id:"best-practices-for-profiles",children:"Best practices for profiles"}),"\n",(0,o.jsx)(s.p,{children:"You an add JSON comments to your profile config files. In a large shared codebase, we recommend adding a standardized header to the top of your files indicating their ownership and purpose. Something like this:"}),"\n",(0,o.jsx)(s.p,{children:(0,o.jsx)(s.strong,{children:"common/sparo-profiles/example-profile.json"})}),"\n",(0,o.jsx)(s.pre,{children:(0,o.jsx)(s.code,{className:"language-js",children:'/**\r\n * OWNER: Customer service team\r\n * PURPOSE: Use this profile when working on the customer service apps.\r\n */\r\n{\r\n "$schema": "https://tiktok.github.io/sparo/schemas/sparo-profile.schema.json",\r\n\r\n /**\r\n * A list of Rush project selectors indicating the project folders to be\r\n * included for sparse checkout. The selectors will be combined to make\r\n * the union superset of projects. See the Rush selector docs for details:\r\n * https://rushjs.io/pages/developer/selecting_subsets/\r\n */\r\n "selections": [\r\n {\r\n "selector": "--to",\r\n "argument": "tag:cs-dashboard"\r\n },\r\n {\r\n "selector": "--to",\r\n "argument": "tag:cs-tools"\r\n }\r\n ]\r\n}\n'})}),"\n",(0,o.jsx)(s.h2,{id:"combining-profiles",children:"Combining profiles"}),"\n",(0,o.jsxs)(s.p,{children:["The simple way to combine profiles is to specify ",(0,o.jsx)(s.code,{children:"--profile"})," multiple times. For example:"]}),"\n",(0,o.jsx)(s.pre,{children:(0,o.jsx)(s.code,{className:"language-shell",children:"# Check out the union of profiles team-a.json, team-b.json, team-c.json\r\n# NOTE: This will replace whatever profile selection was already checked out.\r\nsparo checkout --profile team-a --profile team-b --profile team-c\n"})}),"\n",(0,o.jsxs)(s.p,{children:["You can also use ",(0,o.jsx)(s.code,{children:"--add-profile"})," to incrementally combine them. For example:"]}),"\n",(0,o.jsx)(s.pre,{children:(0,o.jsx)(s.code,{className:"language-shell",children:"# These three commands are equivalent to the above command.\r\nsparo checkout --profile team-a\r\nsparo checkout --add-profile team-b\r\nsparo checkout --add-profile team-c\n"})}),"\n",(0,o.jsxs)(s.p,{children:["How to checkout NO profile? In other words, returning to the ",(0,o.jsx)(s.a,{href:"/sparo/pages/reference/skeleton_folders",children:"skeleton"})," state of a clean ",(0,o.jsx)(s.code,{children:"sparo clone"}),"? It can't be ",(0,o.jsx)(s.code,{children:"sparo checkout"}),", because if ",(0,o.jsx)(s.code,{children:"--profile"})," is entirely omitted then the existing profile selection is preserved."]}),"\n",(0,o.jsx)(s.pre,{children:(0,o.jsx)(s.code,{className:"language-shell",children:"# NOT IMPLEMENTED YET - check out just the skeleton folders\r\n# without applying any profiles\r\nsparo checkout --no-profile\n"})}),"\n",(0,o.jsx)(s.h2,{id:"querying-profiles",children:"Querying profiles"}),"\n",(0,o.jsxs)(s.p,{children:["Engineers can find available profiles in the current branch by invoking the ",(0,o.jsx)(s.a,{href:"../commands/sparo_list-profiles",children:"sparo list-profiles"})," command. The ",(0,o.jsx)(s.code,{children:"--project"})," parameter enables you to query relevant profiles for a given project. For example:"]}),"\n",(0,o.jsx)(s.pre,{children:(0,o.jsx)(s.code,{className:"language-shell",children:'# Suppose you need to make a fix for the "example-app" project.\r\n\r\n# Which sparse checkout profiles include the "example-app" project?\r\nsparo list-profiles --project example-app\r\n\r\n# Great, let\'s add the "example-profile" result to our current checkout\r\n# (combining it with the existing profile).\r\nsparo checkout --add-profile example-profile\n'})})]})}function d(e={}){const{wrapper:s}={...(0,n.R)(),...e.components};return s?(0,o.jsx)(s,{...e,children:(0,o.jsx)(p,{...e})}):p(e)}},4738:(e,s,r)=>{r.d(s,{R:()=>t,x:()=>a});var o=r(6166);const n={},i=o.createContext(n);function t(e){const s=o.useContext(i);return o.useMemo((function(){return"function"==typeof e?e(s):{...s,...e}}),[s,e])}function a(e){let s;return s=e.disableParentContext?"function"==typeof e.components?e.components(n):e.components||n:t(e.components),o.createElement(i.Provider,{value:s},e.children)}}}]); |