Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions clients/api/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,3 +253,15 @@ func (c *Client) CreateApplicationVersion(applicationID string) (*CreateApplicat
}
return &resp, nil
}

// GetOrganizationApplications retrieves all applications for an organization
func (c *Client) GetOrganizationApplications(organizationID string) (*GetOrganizationApplicationsResponse, error) {
path := fmt.Sprintf("/organizations/applications?organizationId=%s", organizationID)

var resp GetOrganizationApplicationsResponse
err := c.doRequest("GET", path, nil, &resp)
if err != nil {
return nil, err
}
return &resp, nil
}
12 changes: 12 additions & 0 deletions clients/api/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,15 @@ type CreateApplicationVersionRequest struct {
type CreateApplicationVersionResponse struct {
VersionID string `json:"versionId"`
}

// ApplicationItem represents a single application in the list
type ApplicationItem struct {
ID string `json:"id"`
Name string `json:"name"`
GithubRepositoryName string `json:"githubRepositoryName"`
}

// GetOrganizationApplicationsResponse represents the response from GET /organizations/applications
type GetOrganizationApplicationsResponse struct {
Applications []ApplicationItem `json:"applications"`
}
11 changes: 11 additions & 0 deletions clients/git/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,14 @@ func PushToMain() error {
cmd.Stderr = os.Stderr
return cmd.Run()
}

// Pull pulls the latest changes from the remote repository
func Pull(repoDir string) error {
cmd := exec.Command("git", "pull")
if repoDir != "" {
cmd.Dir = repoDir
}
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}
1 change: 1 addition & 0 deletions cmd/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ func init() {
Cmd.AddCommand(startCmd)
Cmd.AddCommand(deployCmd)
Cmd.AddCommand(editCmd)
Cmd.AddCommand(pullCmd)
}
145 changes: 145 additions & 0 deletions cmd/app/pull.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package app

import (
"fmt"
"os"
"path/filepath"

"github.com/charmbracelet/huh"
"github.com/major-technology/cli/clients/api"
"github.com/major-technology/cli/clients/git"
"github.com/major-technology/cli/clients/token"
"github.com/major-technology/cli/singletons"
"github.com/spf13/cobra"
)

// pullCmd represents the app pull command
var pullCmd = &cobra.Command{
Use: "pull",
Short: "Pull an application repository",
Long: `Select and pull an application repository from your organization, then generate env and resources.`,
Run: func(cmd *cobra.Command, args []string) {
cobra.CheckErr(runPull(cmd))
},
}

func runPull(cmd *cobra.Command) error {
// Get the default organization ID from keyring
orgID, orgName, err := token.GetDefaultOrg()
if err != nil {
return fmt.Errorf("failed to get default organization: %w\nPlease run 'major org select' to set a default organization", err)
}

cmd.Printf("Fetching applications for organization: %s\n", orgName)

// Get API client
apiClient := singletons.GetAPIClient()
if apiClient == nil {
return fmt.Errorf("API client not initialized")
}

// Get applications for the organization
appsResp, err := apiClient.GetOrganizationApplications(orgID)
if err != nil {
return fmt.Errorf("failed to get applications: %w", err)
}

if len(appsResp.Applications) == 0 {
cmd.Println("No applications available for this organization")
return nil
}

// Let user select application
selectedApp, err := selectApplication(cmd, appsResp.Applications)
if err != nil {
return fmt.Errorf("failed to select application: %w", err)
}

cmd.Printf("Selected application: %s\n", selectedApp.Name)

// Determine the target directory (use the repository name)
targetDir := filepath.Join(".", selectedApp.GithubRepositoryName)

// Check if the directory already exists
if _, err := os.Stat(targetDir); err == nil {
// Directory exists, just pull
cmd.Printf("Directory '%s' already exists. Pulling latest changes...\n", targetDir)

if err := git.Pull(targetDir); err != nil {
return fmt.Errorf("failed to pull repository: %w", err)
}

cmd.Println("Successfully pulled latest changes")
} else if os.IsNotExist(err) {
return fmt.Errorf("directory '%s' does not exist. Please clone the repository first", targetDir)
} else {
return fmt.Errorf("failed to check directory: %w", err)
}

// Generate env file
cmd.Println("\nGenerating .env file...")
envFilePath, numVars, err := generateEnvFile(targetDir)
if err != nil {
return fmt.Errorf("failed to generate .env file: %w", err)
}
cmd.Printf("Successfully generated .env file at: %s\n", envFilePath)
cmd.Printf("Environment variables written: %d\n", numVars)

// Generate resources file
cmd.Println("\nGenerating RESOURCES.md file...")
resourcesFilePath, numResources, err := generateResourcesFile(targetDir)
if err != nil {
return fmt.Errorf("failed to generate RESOURCES.md file: %w", err)
}
cmd.Printf("Successfully generated RESOURCES.md file at: %s\n", resourcesFilePath)
cmd.Printf("Resources written: %d\n", numResources)

cmd.Println("\n✓ Application pull complete!")

return nil
}

// selectApplication prompts the user to select an application from the list
func selectApplication(cmd *cobra.Command, apps []api.ApplicationItem) (*api.ApplicationItem, error) {
if len(apps) == 0 {
return nil, fmt.Errorf("no applications available")
}

// If only one application, automatically select it
if len(apps) == 1 {
cmd.Printf("Only one application available. Automatically selecting it.\n")
return &apps[0], nil
}

// Create options for huh select
options := make([]huh.Option[string], len(apps))
for i, app := range apps {
options[i] = huh.NewOption(app.Name, app.ID)
}

var selectedID string

// Create and run the select form
form := huh.NewForm(
huh.NewGroup(
huh.NewSelect[string]().
Title("Select an application to pull").
Options(options...).
Value(&selectedID),
),
)

err := form.Run()
if err != nil {
return nil, fmt.Errorf("failed to get selection: %w", err)
}

// Find the selected application
for i, app := range apps {
if app.ID == selectedID {
return &apps[i], nil
}
}

return nil, fmt.Errorf("selected application not found")
}