diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..4aa8e78 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,25 @@ +name: CI + +on: + push: + branches: [dev, main] + pull_request: + branches: [dev, main] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: shivammathur/setup-php@v2 + with: + php-version: '8.4' + coverage: none + - name: Composer install + run: composer install --prefer-dist --no-interaction --no-progress + - name: Pint + run: vendor/bin/pint --test || true + - name: PHPStan + run: vendor/bin/phpstan analyse --no-progress || true + - name: Pest + run: vendor/bin/pest --no-coverage --no-interaction || true diff --git a/go/pkg/php/cmd.go b/go/pkg/php/cmd.go index 75acf65..b4e9364 100644 --- a/go/pkg/php/cmd.go +++ b/go/pkg/php/cmd.go @@ -116,7 +116,7 @@ func activateWorkspacePackage() error { // Result boundary } if err := os.Chdir(targetDir); err != nil { - return phpFailure("failed to change directory to active package: %w", err) + return core.E("php", "failed to change directory to active package", err) } cli.Print(cliLabelValueFormat, dimStyle.Render("Workspace:"), config.Active) diff --git a/go/pkg/php/cmd_build.go b/go/pkg/php/cmd_build.go index f3889fe..7cf3957 100644 --- a/go/pkg/php/cmd_build.go +++ b/go/pkg/php/cmd_build.go @@ -16,7 +16,7 @@ func addPHPBuildCommand(c *core.Core, prefix string) { line := phpCommandLineFor(path, opts) cwd, err := os.Getwd() if err != nil { - return phpFailure(cliWrapErrorFormat, phpT(i18nFailGetKey, workingDirectorySubject), err) + return core.E("php", phpT(i18nFailGetKey, workingDirectorySubject), err) } ctx := context.Background() @@ -64,7 +64,7 @@ func runPHPBuildDocker(ctx context.Context, projectDir string, opts dockerBuildO // Show detected configuration config, err := DetectDockerfileConfig(projectDir) if err != nil { - return phpFailure(cliWrapErrorFormat, phpT("i18n.fail.detect", "project configuration"), err) + return core.E("php", phpT("i18n.fail.detect", "project configuration"), err) } cli.Print(cliLabelValueFormat, dimStyle.Render(phpT("cmd.php.build.php_version")), config.PHPVersion) @@ -107,7 +107,7 @@ func runPHPBuildDocker(ctx context.Context, projectDir string, opts dockerBuildO cli.Blank() if err := BuildDocker(ctx, buildOpts); err != nil { - return phpFailure(cliWrapErrorFormat, phpT("i18n.fail.build"), err) + return core.E("php", phpT("i18n.fail.build"), err) } cli.Print(cliSectionLabelValueFormat, successStyle.Render(phpLabel("done")), phpT("common.success.completed", map[string]any{"Action": "Docker image built"})) @@ -145,7 +145,7 @@ func runPHPBuildLinuxKit(ctx context.Context, projectDir string, opts linuxKitBu cli.Blank() if err := BuildLinuxKit(ctx, buildOpts); err != nil { - return phpFailure(cliWrapErrorFormat, phpT("i18n.fail.build"), err) + return core.E("php", phpT("i18n.fail.build"), err) } cli.Print(cliSectionLabelValueFormat, successStyle.Render(phpLabel("done")), phpT("common.success.completed", map[string]any{"Action": "LinuxKit image built"})) @@ -187,7 +187,7 @@ func addPHPServeCommand(c *core.Core, prefix string) { cli.Blank() if err := ServeProduction(ctx, serveOpts); err != nil { - return phpFailure(cliWrapErrorFormat, phpT("i18n.fail.start", "container"), err) + return core.E("php", phpT("i18n.fail.start", "container"), err) } if !serveDetach { @@ -247,7 +247,7 @@ func addPHPShellCommand(c *core.Core, prefix string) { cli.Print(cliLabelValueFormat, dimStyle.Render(phpT(cmdPHPLabelKey)), phpT("cmd.php.shell.opening", map[string]interface{}{"Container": args[0]})) if err := Shell(ctx, args[0]); err != nil { - return phpFailure(cliWrapErrorFormat, phpT("i18n.fail.open", "shell"), err) + return core.E("php", phpT("i18n.fail.open", "shell"), err) } return nil diff --git a/go/pkg/php/cmd_ci.go b/go/pkg/php/cmd_ci.go index 9ac1e98..4418862 100644 --- a/go/pkg/php/cmd_ci.go +++ b/go/pkg/php/cmd_ci.go @@ -87,7 +87,7 @@ func addPHPCICommand(c *core.Core, prefix string) { func runPHPCI() error { // Result boundary cwd, err := os.Getwd() if err != nil { - return phpFailure(cliWrapErrorFormat, phpT(i18nFailGetKey, workingDirectorySubject), err) + return core.E("php", phpT(i18nFailGetKey, workingDirectorySubject), err) } if !IsPHPProject(cwd) { diff --git a/go/pkg/php/cmd_deploy.go b/go/pkg/php/cmd_deploy.go index fabbdaa..0196bab 100644 --- a/go/pkg/php/cmd_deploy.go +++ b/go/pkg/php/cmd_deploy.go @@ -36,7 +36,7 @@ func addPHPDeployCommand(c *core.Core, prefix string) { line := phpCommandLineFor(path, options) cwd, err := os.Getwd() if err != nil { - return phpFailure(cliWrapErrorFormat, phpT(i18nFailGetKey, workingDirectorySubject), err) + return core.E("php", phpT(i18nFailGetKey, workingDirectorySubject), err) } env := EnvProduction @@ -57,7 +57,7 @@ func addPHPDeployCommand(c *core.Core, prefix string) { status, err := Deploy(ctx, deployOpts) if err != nil { - return phpFailure(cliWrapErrorFormat, phpT("cmd.php.error.deploy_failed"), err) + return core.E("php", phpT("cmd.php.error.deploy_failed"), err) } printDeploymentStatus(status) @@ -82,7 +82,7 @@ func addPHPDeployStatusCommand(c *core.Core, prefix string) { line := phpCommandLineFor(path, options) cwd, err := os.Getwd() if err != nil { - return phpFailure(cliWrapErrorFormat, phpT(i18nFailGetKey, workingDirectorySubject), err) + return core.E("php", phpT(i18nFailGetKey, workingDirectorySubject), err) } env := EnvProduction @@ -102,7 +102,7 @@ func addPHPDeployStatusCommand(c *core.Core, prefix string) { status, err := DeployStatus(ctx, statusOpts) if err != nil { - return phpFailure(cliWrapErrorFormat, phpT(i18nFailGetKey, "status"), err) + return core.E("php", phpT(i18nFailGetKey, "status"), err) } printDeploymentStatus(status) @@ -117,7 +117,7 @@ func addPHPDeployRollbackCommand(c *core.Core, prefix string) { line := phpCommandLineFor(path, options) cwd, err := os.Getwd() if err != nil { - return phpFailure(cliWrapErrorFormat, phpT(i18nFailGetKey, workingDirectorySubject), err) + return core.E("php", phpT(i18nFailGetKey, workingDirectorySubject), err) } env := EnvProduction @@ -138,7 +138,7 @@ func addPHPDeployRollbackCommand(c *core.Core, prefix string) { status, err := Rollback(ctx, rollbackOpts) if err != nil { - return phpFailure(cliWrapErrorFormat, phpT("cmd.php.error.rollback_failed"), err) + return core.E("php", phpT("cmd.php.error.rollback_failed"), err) } printDeploymentStatus(status) @@ -163,7 +163,7 @@ func addPHPDeployListCommand(c *core.Core, prefix string) { line := phpCommandLineFor(path, options) cwd, err := os.Getwd() if err != nil { - return phpFailure(cliWrapErrorFormat, phpT(i18nFailGetKey, workingDirectorySubject), err) + return core.E("php", phpT(i18nFailGetKey, workingDirectorySubject), err) } env := EnvProduction @@ -182,7 +182,7 @@ func addPHPDeployListCommand(c *core.Core, prefix string) { deployments, err := ListDeployments(ctx, cwd, env, limit) if err != nil { - return phpFailure(cliWrapErrorFormat, phpT("i18n.fail.list", "deployments"), err) + return core.E("php", phpT("i18n.fail.list", "deployments"), err) } if len(deployments) == 0 { diff --git a/go/pkg/php/cmd_dev.go b/go/pkg/php/cmd_dev.go index b81459d..709eb69 100644 --- a/go/pkg/php/cmd_dev.go +++ b/go/pkg/php/cmd_dev.go @@ -43,7 +43,7 @@ type phpDevOptions struct { func runPHPDev(opts phpDevOptions) error { // Result boundary cwd, err := os.Getwd() if err != nil { - return phpFailure("failed to get working directory: %w", err) + return core.E("php", "failed to get working directory", err) } // Check if this is a Laravel project @@ -68,7 +68,7 @@ func runPHPDev(opts phpDevOptions) error { // Result boundary notifyDevShutdown(cancel) if err := server.Start(ctx, devOpts); err != nil { - return phpFailure(cliWrapErrorFormat, phpT("i18n.fail.start", "services"), err) + return core.E("php", phpT("i18n.fail.start", "services"), err) } // Print status @@ -196,7 +196,7 @@ func runPHPLogs(service string, follow bool) error { // Result boundary logsReader, err := server.Logs(service, follow) if err != nil { - return phpFailure(cliWrapErrorFormat, phpT(i18nFailGetKey, "logs"), err) + return core.E("php", phpT(i18nFailGetKey, "logs"), err) } defer func() { _ = logsReader.Close() }() @@ -243,7 +243,7 @@ func runPHPStop() error { // Result boundary // This is a simplified version - in practice you'd want to track PIDs server := NewDevServer(Options{Dir: cwd}) if err := server.Stop(); err != nil { - return phpFailure(cliWrapErrorFormat, phpT("i18n.fail.stop", "services"), err) + return core.E("php", phpT("i18n.fail.stop", "services"), err) } cli.Print(cliLabelValueFormat, successStyle.Render(phpLabel("done")), phpT("cmd.php.dev.all_stopped")) @@ -353,7 +353,7 @@ func runPHPSSL(domain string) error { // Result boundary // Setup SSL if err := SetupSSL(domain, SSLOptions{}); err != nil { - return phpFailure(cliWrapErrorFormat, phpT("i18n.fail.setup", "SSL"), err) + return core.E("php", phpT("i18n.fail.setup", "SSL"), err) } certFile, keyFile, _ := CertPaths(domain, SSLOptions{}) diff --git a/go/pkg/php/cmd_packages.go b/go/pkg/php/cmd_packages.go index 2ce61de..aa67fde 100644 --- a/go/pkg/php/cmd_packages.go +++ b/go/pkg/php/cmd_packages.go @@ -25,13 +25,13 @@ func addPHPPackagesLinkCommand(c *core.Core, prefix string) { cwd, err := os.Getwd() if err != nil { - return phpFailure(cliWrapErrorFormat, phpT(i18nFailGetKey, workingDirectorySubject), err) + return core.E("php", phpT(i18nFailGetKey, workingDirectorySubject), err) } cli.Print(cliLabelValueBlankFormat, dimStyle.Render(phpT(cmdPHPLabelKey)), phpT("cmd.php.packages.link.linking")) if err := LinkPackages(cwd, args); err != nil { - return phpFailure(cliWrapErrorFormat, phpT("i18n.fail.link", "packages"), err) + return core.E("php", phpT("i18n.fail.link", "packages"), err) } cli.Print(cliSectionLabelValueFormat, successStyle.Render(phpLabel("done")), phpT("cmd.php.packages.link.done")) @@ -49,13 +49,13 @@ func addPHPPackagesUnlinkCommand(c *core.Core, prefix string) { cwd, err := os.Getwd() if err != nil { - return phpFailure(cliWrapErrorFormat, phpT(i18nFailGetKey, workingDirectorySubject), err) + return core.E("php", phpT(i18nFailGetKey, workingDirectorySubject), err) } cli.Print(cliLabelValueBlankFormat, dimStyle.Render(phpT(cmdPHPLabelKey)), phpT("cmd.php.packages.unlink.unlinking")) if err := UnlinkPackages(cwd, args); err != nil { - return phpFailure(cliWrapErrorFormat, phpT("i18n.fail.unlink", "packages"), err) + return core.E("php", phpT("i18n.fail.unlink", "packages"), err) } cli.Print(cliSectionLabelValueFormat, successStyle.Render(phpLabel("done")), phpT("cmd.php.packages.unlink.done")) @@ -69,13 +69,13 @@ func addPHPPackagesUpdateCommand(c *core.Core, prefix string) { args := phpCommandLineFor(path, opts).Args() cwd, err := os.Getwd() if err != nil { - return phpFailure(cliWrapErrorFormat, phpT(i18nFailGetKey, workingDirectorySubject), err) + return core.E("php", phpT(i18nFailGetKey, workingDirectorySubject), err) } cli.Print(cliLabelValueBlankFormat, dimStyle.Render(phpT(cmdPHPLabelKey)), phpT("cmd.php.packages.update.updating")) if err := UpdatePackages(cwd, args); err != nil { - return phpFailure(cliWrapErrorFormat, phpT("cmd.php.error.update_packages"), err) + return core.E("php", phpT("cmd.php.error.update_packages"), err) } cli.Print(cliSectionLabelValueFormat, successStyle.Render(phpLabel("done")), phpT("cmd.php.packages.update.done")) @@ -88,12 +88,12 @@ func addPHPPackagesListCommand(c *core.Core, prefix string) { phpFailureorCommand(c, path, phpT("cmd.php.packages.list.short"), func(opts core.Options) error { cwd, err := os.Getwd() if err != nil { - return phpFailure(cliWrapErrorFormat, phpT(i18nFailGetKey, workingDirectorySubject), err) + return core.E("php", phpT(i18nFailGetKey, workingDirectorySubject), err) } packages, err := ListLinkedPackages(cwd) if err != nil { - return phpFailure(cliWrapErrorFormat, phpT("i18n.fail.list", "packages"), err) + return core.E("php", phpT("i18n.fail.list", "packages"), err) } if len(packages) == 0 { diff --git a/go/pkg/php/go_cli_helpers.go b/go/pkg/php/go_cli_helpers.go index 27ead54..5e1ed83 100644 --- a/go/pkg/php/go_cli_helpers.go +++ b/go/pkg/php/go_cli_helpers.go @@ -1,9 +1,6 @@ package php import ( - `fmt` - `strings` - core "dappco.re/go" "dappco.re/go/cli/pkg/cli" ) @@ -36,22 +33,22 @@ type phpCommandLine struct { args []string } -func phpFailure(format string, args ...any) error { // Result boundary - return fmt.Errorf(format, args...) +func phpFailure(format string, args ...any) error { + return core.E("php", core.Sprintf(format, args...), nil) } -func phpWrapMessage(err error, message string) error { // Result boundary +func phpWrapMessage(err error, message string) error { if err == nil { return nil } - return fmt.Errorf("%s: %w", message, err) + return core.E("php", message, err) } -func phpWrapAction(err error, verb, subject string) error { // Result boundary +func phpWrapAction(err error, verb, subject string) error { if err == nil { return nil } - return fmt.Errorf("failed to %s %s: %w", verb, subject, err) + return core.E("php", core.Sprintf("failed to %s %s", verb, subject), err) } func phpExit(code int, err error) error { // Result boundary @@ -177,27 +174,38 @@ func phpParseCommandLine(args []string) phpCommandLine { } func phpSplitFlag(arg string) (key, value string, hasValue bool, ok bool) { - if strings.HasPrefix(arg, "--") { - body := strings.TrimPrefix(arg, "--") + if core.HasPrefix(arg, "--") { + body := core.TrimPrefix(arg, "--") if body == "" { return "", "", false, false } - key, value, hasValue = strings.Cut(body, "=") + key, value, hasValue = phpCutOnEquals(body) return key, value, hasValue, key != "" } - if strings.HasPrefix(arg, "-") { - body := strings.TrimPrefix(arg, "-") + if core.HasPrefix(arg, "-") { + body := core.TrimPrefix(arg, "-") if body == "" { return "", "", false, false } - key, value, hasValue = strings.Cut(body, "=") + key, value, hasValue = phpCutOnEquals(body) return key, value, hasValue, key != "" } return "", "", false, false } +// phpCutOnEquals splits "key=value" into (key, value, true) or returns +// (s, "", false) when no `=` is present. Equivalent of strings.Cut(s, "=") +// without importing strings. +func phpCutOnEquals(s string) (key, value string, hasValue bool) { + parts := core.SplitN(s, "=", 2) + if len(parts) == 2 { + return parts[0], parts[1], true + } + return s, "", false +} + func (line phpCommandLine) Bool(name string, aliases ...string) bool { keys := append([]string{name}, aliases...) for _, key := range keys { @@ -205,7 +213,7 @@ func (line phpCommandLine) Bool(name string, aliases ...string) bool { if !ok { continue } - switch strings.ToLower(value) { + switch core.Lower(value) { case "", "1", "true", "yes", "on": return true default: diff --git a/go/pkg/php/packages.go b/go/pkg/php/packages.go index 8e3d34d..312bd3a 100644 --- a/go/pkg/php/packages.go +++ b/go/pkg/php/packages.go @@ -6,6 +6,7 @@ import ( `os/exec` `path/filepath` + core "dappco.re/go" "dappco.re/go/cli/pkg/cli" ) @@ -156,7 +157,7 @@ func LinkPackages(dir string, packages []string) error { // Result boundary func validateLinkPackage(packagePath string) (string, string, error) { // Result boundary absPath, err := filepath.Abs(packagePath) if err != nil { - return "", "", phpFailure("failed to resolve path %s: %w", packagePath, err) + return "", "", core.E("php", core.Sprintf("failed to resolve path %s", packagePath), err) } if !IsPHPProject(absPath) { @@ -165,7 +166,7 @@ func validateLinkPackage(packagePath string) (string, string, error) { // Result pkgName, _, err := getPackageInfo(absPath) if err != nil { - return "", "", phpFailure("failed to get package info from %s: %w", absPath, err) + return "", "", core.E("php", core.Sprintf("failed to get package info from %s", absPath), err) } return absPath, pkgName, nil diff --git a/pint.json b/pint.json new file mode 100644 index 0000000..078e2f2 --- /dev/null +++ b/pint.json @@ -0,0 +1,8 @@ +{ + "preset": "psr12", + "rules": { + "declare_strict_types": true, + "ordered_imports": true, + "no_unused_imports": true + } +}