Skip to content

Commit 0d3e2e1

Browse files
committed
Merge remote-tracking branch 'origin/main' into feat/cli-types-python
2 parents a111fcc + d50ff37 commit 0d3e2e1

27 files changed

Lines changed: 1028 additions & 125 deletions

‎src/SDK/Language/CLI.php‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,6 +1122,11 @@ public function getFiles(): array
11221122
'destination' => 'internal/cmd/initscaffold_test.go',
11231123
'template' => 'cli/internal/cmd/initscaffold_test.go',
11241124
],
1125+
[
1126+
'scope' => 'copy',
1127+
'destination' => 'internal/cmd/initsite_test.go',
1128+
'template' => 'cli/internal/cmd/initsite_test.go',
1129+
],
11251130
[
11261131
'scope' => 'default',
11271132
'destination' => 'internal/cmd/initfunction.go',
@@ -1589,6 +1594,11 @@ public function getFiles(): array
15891594
'destination' => 'internal/typegen/casing_test.go',
15901595
'template' => 'cli/internal/typegen/casing_test.go',
15911596
],
1597+
[
1598+
'scope' => 'copy',
1599+
'destination' => 'internal/typegen/enum_style.go',
1600+
'template' => 'cli/internal/typegen/enum_style.go',
1601+
],
15921602
[
15931603
'scope' => 'copy',
15941604
'destination' => 'internal/typegen/language.go',
@@ -1627,6 +1637,16 @@ public function getFiles(): array
16271637
'destination' => 'internal/typegen/testdata/ts.strict.appwrite.d.ts',
16281638
'template' => 'cli/internal/typegen/testdata/ts.strict.appwrite.d.ts',
16291639
],
1640+
[
1641+
'scope' => 'copy',
1642+
'destination' => 'internal/typegen/testdata/ts.const.appwrite.d.ts',
1643+
'template' => 'cli/internal/typegen/testdata/ts.const.appwrite.d.ts',
1644+
],
1645+
[
1646+
'scope' => 'copy',
1647+
'destination' => 'internal/typegen/testdata/ts.const.appwrite.ts',
1648+
'template' => 'cli/internal/typegen/testdata/ts.const.appwrite.ts',
1649+
],
16301650
[
16311651
'scope' => 'copy',
16321652
'destination' => 'internal/typegen/testdata/js.loose.appwrite-types.js',
@@ -1852,6 +1872,11 @@ public function getFiles(): array
18521872
'destination' => 'internal/generator/testdata/server.types.ts',
18531873
'template' => 'cli/internal/generator/testdata/server.types.ts',
18541874
],
1875+
[
1876+
'scope' => 'copy',
1877+
'destination' => 'internal/generator/testdata/server.const.types.ts',
1878+
'template' => 'cli/internal/generator/testdata/server.const.types.ts',
1879+
],
18551880
[
18561881
'scope' => 'copy',
18571882
'destination' => 'internal/generator/testdata/server.index.ts',

‎templates/cli/internal/app/install.go.twig‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"runtime"
88
"strings"
99

10+
"github.com/{{ sdk.gitUserName }}/{{ sdk.gitRepoName | caseDash }}/internal/config"
1011
"github.com/{{ sdk.gitUserName }}/{{ sdk.gitRepoName | caseDash }}/internal/update"
1112
)
1213

@@ -165,7 +166,7 @@ func UpdateChecker() *update.Checker {
165166
return nil
166167
}
167168

168-
home, err := os.UserHomeDir()
169+
directory, err := config.GlobalDirectory(ExecutableName)
169170
if err != nil {
170171
return nil
171172
}
@@ -174,7 +175,7 @@ func UpdateChecker() *update.Checker {
174175
RegistryURL: NPMRegistryURL,
175176
PrereleaseRegistryURL: NPMPrereleaseRegistryURL,
176177
// Beside the preferences, which is already the directory this CLI owns.
177-
CachePath: filepath.Join(home, "."+ExecutableName, "update-check.json"),
178+
CachePath: filepath.Join(directory, "update-check.json"),
178179
Current: Version,
179180
}
180181
}

‎templates/cli/internal/cmd/completion_test.go‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ func setHome(t *testing.T) string {
2323
home := t.TempDir()
2424
t.Setenv("HOME", home)
2525
t.Setenv("USERPROFILE", home)
26+
t.Setenv("XDG_CONFIG_HOME", "")
2627

2728
return home
2829
}

