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
560 changes: 560 additions & 0 deletions api/tooling/client.go

Large diffs are not rendered by default.

477 changes: 477 additions & 0 deletions api/tooling/client_test.go

Large diffs are not rendered by default.

138 changes: 138 additions & 0 deletions api/tooling/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
// Package tooling provides a client for the Salesforce Tooling API.
package tooling

import "time"

// ApexClass represents an Apex class in Salesforce.
type ApexClass struct {
ID string `json:"Id"`
Name string `json:"Name"`
Body string `json:"Body,omitempty"`
Status string `json:"Status"`
IsValid bool `json:"IsValid"`
APIVersion float64 `json:"ApiVersion"`
LengthWithoutComments int `json:"LengthWithoutComments"`
NamespacePrefix string `json:"NamespacePrefix,omitempty"`
}

// ApexTrigger represents an Apex trigger in Salesforce.
type ApexTrigger struct {
ID string `json:"Id"`
Name string `json:"Name"`
Body string `json:"Body,omitempty"`
Status string `json:"Status"`
IsValid bool `json:"IsValid"`
APIVersion float64 `json:"ApiVersion"`
TableEnumOrID string `json:"TableEnumOrId"`
NamespacePrefix string `json:"NamespacePrefix,omitempty"`
}

// ApexLog represents a debug log entry.
type ApexLog struct {
ID string `json:"Id"`
LogUserID string `json:"LogUserId"`
LogUserName string `json:"LogUser.Name,omitempty"`
Operation string `json:"Operation"`
Request string `json:"Request"`
Status string `json:"Status"`
LogLength int `json:"LogLength"`
DurationMS int `json:"DurationMilliseconds"`
StartTime time.Time `json:"StartTime"`
Location string `json:"Location"`
Application string `json:"Application,omitempty"`
LastModified time.Time `json:"LastModifiedDate,omitempty"`
SystemModstamp time.Time `json:"SystemModstamp,omitempty"`
}

// ApexTestQueueItem represents a test class in the test queue.
type ApexTestQueueItem struct {
ID string `json:"Id"`
ApexClassID string `json:"ApexClassId"`
Status string `json:"Status"`
ExtendedStatus string `json:"ExtendedStatus,omitempty"`
ParentJobID string `json:"ParentJobId,omitempty"`
}

// ApexTestResult represents the result of running an Apex test method.
type ApexTestResult struct {
ID string `json:"Id"`
ApexClassID string `json:"ApexClassId"`
ClassName string `json:"ApexClass.Name,omitempty"`
MethodName string `json:"MethodName"`
Outcome string `json:"Outcome"` // Pass, Fail, CompileFail, Skip
Message string `json:"Message,omitempty"`
StackTrace string `json:"StackTrace,omitempty"`
RunTime int `json:"RunTime"` // milliseconds
AsyncApexJobID string `json:"AsyncApexJobId"`
TestTimestamp string `json:"TestTimestamp,omitempty"`
}

// ApexCodeCoverage represents code coverage for an Apex class.
type ApexCodeCoverage struct {
ID string `json:"Id"`
ApexClassOrTriggerID string `json:"ApexClassOrTriggerId"`
ApexClassOrTrigger struct {
Name string `json:"Name"`
} `json:"ApexClassOrTrigger,omitempty"`
ApexTestClassID string `json:"ApexTestClassId"`
NumLinesCovered int `json:"NumLinesCovered"`
NumLinesUncovered int `json:"NumLinesUncovered"`
}

// ApexCodeCoverageAggregate represents aggregate code coverage.
type ApexCodeCoverageAggregate struct {
ID string `json:"Id"`
ApexClassOrTriggerID string `json:"ApexClassOrTriggerId"`
ApexClassOrTrigger struct {
Name string `json:"Name"`
} `json:"ApexClassOrTrigger,omitempty"`
NumLinesCovered int `json:"NumLinesCovered"`
NumLinesUncovered int `json:"NumLinesUncovered"`
}

// ExecuteAnonymousResult represents the result of executing anonymous Apex.
type ExecuteAnonymousResult struct {
Line int `json:"line"`
Column int `json:"column"`
Compiled bool `json:"compiled"`
Success bool `json:"success"`
CompileProblem string `json:"compileProblem,omitempty"`
ExceptionMessage string `json:"exceptionMessage,omitempty"`
ExceptionStackTrace string `json:"exceptionStackTrace,omitempty"`
}

