-
Notifications
You must be signed in to change notification settings - Fork 1
Phase 2: Extract shared atlassian-go package #2
Copy link
Copy link
Closed
Description
What
Create a shared Go module (github.com/open-cli-collective/atlassian-go) containing common code used by both CLIs.
Shared Components to Extract
| Package | Purpose | Source Files |
|---|---|---|
auth/ |
HTTP Basic Auth header generation | api/client.go from both |
client/ |
Base HTTP client (do, Get, Post, Put, Delete) | api/client.go from both |
config/ |
Environment variable precedence (GetWithFallback) |
internal/config/config.go from both |
errors/ |
APIError struct, sentinel errors | api/errors.go (jtk), api/client.go (cfl) |
view/ |
Output renderer (table/JSON/plain) | internal/view/view.go from both |
Target Structure
shared/
├── go.mod # github.com/open-cli-collective/atlassian-go
├── auth/
│ ├── auth.go # BasicAuthHeader(email, token) string
│ └── auth_test.go
├── client/
│ ├── client.go # Client struct, Do, Get, Post, Put, Delete
│ ├── client_test.go
│ └── options.go # ClientOptions (timeout, verbose, etc.)
├── config/
│ ├── env.go # GetEnvWithFallback(primary, fallback string) string
│ └── env_test.go
├── errors/
│ ├── errors.go # APIError, ErrNotFound, ErrUnauthorized, etc.
│ └── errors_test.go
└── view/
├── view.go # Renderer, Format enum
├── view_test.go
├── table.go # Table formatting
└── json.go # JSON formatting
API Design
// auth/auth.go
package auth
func BasicAuthHeader(email, apiToken string) string
// client/client.go
package client
type Client struct {
BaseURL string
HTTPClient *http.Client
AuthHeader string
Verbose bool
}
type Options struct {
Timeout time.Duration
Verbose bool
}
func New(baseURL, email, apiToken string, opts *Options) *Client
func (c *Client) Do(ctx context.Context, method, path string, body interface{}) ([]byte, error)
func (c *Client) Get(ctx context.Context, path string) ([]byte, error)
func (c *Client) Post(ctx context.Context, path string, body interface{}) ([]byte, error)
func (c *Client) Put(ctx context.Context, path string, body interface{}) ([]byte, error)
func (c *Client) Delete(ctx context.Context, path string) ([]byte, error)
// config/env.go
package config
func GetEnvWithFallback(primary, fallback string) string
// errors/errors.go
package errors
var (
ErrNotFound = errors.New("resource not found")
ErrUnauthorized = errors.New("unauthorized")
ErrForbidden = errors.New("forbidden")
)
type APIError struct {
StatusCode int
Message string
Errors []string
}
func (e *APIError) Error() string
func ParseAPIError(resp *http.Response, body []byte) error
// view/view.go
package view
type Format string
const (
FormatTable Format = "table"
FormatJSON Format = "json"
FormatPlain Format = "plain"
)
type Renderer struct { ... }
func New(format Format, w io.Writer, noColor bool) *Renderer
func (r *Renderer) Table(headers []string, rows [][]string) error
func (r *Renderer) JSON(v interface{}) error
func (r *Renderer) Success(msg string)
func (r *Renderer) Error(msg string)Why
DRY (Don't Repeat Yourself)
Both CLIs have nearly identical implementations of:
- HTTP Basic Auth (same algorithm, same headers)
- HTTP client wrapper (same timeout, same JSON handling, same error parsing)
- Output formatting (same table/JSON/plain logic)
- Environment variable fallback (same
ATLASSIAN_*pattern)
Duplicated code means:
- Bug fixes need to be applied twice
- Improvements diverge over time
- Testing effort is doubled
- New contributors learn two slightly different patterns
Public module enables ecosystem
By making this a public Go module (github.com/open-cli-collective/atlassian-go), we enable:
- Other Atlassian CLI tools (Bitbucket, Trello) to share the same foundation
- External projects to import our battle-tested Atlassian client
- Community contributions to the shared layer benefit all tools
Separation of concerns
The shared module has a clear contract:
- It knows about: HTTP, JSON, auth headers, output formatting
- It doesn't know about: Confluence pages, Jira issues, specific API endpoints
This keeps the shared code stable while tool-specific code evolves independently.
Acceptance Criteria
-
shared/go.modexists with module pathgithub.com/open-cli-collective/atlassian-go - All shared packages have tests with >80% coverage
-
go build ./shared/...succeeds -
go test ./shared/...passes - API is documented with GoDoc comments
- No tool-specific code (Confluence/Jira) in shared packages
Dependencies
- Blocked by: Phase 1: Create monorepo structure with git history #1 (Phase 1: Create monorepo structure)
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels