#php

1 messages ยท Page 4 of 1

serene light
#

Hmmm, if I'm reading it correctly the goal of that issue is to return an error and a value (which could be anything normally returned) so I expect it could end up looking like this:

if (!$changeSet->isEmpty()) {
    throw new DaggerError('boo hoo', $changeSet);
}

Just bear in mind I'm simply spitballing here. It entirely depends on how it's handled by Dagger first.

karmic tendon
#

yes of course no worries

#

BTW does anyone have a good schema to present dagger efficiently ? ๐Ÿ˜… that would help my friday presentation !

karmic tendon
#

something that nicely shows how dagger works : the engine, the graohql api, the sdk, the runtimes, etc etc

serene light
#

Oh right so, nice visual representations of what Dagger is under the hood?

karmic tendon
#

yes ๐Ÿ˜„

serene light
#

Dagger Presentation (Friday 28th Nov)

karmic tendon
karmic tendon
#

thanks. Ignore is one thing but sometimes it is more like "include". For example phpstan / cs-fixer and so on we usually set on which directories to run instead of excluding everything where we don't want it.

radiant flume
karmic tendon
#

Yes thank you. Forgot about this and didn't knew dagger supported it.

karmic tendon
serene light
# karmic tendon hmmm actually I think we could improve the DX here... because there is no way to...

There are pros and cons to both.

I chose variadic string to enforce string[] within the PHP language itself, without reliance on doc blocks, third party tools and additional validation in Ignore::__construct .

It's more likely to improve introspection in everyone's editor of choice (not everyone uses PHPStorm).

Lastly, using a variadic string makes the intent clear that this attribute has a single responsibility.

karmic tendon
#

yes but it prevents using arrays and constants. we could use assert or even simple array_map or even a class that extends from ArrayIterator to enforce the type. phpdoc is common in PHP and shouldn't be a blocker to better DX IMO

serene light
#

we could use assert
assert wouldn't throw a good exception for users

array_map or even a class that extends from ArrayIterator

This the way I would do it if we swapped to array, along with a user-friendly exception.
The downside here is additional code and additional tests.

phpdoc is common in PHP and shouldn't be a blocker to better DX

It's only better DX for developers using editors which parse phpdoc. It's worse DX if it doesn't. Most editors outside of PHPStorm rely on LSP which falls down to Intelliphense or Phpactor. Intelliphense is freemium, Phpactor is open source, it can parse some doc blocks but does better if it integrates with PHPStan.

yes but it prevents using arrays and constants.

I think I need to understand the use-case of this more, as I've never needed it personally.

#

In fairness I haven't tested Phpactor without PHPStan to see if it can parse string[] and warn you as you type.

#

I'm not against swapping to an array but the use-case needs to be worth it.

I have never had to duplicate my Ignore patterns, so I haven't had a use for a constant.

I Ignore when it gets passed in, and then those files/directories are gone. So they aren't coming back if you start passing that directory around.

karmic tendon
#

in my main object I have multiple entrypoints that require the source code with ignored patterns. But it is the same multiple times. So yeah repeating it would be useful. I don't put it in construct as it would make it a requirement for all functions and having side effects on caches.

#

both array and variadic can be supported

#

also today it is variadic because we only one type and one kind of data. but what if tomorrow we want to add a named parameter gitignore: true for example then variadic becomes a blocker. I usually avoid variadic because of such cases. phpdoc does pretty well and array like objects can fill in the blank if needed

serene light
#

but what if tomorrow we want to add a named parameter gitignore: true for example then variadic becomes a blocker.

It depends on how the rest of Dagger does it but, if it's up to me:

Lastly, using a variadic string makes the intent clear that this attribute has a single responsibility.

I would make a new attribute like GitIgnore or FollowGitIgnore or UseGitIgnore... we could bikeshed when the time comes.

in my main object I have multiple entrypoints that require the source code with ignored patterns. But it is the same multiple times. So yeah repeating it would be useful. I don't put it in construct as it would make it a requirement for all functions and having side effects on caches.

That's a good use-case. I think there are ways to work around that, but it's definitely worth considering.

serene light
#

We could do it, but it would break backwards compatibility. Ideally a change like that would want to be aligned with a breaking release (and any other breaking changes).

In the mean time though, you could work around it like this:

// main class

#[DaggerFunction]
public function withSrc(
    #[DefaultPath('foo')]
    #[Ignore('bar', 'baz')]
    Directory $src,
): WithSrc {
    return new WithSrc($src); 
}

// WithSrc.php

#[DaggerFunction]
public function entrypointA(): void
{
    $this->src->blabla();
}

#[DaggerFunction]
public function entrypointB(): void
{
    $this->src->blabla();
}
karmic tendon
#

not sure about breaking change... from

#[\Attribute(\Attribute::TARGET_PARAMETER)]
final readonly class Ignore
{
    /** @var string[] */
    public array $ignore;

    public function __construct(
        string ...$ignore,
    ) {
        $this->ignore = $ignore;
    }
}

to

#[\Attribute(\Attribute::TARGET_PARAMETER)]
final readonly class Ignore
{
    /** @var string[] */
    public array $ignore;

    public function __construct(
        string|array $ignore,
        string ...$args,
    ) {
        $this->ignore = [...(array)$ignore, ...$args];
    }
}

shouldn't be a BC IMO and allows both syntaxes. WDYT ?

serene light
# karmic tendon not sure about breaking change... from ``` #[\Attribute(\Attribute::TARGET_PARAM...

That's a good idea to deal with BC, I realise it's pseudo code but just making sure we're on the same page:

This change would require additional validation in __construct

#[\Attribute(\Attribute::TARGET_PARAMETER)]
final readonly class Ignore
{
    /** @var string[] */
    public array $ignore;

    /** @param string|string[] $pattern */
    public function __construct(
        string|array $pattern,
        string ...$patterns,
    ) {
        if (
            is_array($pattern)
            && ! array_all($pattern, is_string(...))
        ) {
            throw RegistrationError\InvalidArgument::arraySubtype('string');
        }

        $this->ignore = [...(array)$pattern, ...$patterns];
    }
}

With the additional validation, we would then need to add a IgnoreTest to cover it

#

Also bikeshedding nitpick but the arguments would want similar names so people are aware it's the same thing, so I pinched pattern from both gitignore and dagger docs.

shy goblet
#

@serene light Hey ๐Ÿ˜„

There's a weird error on our CI triggered by PHP, it seems it fails to donwload some dependencies:

composer
 56/57 [===========================>]  98%    Failed to download symfony/process from dist: The "https://api.github.com/repos/symfony/process/zipball/f24f8f316367b30810810d4eb30c543d7003ff3b" file could not be downloaded (HTTP/2 504 )
composer
    Now trying to download from source
composer

composer
 57/57 [============================] 100%
composer
In GitDownloader.php line 82:
composer
                                                            
composer
  git was not found in your PATH, skipping source download 

https://dagger.cloud/dagger/checks/github.com/dagger/dagger@86279c7abc36e1cf79d2c7fa28faa322f75c5630?check=phpSdk:phpCodeSniffer#585d1296b64fe809:L485

#

It happens on every PRs but not on main so I assumed the issue is quite fresh

shy goblet
#

Looks like it resolved now, maybe something was broken on symfony side

serene light
#

Sorry for the late reply, @shy goblet. Not sure what the issue was honestly. I assume just a temporary outage ๐Ÿคท

mellow gust
#

I'm trying to setup psalm using dagger, it's mostly working but when psalm fails the output is not visible, it just says exit code: 2. How can I get dagger to show me the psalm output as well (I need that to be able to read what the issues are that psalm found).

serene light
# mellow gust I'm trying to setup psalm using dagger, it's mostly working but when psalm fails...

You can add a flag to your withExec call to expect any exit code:

->withExec(args: $args, expect: ReturnType::ANY)

This alone will print the output, but since it tells Dagger to expect any exit code, Dagger will treat anything as a success (a.k.a. exit code 0). Which isn't ideal if you want to run this in a pipeline.

Clean Dagger Method for stdout & Unsuccessful Exit Codes?