‎templates/cli/internal/cmd/fanout_test.go‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ func TestAllSubcommandsNeverPrompt(t *testing.T) {
118118
home := t.TempDir()
119119
t.Setenv("HOME", home)
120120
t.Setenv("USERPROFILE", home)
121+
t.Setenv("XDG_CONFIG_HOME", "")
121122
inDirectory(t, t.TempDir())
122123

123124
root := NewRootCommand()

‎templates/cli/internal/cmd/generate.go‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"github.com/{{ sdk.gitUserName }}/{{ sdk.gitRepoName | caseDash }}/internal/generator"
1414
"github.com/{{ sdk.gitUserName }}/{{ sdk.gitRepoName | caseDash }}/internal/jsonx"
1515
"github.com/{{ sdk.gitUserName }}/{{ sdk.gitRepoName | caseDash }}/internal/output"
16+
"github.com/{{ sdk.gitUserName }}/{{ sdk.gitRepoName | caseDash }}/internal/typegen"
1617
"github.com/spf13/cobra"
1718
)
1819

@@ -26,6 +27,7 @@ func newGenerateCommand() *cobra.Command {
2627
serverSide string
2728
importSource string
2829
importExtension string
30+
enumStyle string
2931
)
3032

3133
command := &cobra.Command{
@@ -39,7 +41,7 @@ func newGenerateCommand() *cobra.Command {
3941
extension = &importExtension
4042
}
4143

42-
return runGenerate(command, outputDirectory, language, serverSide, importSource, extension)
44+
return runGenerate(command, outputDirectory, language, serverSide, importSource, extension, enumStyle)
4345
},
4446
}
4547

