2026-01-28 19:39:04 +00:00
|
|
|
package php
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"context"
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"io"
|
|
|
|
|
"net/http"
|
|
|
|
|
"os"
|
|
|
|
|
"path/filepath"
|
|
|
|
|
"strings"
|
|
|
|
|
"time"
|
2026-01-31 11:39:19 +00:00
|
|
|
|
|
|
|
|
"github.com/host-uk/core/pkg/cli"
|
2026-01-28 19:39:04 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// CoolifyClient is an HTTP client for the Coolify API.
|
|
|
|
|
type CoolifyClient struct {
|
|
|
|
|
BaseURL string
|
|
|
|
|
Token string
|
|
|
|
|
HTTPClient *http.Client
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// CoolifyConfig holds configuration loaded from environment.
|
|
|
|
|
type CoolifyConfig struct {
|
|
|
|
|
URL string
|
|
|
|
|
Token string
|
|
|
|
|
AppID string
|
|
|
|
|
StagingAppID string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// CoolifyDeployment represents a deployment from the Coolify API.
|
|
|
|
|
type CoolifyDeployment struct {
|
|
|
|
|
ID string `json:"id"`
|
|
|
|
|
Status string `json:"status"`
|
|
|
|
|
CommitSHA string `json:"commit_sha,omitempty"`
|
|
|
|
|
CommitMsg string `json:"commit_message,omitempty"`
|
|
|
|
|
Branch string `json:"branch,omitempty"`
|
|
|
|
|
CreatedAt time.Time `json:"created_at"`
|
|
|
|
|
FinishedAt time.Time `json:"finished_at,omitempty"`
|
|
|
|
|
Log string `json:"log,omitempty"`
|
|
|
|
|
DeployedURL string `json:"deployed_url,omitempty"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// CoolifyApp represents an application from the Coolify API.
|
|
|
|
|
type CoolifyApp struct {
|
|
|
|
|
ID string `json:"id"`
|
|
|
|
|
Name string `json:"name"`
|
|
|
|
|
FQDN string `json:"fqdn,omitempty"`
|
|
|
|
|
Status string `json:"status,omitempty"`
|
|
|
|
|
Repository string `json:"repository,omitempty"`
|
|
|
|
|
Branch string `json:"branch,omitempty"`
|
|
|
|
|
Environment string `json:"environment,omitempty"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NewCoolifyClient creates a new Coolify API client.
|
|
|
|
|
func NewCoolifyClient(baseURL, token string) *CoolifyClient {
|
|
|
|
|
// Ensure baseURL doesn't have trailing slash
|
|
|
|
|
baseURL = strings.TrimSuffix(baseURL, "/")
|
|
|
|
|
|
|
|
|
|
return &CoolifyClient{
|
|
|
|
|
BaseURL: baseURL,
|
|
|
|
|
Token: token,
|
|
|
|
|
HTTPClient: &http.Client{
|
|
|
|
|
Timeout: 30 * time.Second,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// LoadCoolifyConfig loads Coolify configuration from .env file in the given directory.
|
|
|
|
|
func LoadCoolifyConfig(dir string) (*CoolifyConfig, error) {
|
|
|
|
|
envPath := filepath.Join(dir, ".env")
|
|
|
|
|
return LoadCoolifyConfigFromFile(envPath)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// LoadCoolifyConfigFromFile loads Coolify configuration from a specific .env file.
|
|
|
|
|
func LoadCoolifyConfigFromFile(path string) (*CoolifyConfig, error) {
|
|
|
|
|
config := &CoolifyConfig{}
|
|
|
|
|
|
|
|
|
|
// First try environment variables
|
|
|
|
|
config.URL = os.Getenv("COOLIFY_URL")
|
|
|
|
|
config.Token = os.Getenv("COOLIFY_TOKEN")
|
|
|
|
|
config.AppID = os.Getenv("COOLIFY_APP_ID")
|
|
|
|
|
config.StagingAppID = os.Getenv("COOLIFY_STAGING_APP_ID")
|
|
|
|
|
|
|
|
|
|
// Then try .env file
|
|
|
|
|
file, err := os.Open(path)
|
|
|
|
|
if err != nil {
|
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
|
// No .env file, just use env vars
|
|
|
|
|
return validateCoolifyConfig(config)
|
|
|
|
|
}
|
2026-01-31 11:39:19 +00:00
|
|
|
return nil, cli.WrapVerb(err, "open", ".env file")
|
2026-01-28 19:39:04 +00:00
|
|
|
}
|
feat: git command, build improvements, and go fmt git-aware (#74)
* feat(go): make go fmt git-aware by default
- By default, only check changed Go files (modified, staged, untracked)
- Add --all flag to check all files (previous behaviour)
- Reduces noise when running fmt on large codebases
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(build): minimal output by default, add missing i18n
- Default output now shows single line: "Success Built N artifacts (dir)"
- Add --verbose/-v flag to show full detailed output
- Add all missing i18n translations for build commands
- Errors still show failure reason in minimal mode
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat: add root-level `core git` command
- Create pkg/gitcmd with git workflow commands as root menu
- Export command builders from pkg/dev (AddCommitCommand, etc.)
- Commands available under both `core git` and `core dev` for compatibility
- Git commands: health, commit, push, pull, work, sync, apply
- GitHub orchestration stays in dev: issues, reviews, ci, impact
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(qa): add docblock coverage checking
Implement docblock/docstring coverage analysis for Go code:
- New `core qa docblock` command to check coverage
- Shows compact file:line list when under threshold
- Integrate with `core go qa` as a default check
- Add --docblock-threshold flag (default 80%)
The checker uses Go AST parsing to find exported symbols
(functions, types, consts, vars) without documentation.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: address CodeRabbit review feedback
- Fix doc comment: "status" → "health" in gitcmd package
- Implement --check flag for `core go fmt` (exits non-zero if files need formatting)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* docs: add docstrings for 100% coverage
Add documentation comments to all exported symbols:
- pkg/build: ProjectType constants
- pkg/cli: LogLevel, RenderStyle, TableStyle
- pkg/framework: ServiceFor, MustServiceFor, Core.Core
- pkg/git: GitError.Error, GitError.Unwrap
- pkg/i18n: Handler Match/Handle methods
- pkg/log: Level constants
- pkg/mcp: Tool input/output types
- pkg/php: Service constants, QA types, service methods
- pkg/process: ServiceError.Error
- pkg/repos: RepoType constants
- pkg/setup: ChangeType, ChangeCategory constants
- pkg/workspace: AddWorkspaceCommands
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* chore: standardize line endings to LF
Add .gitattributes to enforce LF line endings for all text files.
Normalize all existing files to use Unix-style line endings.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: address CodeRabbit review feedback
- cmd_format.go: validate --check/--fix mutual exclusivity, capture stderr
- cmd_docblock.go: return error instead of os.Exit(1) for proper error handling
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: address CodeRabbit review feedback (round 2)
- linuxkit.go: propagate state update errors, handle cmd.Wait() errors in waitForExit
- mcp.go: guard against empty old_string in editDiff to prevent runaway edits
- cmd_docblock.go: log parse errors instead of silently skipping
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 10:48:44 +00:00
|
|
|
defer func() { _ = file.Close() }()
|
2026-01-28 19:39:04 +00:00
|
|
|
|
|
|
|
|
content, err := io.ReadAll(file)
|
|
|
|
|
if err != nil {
|
2026-01-31 11:39:19 +00:00
|
|
|
return nil, cli.WrapVerb(err, "read", ".env file")
|
2026-01-28 19:39:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Parse .env file
|
|
|
|
|
lines := strings.Split(string(content), "\n")
|
|
|
|
|
for _, line := range lines {
|
|
|
|
|
line = strings.TrimSpace(line)
|
|
|
|
|
if line == "" || strings.HasPrefix(line, "#") {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
parts := strings.SplitN(line, "=", 2)
|
|
|
|
|
if len(parts) != 2 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
key := strings.TrimSpace(parts[0])
|
|
|
|
|
value := strings.TrimSpace(parts[1])
|
|
|
|
|
// Remove quotes if present
|
|
|
|
|
value = strings.Trim(value, `"'`)
|
|
|
|
|
|
|
|
|
|
// Only override if not already set from env
|
|
|
|
|
switch key {
|
|
|
|
|
case "COOLIFY_URL":
|
|
|
|
|
if config.URL == "" {
|
|
|
|
|
config.URL = value
|
|
|
|
|
}
|
|
|
|
|
case "COOLIFY_TOKEN":
|
|
|
|
|
if config.Token == "" {
|
|
|
|
|
config.Token = value
|
|
|
|
|
}
|
|
|
|
|
case "COOLIFY_APP_ID":
|
|
|
|
|
if config.AppID == "" {
|
|
|
|
|
config.AppID = value
|
|
|
|
|
}
|
|
|
|
|
case "COOLIFY_STAGING_APP_ID":
|
|
|
|
|
if config.StagingAppID == "" {
|
|
|
|
|
config.StagingAppID = value
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return validateCoolifyConfig(config)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// validateCoolifyConfig checks that required fields are set.
|
|
|
|
|
func validateCoolifyConfig(config *CoolifyConfig) (*CoolifyConfig, error) {
|
|
|
|
|
if config.URL == "" {
|
2026-01-31 11:39:19 +00:00
|
|
|
return nil, cli.Err("COOLIFY_URL is not set")
|
2026-01-28 19:39:04 +00:00
|
|
|
}
|
|
|
|
|
if config.Token == "" {
|
2026-01-31 11:39:19 +00:00
|
|
|
return nil, cli.Err("COOLIFY_TOKEN is not set")
|
2026-01-28 19:39:04 +00:00
|
|
|
}
|
|
|
|
|
return config, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TriggerDeploy triggers a deployment for the specified application.
|
|
|
|
|
func (c *CoolifyClient) TriggerDeploy(ctx context.Context, appID string, force bool) (*CoolifyDeployment, error) {
|
2026-01-31 11:39:19 +00:00
|
|
|
endpoint := cli.Sprintf("%s/api/v1/applications/%s/deploy", c.BaseURL, appID)
|
2026-01-28 19:39:04 +00:00
|
|
|
|
|
|
|
|
payload := map[string]interface{}{}
|
|
|
|
|
if force {
|
|
|
|
|
payload["force"] = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
body, err := json.Marshal(payload)
|
|
|
|
|
if err != nil {
|
2026-01-31 11:39:19 +00:00
|
|
|
return nil, cli.WrapVerb(err, "marshal", "request")
|
2026-01-28 19:39:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint, bytes.NewReader(body))
|
|
|
|
|
if err != nil {
|
2026-01-31 11:39:19 +00:00
|
|
|
return nil, cli.WrapVerb(err, "create", "request")
|
2026-01-28 19:39:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c.setHeaders(req)
|
|
|
|
|
|
|
|
|
|
resp, err := c.HTTPClient.Do(req)
|
|
|
|
|
if err != nil {
|
2026-01-31 11:39:19 +00:00
|
|
|
return nil, cli.Wrap(err, "request failed")
|
2026-01-28 19:39:04 +00:00
|
|
|
}
|
feat: git command, build improvements, and go fmt git-aware (#74)
* feat(go): make go fmt git-aware by default
- By default, only check changed Go files (modified, staged, untracked)
- Add --all flag to check all files (previous behaviour)
- Reduces noise when running fmt on large codebases
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(build): minimal output by default, add missing i18n
- Default output now shows single line: "Success Built N artifacts (dir)"
- Add --verbose/-v flag to show full detailed output
- Add all missing i18n translations for build commands
- Errors still show failure reason in minimal mode
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat: add root-level `core git` command
- Create pkg/gitcmd with git workflow commands as root menu
- Export command builders from pkg/dev (AddCommitCommand, etc.)
- Commands available under both `core git` and `core dev` for compatibility
- Git commands: health, commit, push, pull, work, sync, apply
- GitHub orchestration stays in dev: issues, reviews, ci, impact
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(qa): add docblock coverage checking
Implement docblock/docstring coverage analysis for Go code:
- New `core qa docblock` command to check coverage
- Shows compact file:line list when under threshold
- Integrate with `core go qa` as a default check
- Add --docblock-threshold flag (default 80%)
The checker uses Go AST parsing to find exported symbols
(functions, types, consts, vars) without documentation.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: address CodeRabbit review feedback
- Fix doc comment: "status" → "health" in gitcmd package
- Implement --check flag for `core go fmt` (exits non-zero if files need formatting)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* docs: add docstrings for 100% coverage
Add documentation comments to all exported symbols:
- pkg/build: ProjectType constants
- pkg/cli: LogLevel, RenderStyle, TableStyle
- pkg/framework: ServiceFor, MustServiceFor, Core.Core
- pkg/git: GitError.Error, GitError.Unwrap
- pkg/i18n: Handler Match/Handle methods
- pkg/log: Level constants
- pkg/mcp: Tool input/output types
- pkg/php: Service constants, QA types, service methods
- pkg/process: ServiceError.Error
- pkg/repos: RepoType constants
- pkg/setup: ChangeType, ChangeCategory constants
- pkg/workspace: AddWorkspaceCommands
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* chore: standardize line endings to LF
Add .gitattributes to enforce LF line endings for all text files.
Normalize all existing files to use Unix-style line endings.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: address CodeRabbit review feedback
- cmd_format.go: validate --check/--fix mutual exclusivity, capture stderr
- cmd_docblock.go: return error instead of os.Exit(1) for proper error handling
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: address CodeRabbit review feedback (round 2)
- linuxkit.go: propagate state update errors, handle cmd.Wait() errors in waitForExit
- mcp.go: guard against empty old_string in editDiff to prevent runaway edits
- cmd_docblock.go: log parse errors instead of silently skipping
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 10:48:44 +00:00
|
|
|
defer func() { _ = resp.Body.Close() }()
|
2026-01-28 19:39:04 +00:00
|
|
|
|
|
|
|
|
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated && resp.StatusCode != http.StatusAccepted {
|
|
|
|
|
return nil, c.parseError(resp)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var deployment CoolifyDeployment
|
|
|
|
|
if err := json.NewDecoder(resp.Body).Decode(&deployment); err != nil {
|
|
|
|
|
// Some Coolify versions return minimal response
|
|
|
|
|
return &CoolifyDeployment{
|
|
|
|
|
Status: "queued",
|
|
|
|
|
CreatedAt: time.Now(),
|
|
|
|
|
}, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &deployment, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetDeployment retrieves a specific deployment by ID.
|
|
|
|
|
func (c *CoolifyClient) GetDeployment(ctx context.Context, appID, deploymentID string) (*CoolifyDeployment, error) {
|
2026-01-31 11:39:19 +00:00
|
|
|
endpoint := cli.Sprintf("%s/api/v1/applications/%s/deployments/%s", c.BaseURL, appID, deploymentID)
|
2026-01-28 19:39:04 +00:00
|
|
|
|
|
|
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint, nil)
|
|
|
|
|
if err != nil {
|
2026-01-31 11:39:19 +00:00
|
|
|
return nil, cli.WrapVerb(err, "create", "request")
|
2026-01-28 19:39:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c.setHeaders(req)
|
|
|
|
|
|
|
|
|
|
resp, err := c.HTTPClient.Do(req)
|
|
|
|
|
if err != nil {
|
2026-01-31 11:39:19 +00:00
|
|
|
return nil, cli.Wrap(err, "request failed")
|
2026-01-28 19:39:04 +00:00
|
|
|
}
|
feat: git command, build improvements, and go fmt git-aware (#74)
* feat(go): make go fmt git-aware by default
- By default, only check changed Go files (modified, staged, untracked)
- Add --all flag to check all files (previous behaviour)
- Reduces noise when running fmt on large codebases
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(build): minimal output by default, add missing i18n
- Default output now shows single line: "Success Built N artifacts (dir)"
- Add --verbose/-v flag to show full detailed output
- Add all missing i18n translations for build commands
- Errors still show failure reason in minimal mode
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat: add root-level `core git` command
- Create pkg/gitcmd with git workflow commands as root menu
- Export command builders from pkg/dev (AddCommitCommand, etc.)
- Commands available under both `core git` and `core dev` for compatibility
- Git commands: health, commit, push, pull, work, sync, apply
- GitHub orchestration stays in dev: issues, reviews, ci, impact
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(qa): add docblock coverage checking
Implement docblock/docstring coverage analysis for Go code:
- New `core qa docblock` command to check coverage
- Shows compact file:line list when under threshold
- Integrate with `core go qa` as a default check
- Add --docblock-threshold flag (default 80%)
The checker uses Go AST parsing to find exported symbols
(functions, types, consts, vars) without documentation.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: address CodeRabbit review feedback
- Fix doc comment: "status" → "health" in gitcmd package
- Implement --check flag for `core go fmt` (exits non-zero if files need formatting)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* docs: add docstrings for 100% coverage
Add documentation comments to all exported symbols:
- pkg/build: ProjectType constants
- pkg/cli: LogLevel, RenderStyle, TableStyle
- pkg/framework: ServiceFor, MustServiceFor, Core.Core
- pkg/git: GitError.Error, GitError.Unwrap
- pkg/i18n: Handler Match/Handle methods
- pkg/log: Level constants
- pkg/mcp: Tool input/output types
- pkg/php: Service constants, QA types, service methods
- pkg/process: ServiceError.Error
- pkg/repos: RepoType constants
- pkg/setup: ChangeType, ChangeCategory constants
- pkg/workspace: AddWorkspaceCommands
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* chore: standardize line endings to LF
Add .gitattributes to enforce LF line endings for all text files.
Normalize all existing files to use Unix-style line endings.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: address CodeRabbit review feedback
- cmd_format.go: validate --check/--fix mutual exclusivity, capture stderr
- cmd_docblock.go: return error instead of os.Exit(1) for proper error handling
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: address CodeRabbit review feedback (round 2)
- linuxkit.go: propagate state update errors, handle cmd.Wait() errors in waitForExit
- mcp.go: guard against empty old_string in editDiff to prevent runaway edits
- cmd_docblock.go: log parse errors instead of silently skipping
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 10:48:44 +00:00
|
|
|
defer func() { _ = resp.Body.Close() }()
|
2026-01-28 19:39:04 +00:00
|
|
|
|
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
|
return nil, c.parseError(resp)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var deployment CoolifyDeployment
|
|
|
|
|
if err := json.NewDecoder(resp.Body).Decode(&deployment); err != nil {
|
2026-01-31 11:39:19 +00:00
|
|
|
return nil, cli.WrapVerb(err, "decode", "response")
|
2026-01-28 19:39:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &deployment, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ListDeployments retrieves deployments for an application.
|
|
|
|
|
func (c *CoolifyClient) ListDeployments(ctx context.Context, appID string, limit int) ([]CoolifyDeployment, error) {
|
2026-01-31 11:39:19 +00:00
|
|
|
endpoint := cli.Sprintf("%s/api/v1/applications/%s/deployments", c.BaseURL, appID)
|
2026-01-28 19:39:04 +00:00
|
|
|
if limit > 0 {
|
2026-01-31 11:39:19 +00:00
|
|
|
endpoint = cli.Sprintf("%s?limit=%d", endpoint, limit)
|
2026-01-28 19:39:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint, nil)
|
|
|
|
|
if err != nil {
|
2026-01-31 11:39:19 +00:00
|
|
|
return nil, cli.WrapVerb(err, "create", "request")
|
2026-01-28 19:39:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c.setHeaders(req)
|
|
|
|
|
|
|
|
|
|
resp, err := c.HTTPClient.Do(req)
|
|
|
|
|
if err != nil {
|
2026-01-31 11:39:19 +00:00
|
|
|
return nil, cli.Wrap(err, "request failed")
|
2026-01-28 19:39:04 +00:00
|
|
|
}
|
feat: git command, build improvements, and go fmt git-aware (#74)
* feat(go): make go fmt git-aware by default
- By default, only check changed Go files (modified, staged, untracked)
- Add --all flag to check all files (previous behaviour)
- Reduces noise when running fmt on large codebases
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(build): minimal output by default, add missing i18n
- Default output now shows single line: "Success Built N artifacts (dir)"
- Add --verbose/-v flag to show full detailed output
- Add all missing i18n translations for build commands
- Errors still show failure reason in minimal mode
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat: add root-level `core git` command
- Create pkg/gitcmd with git workflow commands as root menu
- Export command builders from pkg/dev (AddCommitCommand, etc.)
- Commands available under both `core git` and `core dev` for compatibility
- Git commands: health, commit, push, pull, work, sync, apply
- GitHub orchestration stays in dev: issues, reviews, ci, impact
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(qa): add docblock coverage checking
Implement docblock/docstring coverage analysis for Go code:
- New `core qa docblock` command to check coverage
- Shows compact file:line list when under threshold
- Integrate with `core go qa` as a default check
- Add --docblock-threshold flag (default 80%)
The checker uses Go AST parsing to find exported symbols
(functions, types, consts, vars) without documentation.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: address CodeRabbit review feedback
- Fix doc comment: "status" → "health" in gitcmd package
- Implement --check flag for `core go fmt` (exits non-zero if files need formatting)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* docs: add docstrings for 100% coverage
Add documentation comments to all exported symbols:
- pkg/build: ProjectType constants
- pkg/cli: LogLevel, RenderStyle, TableStyle
- pkg/framework: ServiceFor, MustServiceFor, Core.Core
- pkg/git: GitError.Error, GitError.Unwrap
- pkg/i18n: Handler Match/Handle methods
- pkg/log: Level constants
- pkg/mcp: Tool input/output types
- pkg/php: Service constants, QA types, service methods
- pkg/process: ServiceError.Error
- pkg/repos: RepoType constants
- pkg/setup: ChangeType, ChangeCategory constants
- pkg/workspace: AddWorkspaceCommands
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* chore: standardize line endings to LF
Add .gitattributes to enforce LF line endings for all text files.
Normalize all existing files to use Unix-style line endings.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: address CodeRabbit review feedback
- cmd_format.go: validate --check/--fix mutual exclusivity, capture stderr
- cmd_docblock.go: return error instead of os.Exit(1) for proper error handling
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: address CodeRabbit review feedback (round 2)
- linuxkit.go: propagate state update errors, handle cmd.Wait() errors in waitForExit
- mcp.go: guard against empty old_string in editDiff to prevent runaway edits
- cmd_docblock.go: log parse errors instead of silently skipping
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 10:48:44 +00:00
|
|
|
defer func() { _ = resp.Body.Close() }()
|
2026-01-28 19:39:04 +00:00
|
|
|
|
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
|
return nil, c.parseError(resp)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var deployments []CoolifyDeployment
|
|
|
|
|
if err := json.NewDecoder(resp.Body).Decode(&deployments); err != nil {
|
2026-01-31 11:39:19 +00:00
|
|
|
return nil, cli.WrapVerb(err, "decode", "response")
|
2026-01-28 19:39:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return deployments, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Rollback triggers a rollback to a previous deployment.
|
|
|
|
|
func (c *CoolifyClient) Rollback(ctx context.Context, appID, deploymentID string) (*CoolifyDeployment, error) {
|
2026-01-31 11:39:19 +00:00
|
|
|
endpoint := cli.Sprintf("%s/api/v1/applications/%s/rollback", c.BaseURL, appID)
|
2026-01-28 19:39:04 +00:00
|
|
|
|
|
|
|
|
payload := map[string]interface{}{
|
|
|
|
|
"deployment_id": deploymentID,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
body, err := json.Marshal(payload)
|
|
|
|
|
if err != nil {
|
2026-01-31 11:39:19 +00:00
|
|
|
return nil, cli.WrapVerb(err, "marshal", "request")
|
2026-01-28 19:39:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint, bytes.NewReader(body))
|
|
|
|
|
if err != nil {
|
2026-01-31 11:39:19 +00:00
|
|
|
return nil, cli.WrapVerb(err, "create", "request")
|
2026-01-28 19:39:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c.setHeaders(req)
|
|
|
|
|
|
|
|
|
|
resp, err := c.HTTPClient.Do(req)
|
|
|
|
|
if err != nil {
|
2026-01-31 11:39:19 +00:00
|
|
|
return nil, cli.Wrap(err, "request failed")
|
2026-01-28 19:39:04 +00:00
|
|
|
}
|
feat: git command, build improvements, and go fmt git-aware (#74)
* feat(go): make go fmt git-aware by default
- By default, only check changed Go files (modified, staged, untracked)
- Add --all flag to check all files (previous behaviour)
- Reduces noise when running fmt on large codebases
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(build): minimal output by default, add missing i18n
- Default output now shows single line: "Success Built N artifacts (dir)"
- Add --verbose/-v flag to show full detailed output
- Add all missing i18n translations for build commands
- Errors still show failure reason in minimal mode
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat: add root-level `core git` command
- Create pkg/gitcmd with git workflow commands as root menu
- Export command builders from pkg/dev (AddCommitCommand, etc.)
- Commands available under both `core git` and `core dev` for compatibility
- Git commands: health, commit, push, pull, work, sync, apply
- GitHub orchestration stays in dev: issues, reviews, ci, impact
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(qa): add docblock coverage checking
Implement docblock/docstring coverage analysis for Go code:
- New `core qa docblock` command to check coverage
- Shows compact file:line list when under threshold
- Integrate with `core go qa` as a default check
- Add --docblock-threshold flag (default 80%)
The checker uses Go AST parsing to find exported symbols
(functions, types, consts, vars) without documentation.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: address CodeRabbit review feedback
- Fix doc comment: "status" → "health" in gitcmd package
- Implement --check flag for `core go fmt` (exits non-zero if files need formatting)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* docs: add docstrings for 100% coverage
Add documentation comments to all exported symbols:
- pkg/build: ProjectType constants
- pkg/cli: LogLevel, RenderStyle, TableStyle
- pkg/framework: ServiceFor, MustServiceFor, Core.Core
- pkg/git: GitError.Error, GitError.Unwrap
- pkg/i18n: Handler Match/Handle methods
- pkg/log: Level constants
- pkg/mcp: Tool input/output types
- pkg/php: Service constants, QA types, service methods
- pkg/process: ServiceError.Error
- pkg/repos: RepoType constants
- pkg/setup: ChangeType, ChangeCategory constants
- pkg/workspace: AddWorkspaceCommands
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* chore: standardize line endings to LF
Add .gitattributes to enforce LF line endings for all text files.
Normalize all existing files to use Unix-style line endings.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: address CodeRabbit review feedback
- cmd_format.go: validate --check/--fix mutual exclusivity, capture stderr
- cmd_docblock.go: return error instead of os.Exit(1) for proper error handling
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: address CodeRabbit review feedback (round 2)
- linuxkit.go: propagate state update errors, handle cmd.Wait() errors in waitForExit
- mcp.go: guard against empty old_string in editDiff to prevent runaway edits
- cmd_docblock.go: log parse errors instead of silently skipping
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 10:48:44 +00:00
|
|
|
defer func() { _ = resp.Body.Close() }()
|
2026-01-28 19:39:04 +00:00
|
|
|
|
|
|
|
|
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated && resp.StatusCode != http.StatusAccepted {
|
|
|
|
|
return nil, c.parseError(resp)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var deployment CoolifyDeployment
|
|
|
|
|
if err := json.NewDecoder(resp.Body).Decode(&deployment); err != nil {
|
|
|
|
|
return &CoolifyDeployment{
|
|
|
|
|
Status: "rolling_back",
|
|
|
|
|
CreatedAt: time.Now(),
|
|
|
|
|
}, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &deployment, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetApp retrieves application details.
|
|
|
|
|
func (c *CoolifyClient) GetApp(ctx context.Context, appID string) (*CoolifyApp, error) {
|
2026-01-31 11:39:19 +00:00
|
|
|
endpoint := cli.Sprintf("%s/api/v1/applications/%s", c.BaseURL, appID)
|
2026-01-28 19:39:04 +00:00
|
|
|
|
|
|
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint, nil)
|
|
|
|
|
if err != nil {
|
2026-01-31 11:39:19 +00:00
|
|
|
return nil, cli.WrapVerb(err, "create", "request")
|
2026-01-28 19:39:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c.setHeaders(req)
|
|
|
|
|
|
|
|
|
|
resp, err := c.HTTPClient.Do(req)
|
|
|
|
|
if err != nil {
|
2026-01-31 11:39:19 +00:00
|
|
|
return nil, cli.Wrap(err, "request failed")
|
2026-01-28 19:39:04 +00:00
|
|
|
}
|
feat: git command, build improvements, and go fmt git-aware (#74)
* feat(go): make go fmt git-aware by default
- By default, only check changed Go files (modified, staged, untracked)
- Add --all flag to check all files (previous behaviour)
- Reduces noise when running fmt on large codebases
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(build): minimal output by default, add missing i18n
- Default output now shows single line: "Success Built N artifacts (dir)"
- Add --verbose/-v flag to show full detailed output
- Add all missing i18n translations for build commands
- Errors still show failure reason in minimal mode
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat: add root-level `core git` command
- Create pkg/gitcmd with git workflow commands as root menu
- Export command builders from pkg/dev (AddCommitCommand, etc.)
- Commands available under both `core git` and `core dev` for compatibility
- Git commands: health, commit, push, pull, work, sync, apply
- GitHub orchestration stays in dev: issues, reviews, ci, impact
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(qa): add docblock coverage checking
Implement docblock/docstring coverage analysis for Go code:
- New `core qa docblock` command to check coverage
- Shows compact file:line list when under threshold
- Integrate with `core go qa` as a default check
- Add --docblock-threshold flag (default 80%)
The checker uses Go AST parsing to find exported symbols
(functions, types, consts, vars) without documentation.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: address CodeRabbit review feedback
- Fix doc comment: "status" → "health" in gitcmd package
- Implement --check flag for `core go fmt` (exits non-zero if files need formatting)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* docs: add docstrings for 100% coverage
Add documentation comments to all exported symbols:
- pkg/build: ProjectType constants
- pkg/cli: LogLevel, RenderStyle, TableStyle
- pkg/framework: ServiceFor, MustServiceFor, Core.Core
- pkg/git: GitError.Error, GitError.Unwrap
- pkg/i18n: Handler Match/Handle methods
- pkg/log: Level constants
- pkg/mcp: Tool input/output types
- pkg/php: Service constants, QA types, service methods
- pkg/process: ServiceError.Error
- pkg/repos: RepoType constants
- pkg/setup: ChangeType, ChangeCategory constants
- pkg/workspace: AddWorkspaceCommands
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* chore: standardize line endings to LF
Add .gitattributes to enforce LF line endings for all text files.
Normalize all existing files to use Unix-style line endings.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: address CodeRabbit review feedback
- cmd_format.go: validate --check/--fix mutual exclusivity, capture stderr
- cmd_docblock.go: return error instead of os.Exit(1) for proper error handling
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: address CodeRabbit review feedback (round 2)
- linuxkit.go: propagate state update errors, handle cmd.Wait() errors in waitForExit
- mcp.go: guard against empty old_string in editDiff to prevent runaway edits
- cmd_docblock.go: log parse errors instead of silently skipping
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 10:48:44 +00:00
|
|
|
defer func() { _ = resp.Body.Close() }()
|
2026-01-28 19:39:04 +00:00
|
|
|
|
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
|
return nil, c.parseError(resp)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var app CoolifyApp
|
|
|
|
|
if err := json.NewDecoder(resp.Body).Decode(&app); err != nil {
|
2026-01-31 11:39:19 +00:00
|
|
|
return nil, cli.WrapVerb(err, "decode", "response")
|
2026-01-28 19:39:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &app, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// setHeaders sets common headers for API requests.
|
|
|
|
|
func (c *CoolifyClient) setHeaders(req *http.Request) {
|
|
|
|
|
req.Header.Set("Authorization", "Bearer "+c.Token)
|
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
|
req.Header.Set("Accept", "application/json")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// parseError extracts error information from an API response.
|
|
|
|
|
func (c *CoolifyClient) parseError(resp *http.Response) error {
|
|
|
|
|
body, _ := io.ReadAll(resp.Body)
|
|
|
|
|
|
|
|
|
|
var errResp struct {
|
|
|
|
|
Message string `json:"message"`
|
|
|
|
|
Error string `json:"error"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := json.Unmarshal(body, &errResp); err == nil {
|
|
|
|
|
if errResp.Message != "" {
|
2026-01-31 11:39:19 +00:00
|
|
|
return cli.Err("API error (%d): %s", resp.StatusCode, errResp.Message)
|
2026-01-28 19:39:04 +00:00
|
|
|
}
|
|
|
|
|
if errResp.Error != "" {
|
2026-01-31 11:39:19 +00:00
|
|
|
return cli.Err("API error (%d): %s", resp.StatusCode, errResp.Error)
|
2026-01-28 19:39:04 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-31 11:39:19 +00:00
|
|
|
return cli.Err("API error (%d): %s", resp.StatusCode, string(body))
|
2026-01-28 19:39:04 +00:00
|
|
|
}
|