// AsyncApexJob represents an asynchronous Apex job (for test runs).
type AsyncApexJob struct {
ID string `json:"Id"`
Status string `json:"Status"` // Queued, Processing, Completed, Aborted, Failed
JobItemsProcessed int `json:"JobItemsProcessed"`
TotalJobItems int `json:"TotalJobItems"`
NumberOfErrors int `json:"NumberOfErrors"`
MethodName string `json:"MethodName,omitempty"`
ExtendedStatus string `json:"ExtendedStatus,omitempty"`
ParentJobID string `json:"ParentJobId,omitempty"`
ApexClassID string `json:"ApexClassId,omitempty"`
CompletedDate string `json:"CompletedDate,omitempty"`
}

// QueryResult represents the result of a Tooling API query.
type QueryResult struct {
TotalSize int `json:"totalSize"`
Done bool `json:"done"`
Records []Record `json:"records"`
NextRecordsURL string `json:"nextRecordsUrl,omitempty"`
}

// Record represents a generic record from a Tooling API query.
type Record map[string]interface{}

// RunTestsRequest represents a request to run Apex tests.
type RunTestsRequest struct {
ClassIDs []string `json:"classids,omitempty"`
SuiteIDs []string `json:"suiteids,omitempty"`
MaxFailedTests int `json:"maxFailedTests,omitempty"`
TestLevel string `json:"testLevel,omitempty"`
}

// RunTestsAsyncResult represents the result of enqueuing tests.
type RunTestsAsyncResult string
8 changes: 8 additions & 0 deletions cmd/sfdc/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@ import (
"fmt"
"os"

"github.com/open-cli-collective/salesforce-cli/internal/cmd/apexcmd"
"github.com/open-cli-collective/salesforce-cli/internal/cmd/bulkcmd"
"github.com/open-cli-collective/salesforce-cli/internal/cmd/completion"
"github.com/open-cli-collective/salesforce-cli/internal/cmd/configcmd"
"github.com/open-cli-collective/salesforce-cli/internal/cmd/coveragecmd"
"github.com/open-cli-collective/salesforce-cli/internal/cmd/initcmd"
"github.com/open-cli-collective/salesforce-cli/internal/cmd/limitscmd"
"github.com/open-cli-collective/salesforce-cli/internal/cmd/logcmd"
"github.com/open-cli-collective/salesforce-cli/internal/cmd/objectcmd"
"github.com/open-cli-collective/salesforce-cli/internal/cmd/querycmd"
"github.com/open-cli-collective/salesforce-cli/internal/cmd/recordcmd"
Expand Down Expand Up @@ -49,5 +52,10 @@ func run() error {
// Bulk API commands
bulkcmd.Register(rootCmd, opts)

// Tooling API commands
apexcmd.Register(rootCmd, opts)
logcmd.Register(rootCmd, opts)
coveragecmd.Register(rootCmd, opts)

return rootCmd.Execute()
}
36 changes: 36 additions & 0 deletions internal/cmd/apexcmd/apex.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Package apexcmd provides commands for Apex class operations.
package apexcmd

import (
"github.com/spf13/cobra"

"github.com/open-cli-collective/salesforce-cli/internal/cmd/root"
)

// Register registers the apex command with the root command.
func Register(parent *cobra.Command, opts *root.Options) {
parent.AddCommand(NewCommand(opts))
}

// NewCommand creates the apex command.
func NewCommand(opts *root.Options) *cobra.Command {
cmd := &cobra.Command{
Use: "apex",
Short: "Apex class operations",
Long: `Manage Apex classes, triggers, and execute anonymous Apex.

Examples:
sfdc apex list # List all Apex classes
sfdc apex list --triggers # List all Apex triggers
sfdc apex get MyController # Get class source code
sfdc apex execute "System.debug('Hi');" # Execute anonymous Apex
sfdc apex test --class MyTest # Run Apex tests`,
}

cmd.AddCommand(newListCommand(opts))
cmd.AddCommand(newGetCommand(opts))
cmd.AddCommand(newExecuteCommand(opts))
cmd.AddCommand(newTestCommand(opts))

return cmd
}
Loading