@@ -60,6 +62,8 @@ func newGenerateCommand() *cobra.Command {
6062
command.Flags().StringVar(&importExtension, "import-extension", "",
6163
`Override import file extension in generated files (.js for ESM, empty string for CJS). `+
6264
`Auto-detected from package.json "type" field if not provided.`)
65+
command.Flags().StringVar(&enumStyle, "enum-style", string(typegen.EnumStyleEnum),
66+
"How enums are declared in types.ts ("+typegen.EnumStyleChoices()+"); const emits an `as const` object and a union type")
6367

6468
return command
6569
}
@@ -121,6 +125,7 @@ func runGenerate(
121125
command *cobra.Command,
122126
outputDirectory, language, serverSide, importSource string,
123127
importExtension *string,
128+
rawEnumStyle string,
124129
) error {
125130
working, err := os.Getwd()
126131
if err != nil {
@@ -142,6 +147,11 @@ func runGenerate(
142147
return fmt.Errorf("invalid --server value: %s", serverSide)
143148
}
144149

150+
enumStyle, err := typegen.ParseEnumStyle(rawEnumStyle)
151+
if err != nil {
152+
return err
153+
}
154+
145155
created, name, err := resolveGenerator(command, language, working)
146156
if err != nil {
147157
return err
@@ -158,6 +168,7 @@ func runGenerate(
158168
ImportSource: importSource,
159169
ImportExtension: importExtension,
160170
ServerSide: serverSide,
171+
EnumStyle: enumStyle,
161172
})
162173
if err != nil {
163174
return fmt.Errorf("failed to generate SDK: %w", err)

‎templates/cli/internal/cmd/generate_test.go‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ func TestGenerateEndpointFallsBackToTheDefault(t *testing.T) {
4444
home := t.TempDir()
4545
t.Setenv("HOME", home)
4646
t.Setenv("USERPROFILE", home)
47+
t.Setenv("XDG_CONFIG_HOME", "")
4748

4849
if got := resolveGenerateEndpoint(""); got != config.DefaultEndpoint {
4950
t.Errorf("endpoint = %q, want %q", got, config.DefaultEndpoint)

‎templates/cli/internal/cmd/initscaffold.go‎

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010
"os"
1111
"os/exec"
1212
"path/filepath"
13-
"runtime"
1413
"strings"
1514
)
1615

@@ -19,25 +18,6 @@ import (
1918
// All three fetch starter code with git and copy a subtree into the project,
2019
// so the clone, the error translation and the recursive copy live here once.
2120

22-
// runGit runs a git invocation with its output captured.
23-
//
24-
// Output is captured rather than streamed: a sparse checkout prints progress
25-
// that means nothing to someone running `init function`, and the text is only
26-
// wanted when it fails.
27-
func runGit(directory string, script string) error {
28-
var command *exec.Cmd
29-
30-
switch {
31-
case runtime.GOOS == "windows":
32-
// cmd rather than PowerShell, which has no `&&`.
33-
command = exec.Command("cmd", "/c", script)
34-
default:
35-
command = exec.Command("sh", "-c", script)
36-
}
37-
38-
return executeGit(command, directory)
39-
}
40-
4121
// runGitCommand invokes Git without a shell. Use it when arguments contain
4222
// values received from an API or remote repository, so ref names and paths are
4323
// passed literally rather than interpreted as shell syntax.
@@ -101,7 +81,8 @@ func gitError(message string) error {
10181
return fmt.Errorf("%s \n\nSuggestion: Try updating your git to the "+
10282
"latest version, then trying to run this command again", message)
10383
case strings.Contains(message, "is not recognized as an internal or external command,"),
104-
strings.Contains(message, "command not found"):
84+
strings.Contains(message, "command not found"),
85+
strings.Contains(message, "executable file not found"):
10586
return fmt.Errorf("%s \n\nSuggestion: It appears that git is not "+
10687
"installed, try installing git then trying to run this command again", message)
10788
}

‎templates/cli/internal/cmd/initscaffold_test.go‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,3 +161,13 @@ func TestParseSkillFrontmatterWithoutABlock(t *testing.T) {
161161
t.Errorf("got (%q, %q), want two empty strings", name, description)
162162
}
163163
}
164+
165+
func TestRunGitCommandSuggestsInstallingGitWhenItIsMissing(t *testing.T) {
166+
t.Setenv("PATH", t.TempDir())
167+
168+
err := runGitCommand(t.TempDir(), "--version")
169+
170+
if err == nil || !strings.Contains(err.Error(), "git is not installed") {
171+
t.Errorf("err = %v, want the missing-git suggestion", err)
172+
}
173+
}

‎templates/cli/internal/cmd/initsite.go‎

Lines changed: 21 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -313,10 +313,6 @@ func siteEntryRequiresBuildCommand(entry SiteEntry) bool {
313313
}
314314

315315
// downloadSiteTemplate fetches the framework's starter into the site directory.
316-
//
317-
// The clone is built by hand rather than with `git clone` because the template
318-
// lives at a tag in a subdirectory of a shared repository: a sparse checkout of
319-
// one directory at one tag is cheaper than cloning the whole thing.
320316
func downloadSiteTemplate(
321317
out interface{ Write([]byte) (int, error) },
322318
template *siteTemplate,
@@ -330,7 +326,7 @@ func downloadSiteTemplate(
330326
return fmt.Errorf("No starter template found for framework %s", framework)
331327
}
332328

333-
root := template.Frameworks[0].ProviderRootDirectory
329+
root := strings.Trim(strings.TrimPrefix(template.Frameworks[0].ProviderRootDirectory, "./"), "/")
334330

335331
if err := os.MkdirAll(siteFolder, 0o777); err != nil {
336332
return err
@@ -340,48 +336,38 @@ func downloadSiteTemplate(
340336
}
341337
defer os.RemoveAll(templatesDir)
342338

343-
repo := fmt.Sprintf("https://github.com/%s/%s",
339+
repository := fmt.Sprintf("https://github.com/%s/%s",
344340
template.ProviderOwner, template.ProviderRepositoryID)
345341

346-
setup := []string{
347-
"git init",
348-
"git remote add origin " + repo,
349-
"git config --global init.defaultBranch main",
350-
}
351-
352-
if root != "./" {
353-
sparse := strings.TrimPrefix(root, "./")
354-
setup = append(setup,
355-
"git config core.sparseCheckout true",
356-
fmt.Sprintf("echo %q >> .git/info/sparse-checkout", sparse),
357-
"git config --add remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'",
358-
"git config remote.origin.tagopt --no-tags",
359-
)
360-
}
361-
362342
output.Log(out, "Fetching site code ...")
363343

364-
// The tag is resolved remotely and the LAST match taken, which is how a
365-
// version like "0.1.*" picks its newest release.
366-
setup = append(setup,
367-
fmt.Sprintf("git fetch --depth=1 origin refs/tags/$(git ls-remote --tags "+
368-
"origin %q | tail -n 1 | awk -F '/' '{print $3}')", template.ProviderVersion),
369-
"git checkout FETCH_HEAD",
370-
)
344+
tag, err := resolveGitTag(templatesDir, repository, template.ProviderVersion)
345+
if err != nil {
346+
return err
347+
}
371348

372-
if err := runGit(templatesDir, strings.Join(setup, "\n")); err != nil {
349+
cloneArguments := []string{"clone", "--single-branch", "--depth", "1"}
350+
if tag != "" {
351+
cloneArguments = append(cloneArguments, "--branch", tag)
352+
}
353+
if root != "" {
354+
cloneArguments = append(cloneArguments, "--sparse")
355+
}
356+
cloneArguments = append(cloneArguments, repository, ".")
357+
if err := runGitCommand(templatesDir, cloneArguments...); err != nil {
373358
return err
374359
}
360+
if root != "" {
361+
if err := runGitCommand(templatesDir, "sparse-checkout", "add", root); err != nil {
362+
return err
363+
}
364+
}
375365

376366
if err := os.RemoveAll(filepath.Join(templatesDir, ".git")); err != nil {
377367
return err
378368
}
379369

380-
source := templatesDir
381-
if root != "./" {
382-
source = filepath.Join(templatesDir, root)
383-
}
384-
if err := copyTree(source, siteDir); err != nil {
370+
if err := copyTree(filepath.Join(templatesDir, filepath.FromSlash(root)), siteDir); err != nil {
385371
return err
386372
}
387373

0 commit comments

Comments
 (0)