cli/internal/cmd/php/container_test.go

384 lines
10 KiB
Go
Raw Normal View History

package php
import (
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
"context"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestDockerBuildOptions_Good(t *testing.T) {
t.Run("all fields accessible", func(t *testing.T) {
opts := DockerBuildOptions{
ProjectDir: "/project",
ImageName: "myapp",
Tag: "v1.0.0",
Platform: "linux/amd64",
Dockerfile: "/path/to/Dockerfile",
NoBuildCache: true,
BuildArgs: map[string]string{"ARG1": "value1"},
Output: os.Stdout,
}
assert.Equal(t, "/project", opts.ProjectDir)
assert.Equal(t, "myapp", opts.ImageName)
assert.Equal(t, "v1.0.0", opts.Tag)
assert.Equal(t, "linux/amd64", opts.Platform)
assert.Equal(t, "/path/to/Dockerfile", opts.Dockerfile)
assert.True(t, opts.NoBuildCache)
assert.Equal(t, "value1", opts.BuildArgs["ARG1"])
assert.NotNil(t, opts.Output)
})
}
func TestLinuxKitBuildOptions_Good(t *testing.T) {
t.Run("all fields accessible", func(t *testing.T) {
opts := LinuxKitBuildOptions{
ProjectDir: "/project",
OutputPath: "/output/image.qcow2",
Format: "qcow2",
Template: "server-php",
Variables: map[string]string{"VAR1": "value1"},
Output: os.Stdout,
}
assert.Equal(t, "/project", opts.ProjectDir)
assert.Equal(t, "/output/image.qcow2", opts.OutputPath)
assert.Equal(t, "qcow2", opts.Format)
assert.Equal(t, "server-php", opts.Template)
assert.Equal(t, "value1", opts.Variables["VAR1"])
assert.NotNil(t, opts.Output)
})
}
func TestServeOptions_Good(t *testing.T) {
t.Run("all fields accessible", func(t *testing.T) {
opts := ServeOptions{
ImageName: "myapp",
Tag: "latest",
ContainerName: "myapp-container",
Port: 8080,
HTTPSPort: 8443,
Detach: true,
EnvFile: "/path/to/.env",
Volumes: map[string]string{"/host": "/container"},
Output: os.Stdout,
}
assert.Equal(t, "myapp", opts.ImageName)
assert.Equal(t, "latest", opts.Tag)
assert.Equal(t, "myapp-container", opts.ContainerName)
assert.Equal(t, 8080, opts.Port)
assert.Equal(t, 8443, opts.HTTPSPort)
assert.True(t, opts.Detach)
assert.Equal(t, "/path/to/.env", opts.EnvFile)
assert.Equal(t, "/container", opts.Volumes["/host"])
assert.NotNil(t, opts.Output)
})
}
func TestIsPHPProject_Container_Good(t *testing.T) {
t.Run("returns true with composer.json", func(t *testing.T) {
dir := t.TempDir()
err := os.WriteFile(filepath.Join(dir, "composer.json"), []byte(`{}`), 0644)
require.NoError(t, err)
assert.True(t, IsPHPProject(dir))
})
}
func TestIsPHPProject_Container_Bad(t *testing.T) {
t.Run("returns false without composer.json", func(t *testing.T) {
dir := t.TempDir()
assert.False(t, IsPHPProject(dir))
})
t.Run("returns false for non-existent directory", func(t *testing.T) {
assert.False(t, IsPHPProject("/non/existent/path"))
})
}
func TestLookupLinuxKit_Bad(t *testing.T) {
t.Run("returns error when linuxkit not found", func(t *testing.T) {
// Save original PATH and paths
origPath := os.Getenv("PATH")
origCommonPaths := commonLinuxKitPaths
defer func() {
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
_ = os.Setenv("PATH", origPath)
commonLinuxKitPaths = origCommonPaths
}()
// Set PATH to empty and clear common paths
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
_ = os.Setenv("PATH", "")
commonLinuxKitPaths = []string{}
_, err := lookupLinuxKit()
if assert.Error(t, err) {
assert.Contains(t, err.Error(), "linuxkit not found")
}
})
}
func TestGetLinuxKitTemplate_Good(t *testing.T) {
t.Run("returns server-php template", func(t *testing.T) {
content, err := getLinuxKitTemplate("server-php")
assert.NoError(t, err)
assert.Contains(t, content, "kernel:")
assert.Contains(t, content, "linuxkit/kernel")
})
}
func TestGetLinuxKitTemplate_Bad(t *testing.T) {
t.Run("returns error for unknown template", func(t *testing.T) {
_, err := getLinuxKitTemplate("unknown-template")
assert.Error(t, err)
assert.Contains(t, err.Error(), "template not found")
})
}
func TestApplyTemplateVariables_Good(t *testing.T) {
t.Run("replaces variables", func(t *testing.T) {
content := "Hello ${NAME}, welcome to ${PLACE}!"
vars := map[string]string{
"NAME": "World",
"PLACE": "Earth",
}
result, err := applyTemplateVariables(content, vars)
assert.NoError(t, err)
assert.Equal(t, "Hello World, welcome to Earth!", result)
})
t.Run("handles empty variables", func(t *testing.T) {
content := "No variables here"
vars := map[string]string{}
result, err := applyTemplateVariables(content, vars)
assert.NoError(t, err)
assert.Equal(t, "No variables here", result)
})
t.Run("leaves unmatched placeholders", func(t *testing.T) {
content := "Hello ${NAME}, ${UNKNOWN} is unknown"
vars := map[string]string{
"NAME": "World",
}
result, err := applyTemplateVariables(content, vars)
assert.NoError(t, err)
assert.Contains(t, result, "Hello World")
assert.Contains(t, result, "${UNKNOWN}")
})
t.Run("handles multiple occurrences", func(t *testing.T) {
content := "${VAR} and ${VAR} again"
vars := map[string]string{
"VAR": "value",
}
result, err := applyTemplateVariables(content, vars)
assert.NoError(t, err)
assert.Equal(t, "value and value again", result)
})
}
func TestDefaultServerPHPTemplate_Good(t *testing.T) {
t.Run("template has required sections", func(t *testing.T) {
assert.Contains(t, defaultServerPHPTemplate, "kernel:")
assert.Contains(t, defaultServerPHPTemplate, "init:")
assert.Contains(t, defaultServerPHPTemplate, "services:")
assert.Contains(t, defaultServerPHPTemplate, "onboot:")
})
t.Run("template contains placeholders", func(t *testing.T) {
assert.Contains(t, defaultServerPHPTemplate, "${SSH_KEY:-}")
})
}
func TestBuildDocker_Bad(t *testing.T) {
t.Skip("requires Docker installed")
t.Run("fails for non-PHP project", func(t *testing.T) {
dir := t.TempDir()
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
err := BuildDocker(context.TODO(), DockerBuildOptions{ProjectDir: dir})
assert.Error(t, err)
assert.Contains(t, err.Error(), "not a PHP project")
})
}
func TestBuildLinuxKit_Bad(t *testing.T) {
t.Skip("requires linuxkit installed")
t.Run("fails for non-PHP project", func(t *testing.T) {
dir := t.TempDir()
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
err := BuildLinuxKit(context.TODO(), LinuxKitBuildOptions{ProjectDir: dir})
assert.Error(t, err)
assert.Contains(t, err.Error(), "not a PHP project")
})
}
func TestServeProduction_Bad(t *testing.T) {
t.Run("fails without image name", func(t *testing.T) {
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
err := ServeProduction(context.TODO(), ServeOptions{})
assert.Error(t, err)
assert.Contains(t, err.Error(), "image name is required")
})
}
func TestShell_Bad(t *testing.T) {
t.Run("fails without container ID", func(t *testing.T) {
feat: infrastructure packages and lint cleanup (#281) * ci: consolidate duplicate workflows and merge CodeQL configs Remove 17 duplicate workflow files that were split copies of the combined originals. Each family (CI, CodeQL, Coverage, PR Build, Alpha Release) had the same job duplicated across separate push/pull_request/schedule/manual trigger files. Merge codeql.yml and codescan.yml into a single codeql.yml with a language matrix covering go, javascript-typescript, python, and actions — matching the previous default setup coverage. Remaining workflows (one per family): - ci.yml (push + PR + manual) - codeql.yml (push + PR + schedule, all languages) - coverage.yml (push + PR + manual) - alpha-release.yml (push + manual) - pr-build.yml (PR + manual) - release.yml (tag push) - agent-verify.yml, auto-label.yml, auto-project.yml Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: add collect, config, crypt, plugin packages and fix all lint issues Add four new infrastructure packages with CLI commands: - pkg/config: layered configuration (defaults → file → env → flags) - pkg/crypt: crypto primitives (Argon2id, AES-GCM, ChaCha20, HMAC, checksums) - pkg/plugin: plugin system with GitHub-based install/update/remove - pkg/collect: collection subsystem (GitHub, BitcoinTalk, market, papers, excavate) Fix all golangci-lint issues across the entire codebase (~100 errcheck, staticcheck SA1012/SA1019/ST1005, unused, ineffassign fixes) so that `core go qa` passes with 0 issues. Closes #167, #168, #170, #250, #251, #252, #253, #254, #255, #256 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 11:34:43 +00:00
err := Shell(context.TODO(), "")
assert.Error(t, err)
assert.Contains(t, err.Error(), "container ID is required")
})
}
func TestResolveDockerContainerID_Bad(t *testing.T) {
t.Skip("requires Docker installed")
}
func TestBuildDocker_DefaultOptions(t *testing.T) {
t.Run("sets defaults correctly", func(t *testing.T) {
// This tests the default logic without actually running Docker
opts := DockerBuildOptions{}
// Verify default values would be set in BuildDocker
if opts.Tag == "" {
opts.Tag = "latest"
}
assert.Equal(t, "latest", opts.Tag)
if opts.ImageName == "" {
opts.ImageName = filepath.Base("/project/myapp")
}
assert.Equal(t, "myapp", opts.ImageName)
})
}
func TestBuildLinuxKit_DefaultOptions(t *testing.T) {
t.Run("sets defaults correctly", func(t *testing.T) {
opts := LinuxKitBuildOptions{}
// Verify default values would be set
if opts.Template == "" {
opts.Template = "server-php"
}
assert.Equal(t, "server-php", opts.Template)
if opts.Format == "" {
opts.Format = "qcow2"
}
assert.Equal(t, "qcow2", opts.Format)
})
}
func TestServeProduction_DefaultOptions(t *testing.T) {
t.Run("sets defaults correctly", func(t *testing.T) {
opts := ServeOptions{ImageName: "myapp"}
// Verify default values would be set
if opts.Tag == "" {
opts.Tag = "latest"
}
assert.Equal(t, "latest", opts.Tag)
if opts.Port == 0 {
opts.Port = 80
}
assert.Equal(t, 80, opts.Port)
if opts.HTTPSPort == 0 {
opts.HTTPSPort = 443
}
assert.Equal(t, 443, opts.HTTPSPort)
})
}
func TestLookupLinuxKit_Good(t *testing.T) {
t.Skip("requires linuxkit installed")
t.Run("finds linuxkit in PATH", func(t *testing.T) {
path, err := lookupLinuxKit()
assert.NoError(t, err)
assert.NotEmpty(t, path)
})
}
func TestBuildDocker_WithCustomDockerfile(t *testing.T) {
t.Skip("requires Docker installed")
t.Run("uses custom Dockerfile when provided", func(t *testing.T) {
dir := t.TempDir()
err := os.WriteFile(filepath.Join(dir, "composer.json"), []byte(`{"name":"test"}`), 0644)
require.NoError(t, err)
dockerfilePath := filepath.Join(dir, "Dockerfile.custom")
err = os.WriteFile(dockerfilePath, []byte("FROM alpine"), 0644)
require.NoError(t, err)
opts := DockerBuildOptions{
ProjectDir: dir,
Dockerfile: dockerfilePath,
}
// The function would use the custom Dockerfile
assert.Equal(t, dockerfilePath, opts.Dockerfile)
})
}
func TestBuildDocker_GeneratesDockerfile(t *testing.T) {
t.Skip("requires Docker installed")
t.Run("generates Dockerfile when not provided", func(t *testing.T) {
dir := t.TempDir()
// Create valid PHP project
composerJSON := `{"name":"test","require":{"php":"^8.2","laravel/framework":"^11.0"}}`
err := os.WriteFile(filepath.Join(dir, "composer.json"), []byte(composerJSON), 0644)
require.NoError(t, err)
opts := DockerBuildOptions{
ProjectDir: dir,
// Dockerfile not specified - should be generated
}
assert.Empty(t, opts.Dockerfile)
})
}
func TestServeProduction_BuildsCorrectArgs(t *testing.T) {
t.Run("builds correct docker run arguments", func(t *testing.T) {
opts := ServeOptions{
ImageName: "myapp",
Tag: "v1.0.0",
ContainerName: "myapp-prod",
Port: 8080,
HTTPSPort: 8443,
Detach: true,
EnvFile: "/path/.env",
Volumes: map[string]string{
"/host/storage": "/app/storage",
},
}
// Verify the expected image reference format
imageRef := opts.ImageName + ":" + opts.Tag
assert.Equal(t, "myapp:v1.0.0", imageRef)
// Verify port format
portMapping := opts.Port
assert.Equal(t, 8080, portMapping)
})
}
func TestShell_Integration(t *testing.T) {
t.Skip("requires Docker with running container")
}
func TestResolveDockerContainerID_Integration(t *testing.T) {
t.Skip("requires Docker with running containers")
}