client

package
v0.3.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 2, 2026 License: MIT Imports: 18 Imported by: 0

README

TFX Client Package

This package provides a clean interface for creating and managing Terraform Enterprise/Cloud API clients.

Usage

Basic Usage
import "github.com/straubt1/tfx/client"

// Create a client with explicit configuration
tfxClient, err := client.New("app.terraform.io", "your-token", "your-org")
if err != nil {
    log.Fatal(err)
}

// Use the client
workspaces, err := tfxClient.Client.Workspaces.List(
    tfxClient.Context,
    tfxClient.OrganizationName,
    nil,
)
Using Viper Configuration
import "github.com/straubt1/tfx/client"

// Create a client from viper configuration (hostname, token, organization)
tfxClient, err := client.NewFromViper()
if err != nil {
    log.Fatal(err)
}
Using Custom Context
import (
    "context"
    "time"
    "github.com/straubt1/tfx/client"
)

// Create a client with timeout context
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

tfxClient, err := client.NewWithContext(ctx, "app.terraform.io", "your-token", "your-org")
if err != nil {
    log.Fatal(err)
}
Debugging

If any of these ENV variables are set, enable the action:

  • "TFX_LOG" - this is the log level and if enabled, will log debug statements to the terminal
  • "TFX_LOG_PATH" - this is a directory string that will be created and where files can be saved
HTTP Request/Response Logging

For debugging or auditing purposes, you can enable HTTP logging to capture all API requests and responses:

import "github.com/straubt1/tfx/client"

// Create a client with HTTP logging enabled
tfxClient, closer, err := client.NewFromViperWithLogging("/tmp/tfx-http.log")
if err != nil {
    log.Fatal(err)
}
// Important: Always close the log file when done
defer closer.Close()

// All HTTP requests and responses will now be logged to the file
projects, err := tfxClient.FetchProjects("my-org", "")

Log File Format:

################################################################################
# TFX HTTP LOG - Started at 2025-10-07T10:30:45Z
################################################################################

================================================================================
REQUEST @ 2025-10-07T10:30:45Z
================================================================================
GET /api/v2/organizations/my-org/projects?page[number]=1&page[size]=100 HTTP/1.1
Host: app.terraform.io
Authorization: Bearer [REDACTED]
Accept: application/vnd.api+json
...

--------------------------------------------------------------------------------
RESPONSE @ 2025-10-07T10:30:46Z
--------------------------------------------------------------------------------
HTTP/2.0 200 OK
Content-Type: application/vnd.api+json
...

Environment Variable Support:

You can also enable logging via environment variable in your commands:

// In your command RunE function:
logFile := os.Getenv("TFX_HTTP_LOG")
if logFile != "" {
    c, closer, err := client.NewFromViperWithLogging(logFile)
    if err != nil {
        return err
    }
    defer closer.Close()
    // ... use c
} else {
    c, err := client.NewFromViper()
    if err != nil {
        return err
    }
    // ... use c
}

Then run:

TFX_HTTP_LOG=/tmp/debug.log ./tfx project list

TfxClient Structure

The TfxClient struct provides:

  • Client - The underlying *tfe.Client from hashicorp/go-tfe
  • Context - A context.Context for API calls
  • Hostname - The TFE/TFC hostname
  • OrganizationName - The default organization name

Client Methods

Organization Operations
  • FetchOrganizations() ([]*tfe.Organization, error) - Fetch all organizations
Project Operations
  • FetchProjects(orgName, searchString string) ([]*tfe.Project, error) - Fetch projects for an organization
  • FetchProjectsAcrossOrgs(searchString string) ([]*tfe.Project, error) - Fetch projects across all organizations
  • FetchProject(projectID string, options *tfe.ProjectReadOptions) (*tfe.Project, error) - Fetch a single project

Error Handling

All functions return proper errors that can be wrapped and handled gracefully:

tfxClient, err := client.NewFromViper()
if err != nil {
    return fmt.Errorf("failed to create TFE client: %w", err)
}

Testing

The package includes unit tests. Run them with:

go test ./client/...

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func FetchAll

func FetchAll[T any](ctx context.Context, fetcher func(pageNumber int) ([]T, *Pagination, error)) ([]T, error)

FetchAll is a generic pagination helper that fetches all pages of results from the TFE API. It accepts a fetcher function that takes a page number and returns items, pagination info, and an error.

Example usage:

projects, err := FetchAll(ctx, func(pageNumber int) ([]*tfe.Project, *Pagination, error) {
    opts := &tfe.ProjectListOptions{
        ListOptions: tfe.ListOptions{PageNumber: pageNumber, PageSize: 100},
    }
    result, err := client.Projects.List(ctx, "org-name", opts)
    if err != nil {
        return nil, nil, err
    }
    return result.Items, &Pagination{
        CurrentPage: result.CurrentPage,
        NextPage:    result.NextPage,
        TotalPages:  result.TotalPages,
    }, nil
})

func IsTFXLogEnabled

func IsTFXLogEnabled() bool

func MethodDisplayLabel added in v0.3.0

func MethodDisplayLabel(method string) string

methodColor returns an ANSI color prefix for a given HTTP method for display purposes. Not used internally — exported so the TUI debugpanel can reference it.

func NewHTTPClientWithLogging

func NewHTTPClientWithLogging(bus *APIEventBus) (*http.Client, io.Closer, error)

NewHTTPClientWithLogging creates an HTTP client that logs all requests and responses to a file if TFX_LOG_PATH is set, and/or to the terminal if TFX_LOG is set. An optional EventBus may be provided to also publish events for the TUI inspector panel.

Types

type APIEvent added in v0.3.0

type APIEvent struct {
	Timestamp   time.Time
	Method      string        // HTTP method (GET, POST, PATCH, DELETE, …)
	URL         string        // Full URL — used for filter matching
	Path        string        // Path-only (scheme+host stripped) — used for display
	StatusCode  int           // 0 if the round-trip errored before a response was received
	Duration    time.Duration // wall-clock time from request start to response end
	ReqHeaders  []string      // sorted "Name: value" lines; sensitive values are [REDACTED]
	ReqBody     string        // Request body; empty for GET/HEAD/DELETE
	RespHeaders []string      // sorted "Name: value" lines from the HTTP response
	RespBody    string        // Response body, pretty-printed if valid JSON
	Err         string        // Non-empty when the round-trip returned an error
}

APIEvent captures a single TFE HTTP round-trip for the TUI API Inspector panel. It is published to an APIEventBus by the LoggingTransport after every request, regardless of whether TFX_LOG is set.

type APIEventBus added in v0.3.0

type APIEventBus struct {
	// contains filtered or unexported fields
}

APIEventBus is a goroutine-safe, non-blocking event sink. The LoggingTransport writes events; the TUI reads them via a blocking Bubble Tea Cmd.

func NewAPIEventBus added in v0.3.0

func NewAPIEventBus() *APIEventBus

NewAPIEventBus returns a new bus with a 256-event buffer. A buffer this size prevents the HTTP transport from ever blocking even if the TUI is slow to drain (events are dropped when the buffer is full, not the HTTP request).

func (*APIEventBus) Receive added in v0.3.0

func (b *APIEventBus) Receive() <-chan APIEvent

Receive returns the read-only channel for use in a Bubble Tea Cmd:

func waitForAPIEvent(bus *client.APIEventBus) tea.Cmd {
    return func() tea.Msg { return <-bus.Receive() }
}

func (*APIEventBus) Send added in v0.3.0

func (b *APIEventBus) Send(e APIEvent)

Send publishes e to the bus. It never blocks: if the buffer is full the event is silently dropped rather than stalling the HTTP round-trip.

type LoggingTransport

type LoggingTransport struct {
	Transport http.RoundTripper
	LogFile   *os.File
	EventBus  *APIEventBus // nil when not running in TUI mode
}

LoggingTransport wraps an http.RoundTripper to log requests and responses. It optionally publishes APIEvents to an APIEventBus for the TUI inspector panel.

func (*LoggingTransport) Close

func (t *LoggingTransport) Close() error

Close closes the log file

func (*LoggingTransport) RoundTrip

func (t *LoggingTransport) RoundTrip(req *http.Request) (*http.Response, error)

RoundTrip implements the http.RoundTripper interface with logging and event publishing.

type Pagination

type Pagination struct {
	CurrentPage int
	NextPage    int
	TotalPages  int
}

Pagination represents the pagination information from TFE API responses

func NewPaginationFromTFE

func NewPaginationFromTFE(p *tfe.Pagination) *Pagination

NewPaginationFromTFE converts TFE pagination to our Pagination type

type TfxClient

type TfxClient struct {
	Client           *tfe.Client
	Context          context.Context
	Hostname         string
	Token            string
	OrganizationName string
	EventBus         *APIEventBus // non-nil in TUI mode; publishes HTTP events to the inspector panel
	HTTPClient       *http.Client // the underlying HTTP client; shares the LoggingTransport in TUI mode
}

TfxClient encapsulates the TFE client and context for API operations

func New

func New(hostname, token, organization string) (*TfxClient, error)

New creates a new TFE client with the provided configuration

func NewFromViper

func NewFromViper() (*TfxClient, error)

NewFromViper creates a TfxClient using configuration from viper

func NewFromViperForTUI added in v0.3.0

func NewFromViperForTUI(bus *APIEventBus) (*TfxClient, error)

NewFromViperForTUI creates a TfxClient for TUI mode. It always installs a LoggingTransport that publishes HTTP events to bus, enabling the API Inspector panel regardless of whether TFX_LOG is set.

func NewFromViperWithContext

func NewFromViperWithContext(ctx context.Context) (*TfxClient, error)

NewFromViperWithContext creates a TfxClient using viper configuration with a parent context

func NewWithContext

func NewWithContext(ctx context.Context, hostname, token, organization string) (*TfxClient, error)

NewWithContext creates a new TFE client with a parent context. HTTP logging is enabled when TFX_LOG or TFX_LOG_PATH is set. To also attach an APIEventBus (TUI inspector), use NewWithContextAndBus.

func NewWithContextAndBus added in v0.3.0

func NewWithContextAndBus(ctx context.Context, hostname, token, organization string, bus *APIEventBus) (*TfxClient, error)

NewWithContextAndBus creates a new TFE client with optional event bus support. When bus is non-nil a LoggingTransport is always installed (regardless of TFX_LOG) so the TUI inspector panel receives every API call.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL