From ebd34f3fa296c0a12cc2bcfb9e358c25f1e1d099 Mon Sep 17 00:00:00 2001 From: adarshm11 Date: Fri, 24 Apr 2026 16:14:22 -0700 Subject: [PATCH 1/5] rewrite sce cli in go --- .gitignore | 9 ++++++ cmd/aliases.go | 58 ++++++++++++++++++++++++++++++++++ cmd/clone.go | 43 ++++++++++++++++++++++++++ cmd/completion.go | 35 +++++++++++++++++++++ cmd/config.go | 36 +++++++++++++++++++++ cmd/create.go | 74 ++++++++++++++++++++++++++++++++++++++++++++ cmd/link.go | 38 +++++++++++++++++++++++ cmd/lint.go | 46 +++++++++++++++++++++++++++ cmd/nicknames.go | 24 ++++++++++++++ cmd/paths.go | 56 +++++++++++++++++++++++++++++++++ cmd/root.go | 21 +++++++++++++ cmd/run.go | 79 +++++++++++++++++++++++++++++++++++++++++++++++ cmd/setup.go | 72 ++++++++++++++++++++++++++++++++++++++++++ go.mod | 9 ++++++ go.sum | 10 ++++++ main.go | 7 +++++ 16 files changed, 617 insertions(+) create mode 100644 cmd/aliases.go create mode 100644 cmd/clone.go create mode 100644 cmd/completion.go create mode 100644 cmd/config.go create mode 100644 cmd/create.go create mode 100644 cmd/link.go create mode 100644 cmd/lint.go create mode 100644 cmd/nicknames.go create mode 100644 cmd/paths.go create mode 100644 cmd/root.go create mode 100644 cmd/run.go create mode 100644 cmd/setup.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go diff --git a/.gitignore b/.gitignore index 4aaf26e..1163fb6 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,12 @@ !sce.bat !sce.sh !create_user.txt +!LICENSE +!main.go +!go.mod +!go.sum +!cmd/ +!cmd/** +!.goreleaser.yaml +!.github/ +!.github/** diff --git a/cmd/aliases.go b/cmd/aliases.go new file mode 100644 index 0000000..82d196f --- /dev/null +++ b/cmd/aliases.go @@ -0,0 +1,58 @@ +package cmd + +type RepoInfo struct { + RepoName string + ConfigPaths []string + MongoDBOnly bool +} + +var aliasMap = map[string]RepoInfo{ + // Clark + "clark": {RepoName: "Clark", ConfigPaths: []string{"src/config/config.json", "api/config/config.json"}}, + "dog": {RepoName: "Clark", ConfigPaths: []string{"src/config/config.json", "api/config/config.json"}}, + "clrk": {RepoName: "Clark", ConfigPaths: []string{"src/config/config.json", "api/config/config.json"}}, + "ck": {RepoName: "Clark", ConfigPaths: []string{"src/config/config.json", "api/config/config.json"}}, + "c": {RepoName: "Clark", ConfigPaths: []string{"src/config/config.json", "api/config/config.json"}}, + + // MongoDB (uses Clark repo, only starts mongodb service) + "mongo": {RepoName: "Clark", MongoDBOnly: true}, + "db": {RepoName: "Clark", MongoDBOnly: true}, + "mongodb": {RepoName: "Clark", MongoDBOnly: true}, + + // Cleezy + "cleezy": {RepoName: "cleezy"}, + "url": {RepoName: "cleezy"}, + "z": {RepoName: "cleezy"}, + + // Quasar + "quasar": {RepoName: "Quasar", ConfigPaths: []string{"config/config.json"}}, + "q": {RepoName: "Quasar", ConfigPaths: []string{"config/config.json"}}, + "idsmile": {RepoName: "Quasar", ConfigPaths: []string{"config/config.json"}}, + + // SCE-discord-bot + "sarah": {RepoName: "SCE-discord-bot", ConfigPaths: []string{"config.json"}}, + "sce-discord-bot": {RepoName: "SCE-discord-bot", ConfigPaths: []string{"config.json"}}, + "discord-bot": {RepoName: "SCE-discord-bot", ConfigPaths: []string{"config.json"}}, + "discord": {RepoName: "SCE-discord-bot", ConfigPaths: []string{"config.json"}}, + "bot": {RepoName: "SCE-discord-bot", ConfigPaths: []string{"config.json"}}, + "s": {RepoName: "SCE-discord-bot", ConfigPaths: []string{"config.json"}}, + "d": {RepoName: "SCE-discord-bot", ConfigPaths: []string{"config.json"}}, + + // SCEta + "sceta": {RepoName: "SCEta"}, + "transit": {RepoName: "SCEta"}, +} + +func resolveAlias(input string) (RepoInfo, bool) { + info, ok := aliasMap[input] + return info, ok +} + +var repoNicknames = []string{ + "Clark: clark, dog, clrk, ck, c", + "MongoDB (requires Clark linked): mongo, db, mongodb", + "Quasar: quasar, q, idsmile", + "SCE-discord-bot: sarah, sce-discord-bot, discord-bot, discord, bot, s, d", + "cleezy: cleezy, url, z", + "SCEta: sceta, transit", +} diff --git a/cmd/clone.go b/cmd/clone.go new file mode 100644 index 0000000..b3f3990 --- /dev/null +++ b/cmd/clone.go @@ -0,0 +1,43 @@ +package cmd + +import ( + "fmt" + "os" + "os/exec" + + "github.com/spf13/cobra" +) + +var sshFlag bool + +var cloneCmd = &cobra.Command{ + Use: "clone ", + Short: "Clone the given repo from GitHub", + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + repo, ok := resolveAlias(args[0]) + if !ok { + fmt.Fprintf(os.Stderr, "unknown repo: %s\n", args[0]) + os.Exit(1) + } + + var url string + if sshFlag { + url = githubBaseSSHURL + repo.RepoName + ".git" + } else { + url = githubBaseHTTPURL + repo.RepoName + ".git" + } + + gitCmd := exec.Command("git", "clone", url) + gitCmd.Stdout = os.Stdout + gitCmd.Stderr = os.Stderr + if err := gitCmd.Run(); err != nil { + os.Exit(1) + } + }, +} + +func init() { + cloneCmd.Flags().BoolVar(&sshFlag, "ssh", false, "clone using SSH instead of HTTPS") + rootCmd.AddCommand(cloneCmd) +} diff --git a/cmd/completion.go b/cmd/completion.go new file mode 100644 index 0000000..e722f36 --- /dev/null +++ b/cmd/completion.go @@ -0,0 +1,35 @@ +package cmd + +import ( + "fmt" + "os" + + "github.com/spf13/cobra" +) + +var completionCmd = &cobra.Command{ + Use: "completion", + Short: "Output shell alias/completion for the sce command", + Run: func(cmd *cobra.Command, args []string) { + fishVersion := os.Getenv("FISH_VERSION") + if fishVersion != "" { + exe, _ := os.Executable() + fmt.Println("# add this to your fish config") + fmt.Printf("function sce; %s $argv; end\n", exe) + return + } + + shell := os.Getenv("SHELL") + exe, _ := os.Executable() + if shell != "" { + fmt.Println("# add this to your shell config") + fmt.Printf("alias sce=\"%s\"\n", exe) + } else { + fmt.Printf("# alias sce to: %s\n", exe) + } + }, +} + +func init() { + rootCmd.AddCommand(completionCmd) +} diff --git a/cmd/config.go b/cmd/config.go new file mode 100644 index 0000000..1a5df2e --- /dev/null +++ b/cmd/config.go @@ -0,0 +1,36 @@ +package cmd + +const ( + githubBaseHTTPURL = "https://github.com/SCE-Development/" + githubBaseSSHURL = "git@github.com:SCE-Development/" + + mongoDBContainer = "sce-mongodb-dev" + dockerComposeFile = "docker-compose.dev.yml" + + bcryptHash = "$2a$10$HWbBiWRso1IUgqnuV6t1hO6lCBWO7KTC/E3G1MsFoXKH7/l/4FVK2" +) + +var accessLevels = map[string]int{ + "admin": 3, + "officer": 2, + "member": 1, + "nonmember": 0, + "pending": -1, + "banned": -2, +} + +type lintTarget struct { + Container string + EslintConfig string +} + +var lintContainers = map[string][]lintTarget{ + "Clark": { + {Container: "sce-frontend-dev", EslintConfig: "/frontend/.eslintrc.json"}, + {Container: "sce-main-endpoints-dev", EslintConfig: "/app/.eslintrc.json"}, + {Container: "sce-cloud-api-dev", EslintConfig: "/app/.eslintrc.json"}, + }, + "SCE-discord-bot": { + {Container: "sarah", EslintConfig: "/sarah/.eslintrc.json"}, + }, +} diff --git a/cmd/create.go b/cmd/create.go new file mode 100644 index 0000000..7651b3d --- /dev/null +++ b/cmd/create.go @@ -0,0 +1,74 @@ +package cmd + +import ( + "crypto/rand" + "encoding/hex" + "fmt" + "os" + "os/exec" + "strings" + + "github.com/spf13/cobra" +) + +var createCmd = &cobra.Command{ + Use: "create [level]", + Short: "Create a test user for the SCE website", + Long: `Create a test user for the SCE website. +Levels: admin (default), officer, member, nonmember, pending, banned.`, + Args: cobra.MaximumNArgs(1), + Run: func(cmd *cobra.Command, args []string) { + levelName := "admin" + if len(args) > 0 { + levelName = args[0] + } + + level, ok := accessLevels[levelName] + if !ok { + fmt.Fprintf(os.Stderr, "unknown access level: %s\n", levelName) + keys := make([]string, 0, len(accessLevels)) + for k := range accessLevels { + keys = append(keys, k) + } + fmt.Fprintf(os.Stderr, "valid options: %s\n", strings.Join(keys, ", ")) + os.Exit(1) + } + + suffix := randomHex(2) + email := fmt.Sprintf("test_%s@one.sce", suffix) + + mongoScript := fmt.Sprintf(`use sce_core +db.User.insertOne({ + emailVerified: true, + accessLevel: %d, + pagesPrinted: 0, + password: '%s', + firstName: 'Development', + lastName: 'Account', + email: '%s', +})`, level, bcryptHash, email) + + dockerCmd := exec.Command("docker", "exec", "-i", mongoDBContainer, "mongosh", "--shell", "--norc", "--quiet") + dockerCmd.Stdin = strings.NewReader(mongoScript) + dockerCmd.Stdout = os.Stdout + dockerCmd.Stderr = os.Stderr + if err := dockerCmd.Run(); err != nil { + fmt.Fprintf(os.Stderr, "error creating user: %v\n", err) + os.Exit(1) + } + + fmt.Printf("created %s user for the SCE website with:\n", levelName) + fmt.Printf("email: %s\n", email) + fmt.Println("password: sce") + }, +} + +func randomHex(n int) string { + bytes := make([]byte, n) + rand.Read(bytes) + return hex.EncodeToString(bytes) +} + +func init() { + rootCmd.AddCommand(createCmd) +} diff --git a/cmd/link.go b/cmd/link.go new file mode 100644 index 0000000..7f5a718 --- /dev/null +++ b/cmd/link.go @@ -0,0 +1,38 @@ +package cmd + +import ( + "fmt" + "os" + + "github.com/spf13/cobra" +) + +var linkCmd = &cobra.Command{ + Use: "link ", + Short: "Tell the sce tool where to find the repo on your computer", + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + repo, ok := resolveAlias(args[0]) + if !ok { + fmt.Fprintf(os.Stderr, "unknown repo: %s\n", args[0]) + os.Exit(1) + } + + cwd, err := os.Getwd() + if err != nil { + fmt.Fprintf(os.Stderr, "error getting current directory: %v\n", err) + os.Exit(1) + } + + if err := createLink(repo.RepoName, cwd); err != nil { + fmt.Fprintf(os.Stderr, "error creating link: %v\n", err) + os.Exit(1) + } + + fmt.Printf("linked %s → %s\n", repo.RepoName, cwd) + }, +} + +func init() { + rootCmd.AddCommand(linkCmd) +} diff --git a/cmd/lint.go b/cmd/lint.go new file mode 100644 index 0000000..928567b --- /dev/null +++ b/cmd/lint.go @@ -0,0 +1,46 @@ +package cmd + +import ( + "fmt" + "os" + "os/exec" + "strings" + + "github.com/spf13/cobra" +) + +var lintCmd = &cobra.Command{ + Use: "lint ", + Short: "Run eslint --fix on running containers (Clark and SCE-discord-bot only)", + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + repo, ok := resolveAlias(args[0]) + if !ok { + fmt.Fprintf(os.Stderr, "unknown repo: %s\n", args[0]) + os.Exit(1) + } + + targets, ok := lintContainers[repo.RepoName] + if !ok { + fmt.Fprintf(os.Stderr, "lint is not supported for %s\n", repo.RepoName) + fmt.Fprintln(os.Stderr, "lint is only available for Clark and SCE-discord-bot.") + os.Exit(1) + } + + for _, target := range targets { + fmt.Printf("linting in %s...\n", target.Container) + lintCommand := fmt.Sprintf("npm run lint -- -c %s --fix", target.EslintConfig) + dockerCmd := exec.Command("docker", "exec", "-i", target.Container, "/bin/sh") + dockerCmd.Stdin = strings.NewReader(lintCommand) + dockerCmd.Stdout = os.Stdout + dockerCmd.Stderr = os.Stderr + if err := dockerCmd.Run(); err != nil { + fmt.Fprintf(os.Stderr, "error linting in %s: %v\n", target.Container, err) + } + } + }, +} + +func init() { + rootCmd.AddCommand(lintCmd) +} diff --git a/cmd/nicknames.go b/cmd/nicknames.go new file mode 100644 index 0000000..f87154f --- /dev/null +++ b/cmd/nicknames.go @@ -0,0 +1,24 @@ +package cmd + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +var nicknamesCmd = &cobra.Command{ + Use: "nicknames", + Short: "Show repo nicknames", + Run: func(cmd *cobra.Command, args []string) { + fmt.Println() + fmt.Println("each repo has nicknames:") + for _, line := range repoNicknames { + fmt.Printf(" %s\n", line) + } + fmt.Println() + }, +} + +func init() { + rootCmd.AddCommand(nicknamesCmd) +} diff --git a/cmd/paths.go b/cmd/paths.go new file mode 100644 index 0000000..2af68db --- /dev/null +++ b/cmd/paths.go @@ -0,0 +1,56 @@ +package cmd + +import ( + "fmt" + "os" + "path/filepath" +) + +func getCliDirectory() (string, error) { + exe, err := os.Executable() + if err != nil { + return "", err + } + resolved, err := filepath.EvalSymlinks(exe) + if err != nil { + return "", err + } + return filepath.Dir(resolved), nil +} + +func getRepoPath(repoName string) (string, error) { + cliDir, err := getCliDirectory() + if err != nil { + return "", err + } + linkPath := filepath.Join(cliDir, repoName) + + info, err := os.Lstat(linkPath) + if err != nil { + return "", fmt.Errorf("repo %s is not linked", repoName) + } + + // Follow symlink if it is one + if info.Mode()&os.ModeSymlink != 0 { + resolved, err := filepath.EvalSymlinks(linkPath) + if err != nil { + return "", err + } + return resolved, nil + } + + return linkPath, nil +} + +func createLink(repoName string, targetDir string) error { + cliDir, err := getCliDirectory() + if err != nil { + return err + } + linkPath := filepath.Join(cliDir, repoName) + + // Remove existing symlink if present + os.Remove(linkPath) + + return os.Symlink(targetDir, linkPath) +} diff --git a/cmd/root.go b/cmd/root.go new file mode 100644 index 0000000..de40e07 --- /dev/null +++ b/cmd/root.go @@ -0,0 +1,21 @@ +package cmd + +import ( + "fmt" + "os" + + "github.com/spf13/cobra" +) + +var rootCmd = &cobra.Command{ + Use: "sce", + Short: "CLI tool for managing SCE Development projects", + Long: "Command line tool to run any of the SCE projects. Works on Windows, Mac and Linux.", +} + +func Execute() { + if err := rootCmd.Execute(); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} diff --git a/cmd/run.go b/cmd/run.go new file mode 100644 index 0000000..69cb0d3 --- /dev/null +++ b/cmd/run.go @@ -0,0 +1,79 @@ +package cmd + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + + "github.com/spf13/cobra" +) + +var runCmd = &cobra.Command{ + Use: "run ", + Short: "Run the repo using docker", + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + repo, ok := resolveAlias(args[0]) + if !ok { + fmt.Fprintf(os.Stderr, "unknown repo: %s\n", args[0]) + os.Exit(1) + } + + repoPath, err := getRepoPath(repo.RepoName) + if err != nil { + fmt.Printf("it looks like you haven't linked %s to the sce tool.\n", repo.RepoName) + fmt.Println() + fmt.Printf("either link the repo with sce link %s or clone it first with sce clone %s.\n", repo.RepoName, repo.RepoName) + os.Exit(1) + } + + // Check config files exist + for _, configPath := range repo.ConfigPaths { + fullPath := filepath.Join(repoPath, configPath) + if _, err := os.Stat(fullPath); os.IsNotExist(err) { + fmt.Println() + fmt.Println("it seems like you forgot to create/configure the config.json file(s)") + fmt.Println("follow the config.example.json as a template and add it at the following paths:") + for _, p := range repo.ConfigPaths { + fmt.Println(filepath.Join(repoPath, p)) + } + fmt.Println() + os.Exit(1) + } + } + + composeCmd := dockerComposeCommand() + + if repo.MongoDBOnly { + dockerCmd := exec.Command(composeCmd[0], append(composeCmd[1:], "-f", dockerComposeFile, "up", "mongodb", "-d")...) + dockerCmd.Dir = repoPath + dockerCmd.Stdout = os.Stdout + dockerCmd.Stderr = os.Stderr + if err := dockerCmd.Run(); err != nil { + os.Exit(1) + } + } else { + dockerCmd := exec.Command(composeCmd[0], append(composeCmd[1:], "-f", dockerComposeFile, "up", "--build")...) + dockerCmd.Dir = repoPath + dockerCmd.Stdout = os.Stdout + dockerCmd.Stderr = os.Stderr + dockerCmd.Stdin = os.Stdin + if err := dockerCmd.Run(); err != nil { + os.Exit(1) + } + } + }, +} + +func dockerComposeCommand() []string { + // Try docker compose v2 first + if err := exec.Command("docker", "compose", "version").Run(); err == nil { + return []string{"docker", "compose"} + } + return []string{"docker-compose"} +} + +func init() { + rootCmd.AddCommand(runCmd) +} diff --git a/cmd/setup.go b/cmd/setup.go new file mode 100644 index 0000000..de0d23f --- /dev/null +++ b/cmd/setup.go @@ -0,0 +1,72 @@ +package cmd + +import ( + "fmt" + "io" + "os" + "path/filepath" + "strings" + + "github.com/spf13/cobra" +) + +var setupCmd = &cobra.Command{ + Use: "setup ", + Short: "Copy config.example.json in a repo to config.json", + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + repo, ok := resolveAlias(args[0]) + if !ok { + fmt.Fprintf(os.Stderr, "unknown repo: %s\n", args[0]) + os.Exit(1) + } + + repoPath, err := getRepoPath(repo.RepoName) + if err != nil { + fmt.Printf("it looks like you haven't linked %s to the sce tool.\n", repo.RepoName) + fmt.Println() + fmt.Printf("either link the repo with sce link %s or clone it first with sce clone %s.\n", repo.RepoName, repo.RepoName) + os.Exit(1) + } + + if len(repo.ConfigPaths) == 0 { + fmt.Printf("%s has no config files to set up.\n", repo.RepoName) + return + } + + for _, configPath := range repo.ConfigPaths { + examplePath := filepath.Join(repoPath, strings.Replace(configPath, "config.json", "config.example.json", 1)) + targetPath := filepath.Join(repoPath, configPath) + + if err := copyFile(examplePath, targetPath); err != nil { + fmt.Fprintf(os.Stderr, "error copying %s: %v\n", configPath, err) + continue + } + fmt.Printf("copied %s → %s\n", + strings.Replace(configPath, "config.json", "config.example.json", 1), + configPath, + ) + } + }, +} + +func copyFile(src, dst string) error { + in, err := os.Open(src) + if err != nil { + return err + } + defer in.Close() + + out, err := os.Create(dst) + if err != nil { + return err + } + defer out.Close() + + _, err = io.Copy(out, in) + return err +} + +func init() { + rootCmd.AddCommand(setupCmd) +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..346646e --- /dev/null +++ b/go.mod @@ -0,0 +1,9 @@ +module github.com/SCE-Development/SCE-CLI + +go 1.25.0 + +require ( + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/spf13/cobra v1.10.2 // indirect + github.com/spf13/pflag v1.0.9 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..a6ee3e0 --- /dev/null +++ b/go.sum @@ -0,0 +1,10 @@ +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= +github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= +github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= +github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/main.go b/main.go new file mode 100644 index 0000000..ffad551 --- /dev/null +++ b/main.go @@ -0,0 +1,7 @@ +package main + +import "github.com/SCE-Development/SCE-CLI/cmd" + +func main() { + cmd.Execute() +} From 1a5069f2897815485a18f11fa9bf4b921436116c Mon Sep 17 00:00:00 2001 From: adarshm11 Date: Fri, 24 Apr 2026 16:23:25 -0700 Subject: [PATCH 2/5] add automatic release workflow and installation script --- .github/workflows/release.yaml | 31 ++++++++++++++++++++++++++ .gitignore | 1 + .goreleaser.yaml | 25 +++++++++++++++++++++ install.sh | 40 ++++++++++++++++++++++++++++++++++ 4 files changed, 97 insertions(+) create mode 100644 .github/workflows/release.yaml create mode 100644 .goreleaser.yaml create mode 100644 install.sh diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..35db327 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,31 @@ +name: Release + +on: + push: + branches: + - master + +permissions: + contents: write + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + + - name: Set version from commit count + run: echo "GORELEASER_CURRENT_TAG=v0.$(git rev-list --count HEAD)" >> $GITHUB_ENV + + - uses: goreleaser/goreleaser-action@v6 + with: + version: latest + args: release --clean + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 1163fb6..ddc3c82 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ !.goreleaser.yaml !.github/ !.github/** +!install.sh diff --git a/.goreleaser.yaml b/.goreleaser.yaml new file mode 100644 index 0000000..002a3c7 --- /dev/null +++ b/.goreleaser.yaml @@ -0,0 +1,25 @@ +version: 2 + +builds: + - main: . + binary: sce + env: + - CGO_ENABLED=0 + goos: + - linux + - darwin + - windows + goarch: + - amd64 + - arm64 + +archives: + - format: binary + name_template: "sce-{{ .Os }}-{{ .Arch }}" + +changelog: + use: github-native + +release: + make_latest: true + name_template: "v{{ .Version }}" diff --git a/install.sh b/install.sh new file mode 100644 index 0000000..b917874 --- /dev/null +++ b/install.sh @@ -0,0 +1,40 @@ +#!/bin/sh +set -e + +REPO="SCE-Development/SCE-CLI" +INSTALL_DIR="/usr/local/bin" + +# Detect OS +OS=$(uname -s | tr '[:upper:]' '[:lower:]') +case "$OS" in + darwin) OS="darwin" ;; + linux) OS="linux" ;; + *) + echo "unsupported OS: $OS" + exit 1 + ;; +esac + +# Detect architecture +ARCH=$(uname -m) +case "$ARCH" in + x86_64) ARCH="amd64" ;; + aarch64) ARCH="arm64" ;; + arm64) ARCH="arm64" ;; + *) + echo "unsupported architecture: $ARCH" + exit 1 + ;; +esac + +BINARY="sce-${OS}-${ARCH}" +URL="https://github.com/${REPO}/releases/latest/download/${BINARY}" + +echo "downloading sce for ${OS}/${ARCH}..." +curl -sSL "$URL" -o /tmp/sce + +echo "installing to ${INSTALL_DIR}/sce..." +sudo install -m 755 /tmp/sce "${INSTALL_DIR}/sce" +rm /tmp/sce + +echo "sce installed successfully! run 'sce --help' to get started." From f7bf4166020e272317fc9e379408e8d7a1b386e4 Mon Sep 17 00:00:00 2001 From: adarshm11 Date: Fri, 24 Apr 2026 16:28:43 -0700 Subject: [PATCH 3/5] add windows install script, readme changes --- .gitignore | 1 + README.md | 135 ++++++++++++++++++++++------------------------------ install.ps1 | 24 ++++++++++ 3 files changed, 82 insertions(+), 78 deletions(-) create mode 100644 install.ps1 diff --git a/.gitignore b/.gitignore index ddc3c82..64d07b4 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ !.github/ !.github/** !install.sh +!install.ps1 diff --git a/README.md b/README.md index 8b49388..9bd6c00 100644 --- a/README.md +++ b/README.md @@ -2,117 +2,96 @@ Command line tool to run any of the SCE projects. Works on Windows, Mac and Linux. Available with the `sce` command. -## Setup -⚠️ **IMPORTANT WARNING**: If your Windows username contains spaces (e.g. "John Smith"), DO NOT install this in your user directory. Follow these special instructions instead: -1. Open File Explorer and go to the C: drive -2. Create a new folder called `SCE` -3. Open Command Prompt or PowerShell and run: -``` -cd C:\SCE -git clone https://github.com/SCE-Development/SCE-CLI.git -``` +## Prerequisites -For users without spaces in their username, you can proceed with the normal installation: +- [Docker](https://www.docker.com/) -Before starting, be sure you have Docker installed! This tool - runs SCE's projects with Docker. +## Setup -Clone this repository to your computer with -``` -git clone https://github.com/SCE-Development/SCE-CLI.git +### Mac/Linux + +Install with one command: +```sh +curl -sSL https://raw.githubusercontent.com/SCE-Development/SCE-CLI/master/install.sh | sh ``` -Next, we will add the `sce` command to your terminal. + +This downloads the correct binary for your system and installs it to `/usr/local/bin/sce`. ### Windows -You will need to add the location where the batch file is to your path. To do - this: -1. Copy the path where `SCE-CLI` is installed. The path should look like -``` -C:\Users\\path\to\SCE-CLI\ -``` -2. We need to edit (your env vars or something) we can do this with: -- Press `Window + R` to open the Windows Run prompt. -- Type in `sysdm.cpl` and click `OK`. -![image](https://phoenixnap.com/kb/wp-content/uploads/2021/04/setting-environment-variables-in-windows-06.png) -- Then go to the `Advanced` tab and click `Environment Variables`: -![image](https://phoenixnap.com/kb/wp-content/uploads/2021/04/setting-environment-variables-in-windows-07.png) -- Click on path in `System variables` -![edit_path](https://user-images.githubusercontent.com/10038262/180634975-6a7c7947-5560-4df6-bd5a-3d8bda033c70.png) -- Add the location where `SCE-CLI` is installed from earlier into - this path (see highlighted) -![path](https://user-images.githubusercontent.com/10038262/180634962-abd4ba91-30a2-47e7-8c50-4cc26a41b669.png) -3. After doing so, typing `sce` in the Command Prompt - should work, and the help page should show like below: -![eb2015026b076e7b31a8caa2ff8f2e55](https://user-images.githubusercontent.com/10038262/180635207-2ea70c08-003f-4f59-95f8-35817bc6a51b.png) -### Mac/Linux -1. cd into the `SCE-CLI` -2. Add an alias to your terminals config file like: -```sh -# for linux -./sce.sh completion >> ~/.bashrc +Run in PowerShell: +```powershell +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/SCE-Development/SCE-CLI/master/install.ps1" -UseBasicParsing | Invoke-Expression +``` + +### Verify -# for mac, first run the below command -echo $SHELL -# if the above is /bin/bash -./sce.sh completion >> ~/.bash_profile -# if the above is /bin/zsh -./sce.sh completion >> ~/.zshrc +After installing, open a new terminal and run: +``` +sce --help ``` -3. After doing the above, making a new terminal and typing `sce` should work. ## Usage -To use the script, you use the command `sce` with a command and repo name -The commands that you can run are: clone, link, run. -Alternatively, just run the command `sce` to see the usages in the terminal. +Use the command `sce` with a command and repo name. +Run `sce --help` to see all available commands. + ### Repo Names -The name of the repositories are (the nicknames are alternate names you can use in the command): -core-v4 (nicknames: core-v4, corev4, cv4, c4, c) -quasar (nicknames: quasar, q, idsmile) -sarah (nicknames: sarah, sce-discord-bot, discord-bot, discord, bot, s, d) +Each repo has nicknames you can use interchangeably: + +| Repo | Nicknames | +|------|-----------| +| Clark | clark, dog, clrk, ck, c | +| MongoDB | mongo, db, mongodb | +| Quasar | quasar, q, idsmile | +| SCE-discord-bot | sarah, sce-discord-bot, discord-bot, discord, bot, s, d | +| cleezy | cleezy, url, z | +| SCEta | sceta, transit | ### Clone -To clone an SCE project from GitHub, simply enter +Clone an SCE project from GitHub: ``` sce clone [--ssh] ``` -The repository will be cloned from wherever the command was ran. -Project names can be `quasar`, `core-v4`, `discord` etc. See the above repo - names section for all options. - -The `--ssh` parameter can be optionally added after the project name. - Supplying this will clone the repo with the GitHub SSH URL over the - HTTPS one. +The `--ssh` flag clones using the SSH URL instead of HTTPS. ### Link -To link a sce repo to your directory where you are running the command, simply enter +Link a repo directory to the sce tool (run from inside the repo): ``` sce link ``` -Project names can be `quasar`, `core-v4`, `discord` etc. See the above repo - names section for all options. ### Run -To run an SCE project, simply enter - +Run an SCE project with Docker: ``` sce run ``` -where project can be `quasar`, `core-v4`, `discord` etc. See the above repo - names section for all options. +To start only MongoDB: +``` +sce run db +``` + +### Setup +Copy config.example.json to config.json for a project: +``` +sce setup +``` ### Create -This will create a test account when running the SCE website locally. Before running, - make sure you have MongoDB running with: +Create a test account for the SCE website. Make sure MongoDB is running first: ``` sce run db ``` -Then, run the below command: +Then create a user: ``` -sce create +sce create [level] ``` -After running the SCE website locally, ensure you can log in with the email - `test@one.sce` and password `sce` - +Levels: `admin` (default), `officer`, `member`, `nonmember`, `pending`, `banned`. +Log in with the generated email and password `sce`. +### Lint +Run eslint --fix on running containers (Clark and SCE-discord-bot only): +``` +sce lint +``` +Make sure the project is running with `sce run` first. diff --git a/install.ps1 b/install.ps1 new file mode 100644 index 0000000..cf33992 --- /dev/null +++ b/install.ps1 @@ -0,0 +1,24 @@ +$ErrorActionPreference = "Stop" + +$repo = "SCE-Development/SCE-CLI" +$installDir = "$env:LOCALAPPDATA\sce" + +# Detect architecture +$arch = if ([Environment]::Is64BitOperatingSystem) { "amd64" } else { "amd64" } +if ($env:PROCESSOR_ARCHITECTURE -eq "ARM64") { $arch = "arm64" } + +$binary = "sce-windows-$arch.exe" +$url = "https://github.com/$repo/releases/latest/download/$binary" + +Write-Host "downloading sce for windows/$arch..." +New-Item -ItemType Directory -Path $installDir -Force | Out-Null +Invoke-WebRequest -Uri $url -OutFile "$installDir\sce.exe" -UseBasicParsing + +# Add to PATH if not already there +$userPath = [Environment]::GetEnvironmentVariable("Path", "User") +if ($userPath -notlike "*$installDir*") { + [Environment]::SetEnvironmentVariable("Path", "$userPath;$installDir", "User") + Write-Host "added $installDir to your PATH." +} + +Write-Host "sce installed successfully! restart your terminal and run 'sce --help' to get started." From 84fc9a549d38db5837addc5ebc61795a2310b031 Mon Sep 17 00:00:00 2001 From: adarshm11 Date: Fri, 24 Apr 2026 16:41:46 -0700 Subject: [PATCH 4/5] remove legacy implementation --- create_user.txt | 13 --- sce.bat | 276 ---------------------------------------------- sce.sh | 288 ------------------------------------------------ 3 files changed, 577 deletions(-) delete mode 100644 create_user.txt delete mode 100644 sce.bat delete mode 100755 sce.sh diff --git a/create_user.txt b/create_user.txt deleted file mode 100644 index 9825cac..0000000 --- a/create_user.txt +++ /dev/null @@ -1,13 +0,0 @@ -use sce_core - -show collections - -db.User.insertOne({ - emailVerified: true, - accessLevel: 3, - pagesPrinted: 0, - password: '$2a$10$HWbBiWRso1IUgqnuV6t1hO6lCBWO7KTC/E3G1MsFoXKH7/l/4FVK2', - firstName: 'Development', - lastName: 'Account', - email: 'test@one.sce', - }) diff --git a/sce.bat b/sce.bat deleted file mode 100644 index c3e035a..0000000 --- a/sce.bat +++ /dev/null @@ -1,276 +0,0 @@ -@echo off - -setlocal ENABLEDELAYEDEXPANSION - -REM aliases for the sce dev projects -set CLARK_OPTIONS="clark" "clrk" "ck" "c" -set CLEEZY_OPTIONS="cleezy" "url" "z" -set MONGODB_OPTIONS="mongo" "db" "mongodb" -set QUASAR_OPTIONS="quasar" "q" "idsmile" -set DISCORD_BOT_OPTIONS="sarah" "discord-bot" "discord" "bot" "s" "d" -set SCETA_OPTIONS="sceta" "transit" -set GITHUB_BASE_URL=https://github.com/SCE-Development/ -set CLARK_REPO_NAME=Clark -set CLEEZY_REPO_NAME=cleezy -set QUASAR_REPO_NAME=Quasar -set SCE_DISCORD_BOT_REPO_NAME=sarah -set SCETA_REPO_NAME=SCEta -REM parse the location where: -REM 1. the `sce` command was ran from in the command line -REM 2. the actual sce.bat script is located on the user's disk -FOR /F "tokens=*" %%g IN ('where sce.bat') do (SET SCE_SCRIPT_LOCATION=%%g) -FOR /F "tokens=*" %%g IN ('cd') do (SET WHERE_COMMAND_WAS_RAN_FROM=%%g) - -REM this yields the location of where the sce command line -REM is installed. for example if the batch script lives -REM in D:\user\sce\sce.bat, the below variable will have -REM the value D:\user\sce\ -REM for more info on substrings in batch: https://stackoverflow.com/a/47989051 -SET SCE_COMMAND_DIRECTORY=!SCE_SCRIPT_LOCATION:~0,-7! - -REM the usage for the sce command line tool is -REM sce . these command line -REM arguments are referenced as %1% and %2% respectively. -IF "%1%"=="link" ( - goto :extract_repo_name -) ELSE IF "%1%"=="clone" ( - goto :extract_repo_name -) ELSE IF "%1%"=="run" ( - goto :extract_repo_name -) ELSE IF "%1%"=="setup" ( - goto :extract_repo_name -) ELSE IF "%1%"=="create" ( - goto :create_mongodb_user -) ELSE ( - goto :print_usage -) - -REM Resolve the given repo name from the user to actual repo name. -REM We iterate over the possible nicknames for each project and then -REM set the varible %name% to the resolved repo. -:extract_repo_name - REM check if argument is set https://stackoverflow.com/a/830566 - if "%2%" == "" ( - goto :print_command_usage - ) - REM comparing variable with a bunch of values: - REM https://stackoverflow.com/a/38481845 - SET name="" - set is_mongodb_alias="" - SET repo_to_link="%2%" - (for %%a in (%CLARK_OPTIONS%) do ( - if %repo_to_link% == %%a ( - SET name=%CLARK_REPO_NAME% - SET CONFIG_LOCATION[1]=src\config\config.json - SET CONFIG_LOCATION[2]=api\config\config.json - SET CONFIG_LOCATION_LENGTH=2 - goto :%1% - ) - )) - (for %%a in (%CLEEZY_OPTIONS%) do ( - if %repo_to_link% == %%a ( - SET name=%CLEEZY_REPO_NAME% - goto :%1% - ) - )) - (for %%a in (%MONGODB_OPTIONS%) do ( - if %repo_to_link% == %%a ( - SET name=%CLARK_REPO_NAME% - SET is_mongodb_alias="true" - goto :%1% - ) - )) - (for %%a in (%QUASAR_OPTIONS%) do ( - if %repo_to_link% == %%a ( - SET name=%QUASAR_REPO_NAME% - SET CONFIG_LOCATION[1]=config\config.json - SET CONFIG_LOCATION_LENGTH=1 - goto :%1% - ) - )) - (for %%a in (%DISCORD_BOT_OPTIONS%) do ( - if %repo_to_link% == %%a ( - SET name=%SCE_DISCORD_BOT_REPO_NAME% - SET CONFIG_LOCATION[1]=config.json - SET CONFIG_LOCATION_LENGTH=1 - goto :%1% - ) - )) - (for %%a in (%SCETA_OPTIONS%) do ( - if %repo_to_link% == %%a ( - SET name=%SCETA_REPO_NAME% - goto :%1% - ) - )) - goto :print_command_usage - -:link - SET NEW_JUNCTION=%SCE_COMMAND_DIRECTORY%%name% - REM try deleting any existing junction to the repo. - REM we hide the output of this command just in case - REM the junction does not exist. - REM see https://stackoverflow.com/a/1262726 - rmdir %NEW_JUNCTION% > nul 2>&1 - REM mklik /j - SET mklik_params=%NEW_JUNCTION% %WHERE_COMMAND_WAS_RAN_FROM% - mklink /j %mklik_params% - goto :exit_success - -:setup - REM run the docker container - SET REPO_LOCATION=%SCE_COMMAND_DIRECTORY%%name% - REM if location doesnt exist, prompt the user to link the directory - REM copy api\config\config.example.json api\config\config.json - REM copy src\config\config.example.json src\config\config.json - IF NOT EXIST %REPO_LOCATION% ( - goto :print_repo_not_found - ) - cd %REPO_LOCATION% - if %name%==%CLARK_REPO_NAME% ( - copy api\config\config.example.json api\config\config.json - copy src\config\config.example.json src\config\config.json - ) else if %name%==%QUASAR_REPO_NAME% ( - copy config\config.example.json config\config.json - ) else if %name%==%SCE_DISCORD_BOT_REPO_NAME% ( - copy config.example.json config.json - ) - goto :exit_success - -:clone - REM clone the repo via HTTPS, note that the end of every - REM GitHub repo url has a ".git" so we append it below. - git clone "%GITHUB_BASE_URL%%name%.git" - goto :exit_success - -:run - REM run the docker container - SET REPO_LOCATION=%SCE_COMMAND_DIRECTORY%%name% - REM if location doesnt exist, prompt the user to link the directory - IF NOT EXIST %REPO_LOCATION% ( - goto :print_repo_not_found - ) - cd %REPO_LOCATION% - REM Check if config file exists before running - CALL :check_config_file - IF NOT "!MISSING_PATHS_LENGTH!"=="0" ( - - goto :print_missing_config - ) - IF %is_mongodb_alias%=="true" ( - docker-compose -f docker-compose.dev.yml up mongodb -d - goto :exit_success - ) - docker-compose -f docker-compose.dev.yml up --build - goto :exit_success - -:create_mongodb_user - SET access_level_name=%2% - IF "%access_level_name%"=="" SET access_level_name=admin - - IF "%access_level_name%"=="admin" (SET access_level=3) ELSE ^ - IF "%access_level_name%"=="officer" (SET access_level=2) ELSE ^ - IF "%access_level_name%"=="member" (SET access_level=1) ELSE ^ - IF "%access_level_name%"=="nonmember" (SET access_level=0) ELSE ^ - IF "%access_level_name%"=="pending" (SET access_level=-1) ELSE ^ - IF "%access_level_name%"=="banned" (SET access_level=-2) ELSE ( - echo unknown access level: %access_level_name% - echo valid options: admin, officer, member, nonmember, pending, banned - goto :exit_error - ) - - SET "chars=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" - SET "random_suffix=" - FOR /L %%i IN (1,1,4) DO ( - SET /A "idx=!RANDOM! %% 62" - FOR %%j IN (!idx!) DO SET "random_suffix=!random_suffix!!chars:~%%j,1!" - ) - SET "generated_email=test_!random_suffix!@one.sce" - - ( - echo use sce_core - echo db.User.insertOne({ - echo emailVerified: true, - echo accessLevel: !access_level!, - echo pagesPrinted: 0, - echo password: '$2a$10$HWbBiWRso1IUgqnuV6t1hO6lCBWO7KTC/E3G1MsFoXKH7/l/4FVK2', - echo firstName: 'Development', - echo lastName: 'Account', - echo email: '!generated_email!', - echo }) - ) | docker exec -i sce-mongodb-dev mongosh --quiet --norc --shell - echo created %access_level_name% user for the SCE website with: - echo email: !generated_email! - echo password: sce - goto :exit_success - -:check_config_file - - SET MISSING_PATHS_LENGTH=0 - FOR /L %%a IN (1,1,%CONFIG_LOCATION_LENGTH%) DO ( - IF NOT EXIST ".\!CONFIG_LOCATION[%%a]!" ( - SET /A MISSING_PATHS_LENGTH+=1 - SET MISSING_PATHS[!MISSING_PATHS_LENGTH!]=!CONFIG_LOCATION[%%a]! - ) - ) - exit /B 0 - -:print_command_usage - echo usage: sce %1% {repo name} - goto :print_repo_nicknames - -:print_usage - echo usage: sce {clone,run,link,setup} {repo name} - echo. - echo clone: clone the given repo from github. - echo run: run the repo using docker - echo link: tell the sce tool where to find the repo on your computer - echo create: create a user for the SCE website. - echo optionally specify an access level: admin (default), officer, member, - echo nonmember, pending, or banned. - echo example: sce create officer - echo setup: copy config.example.json in a repo to config.json - goto :print_repo_nicknames - -:print_repo_nicknames - echo. - echo each repo has nicknames: - echo Clark:clark, clrk, ck, c - echo MongoDB:mongo, db, mongodb - echo Quasar:quasar, q, idsmile - echo Cleezy:cleezy url z - echo sarah:sarah, sce-discord-bot, discord-bot, discord, bot, s, d - echo SCEta:sceta, transit - REM assumes this was printed when the user incorrectly used the command - goto :exit_error - -:print_repo_not_found - echo it looks like you havent linked %name% to the sce tool. - echo. - echo either link the repo with `sce link %name% or clone it first with sce link %name%. - goto :exit_error - -:print_missing_config - REM Get real path to config file from symlink - REM The below fsutil command prints out a bunch of stuff related to the - REM The line we are looking for looks like this - REM Print Name: E:\vs\temp2\Quasar - REM This line referes to the acutual directory location, and we want - REM to parse this line and tell the user where they need to make a config file - FOR /f "tokens=*" %%a IN ('fsutil reparsepoint QUERY %REPO_LOCATION% ^| FINDSTR "Print Name: "') DO ( - SET "REAL_PATH=%%a" - ) - SET "REAL_PATH=!REAL_PATH:Print Name: =!" - echo. - echo it seems like you forgot to create/configure the config.json file - echo follow the config.example.json as a template and add it at the following paths: - FOR /L %%a IN (1,1,%MISSING_PATHS_LENGTH%) DO ( - echo %REAL_PATH%\!MISSING_PATHS[%%a]! - ) - echo. - goto :exit_error - -:exit_error - EXIT /B 1 - -:exit_success - EXIT /B 0 diff --git a/sce.sh b/sce.sh deleted file mode 100755 index 8eeb442..0000000 --- a/sce.sh +++ /dev/null @@ -1,288 +0,0 @@ -#!/bin/bash - -function print_repo_nicknames { - echo - echo "each repo has nicknames:" - echo "Clark:clark, dog, clrk, ck, c" - echo "MongoDB (must have clark installed and linked):mongo, db, mongodb" - echo "Quasar:quasar, q, idsmile" - echo "SCE-discord-bot:sarah, sce-discord-bot, discord-bot, discord, bot, d" - echo "cleezy:cleezy url z" - echo "sceta:sceta, transit" -} - -function print_usage { - echo "usage: sce {clone,run,link,setup} {repo name}" - echo - echo "clone: clone the given repo from github." - echo "run: run the repo using docker" - echo "link: tell the sce tool where to find the repo on your computer" - echo "create: create a user for the SCE website." - echo " optionally specify an access level: admin (default), officer, member," - echo " nonmember, pending, or banned." - echo " example: sce create officer" - echo "lint: [For Clark and Discord bot only] run eslint --fix on JavaScript/Node files." - echo " Use this while the associated project is running with 'sce run PROJECT'." - echo "setup: copy config.example.json in a repo to config.json" - print_repo_nicknames - exit 1 -} - -function print_missing_config { - echo - echo it seems like you forgot to create/configure the config.json file/files - echo follow the config.example.json as a template and add it at the following paths: - for str in ${missingPaths[@]}; do - echo $(readlink -f $REPO_LOCATION)/$str - done - echo - exit 1 -} - -function print_repo_not_found { - echo it looks like you havent linked $1 to the sce tool. - echo - echo either link the repo with sce link $1 or clone it first with sce link $1. - exit 1 -} - -SCE_COMMAND_DIRECTORY=$(echo $0 | rev | cut -c7- | rev) -GITHUB_BASE_HTTP_URL="https://github.com/SCE-Development/" -# sce clone --ssh -# sce clone -# git@github.com:SCE-Development/Clark.git -GITHUB_BASE_SSH_URL="git@github.com:SCE-Development/" - -CLARK_REPO_NAME="Clark" -CLEEZY_REPO_NAME="cleezy" -QUASAR_REPO_NAME="Quasar" -SCE_DISCORD_BOT_REPO_NAME="SCE-discord-bot" -SCETA_REPO_NAME="SCEta" - -CLARK_NAMES=("clark" "dog" "clrk" "ck" "c") -CLEEZY_NAMES=("cleezy" "url" "z") -MONGODB_NAMES=("mongo" "db" "mongodb") -QUASAR_NAMES=("quasar" "q" "idsmile") -SCE_DISCORD_BOT_NAMES=("sarah" "sce-discord-bot" "discord-bot" "discord" "bot" "s" "d") -SCETA_NAMES=("sceta" "transit") - -VALID_COMMANDS=("link" "clone" "run" "setup" "completion" "create" "lint") - -function contains_element { - local e match="$1" - shift - for e; do [[ "$e" == "$match" ]] && return 0; done - return 1 -} - -function contains_config { - # check file for each path in configPaths - for str in "${configPaths[@]}"; do - if [ ! -f "$str" ]; then - missingPaths+=($str) - fi - done - if [ ${#missingPaths[@]} -gt 0 ]; then - return 1 - fi - return 0 -} - -function is_quasar_alias { - result=$(contains_element "$1" "${QUASAR_NAMES[@]}") - return $result -} - -function is_clark_alias { - result=$(contains_element "$1" "${CLARK_NAMES[@]}") - return $result -} - -function is_cleezy_alias { - result=$(contains_element "$1" "${CLEEZY_NAMES[@]}") - return $result -} - -function is_mongodb_alias { - result=$(contains_element "$1" "${MONGODB_NAMES[@]}") - return $result -} - -function is_discord_bot_alias { - result=$(contains_element "$1" "${SCE_DISCORD_BOT_NAMES[@]}") - return $result -} - -function is_sceta_alias { - result=$(contains_element "$1" "${SCETA_NAMES[@]}") - return $result -} - -function is_valid_command { - result=$(contains_element "$1" "${VALID_COMMANDS[@]}") - return $result -} - -is_valid_command "$1" -if [ $? -eq 1 ] -then - print_usage - exit 1 -fi - -if [ $1 == "completion" ] -then - if [ -n "$FISH_VERSION" ]; then - # Fish shell detected - echo "function sce; bash $(pwd)/sce.sh \$argv; end" - exit 0 - fi - # For other shells (Bash, Zsh, etc.) - echo "# for the sce dev tool" - echo "alias sce=\"$(pwd)/sce.sh\"" - echo "" - exit 0 -fi - -if [ $1 == "create" ] -then - access_level_name="${2:-admin}" - case "$access_level_name" in - admin) access_level=3 ;; - officer) access_level=2 ;; - member) access_level=1 ;; - nonmember) access_level=0 ;; - pending) access_level=-1 ;; - banned) access_level=-2 ;; - *) - echo "unknown access level: $access_level_name" - echo "valid options: admin, officer, member, nonmember, pending, banned" - exit 1 - ;; - esac - - random_suffix=$(cat /dev/urandom | LC_ALL=C tr -dc 'a-zA-Z0-9' | head -c 4) - generated_email="test_${random_suffix}@one.sce" - - mongo_script="use sce_core - db.User.insertOne({ - emailVerified: true, - accessLevel: $access_level, - pagesPrinted: 0, - password: '\$2a\$10\$HWbBiWRso1IUgqnuV6t1hO6lCBWO7KTC/E3G1MsFoXKH7/l/4FVK2', - firstName: 'Development', - lastName: 'Account', - email: '$generated_email', - })" - - echo "$mongo_script" | docker exec -i sce-mongodb-dev mongosh --shell --norc --quiet - echo "created $access_level_name user for the SCE website with:" - echo "email: $generated_email" - echo "password: sce" - exit 0 -fi - -name="" -configPaths=() -missingPaths=() -is_quasar_alias "$2" -if [ $? -eq 0 ] -then - name=$QUASAR_REPO_NAME - configPaths+=("config/config.json") -fi - -is_clark_alias "$2" -if [ $? -eq 0 ] -then - name=$CLARK_REPO_NAME - configPaths+=("src/config/config.json") - configPaths+=("api/config/config.json") -fi - -is_cleezy_alias "$2" -if [ $? -eq 0 ] -then - name=$CLEEZY_REPO_NAME -fi - -is_mongodb_alias "$2" -start_only_mongodb_container=$? -if [ $start_only_mongodb_container -eq 0 ] -then - name=$CLARK_REPO_NAME -fi - -is_discord_bot_alias "$2" -if [ $? -eq 0 ] -then - name=$SCE_DISCORD_BOT_REPO_NAME - configPaths+=("config.json") -fi - -is_sceta_alias "$2" -if [ $? -eq 0 ] -then - name=$SCETA_REPO_NAME -fi - -if [ -z "$name" ] -then - print_usage -fi - -if [ $1 == "clone" ] -then - # clone with the SSH URL if the user wanted to - # if the third argument is absent or anything else - # just default to the HTTPS url - if [[ ! -z "$3" ]] && [[ $3 == "--ssh" ]] - then - git clone "$GITHUB_BASE_SSH_URL$name.git" - else - git clone "$GITHUB_BASE_HTTP_URL$name.git" - fi - exit 0 -elif [ $1 == "link" ] -then - sce_run_location=$(pwd) - # remove sim link if it exists, ignore any stderr/stdout - rm "$SCE_COMMAND_DIRECTORY$name" &> /dev/null - ln -s "$sce_run_location" "$SCE_COMMAND_DIRECTORY$name" -elif [ $1 == "run" ] -then - REPO_LOCATION="$SCE_COMMAND_DIRECTORY$name" - if [ ! -d "$REPO_LOCATION" ] - then - print_repo_not_found $name - fi - cd $REPO_LOCATION - contains_config $configPaths - if [ $? -eq 1 ] - then - print_missing_config $REPO_LOCATION $missingPaths - fi - if [ $start_only_mongodb_container -eq 0 ] - then - docker-compose -f docker-compose.dev.yml up mongodb -d - exit 0 - fi - docker-compose -f docker-compose.dev.yml up --build - exit 0 -elif [ $1 == "lint" ] -then - if [ $name == $SCE_DISCORD_BOT_REPO_NAME ] - then - echo "npm run lint -- -c /sarah/.eslintrc.json --fix" | docker exec -i sarah "/bin/sh" - exit 0 - fi - - if [ $name == $CLARK_REPO_NAME ] - then - echo "npm run lint -- -c /frontend/.eslintrc.json --fix" | docker exec -i sce-frontend-dev "/bin/sh" - echo "npm run lint -- -c /app/.eslintrc.json --fix" | docker exec -i sce-main-endpoints-dev "/bin/sh" - echo "npm run lint -- -c /app/.eslintrc.json --fix" | docker exec -i sce-cloud-api-dev "/bin/sh" - exit 0 - fi -fi - From e6b37c09413e1e8e020626347b65b65c8c065aaa Mon Sep 17 00:00:00 2001 From: adarshm11 Date: Fri, 24 Apr 2026 16:42:01 -0700 Subject: [PATCH 5/5] reorganize go project structure --- .gitignore | 2 ++ cmd/clone.go | 7 ++++--- cmd/create.go | 11 ++++++----- cmd/link.go | 5 +++-- cmd/lint.go | 5 +++-- cmd/nicknames.go | 3 ++- cmd/run.go | 9 +++++---- cmd/setup.go | 5 +++-- {cmd => internal}/aliases.go | 6 +++--- {cmd => internal}/config.go | 18 +++++++++--------- {cmd => internal}/paths.go | 12 ++++++------ 11 files changed, 46 insertions(+), 37 deletions(-) rename {cmd => internal}/aliases.go (95%) rename {cmd => internal}/config.go (57%) rename {cmd => internal}/paths.go (77%) diff --git a/.gitignore b/.gitignore index 64d07b4..1cfa0bd 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,8 @@ !go.sum !cmd/ !cmd/** +!internal/ +!internal/** !.goreleaser.yaml !.github/ !.github/** diff --git a/cmd/clone.go b/cmd/clone.go index b3f3990..0b21990 100644 --- a/cmd/clone.go +++ b/cmd/clone.go @@ -5,6 +5,7 @@ import ( "os" "os/exec" + "github.com/SCE-Development/SCE-CLI/internal" "github.com/spf13/cobra" ) @@ -15,7 +16,7 @@ var cloneCmd = &cobra.Command{ Short: "Clone the given repo from GitHub", Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { - repo, ok := resolveAlias(args[0]) + repo, ok := internal.ResolveAlias(args[0]) if !ok { fmt.Fprintf(os.Stderr, "unknown repo: %s\n", args[0]) os.Exit(1) @@ -23,9 +24,9 @@ var cloneCmd = &cobra.Command{ var url string if sshFlag { - url = githubBaseSSHURL + repo.RepoName + ".git" + url = internal.GithubBaseSSHURL + repo.RepoName + ".git" } else { - url = githubBaseHTTPURL + repo.RepoName + ".git" + url = internal.GithubBaseHTTPURL + repo.RepoName + ".git" } gitCmd := exec.Command("git", "clone", url) diff --git a/cmd/create.go b/cmd/create.go index 7651b3d..8974a4e 100644 --- a/cmd/create.go +++ b/cmd/create.go @@ -8,6 +8,7 @@ import ( "os/exec" "strings" + "github.com/SCE-Development/SCE-CLI/internal" "github.com/spf13/cobra" ) @@ -23,11 +24,11 @@ Levels: admin (default), officer, member, nonmember, pending, banned.`, levelName = args[0] } - level, ok := accessLevels[levelName] + level, ok := internal.AccessLevels[levelName] if !ok { fmt.Fprintf(os.Stderr, "unknown access level: %s\n", levelName) - keys := make([]string, 0, len(accessLevels)) - for k := range accessLevels { + keys := make([]string, 0, len(internal.AccessLevels)) + for k := range internal.AccessLevels { keys = append(keys, k) } fmt.Fprintf(os.Stderr, "valid options: %s\n", strings.Join(keys, ", ")) @@ -46,9 +47,9 @@ db.User.insertOne({ firstName: 'Development', lastName: 'Account', email: '%s', -})`, level, bcryptHash, email) +})`, level, internal.BcryptHash, email) - dockerCmd := exec.Command("docker", "exec", "-i", mongoDBContainer, "mongosh", "--shell", "--norc", "--quiet") + dockerCmd := exec.Command("docker", "exec", "-i", internal.MongoDBContainer, "mongosh", "--shell", "--norc", "--quiet") dockerCmd.Stdin = strings.NewReader(mongoScript) dockerCmd.Stdout = os.Stdout dockerCmd.Stderr = os.Stderr diff --git a/cmd/link.go b/cmd/link.go index 7f5a718..bd5e18b 100644 --- a/cmd/link.go +++ b/cmd/link.go @@ -4,6 +4,7 @@ import ( "fmt" "os" + "github.com/SCE-Development/SCE-CLI/internal" "github.com/spf13/cobra" ) @@ -12,7 +13,7 @@ var linkCmd = &cobra.Command{ Short: "Tell the sce tool where to find the repo on your computer", Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { - repo, ok := resolveAlias(args[0]) + repo, ok := internal.ResolveAlias(args[0]) if !ok { fmt.Fprintf(os.Stderr, "unknown repo: %s\n", args[0]) os.Exit(1) @@ -24,7 +25,7 @@ var linkCmd = &cobra.Command{ os.Exit(1) } - if err := createLink(repo.RepoName, cwd); err != nil { + if err := internal.CreateLink(repo.RepoName, cwd); err != nil { fmt.Fprintf(os.Stderr, "error creating link: %v\n", err) os.Exit(1) } diff --git a/cmd/lint.go b/cmd/lint.go index 928567b..434e053 100644 --- a/cmd/lint.go +++ b/cmd/lint.go @@ -6,6 +6,7 @@ import ( "os/exec" "strings" + "github.com/SCE-Development/SCE-CLI/internal" "github.com/spf13/cobra" ) @@ -14,13 +15,13 @@ var lintCmd = &cobra.Command{ Short: "Run eslint --fix on running containers (Clark and SCE-discord-bot only)", Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { - repo, ok := resolveAlias(args[0]) + repo, ok := internal.ResolveAlias(args[0]) if !ok { fmt.Fprintf(os.Stderr, "unknown repo: %s\n", args[0]) os.Exit(1) } - targets, ok := lintContainers[repo.RepoName] + targets, ok := internal.LintContainers[repo.RepoName] if !ok { fmt.Fprintf(os.Stderr, "lint is not supported for %s\n", repo.RepoName) fmt.Fprintln(os.Stderr, "lint is only available for Clark and SCE-discord-bot.") diff --git a/cmd/nicknames.go b/cmd/nicknames.go index f87154f..325ad7c 100644 --- a/cmd/nicknames.go +++ b/cmd/nicknames.go @@ -3,6 +3,7 @@ package cmd import ( "fmt" + "github.com/SCE-Development/SCE-CLI/internal" "github.com/spf13/cobra" ) @@ -12,7 +13,7 @@ var nicknamesCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { fmt.Println() fmt.Println("each repo has nicknames:") - for _, line := range repoNicknames { + for _, line := range internal.RepoNicknames { fmt.Printf(" %s\n", line) } fmt.Println() diff --git a/cmd/run.go b/cmd/run.go index 69cb0d3..805ff9e 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -6,6 +6,7 @@ import ( "os/exec" "path/filepath" + "github.com/SCE-Development/SCE-CLI/internal" "github.com/spf13/cobra" ) @@ -14,13 +15,13 @@ var runCmd = &cobra.Command{ Short: "Run the repo using docker", Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { - repo, ok := resolveAlias(args[0]) + repo, ok := internal.ResolveAlias(args[0]) if !ok { fmt.Fprintf(os.Stderr, "unknown repo: %s\n", args[0]) os.Exit(1) } - repoPath, err := getRepoPath(repo.RepoName) + repoPath, err := internal.GetRepoPath(repo.RepoName) if err != nil { fmt.Printf("it looks like you haven't linked %s to the sce tool.\n", repo.RepoName) fmt.Println() @@ -46,7 +47,7 @@ var runCmd = &cobra.Command{ composeCmd := dockerComposeCommand() if repo.MongoDBOnly { - dockerCmd := exec.Command(composeCmd[0], append(composeCmd[1:], "-f", dockerComposeFile, "up", "mongodb", "-d")...) + dockerCmd := exec.Command(composeCmd[0], append(composeCmd[1:], "-f", internal.DockerComposeFile, "up", "mongodb", "-d")...) dockerCmd.Dir = repoPath dockerCmd.Stdout = os.Stdout dockerCmd.Stderr = os.Stderr @@ -54,7 +55,7 @@ var runCmd = &cobra.Command{ os.Exit(1) } } else { - dockerCmd := exec.Command(composeCmd[0], append(composeCmd[1:], "-f", dockerComposeFile, "up", "--build")...) + dockerCmd := exec.Command(composeCmd[0], append(composeCmd[1:], "-f", internal.DockerComposeFile, "up", "--build")...) dockerCmd.Dir = repoPath dockerCmd.Stdout = os.Stdout dockerCmd.Stderr = os.Stderr diff --git a/cmd/setup.go b/cmd/setup.go index de0d23f..7cbf60a 100644 --- a/cmd/setup.go +++ b/cmd/setup.go @@ -7,6 +7,7 @@ import ( "path/filepath" "strings" + "github.com/SCE-Development/SCE-CLI/internal" "github.com/spf13/cobra" ) @@ -15,13 +16,13 @@ var setupCmd = &cobra.Command{ Short: "Copy config.example.json in a repo to config.json", Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { - repo, ok := resolveAlias(args[0]) + repo, ok := internal.ResolveAlias(args[0]) if !ok { fmt.Fprintf(os.Stderr, "unknown repo: %s\n", args[0]) os.Exit(1) } - repoPath, err := getRepoPath(repo.RepoName) + repoPath, err := internal.GetRepoPath(repo.RepoName) if err != nil { fmt.Printf("it looks like you haven't linked %s to the sce tool.\n", repo.RepoName) fmt.Println() diff --git a/cmd/aliases.go b/internal/aliases.go similarity index 95% rename from cmd/aliases.go rename to internal/aliases.go index 82d196f..d459c3a 100644 --- a/cmd/aliases.go +++ b/internal/aliases.go @@ -1,4 +1,4 @@ -package cmd +package internal type RepoInfo struct { RepoName string @@ -43,12 +43,12 @@ var aliasMap = map[string]RepoInfo{ "transit": {RepoName: "SCEta"}, } -func resolveAlias(input string) (RepoInfo, bool) { +func ResolveAlias(input string) (RepoInfo, bool) { info, ok := aliasMap[input] return info, ok } -var repoNicknames = []string{ +var RepoNicknames = []string{ "Clark: clark, dog, clrk, ck, c", "MongoDB (requires Clark linked): mongo, db, mongodb", "Quasar: quasar, q, idsmile", diff --git a/cmd/config.go b/internal/config.go similarity index 57% rename from cmd/config.go rename to internal/config.go index 1a5df2e..6485ded 100644 --- a/cmd/config.go +++ b/internal/config.go @@ -1,16 +1,16 @@ -package cmd +package internal const ( - githubBaseHTTPURL = "https://github.com/SCE-Development/" - githubBaseSSHURL = "git@github.com:SCE-Development/" + GithubBaseHTTPURL = "https://github.com/SCE-Development/" + GithubBaseSSHURL = "git@github.com:SCE-Development/" - mongoDBContainer = "sce-mongodb-dev" - dockerComposeFile = "docker-compose.dev.yml" + MongoDBContainer = "sce-mongodb-dev" + DockerComposeFile = "docker-compose.dev.yml" - bcryptHash = "$2a$10$HWbBiWRso1IUgqnuV6t1hO6lCBWO7KTC/E3G1MsFoXKH7/l/4FVK2" + BcryptHash = "$2a$10$HWbBiWRso1IUgqnuV6t1hO6lCBWO7KTC/E3G1MsFoXKH7/l/4FVK2" ) -var accessLevels = map[string]int{ +var AccessLevels = map[string]int{ "admin": 3, "officer": 2, "member": 1, @@ -19,12 +19,12 @@ var accessLevels = map[string]int{ "banned": -2, } -type lintTarget struct { +type LintTarget struct { Container string EslintConfig string } -var lintContainers = map[string][]lintTarget{ +var LintContainers = map[string][]LintTarget{ "Clark": { {Container: "sce-frontend-dev", EslintConfig: "/frontend/.eslintrc.json"}, {Container: "sce-main-endpoints-dev", EslintConfig: "/app/.eslintrc.json"}, diff --git a/cmd/paths.go b/internal/paths.go similarity index 77% rename from cmd/paths.go rename to internal/paths.go index 2af68db..8c7d1e2 100644 --- a/cmd/paths.go +++ b/internal/paths.go @@ -1,4 +1,4 @@ -package cmd +package internal import ( "fmt" @@ -6,7 +6,7 @@ import ( "path/filepath" ) -func getCliDirectory() (string, error) { +func GetCliDirectory() (string, error) { exe, err := os.Executable() if err != nil { return "", err @@ -18,8 +18,8 @@ func getCliDirectory() (string, error) { return filepath.Dir(resolved), nil } -func getRepoPath(repoName string) (string, error) { - cliDir, err := getCliDirectory() +func GetRepoPath(repoName string) (string, error) { + cliDir, err := GetCliDirectory() if err != nil { return "", err } @@ -42,8 +42,8 @@ func getRepoPath(repoName string) (string, error) { return linkPath, nil } -func createLink(repoName string, targetDir string) error { - cliDir, err := getCliDirectory() +func CreateLink(repoName string, targetDir string) error { + cliDir, err := GetCliDirectory() if err != nil { return err }