@pine bridge Sorry to always pick on you, but do you know if there's a clean Dagger way of getting a non-zero exit code and still print stdout?

If not then @mellow gust , feel free to peruse the workaround I use in CLI a.t.m.

Workaround Hack

This relies on a bit of internal knowledge, but this is how I do it for CLI reports:

        $container = // do stuff...;

        $container->withExec(args: $args, expect: ReturnType::ANY)

        $exitCode = $container->exitCode();
        $stdout = $container->stdout();
        $stderr = $container->stderr();
        
        // if exec was not successful
        if ($exitCode !== 0) { 
            // throw GQL query error, populated with exec data
            throw new \GraphQL\Exception\QueryError(['errors' => [[ 
                'message' => 'problem(s) found during static analysis',
                'extensions' => [
                    'exitCode' => $exitCode,
                    'stdout' => $stdout,
                    'stderr' => $stderr,
                ]]]]);
        }

        return $stdout;
pine bridge
# serene light You can add a flag to your `withExec` call to `expect` any exit code: ```php ->...

One way yes is to catch all return type then deal with it. So if the exit code is not 0, it's possible to access to stderr/combined output and then send it again.
But I think that should be automatically done and the error should be displayed. But IIRC it depends how the SDK is sending the error back to the engine.
For instance in the Java SDK we have this code in case of an error: https://github.com/dagger/dagger/blob/1be66251d8a770165e61d284999cfbbfa8477738/sdk/java/dagger-java-annotation-processor/src/test/resources/io/dagger/gen/entrypoint/Entrypoint.java#L74-L76
Roughly it's calling returnError with a dagger.Error containing the stdout, stderr, cmd, exitCode and path values so the engine can display what's needed.
Is that also exists in the PHP SDK?

GitHub

Automation engine to build, test and ship any codebase. Runs locally, in CI, or directly in the cloud - dagger/dagger

serene light
karmic tendon
mellow gust
#

That does work indeed, thanks

#

Is there a reason this isn't a default?

karmic tendon
#

no idea but I too would like it to be the default on my machine ๐Ÿ˜…

pine bridge
#

You can set DAGGER_PROGRESS=logs so it's available everywhere by default

serene light
#

Ah, it's a new option, I couldn't find it until I updated dagger XD

serene light
pine bridge
serene light
#

stdout looks like this:

... $ dagger functions --progress=logs

charming_noether
gifted_wright
friendly_almeida
ecstatic_chaum
gallant_galileo
sad_haslett
elegant_bassi
quirky_liskov
serene_beaver
nifty_engelbart
distracted_gould
laughing_elgamal
hungry_brahmagupta
awesome_benz
practical_swanson
pedantic_wing
elastic_wu
zealous_cohen
angry_ramanujan
suspicious_villani
hardcore_goodall
inspiring_montalcini
serene_moore
goofy_zhukovsky
epic_hodgkin
youthful_banzai
trusting_davinci
nifty_heyrovsky
compassionate_yonath
quizzical_taussig
fervent_pascal
determined_neumann
great_antonelli
interesting_easley
wonderful_zhukovsky
epic_mayer

โ–ผ exec docker start dagger-engine-v0.20.1
dagger-engine-v0.20.1

โ–ผ connecting to engine
14:49:12 INF connected name=21fec39d8d49 client-version=v0.20.1 server-version=v0.20.1

โ–ถ ............

...โœ” connect 0.5s
โœ” load module: . 2.3s

Name                     Description
build                    -
build-admin-frontend     -
build-frontend           -
make-tag                 -
publish                  -
publish-admin-frontend   -
publish-frontend         -
up                       -


pine bridge
serene light
#

Not sure but it does it for dots and plain as well. Regardless of whether the TTY handles ncurses or not. (at least, it does so on my machine)

pine bridge
#

yes, it prints out the logs of the command (that's also the purpose of the --progress=logs) I think that's just the default behavior of any command.
Is that an issue it's displayed?

serene light
#

For logs it is valuable, what is progress=dots for?

pine bridge
# serene light For logs it is valuable, what is `progress=dots` for?

Added a new dots progress format, which is a much quieter alternative to plain suitable for use in CI https://github.com/dagger/dagger/pull/10617
Extracted from the changelog.

Those are multiple outputs depending on what to focus on. Depending on the use cases dots or logs are also interesting for AI agents (shorter than plain for instance)
I think it's impossible to find the one and only way to deal with outputs, so it's a set of different variations.

radiant flume
#

@serene light any chance you're around? We're running into a weird codegen issue with the php sdk...

#

It looks like the error was there for a while, but the Go SDK was suppressing it - now that we fixed the suppression, we're getting a random error in sdk/php/scripts/codegen.php

serene light
#

Sorry, UK timezone, missed this.

serene light
radiant flume
serene light
karmic tendon
serene light
karmic tendon
serene light
#

It's going to take me a bit to review this, I'll need to give it a play test locally tomorrow, see how it fares.

#

Just want to ask, because I noticed the LLM assist in the commit messages. Are there any parts to this PR that should be checked more carefully than others?

karmic tendon
#

Yes I use the Linux policy to apply the "Assisted-By" metadata in commits. I am not completely usre yet how does the codegen really works. So maybe it went a bit too far or overengineered things. I tested it and tried to modify simplify stuff as much as I could.

karmic tendon
#

yes ๐Ÿ™‚

serene light
#

One thing I noted atm is we probably don't want to "silently ignore pure enums", we probably want to break immediately with a clear exception that they aren't supported yet.

#

Because having BackedEnums work is awesome, but someone's going to try a pure Enum, making it super clear for them would be nice ๐Ÿ™‚

karmic tendon
#

I think it does throw. I'll check this evening

serene light
#

If it helps: FindsDaggerEnums L51 looks like the spot to do it ๐Ÿ‘

karmic tendon
#

updated ๐ŸŽ‰

serene light
#

I just did a quick run of PHPCBF to fix a coding issue, should get CI green

#

I pushed to your fork, hope you don't mind.

#

What I'd like to do, for more confidence, is write some integration tests as well.

#

I have some leftover built-in enum tests from an old branch... so I should be able to cherry pick the files over.

karmic tendon
#

yeah no worries of course you can contribute. and if you need me to do something else let me know ๐Ÿ˜‰

serene light
#

Will do, what I'm thinking is this:

  • I write some integration tests (I'm totally stealing your Priority enum for them btw.)
  • I push them to the branch.
  • We see if they pass CI.
    • If they pass, happy days, I'll review it for good measure and we're in.
    • If they fail, we'll figure it out from there ๐Ÿคท

In the meantime if you need to make any changes, go ahead I doubt we'll have merge conflicts. (The integration tests are in dagger/core/integration/module_php_test.go)

#

I'll work on it a bit now locally, probably have to finish it off Monday. But I'd rebase before I push

serene light
#

Alright, I added some tests that look like this:

func (PHPSuite) TestEnumKind(ctx context.Context, t *testctx.T) {
    c := connect(ctx, t)
    module := phpModule(t, c, "enum-kind")

    t.Run("built-in (string-backed)", func(ctx context.Context, t *testctx.T) {
        out, err := module.
            With(daggerCall("opposite-network-protocol", "--arg=TCP")).
            Stdout(ctx)
        require.NoError(t, err)
        require.Equal(t, "UDP", out)
    })

    t.Run("custom (int-backed)", func(ctx context.Context, t *testctx.T) {
        out, err := module.
            With(daggerCall("increase-priority", "--priority=1")).
            Stdout(ctx)
        require.NoError(t, err)
        require.Equal(t, "2", out)
    })

    t.Run("custom (string-backed)", func(ctx context.Context, t *testctx.T) {
        out, err := module.
            With(daggerCall("toggle-todo", "--task=todo")).
            Stdout(ctx)
        require.NoError(t, err)
        require.Equal(t, "done", out)
    })
}

The module they're calling is located at core/integration/testdata/modules/php/enum-kind/src/EnumKind.php

I believe there's a way to call the entire test suite from Dagger, but honestly... I always forget what it is.

What I end up doing is going into the module's dagger.json and changing the sdk's source to "source": "../../../../../../sdk/php" and just calling it from inside the module.

Right now, it's breaking: I'm getting this sorta thing Error: convert return value: unexpected result value type map[string]interface {} for enum "EnumKindTask" [traceparent:3b1b3acdbf083f34842525649bf2fd4a-47162dbf703935d4]

karmic tendon
#

nice one. Barely can read it since I am not a go developper ๐Ÿ˜…

serene light
#

Yeah neither am I. I've just been picking it up as I... ahem, Go.

The main points are

  • daggerCall("toggle-todo", "--task=todo") translates to dagger call toggle-todo --task=todo
  • require.NoError(t, err) translates to assert no stderr
  • require.Equal(t, "done", out) translates to assert stdout equals "done"
#

You don't have to use the tests specifically to check. You can make your own module to test it and have the dagger.json point to the local filepath of your php sdk

#

Personally, I don't know what the error means atm. But we might be able to get some help on it from the Dagger team. Or it might just take a bit more digging.

karmic tendon
#

What I usually do is in my own module, create a symlink "dagger" towards the WIP of my dagger fork. Then modifier the json to use this sdk

serene light
#

What difference does the symlink make in this case? (Genuine question: your way sounds neater)

karmic tendon
#

none it just I have the sdk and the module in the same "project"

serene light
#

@karmic tendon If you're stuck with the PR, let me know and I can have a look at some point.

There is no rush:

I do not know how to do it either, otherwise I'd have done it. But I know some of the steps so I might be able to help (or beg the right person for help ๐Ÿ‘€ )

#

Just thought I'd clarify, don't feel pressured into having to push it through solo ๐Ÿ’ช. If you scroll your way through the history of the PHP channel you will find endless questions, all by me asking how to do things ๐Ÿ˜†

karmic tendon
#

what is left to do ? Add more tests ? I pushed (this weekend I think) a fix for BackedEnum because I was using a deprecated call it seems.

serene light
#

Oh, is it working locally? I was looking the pipeline and the PHP integration tests were failing.

I'll pull the changes locally and see

karmic tendon
#

Locally Yes it works. Regarding the tests I am not sure it is related to my PR. I might be wrong though. I'd be happy to have some feedback on this. And if I need to change something of course I will ๐Ÿ˜‰

#

This is the first PR to try to port to php same features that exists in other SDK

serene light
#

Yeah, that's completely fair. It might just be a flake that needs rerunning

karmic tendon
#

looking at the link you gave yes clearly those are my tests failing. I'll look into it

#

TestPHP/TestEnumKind/built-in_(string-backed)

serene light
#

Give me a sec, I'll try locally first

serene light
#

I'm getting these errors:

$ dagger call increase-priority --priority=1
! invalid argument "1" for "--priority" flag: value should be one of
  HIGH,LOW,MEDIUM

Which is promising, I'm guessing other SDKs specifically take the name of the enum rather than value here.

@pine bridge is that the same for Java?

#

@karmic tendon What's weird is when I try to enter it correctly...

$ dagger call increase-priority --priority=MEDIUM
! convert return value: unexpected result value type map[string]interface {} for
  enum "EnumKindPriority"
#

At least, that's what is happening locally for me ๐Ÿคท

karmic tendon
#

hmmm I didn't tried with cli ๐Ÿ˜… my tests (don't know why I didn't though) were focused on one module "using" another one which declares backed enums.

#

I'll try to debug this part

serene light
#

In what sense? Was it passing enums around successfully between modules?

karmic tendon
#

yup

#

which didnt worked for me before

#

at least not correctly

serene light
#

Ah... In that case it might be specifically when it has to return the enum to stdout

#

and Dagger is freaking out because it's probably being passed something like this: [name => HIGH, value => 2]

#

I think I found my mess of a branch where I was dealing with this part.

#

If I recall correctly, I got enums working, but it was put on hold because enums could only handle values before (which you found out with the deprecated withEnumValue thing). So my PR was inconsistent with every other SDK.

#

I might be able to salvage some of it and push it into your branch if that's alright? (Not immediately, but I'll try to get round to it this week)

karmic tendon
#

sur go ahead no worries ๐Ÿ˜‰

serene light
#

What a quality commit message I left for myself: