#php
1 messages Β· Page 3 of 1
I'll have to double check this it might only be local
Hey is the PHP CI broken? I keep having a test fails on my PR: https://github.com/dagger/dagger/pull/8653
Link to trace: https://dagger.cloud/dagger/traces/8da523f2ec05a217fb4768d7ef849bae
those look like canceled jobs from spot instances, may just need to retry moreπ’
I already tried 3 time but yeah
I'll wait a bit before retrying, maybe the instance is broken
hallo, started noticing a lot more php flakes recently π€
it looks like somehow we're not getting any sessionInformation? this code looks potentially tricky here: https://github.com/jedevc/dagger/blob/959466ce45b5a3376edf0b2babdf152b339f1edc/sdk/php/src/Connection/ProcessSessionConnection.php#L64-L77
does anyone know why we do this array shifting? i'm a bit confused as to the logic here, specifically, shouldn't we avoid breaking out of the loop until we have sessionInformation?
https://github.com/dagger/dagger/actions/runs/11478378808/job/31942452004?pr=8763
Are the flakes always specific to theDagger\Tests\Integration\ClientTest?
It might be alright to do away with it, as I'm not sure what it really tests at this point.
It seems to test that it can make a file, directory and container, but here's the thing: We already make a Dev container with a source directory containing the sdk files just to run the tests. So by the time we're running those tests... what do they prove?
I'm not sure of what is in the sessionOutput. That code was mostly fleshed out before I got involved so I can't say for sure but here's what I can gather.
- It finds any valid lines of json.
if (str_contains((string) $output, 'session_token')) {
// @TODO Rewrite when PHP 8.3 json_validate is available
$lines = explode("\n", (string) $output);
$validLines = array_filter($lines, function ($line) {
$this->logger->debug($line);
json_decode(trim($line));
return JSON_ERROR_NONE === json_last_error();
});
$validLines will only contain strings that we can use json_decode on. If there isn't any, then it will be an empty array.
- It takes the first element of the array, and decodes it.
$sessionInformation = json_decode(array_shift($validLines));
$sessionInformation will only be null if:
- json_decode fails (impossible, because only valid json can make it into the
$validlinesarray) - array_shift fails because
$validLinesis empty.
So $validLines must be coming back empty occasionally, what that means I don't know right now.
I know we want to remove that ProcessSession code eventually but its a bigger task than I have time for currently.
the array shifting is completely unnecessary, as the array is never used again.
It could be replaced without any change to behaviour like so:
$sessionInformation = json_decode($validLines[0] ?? null);
thanks @lusty grove https://daggerverse.dev/search?sdk=php
π I submit a PR to add support for TRACEPARENT at https://github.com/dagger/dagger/pull/8896.
we were struggling with tracing not working; I think we were going in completly the wrong direction with it though
Thanks @ocean creek πͺ
Hey
hey !
Already starting to migrate our project to dagger based on your presentation @green otter . Thanks for these insights ! Eager to try more and reports any ideas I may have to see how I can help make this the default CI / CD for any PHP / symfony developper
welcome @karmic tendon
@karmic tendon I'm setting up a call with Grekas, and a few others next week, to begin the planning phase for this, and I can help with it .. so feel free to play around, but hold off on anything formal.
I'll ask Grekas to add you to the call
Is that cool ?
for this = for Symfony **
Sure. Wasn't going on anything formal for a while about this. Not until I fully grasps what are the limits and work required on this kind of tool. So far I thought about having some modules around :
- Pie / Pecl
- Composer
A flex "hook" of some kind to allow when requiring phpstan for example taht it provides a way to connect to your main container.
So yeah. Glad to be here to help and to learn more on dagger !
@karmic tendon yes, I can guide your understanding of how it can all work together, that's why I will have some call(s) with Symfony/Sensio team to start advising how we can best to it.. as I've been sitting for 6+ months on DaggerPHP, and have my own ideas and conclusions on how it should/could be done π
@karmic tendon go to an existing project, and type dagger init --sdk=php .
it will become "Daggerized"
Then type dagger functions to see the 2x stub functions it added for you
Look at .dagger/src/SomeModule.php for the code
dagger call method-name on the CLI, to call it, and test it
Did you get this far, yet ?
yup already migrated most of our Dockerfile (with some strange behaviours) to dagger functions already. Also multi stages.
multi stage πͺ
Which project is it ? internal private project?
I'm keen to see a private gist.github.com copy (DM me?) of your file.
I can offer support on any of the strange stuff you're experiencing πe
LMK
@karmic tendon
yup private one for a client. Will share you a private gist no worries. Some of the weirdeness I encountered :
- no easy access to local filesystem files. (
$phpConfigDirectory = dag()->currentModule()->source()->directory('/config/php');but had to move the config folder to within.daggerseems relatable to docker context scope) - apt-get update gets weird fail errors which I can't figure out why at the moment
- not confident what are the best practices for caching steps / apt-get list / etc etc
- didn't find a way to save a container in local registry (build but not push)
- didn't find a way to apply the "cache_form" equivalent
- dagger call --help is quite slow (maybe because of dynamic modules loading ?)
- also had some things like
bash -c "$(curl -sL https://get-gnmic.openconfig.net)"which is not as trivial to migrate to dagger. Need to download the file as a temporary file, execute it, then remove the temp file
dagger call --help is quite slow (maybe because of dynamic modules loading ?) - yes I think it's looking up the internet for "stuff"
...
$phpConfigDirectory = dag()->currentModule()->source()->directory('/config/php')
I'm not sure you want to use currentModule()->source() any longer, i think it's the legacy way ..
I think there's a new better method ..
@sudden shuttle can you advise? or @obsidian forge if you're about.
the only thing I found was to provide the source as an argument and auto resolve Directory class
@karmic tendon this is the ONLY way, the new way is to pass the source via argument
dagger call my-function --source=.
As per the grepDir sub example. Let me also link you to my "slides" from the SymfonyCon talk
Here, this is all the code examples - https://github.com/dragoonis/Sylius/blob/dragoonis-dagger-integration/.dagger/src/DragoonisSylius.php
yes but I was hoping to not have to use a cli option for this. It won't change dynamically and will always be the same value for this project
@karmic tendon then you don't need to use CLI option for it - you can use static path .. that is why I pinged @sudden shuttle or @obsidian forge to advise.
it contains php.ini configuration, entrypoint scripts. well basically anything we want to mount in the container
@green otter are you referring to the local filesystem files question?
@karmic tendon to help Marco and such .. what are you curerntly trying to do with this /config/php/ directory object .. example? Can you show your code
Are you trying to "copy files" or something? what's your use case
he is doing this - to store a variable of the a directory -
$phpConfigDirectory = dag()->currentModule()->source()->directory('/config/php')
IIUC he needs to read files from the host, correct?
sure. BAsically I have a Dockerfile at the moment with
COPY "./bin/" "/var/www/bin/"
COPY "./cachetool.yml" "/etc/cachetool.yml"
COPY "./conf.d/" "/var/www/conf.d/"
COPY "./php.conf/" "${PHP_INI_DIR}/conf.d/"
COPY "./sudoer" "/etc/sudoers.d/sudoer"
COPY "./php-fpm.d/" "${FPM_CONFIG_DIR}/"
and moving this to dagger I need to copy those files from local filesystem over to the conatienr withotu having to pass a cli option for this
could be a simple file or a whole directory. Bonus point if it follows dockerignore
correct
cool, you're looking "context directories" which is resolved by using the defaultPath directive / annotation /pragma (https://docs.dagger.io/api/arguments/#directories-and-files)
@green otter do you know if the PHP SDK already supports that?
ok. So it is an option but with a default value then ?
Yes, most things are supported.
so it is nto mandatory to provide a custom value
yes, correct
ok thanks will try then
π .Not sure how you define that in PHP π
python == php - will be the same
function(Directory $default = ...) not sure either as it needs to be type hinted Directory so how can I provide a default string value ?
DefaultPath
found it
π
show us when you have it working, or at least as close as you can
sure will do some try later (have a meeting :/ )
@karmic tendon I will invite you to the meeting with Grekas, cool ?
sure thank you π
(if its on monday / tuesday french working hours : might not be available because I will be training people, but I don't think I am required so no worries if I can't make it)
first thing : dag()->currentModule()->source()->directory('/config/php'); was relative to dagger module "source" when ```
#[DefaultPath('/config/php')]
Directory $phpConfigDirectory,
seems to be relative to the proejct root directory
but it is working
thanks !
#[DaggerFunction]
#[Doc('Build the base image for PHP')]
public function buildPhpBase(
#[DefaultPath('/.infrastructure/php')]
Directory $phpConfigDirectory,
string $phpVersion = self::DEFAULT_PHP_VERSION,
string $icuVersion = self::DEFAULT_ICU_VERSION,
string $timezone = self::DEFAULT_TIMEZONE,
): Container {
return dag()
->container()
->from("php:{$phpVersion}-fpm")
->withEnvVariable('PHP_CPPFLAGS', '$PHP_CPPFLAGS -std=c++17', true)
->withEnvVariable('FPM_CONFIG_DIR', '/usr/local/etc/php-fpm.d')
->withEnvVariable('ICU_RELEASE', $icuVersion)
->withEnvVariable('CXXFLAGS', '--std=c++0x')
->withEnvVariable('TZ', $timezone)
->withEnvVariable('SYMFONY_ENABLED', 'false')
->withEnvVariable('PHP_ENV', 'dev')
->withEnvVariable('SCRIPTS_FOLDER', self::SCRIPTS_FOLDER)
->withEnvVariable('GPG_PASSPHRASE', '')
->withEnvVariable('ENTRYPOINT_DOCTRINE_MIGRATIONS_MIGRATE', 'false')
->withEnvVariable('ENABLE_CONSOLE_SERVER', 'false')
->withEnvVariable('CONSOLE_SERVER_PORT', '8000')
->withDirectory('/var/www/bin/', $phpConfigDirectory->directory('./bin/'))
->withDirectory('/var/www/conf.d/', $phpConfigDirectory->directory('./conf.d/'))
->withDirectory('${PHP_INI_DIR}/conf.d/', $phpConfigDirectory->directory('./php.conf/'), expand: true)
->withDirectory('${FPM_CONFIG_DIR}/', $phpConfigDirectory->directory('./php-fpm.d/'), expand: true)
->withFile('/etc/cachetool.yml', $phpConfigDirectory->file('./cachetool.yml'))
->withFile('/etc/sudoers.d/sudoer', $phpConfigDirectory->file('./sudoer'))
This is only the start of the function (too big)
@summer sequoia you about?
what do you think about [DefaultPath] annotation usage? π
@karmic tendon have you called that function without any --php-config-directory CLI args, to make sure it allows you to bypass it ? π and use DefaultPath
sorry yes. I used 0 arguments / options and it worked
thre's a #[DefaultPath] attribute which might be able to solve the problem for you in a slightly different way
@summer sequoia look at the above code example, that's exactly what I'm asking/showing you
soory, was reading back the whole convo and replying to parts as I went
that's my latest iteration of a dagger module for my codebase
up doesn't work properly yet though
makes use of https://github.com/sai-php/sai/tree/main
Yeah the #[DefaultPath] attribute is the only way to set a path without specifying it.
@serene light that's good - it will do very nicely, for the PHP community adoption.
We don't support it being specified in any other format
Do we need another way? If there's 1 way that's good. If there's 2 ways, that's not the easiest to adopt. π
You're correct, we plan to stick with only attributes.
That way we can keep any documentation brief, simple and have one defacto way to do it
If it's of any use we do also have an #[Ignore] Attribute for ignoring files from your directory @karmic tendon .
@karmic tendon this is good to emulate your .dockerignore file, conceptually similar. βοΈ
Good to know. altough I feel like tehre should be a bridge native to dagger about this. As it seems to have some kind of restricted context similar to docker build it should load dockerignore file by default.
regarding attributes I feel not so confident. It wasn't intuitive that to load a local filesystem I had to use it as an argument (mandatory one in regards of PHP) but make it optional by using an attribute. It feel counter intuitive IMO.
That being said I don't really see another way to do it. Except maybe Directory&string = 'default/path' But I suspect it won't be valid in regards of PHP
yeah, the ideal would have been if we could have allowed setting a default path as a directory object in the function definition but you can't do that in PHP so it has to use an attribute
@karmic tendon take a look at my Sai module and see if you have any thoughts on how it works. Idea is to abstract knowledge about how various common tasks are performed in the underlying image: eg you request the xdebug extension; you shouldn't care if we install using pie or using the docker extension installer or some other method all you care about is having a PHP container with xdebug installed
It also encodes information about the container in labels to allow other modules to introspect that info: eg a future PHPUnit module could interogate the metadata to see if pcov, xdebug etc are installed so it can pick one to use to generate coverage for you
Smart !!
Will do. First I wanna finish having a proper build and start using dagger. And then try to play with it and other modules. See how it simplify things.
new Directory is allowed as an argument. Although I understand that it goes against the public API you are targeting. Maybe a sub object DefaultDirectory ?
When picking the design, there was a secondary concern: The SDK also needed to closely resemble other SDKs.
That said it would be brilliant to use default paths the intuitive PHP way with default values.
If a solution can be conceived, then I am all for it.
I see. I'll try to think of something.
https://dagger.io/blog/dagger-0-15
Dagger 0.15 just got released, upgrade for serious filesystem sync performance improvements.
Dagger.php
How does it work if you want to split accrosse several files ? I see in the sai modules that you have PHPComtainer & NginxContainer. What about if in my project I'd like also to have the PhpContainer class seperated from the app orchestration separated from the tests / qa analysis.
Is it as simple as new PHPContainer($container) ? or is it something "Generated" that adds ->withComposer to Container class automagically ?
Everything needs to work using the Base main class as an entry point; to use sub files, you provide a function which returns an instance of the class from the subfile -> you can see this in the main Sai.php class
Adding on from what @summer sequoia said: If you look at Sai.php
dagger call php would:
- Call the
phpfunction from the Sai.php - Return a PHPContainer
Because the PHPContainer has the #[DaggerObject] attribute, you can chain another function on to it.
dagger call php with-composer would:
- Call the
phpfunction from the main entrypoint - Call the
withComposermethod on the returned PHPContainer - Return the PHPContainer with composer installed.
You can start chaining functions together like that
ok thanks
One thing I might add : debug is quite painful at the moment π . It says it failed but no way to actually linked to the action that really failed :/
yeah; that's something we're finding as well
the traces might help if you set it up with dagger.cloud
@summer sequoia everything in Sai looks over engineered and non standard dagger practice. I don't like it, or that we are recommending people look at it for examples.
In what way is it over engineered? It's API is similar to this featured module for example: https://daggerverse.dev/mod/github.com/seungyeop-lee/daggerverse/java@f68fd5ad99b77c58a152c173fa505f6f9388045f
Both provide an abstraction layer over common configuration for their respective languages.
@summer sequoia you're solving the problem of having multiple dagger module files in your repo .. aren't you? Yes/No <-- to make sure I understand correctly
No?
It's a module which provides an abstraction layer for PHP and nginx containers; might separate it out a bit in the future but they currently live in the save module as there's some shared behavior around labeling
And you'd typically use them together
I'd be more inclined to separate them into their own modules if dagger had vendor namespaces though
Why do we need ->withLabel() ? - what value is it adding?
The labeling annotates the state of the created container, allows the module to pick it back up later. Eg you could build a production container; then return to the module to install pcov for test coverage
Or something I'm planning later; once I get the hang of mounting files properly from the host; enable doing things like running composer require within the built container while in dev
ok
@summer sequoia can other SDK's have multiple modules in the .dagger/src/ directory?
Such as MyModule.php SomeOtherModule.php
Yes, they are just additional dagger objects
It's how everything in dagger works, call container, you get a container object back which you can call functions on
@summer sequoia it's just lots of extra files, lots of complexity .. from a DX perspective there is "a lot to take in" .. and I'm asking myself how can we make this all very simple .. they shouldn't need to know about "labels" for starters.. that's an engine implementation detail
@summer sequoia why is the PHP docker image tag inside the nginx class? https://github.com/sai-php/sai/blob/main/dagger/src/Labels/NginxContainerInfo.php#L31
for Sai, the labels are an implementation detail
now that, would be a bug
the public API can be seen here: https://daggerverse.dev/mod/github.com/sai-php/sai@d0380650a1a5ca0b0244ce34820a6b5cc99f6c1b
@summer sequoia
$baseContainer = dag()
->container()
->from($containerInfo->getTag())
->withLabel(PHPContainerInfo::LABEL, (string) $containerInfo);
Why do I **need a label here? why can't I just do ->from() and crack on?
my question is why do I (as the end user consumer of Dagger), need to worry about Labels at all ? why isn't ->container()->from()->withDirectory()->withEnvVar()->withExec(), enough for me ?
you could use it that way, or you could do sai()->php('8.3', 'fpm')->withExtension('mysql')->withExtension('redis')->withComposer()->withSource($mySource)->container();
that's more expressive
abstracts the detail
why would you use symfony instead of raw PHP?
Okay, fine. If someone wants to make something for their own project.
the angle here is, people will want to make their own abstractions for their own projects and things (like nginx), and if we are giving them examples then it needs to be as simple as possible.
People will very quickly outgrow the standard SDK objects API
yes; I'm moving towards creating a simple enough toolset that someone could just grab off the shelf and get 90% of the way to a deployable project
but also, get out of the way and let people do their own thing if they wish
you can still grab the raw container and do whatever you need with it
this is more like it .. I'm not feeling these "Label objects" .. they contain meta data about the docker image to use .. and people are like "wtf is a label and why does it contain my image name/tag" ... do you get me ?
(one of my next projects is to read from the composer.json to do the withExtension stuff automatically for you)
it's an internal implementation detail though; as an end user you don't need to worry about them
actually, they need to worry about it if they're going to be making their own versions of that abstraction .. they'll be copying it .. you're already showing newcomers it, as a reference,
I don't think it's a bad idea to label your containers with metadata about their built contents
it is used internally for some checks eg with withExtension won't install the same extension twice
i'll probably use the source dir label to make sure you're in the right workdir for doing stuff with composer
pretty sure chainguard is doing that to aid with their security stuff for example
$containerInfo = new NginxContainerInfo(
$version,
$os,
$variant
);
return new NginxContainer(dag()->container(), $containerInfo);
What about this, instead? Why do I (need) to be specifying the ->from() at consumer level?, and why do I need to be specifying ->label() at this level?
If you don't add the label to the container you lose the meta data once you hand the container to the user. Makes it harder to pick up again
I'm saying to keep label() but not let the consumer be responsible for that .. surely we can do it inside of NginxContainer()
It does it inside the sai module
okay. I know it does, but I'm wondering why it needs to .. it's exposing complexity that I thought could be encapsulated inside NginxContainer() .. like in the __construct()
$containerInfo = new NginxContainerInfo(
$version,
$os,
$variant
);
return new NginxContainer($containerInfo);
This is simple, and clean .. can't we have NginxContainer->__construct() take care of the dag()->container() ?
That would solve this
That would prevent creating an nginx container from an existing container though, see adopt PHP container function
Do you have sample code (scenario) for adoptPHPContainer() ? trying to see it
Something like: sai()-php()-withExtension('mysql')-cintainer()-someCustomStuff(); sai()-adopt()-withComposer()-etc
Let's talk over the weekend about it, when you're at your computer π
Oh, I just remembered the biggest issue it was solving: you can't depend on objects from another module in your module.
So a PHP unit module couldn't depend on a PHP container object from Sai
It would need to depend on a dagger container
What if you passed the container in, though? between the modules
Then call adopt to get the sai container
what about this?
$container = dag()->container()->from('php:8.2')
->withDirectory($stuff ....)->withExec(['apk add', 'some package']);
phpunit()->fromContainer($container)->runTests();
phpunit being a separate module
I need to open source a few more bits I think to demonstrate this better
I'll see if I've time on Sunday
The PHP community can't rely on sai(), there needs to be "a clean simple way" so they can adopt that technique for their own modules, and their own things .. for their own private company projects
Agreed?
It's a good example right now, but I'd not push it as the one true way.
I do plan for it to be a standard ish toolkit but it's got a way to go yet
Ok.. see DM .. night π
I find having everything for my project in one file (build base, build local, build prod, build assets, build nginx, run phpunit, run phpstan, etc etc etc etc) not very "friendly" in DX PoV. Do you have any recommandation on how to split concerns properly ? I like some examples you shared @green otter for your talk about having ->withBaseEnvVars, ->withComposer() or stuff like this. But whenever I want to put it in another class it feels weirder... Will try to provide code to better demonstrate what I mean
Hey, I make a separate trait .. and bring it into the main class context. That way it's the same class but separate code π
How about this?
@karmic tendon
Trait for Building stuff
Trait for Testing stuff.
Each function in a Trait, can either do dag()->container()
Or it can just receive argument Container object and return Container once it is finished
WDYT?
yup good idea. I think trait is the better of both worlds. Altough we might have to try it on very bog project where dagger would become central to everything to see if it does bring any cognition load to have all the "Functions" in one place only.
This is valid PHP but seems to be failing using dagger : https://onlinephp.io/c/c0d56 [ERROR] Cannot access trait constant self::DEFAULT_PHP_VERSION directly Does dagger resolves self:: to replace it with Trait::? Because that is not allowed indeed :/
This one is closer to what I currently have : https://onlinephp.io/c/689b8
I use those constants as default cli options for a dagger Function
@karmic tendon hold on. Let's ask @summer sequoia I might know why but Chris will know better.
It could be a PHP version issue, or it could be our introspection code..
Let's see what he says
@karmic tendon I couldn't reach Chris yet, but will eventually
@karmic tendon I think this is a PHP issue now Dagger. So the runtime where all your code runs inside of, is a PHP 8.2 container...
no worries. I'll be full until end of next week
@karmic tendon show your code that's throwing the error. So we can see and maybe chris can replicate it.. if anyone will know it will be him
Are you hitting that error when running a function call or when doing discovery eg dagger develop? Might be an issue in the way the reflection stuff handles traits if it's happening during discovery.
As for code organisation. There are two ways you could do it.
The first, is what I posted with the gist up above; whereby your module entrypoint contains the only public API for your module and you then separate using non-dagger classes or functions. There's nothing to stop you creating a Unit tests class, an integrations tests class and a static analysis class which takes a container as a constructor arg and has functions you can call to do your build steps. Youd' then have a single "runTests" function in your module entrypoint which does some setup and then defers to calling each of the subclasses. If any of these sub class components are reusable across your projects, you could turn them into modules in their own right.
The second is similar but instead of using the entrypoint to rollup lots of calls into a single function; you use it to provide access to the separate components of your module; so you might have a function tests() which returns a Tests object which in turn contains functions which return A Unit tests, integration tests and static analysis objects which you can then call the functions to perform your build. This allows more granularity in the function calls and will play nicer if you want to integrate with tools which visualise or do further processing on results (eg showing code coverage against your code in the PR)
Personally I'd tend to lean towards the second option as the longer term aim, but the first is a good starting point to move pipelines into dagger to start with and if you organise it well, it'll naturally convert to the second option further down the line.
@hallow hinge ask here your Qs π
Iβm crafting a PoC for Symfony-cli as dagger module. It could be a base module for : console (importmap, doctrine, cache, linters, tailwind, etc). All those things are commonly used in CI pipelines of Symfony apps
Besides, it could be awesome to have modules for quality tools! Here a non exhaustive list:
- Phpstan in pure php(it exists coded in Go)
- Php-cs-fixer in pure php (it exists coded in Go)
- ECS
- Rector
- TwigStan
- PHPUnit
- Pest
- Psalm
- Behat
- Deptrac
- PHPat
Feel free to complete this list, and share if you want to craft some. Maybe we could share base module ship standardized and solid modules π¦Ύ
@hallow hinge I already have the code for the above things, already created .. If you have a Module question then we can ask .. otherwise let's set up a call (and a repo?) for me to start putting in the code for all the above stuff .. as mentioend I've already built most of it
I guess you can publish them under your name, and we (php devs) will use/contribute then π
@hallow hinge I will publish my code onto a Dagger Module (the daggerverse) so you can immediately start using them in whatever context you wish (symfony-cli?) and you can contribute to any of these modules for missing fields/functions/flags π
So then they will be ready for "the PHP community at large" π
I didn't make one for Pest or TwigStan or Rector π
So maybe once you see my modules for the others you can have a try at making the TwigStan one and Rector π
I'll go and charge my laptop and grab all the code now..
I'm wondering if we want 1 repository for all the "dagger-php-tools" or we have 1 repo per module
Let me make 1 repo per tool, actually, as I see "issues" π
I'm running static analysis on the Symfony project, using my new phpstan module π
ALL ZE CORES π
Yeah! I will check it properly tomorrow morning, but yes, shoot the link here!
(I was wondering about a GitHub organization dedicated to dagger php modules, WDYT?)
@hallow hinge yessir, been thinking about it for a few months now .. I'm thinking of php-dagger or dagger-php org ??
WDYT?
I have the exact same question in mind π
So I built the official phpstan module π
I went to the symfony/symfony git repo, and now I'm calling it from inside the Symfony repo's dagger module
@hallow hinge all of this works π
Letβs roll a dice? Odd for dagger-php, even for php-dagger? Do you have a dice?
dagger call static-component --source=. --Translation
dagger call static-component --source=. --Asset
π
ok, I'm now changing it to run so that it's not confusing with x2 phpstan()
Do you liiiiiiike? @hallow hinge
Run? Or analyze, to reflect the real command?
Love it! And it will be a great argument to push usage of phpstan on Symfony code base instead of Psalm (even if I donβt really want to be the one who make the PR with the first run π)
analyze++
I'll go make an official psalm module now .. and then I'll add psalm as well as phpstan, to align with official Symfony stuff
Final phpstan copy π
official psalm() module now exists - and here is the symfony project using it π
PR made to Symfony project https://github.com/symfony/symfony/pull/59240
/cc @hallow hinge
integration tests code, so far - WIP - https://github.com/symfony/symfony/pull/59240/commits/8aa3aa9b0a5a7c65eea499cf458d0710714489d3
Woow. Moving so fast ! Congrats on this workload ! Can't catch up yet sorry (end of year is kind of a marathon on my side). Eager to check those out !
If I may share a few thoughts: I think it's generally a good practice to set versions in module constructors. In the end, the module just invokes a container which could be anything and in some cases, the container itself may need to be custom as well.
That's why I generally allow setting versions and a container (taking precedence over version) in a module constructor.
That's how I built my phpstan module (and most of my modules): https://daggerverse.dev/mod/github.com/sagikazarmark/daggerverse/phpstan@84e479601ced57c999880867f0beb56e2afd683d
A couple other thoughts:
- If there is a module constructor, you can build most of the container upfront which simplifies the actual function that you invoke (mostly useful when there are multiple functions. For phpstan, I also have a generate baseline function)
- sometimes it's a good idea to pin tool versions to avoid breaking due to accidental upgrades
- nit: phpstan accepts multiple paths AFAIK.
- it's generally a good idea to disable any interactive mode or progress reporting as they don't display nicely in some consoles/logs (phpstan has --no-progress AFAIK)
Instead of
->withMountedDirectory('/tmp/app', $source)
->withWorkDir('/tmp/app')
you can write
->withWorkDir('/tmp/app')
->withMountedDirectory('', $source)
Well, that became a bit longer than I expected π
Anyway, kudos on bringing Dagger to the PHP world!
One last note regarding your symfony PR: if those functions are always supposed to be called with --source=. why not set a default path?
Or better yet: why not just pass the source in the module constructor (with a default path)?
^ Which, if you decide to do, could look like this:
#[DaggerFunction]
public function __construct(
#[DefaultPath('./my/default/path')]
private Directory $source,
) {
}
The difference then being that your calls would change:
From dagger call psalm --source=.
To dagger call --source=. psalm
fun bug. Turns out if you mount a composer.lock file in place of a composer.json file; composer will happily run and do... nothing.
Bug when mounting composer lock without composer.json
Teaser π€«
would there be a way to dynamically add all current composer / symfony commands ?
IDK, for now it's static. I've mapped all those commands manually. For most of them, there is no specific flags, for others, I've mapped the flags too (i.e --no-interaction for doctrine:migrations:migrate).
I've took 15 min to craft this, I'll take a look deeper to find out if we can dynamically map the commands from symfony, console and composer, even if we don't need all of them. Only the ones useful in CI are important for now (who runs make:auth in CI? π )
true but how do you make sure which ones are important ? They can all be. Not our decision to make IMO. For doctrine migration there is also the --allow-no-migrations or something
Sure, we can ship a set of ultra popular commands and let users add some more in the future, based on their need. BTW, I also expose console, symfony and composer commands to let users run any available command. Ex: dagger call console --cmd="make:controller FooController --no-template". Kinda ugly but given the nature of Dagger, almost no one will write this manually everyday, but one time in a CI file.
I put a bit of thought into this; you could have the SDK introspection somehow understand symfony CLI objects and report them back as dagger functions; unfortunatly, that'd mean they'd all have to run in the SDK PHP container, which would work some of the time; but will break horribly if you need custom extensions or a newer/older PHP version than the default 8.3
A better approach might be to write something which automatically generates a dagger module based on the CLI interface; should probably take a container as a constructor parameter to run the commands in but then there will still be a bit of complexity as to figuring out how exactly to run the command within a custom container you don't know anything about.
eg if the symfony binary wasnt in the place you expected it to be; or the workdir wasn't set as the directory containing the code (or maybe it is, but due to project layout, the php code is in a sub dir); or perhaps it's using an older version of a tool that you don't pass the correct args to...
lot of complexity to manage.
Yes, it sounds great but incredibly complicated regarding the goal to reach. Letβs provide useful commands in CI context and users contribute complementary commands later. WDYT?
I think we'll need to iterate over how this is done quite a bit really; until we get people using it, we won't know all the issues we need to solve
Donβt remember if you can change the output of the Symfony CLI, if you could output that as json I wonder if that could help with auto discovering commands in the module?
No, the Symfony CLI does not support --output to write JSON in stdout. It would have been a great way to generate dagger functions.
But for composer it is a bit more difficult I think... Composer allows through plugin to register new functions. So Yeah maybe something basic at first for common use case and create something more powerful later on.
- instantiate the cli application
- call all() to get registered commands,
- call getDefinition (or getNativeDefinition?) on each to get name & args
- create PHP code to turn that into a dagger function.
- create a boilerplate dagger object which takes care of
-- taking a container to run stuff in as a constructor arg
-- mounting your local src directory into said container
-- returning an object which contains the string output of the command and the modified directory from the container - each function can then rely on the boilerplate for running the command; code is generated to handle passing in args
extra credit: use namespacing information to separate commands into multiple dagger objects
that will get you the basics sorted for any symfony cli based application
you can then modify the code as needed to handle special cases
Is there a way to "publish" an image in the local registry ? (do not push)
to the local docker image cache?
Yup
$ dagger shell -c 'container | from alpine | with-directory /dagger $(git https://github.com/dagger/dagger | head | tree) | export ./my.tar'
$ docker tag $(docker load -i my.tar | cut -d: -f3) my-image
$ docker run -it my-image ls /dagger
The other way is to run a local docker registry and publish to that; you can then pull from it.
Generating dagger functions based on json could work for the Symfony console, but not for the CLI tool (as it does not provide any other format than text for output).
That said, the most important commands live in the Symfony console, not in CLI (actually, the only important command from CLI is security:check I guess, others are related to Platform.sh (and could be a separated module), or to instantiate a new symfony app, or managing the dev server)
Hey @hallow hinge we're both awake hacking on Symfony/Dagger π
I'm focusing on the integration tests stuff .. grinding through that right now ..
don't need to do it based on the help output; grab the code directly and introspect the objects
@hallow hinge update - all the services are now binding on my IntegrationTests work
Still got lots more work to do .. but the base services are running now π
Very quick example: https://gist.github.com/carnage/d6b559b17093b037056843a02db27577
I've pushed my 1st draft of the module for symfony-cli https://github.com/dagger-php/symfony-cli-module/pull/1
Feel free to comment, and/or open other PRs with codegen.
Ping me if you want to join the GitHub org Dagger-PHP π
(PS: please ignore the logo of the arg, chatgpt was not very collaborative π«£ )
does that work?
I know at one point we were having issues in getting changes made in dagger functions to go back to the host.
dagger sdk build module returns a directory: https://github.com/dagger/dagger/blob/main/sdk/php/dev/src/PhpSdkDev.php#L64
AFAIK, yes. Iβve tested it on a Symfony app locally, it worked.
Now, Iβm wondering about using Dagger to build the CI of the module itself π
π
@hallow hinge I'll check your cli module PR soon. Still crazy busy with first of the year rush.
@green otter same here, no free time to work on it. Donβt hesitate to ping me if needed
hm something weird seems to be going on with the php traces - it seems like we lose all spans from a php dependency module, which means there's no info on what's going wrong when we get a failure
for example, if i run dagger call -E sdk php lint in the dagger repo, i don't seem to be able to find a span in the TUI or the cloud that corresponds to the withExec for phpcs
this is a bit of a pain, because it seems like phpcs is a bit flaky
but i can't ever seem to catch a failure of it
Has it been working in the past?
I know @ocean creek did some work on traces for PHP, but I hadn't tested whether it worked yet
aha
i found the issue π
the dev module was using a very old version of the php sdk
which didn't have this support
we can bump that (in https://github.com/dagger/dagger/pull/9337)
Ah... good to know. @obsidian forge While you're here, are there any updates on using the names of enums?
I know that issue turned into a bit of a rabbit hole. #8671
Just curious, we're still looking forward to that support on the PHP front π
Opening an issue from #go message - me and @helderco had a chat about this in person at our offsite. Current enum support...
uh no updates, it's not really been on my radar recently
the issue is still the plan
we just haven't really had the time to properly do it
That's completely fine, thanks for the update π
Just wanted to double check if I should be brushing the dust off my enum PR
@ocean creek you wizard, just admiring your work on the traces for PHP. π
Thanks π
okay, i wrote this up into an issue since it's still happening - and submitted a potential fix in https://github.com/dagger/dagger/pull/9348
my best theory atm is that using setPty is doing weird things - somehow, i'm seeing progress output come through the callback? which shouldn't be happening, it should only be appearing in stderr.
Well the CI is passing and scanning the symfony docs, it looks like a reasonable swap.
I honestly can't say what the problem is, I think I'd really need to dig into it to understand.
yeah, no real clue what's going on - we'll see if it keeps happening with that change π
it occurs with some amount of consistency π
I'd really like to get rid of the cli client downloader thing. I really feel that it shouldn't be required if everyone is using the PHP SDK to build dagger modules (Rather than just making dagger calls) as we know the details for connecting to the dagger graphql API will be present in the container spun up by the SDK
the client download is only a fallback if there are no creds defined in the environment
//cc @green otter what do you think?
I think at this point; if someone wants to continue using dagger the old way, they can always use an old version.
If it was not causing any harm, I might feel differently. As it stands, continuing to support the old way seems to be cause consistent CI flakes which wastes further development time.
Arguably, we could simply remove any tests related to it, but at that point, we're just holding on to an outdated and untested piece of kit.
While we're talking about removing things:
It would be nice to get rid of the committed generated/ directory.
That whole weird chicken and egg situation of needing a Client to generate a Client.
yeah, again with the generated stuff; that's only needed if it's being run stand alone; as a module the SDK should inject the graph ql spec file already
imo, i think removing the provisioning stuff is a decision to be made across several sdks? obviously kind of up to y'all, support can just be dropped, but i think there's a conversation to be had about whether we just entirely remove it
you can still use the standalone sdk without automatic provisioning using dagger run
cc @cobalt pelican since we've had this conversation a few times before
Yeah. Using dagger run has a better experience (e.g., TUI), but some old timers still like the automatic provisioning stuff still so they don't have to fetch the dagger CLI first. However, for new/experimental SDKs, I suggest to keep it off. Standardize around dagger run for non-modules. Keep the maintenance burden lower by not worrying about automatic provisioning support.
If we remove auto-provisioning, the SDK will still be capable of executing dagger session on its own, it just will require dagger already being installed, correct? So even dagger run won't be mandatory, just installing the dagger CLI yourself as a runtime dependency of your dagger-powered tool.
I'm perfectly OK with that π and I believe we agreed to do this in the past @obsidian forge @cobalt pelican ? Perhaps we neglected to make it an issue, I can't find it in the record
We usually refer to automatic provisioning as both the download and running dagger session. We haven't discussed splitting those afaik. But notice that I'm only arguing for ditching automatic provisioning for experimental SDKs, which don't have the same baggage as the 3 stable ones. The SDK docs mention since the start that this is an optional feature. That was written before modules, at a time where we wanted to shift focus to the dagger CLI (dagger run and the TUI were new) . I think for Go, Python, and TypeScript, it requires it's own discussion because there's different things to consider.
I think we should discuss the download & running separately. Ditching the download makes sense. Ditching the running IMO doesn't, the loss of feature isn't worth the saved work IMO (download is more work than run)
There are a couple of separate things here; the first is that using calls out to the dagger cli to talk to the engine was a bit flakey. Using the graphql client is preferred; however that needs the session data set as env vars to work
Was it flakey for PHP reasons or Dagger reasons?
PHP reasons, which were hopefully fixed with the PR; but also it's not used much as a feature so gets neglected in development
Ah, sorry I'm not familiar with the specifics of this sdk. But generally executing dagger session is the recommended way to open a session, it's not recommended to do it with a native http client, because the logic and use of env variables and config files will evolve over time and it's not realistic for all SDKs to implement it all correctly and thoroughly as it changes
hmm, well for dagger modules, I thought we could always rely on having the session env vars set. I was also under the impression that dagger modules were the way to go, going forward; so since the PHP SDK is new and/or shiney we can encourage users to only go down that path; meaning the other options are far less important
Hi, i've been following dagger for a couple weeks now. Interesting tool. We are using php/symfony at our company. Is the php sdk ready for a poc or is it too early? Is there an overview somewhere of outstanding/known issues? On what topics is help needed?
I want to start with the dagger quickstart and something like running phpstan or php cs fixer with the php sdk. Is that doable right now?
PHP SDK Quickstart
Hey @kind linden welcome here! Did you attend my Dagger PHP talk at SymfonyCon Vienna (December 2024) ?
You can indeed use the phpsdk, it is indeed ready for you to start using.
Don't worry about the "Experimental" keyword, that's because it's not being updated by dagger core team on every release, for any new shiny stuff.
We (the php community) are updating the PHPSDK as new features come online.
95% of all the features you want to use for your pipelines, are 100% functional and working for many months now π
If anyone here joined from SymfonyCon or SymfonyOnline, just wave here π
ππΌ
I saw the announcement of your talk and am very interested but have not seen it as i didnt join the conf.
Hey @cunning pine so if you're thinking about building a Dagger module for PHP community - ping me (and others here) first, as we have loads created that are just pending publishing, and you may be building stuff that already exists .. and thus instead you can focus on things that don't exist π just let us know what's on your mind
I have a few modules that are PHP adjacent, but not written in PHP. Those are more in the context of a larger effort on documenting the process of developing modules - using multiple languages π
ok
"I have a few modules that are PHP adjacent," - feel free to share with me stuff you're upto π curious and enthusiastic
@green otter @serene light @summer sequoia @shy goblet π I open a PR to add float type support here https://github.com/dagger/dagger/pull/9411.
The most commits in this PR come from https://github.com/dagger/dagger/pull/9396 which is based PR so you can focus on https://github.com/dagger/dagger/pull/9411/commits/458361717dd2cbf00f8833e26b0cd8da447001b3 afterwards.
My PHP knowledge is very very limit so please tell me if I'm missing something. πββοΈ
Summary
Add float support and fixes #9280.
Doc page available on #9408
Examples
Go
package main
import "context"
type Test struct{}
func (m *Test) Test(n float64) float64 {
re...
hello again @ocean creek - hope you had a good christmas holiday period π
@ocean creek I checked your PR - I believe it's all that's necessary. Only thing I can think of is that we could have a unit/functional test in the test suite, to make sure the correct GraphQL is generated, for float .. or that we're correctly parsing the GraphQL and ensuring things basically work end to end.
I'm not 100% remembering how we do our testing, so I'll defer to @summer sequoia and @serene light on any other comments or on their thoughts on how we can make the testing more robust.
@green otter π Hi, hope you had a good christmas holiday period as well.
This is the first time for me to use PHP type system, I'm unsure if it has any other types than float.
Hi Paul, I saw the https://github.com/dagger/dagger-php-sdk, but I'm not sure how it could be used like you presented it this morning? (with a PHP class, with attributes and so on)
@ocean creek PHP is fully typed. Everything apart from Generics and scalar variables.
Every argument. Every return value. All class properties. All scalar types and instance types, fully typed.
@lapis drum
What do you want to make? We will paste you code snippets π
Install dagger and then go to your PHP project and type
dagger init --sdk=php .
Then look at the new .dagger dir
at the new /src/YourModuleName.php
Ah okay, thanks π
Hmm so I'm first trying to run PHPUnit in a PHP 8.4 container (because, why not? :p)
Any idea how I could mount automatically the app directory into the container?
Yep
Stand by
Stills requires me to pass the directory :/
! required flag(s) "dir" not set
Replace the docker image with your own image.
Run your own exec command. Do "php -v" like this
https://github.com/dragoonis/Sylius/blob/dragoonis-dagger-integration/.dagger/src/DragoonisSylius.php#L28
I mean, in your example here, you still have to pass the --dir option; I'd like to avoid that π
dagger call <func name> --dir=. stdout
Mount the entire cwd
I'm at the bar. I can't show you that. Just do this to learn π fix later
type "dagger functions" to see the function list
It's like symfony console basically
Ah found it, #[DefaultPath('.')]
Yea, that's a thing. You can use it. Either works
yeah, because Directories are objects, you can't give them a default in your code; the attribute exists so that you can give a default as a string and have it converted into a real directory
That attribute also pairs with #[Ignore] so you can avoid adding things to dagger you don't need (and might mess with it's cache)
More detailed explanation in https://docs.dagger.io/api/filters
Thanks for the information π
Thank you for the PR I requested a few changes that are necessary for it to pass CI.
I also gave an example of a couple tests that could be added, but I'm fairly certain it will already handle floats.
I open up a PR to modify dev module to uses the default path against source directory at the constructor level instead of passing source to every function.
chore(sdk/php): use DefaultPath to SDK s...
Hey all π Laravel dev here, looking to start looking into using Dagger for our testing and asset build pipelines as they are phenominally painful to get running on github actions, and slow to run locally with act. Any tips or trick, or starting points specifically for Laravel that anyone knows about would be amazing.
A list of first steps:
-
Initialize a dagger module. From your application root directory call:
dagger init --sdk=php
That would get you a basic module, those would be the first steps regardless of framework
Done, although, i started with Typescript just because the docs for the PHP SDK didn't seem to exist currently
I know it's WIP
Ah fair enough, if you prefer you can always work in Typescript
But if you prefer to use PHP it should be more than capable
Thanks, i'll take a look! I'm on the lookout for example dagger modules anyone might have for Laravel projects, but i know that's a stretch at the moment, if anyone spots one let me know!
I guess it depends what you're trying to set up exactly, is this CI stuff like phpunit, pest, phpcs, php-cs-fixer etc.
Yeah, so running our tests with phpunit/pest, and then we also have an asset pipeline where we (currently) build our front-end assets locally, but we'd like to move that to CI so it can happen on push etc.
For a quick start with basic checks you could have a look at this explanation:
#1327946009917001768 message
It's for phpstan instead of phpunit, but you'll get the idea. Gives you something to play around with.
Thanks!
No problem, also in terms of docs for PHP SDK, if you generate a PHP module, it comes with a README that has some rough guides on each feature
Ah beautiful, thank you again.
π€ I have a suspicion that there's something wrong with enums here: https://github.com/dagger/dagger/blob/70ae1c2448ff6ac437a5c3f0c730970b010cbb72/sdk/php/src/Client/QueryBuilder.php#L13-L19
By unpacking the BackedEnum type, it seems that we're submitting the enums as quoted strings like "STRING_KIND" instead of STRING_KIND.
I've been enabling graphql validations, and just caught this here π€
does it make sense to remove the first couple lines there?
It's been a while since I went that deep on the GQL part of it but this is the function that it boils down to
public static function formatValueForRHS(
null|bool|float|int|string|BackedEnum|Stringable $value
): string {
if (is_null($value)) {
return 'null';
}
if (is_bool($value)) {
return $value ? 'true' : 'false';
}
if (
is_float($value)
|| is_int($value)
|| $value instanceof Stringable
) {
return (string) $value;
}
if ($value instanceof BackedEnum) {
return (string) $value->value;
}
if (self::isVariable($value)) {
return $value;
}
if (str_contains($value, "\n")) {
return sprintf('"""%s"""', $value);
}
$value = preg_replace_callback(
'/[\x00-\x1f\x22\x5c\x7f-\x9f]/u',
function (array $matches) {
$str = $matches[0];
return self::ESCAPE_SEQUENCES[ord($str[0])];
},
$value
);
return sprintf('"%s"', $value);
}
So yeah, it gets in here... looks at it, if it's a string it's going aaaaaaall the way to the bottom and surrounding it in double quotes.
So yes
For a backed enum we actually want to just pass it in
awesome okay
Obviously, give it a whirl and see if it explodes π€
definitely π thanks for the help, i'm really really not familiar with php, so the assistance is always appreciated π
Thank you for the spot, honestly I'm admittedly not familiar with the setup before I started working on it. I want to look into it and start understanding the guts of it more.
But working out where to start is hard.
oh also i had a thought π€¦
dagger.json for the php dev module can just be:
{
"name": "php-sdk-dev",
"engineVersion": "v0.15.2",
"sdk": "../",
"source": "."
}
that way it always uses the same version as in-tree
i wonder if there's a downside to that
otherwise i'm gonna have to work out how to stagger this change somehow
Oh that's interesting, I didn't know it could reference another dagger.json like that!
I think that would be a decent change. As testing in development is literally what the dev module is for
working on this fix in https://github.com/dagger/dagger/pull/9436 π (among everything else that needs fixing)
more weirdness found π
this doesn't seem quite right to me: https://github.com/dagger/dagger/blame/e8c68fae41f35cec91a606f1451200b411a4c0f5/sdk/php/src/Command/EntrypointCommand.php#L117-L117
see the ci failure in https://v3.dagger.cloud/dagger/traces/f6b43fc8d69d1fdbcdc09218ed3b9c98#b6a8f6038985b6b2:EL233
π€ I believe we did that to normalize objects and arrays for GQL.
So PHP has:
- lists
[1, 2, 3] - arrays
[a => 1, b => 2, c => 3] - objects which if they're serializable, then they can end up looking like ``[a => 1, b => 2, c => 3]`
There's going to a neater way to do it, but it worked, so for now it stayed.
But clearly something is going awry there
mm, i get that - but the problem is that this should error (but it hasn't been)
see https://github.com/dagger/dagger/issues/6561
even something like echo "{container}" | dagger query produces an invalid result
(it should error out, but isn't for some reason)
since inputArgs is actually an object type
since it's a list, we should just be able to iterate over it and fill a map like we do in the go example?
Sorry, my memory of why it's done that way is a bit hazy, so whether I'm forgetting the reason or not... π€·
I think in part, it was done this way due to limited knowledge of what inputArgs could be.
So this decode, encode bit...
$args = $this->formatArguments(
$parentName,
$functionName,
json_decode(json_encode($functionCall->inputArgs()), true)
);
... forced the data into a format that was a bit friendlier for me to inspect.
I was able to see that it was simply an array with a Name and Value, ready for formatting.
/**
* @param array<array{Name:string,Value:string}> $arguments
*
* @return array<string,mixed>
*/
private function formatArguments(
So, this, may be tech debt to be honest.
I think the changes required are quite small. I should be able to sort them fairly quickly when I find the time, but I would like to know if there is an exact format I should expect each argument to be in?
Is inputArgs always a list of objects, each with the properties: Name and Value ?
I'm trying to simplify it and remove that weird part but I'm having trouble getting dagger to work on 0.15.2
β β β /tmp/dagger/dagger-0.15.2 session --workdir --label dagger.io/sdk.name:php --label dagger.io/sdk.version:1.0.0.0 0.0s
β β ! start engine: failed to pull image: failed to run command: exec: "docker": executable file not found in $PATH
But that is only occuring on the phpsdkdev test function.
It builds all of the container before that stage
and i can run dagger/sdk/php dagger call -m dev format and it works
I also keep running into a lot of [ERROR] Undefined constant Dagger\TypeDefKind::FLOAT_KIND When trying to test a WIP branch as the SDK version.
I assume that might be an issue until 0.15.3 is tagged?
It will work if you are using dev engine otherwise we need a new release to make float type available on the engine side.
Thank you Win. π
How do I use the dev engine?
As far as I know, you can build the engine by cloning a dagger repo and run ./hack/dev to build the engine and use ./hack/with-dev to run dagger command (e.g ./hack/with-dev dagger call ...).
this yes π
yup, that's what it should look like, yup
if it helps, this is the graphql schema: https://github.com/dagger/dagger/blob/70b4285974af16a6d7ad58a25f4180897bc04eee/docs/docs-graphql/schema.graphqls#L1804-L1804
That does help a lot, since dagger is quite large I'm not always sure where to look for things.
I'll look into that when I get a bit of time
@serene light @green otter @summer sequoia is there already a generated SDK reference for PHP SDK somewhere similar to:
- https://dagger-io.readthedocs.io/en/sdk-python-v0.15.3/
- https://pkg.go.dev/dagger.io/dagger
I don't see a reference right away here: https://packagist.org/packages/dagger/dagger
Dagger PHP SDK
With TypeScript SDK, we have the package here with no real docs: https://www.npmjs.com/package/@dagger.io/dagger
but host the reference here: https://docs.dagger.io/reference/typescript/modules
We do not but that would be an excellent addition
Should I make an issue for it?
Yes please!
Done.
Feel free to edit it or add anything if I missed the point π
The other thing would be to understand what IDE integration setup folks would need to do for code-completion, etc similar to:
https://docs.dagger.io/api/ide-integration/
Dagger uses GraphQL as its low-level language-agnostic API query language, and each Dagger SDK generates native code-bindings for all dependencies from this API. This gives you all the benefits of type-checking, code completion and other IDE features for your favorite language when developing Dagger Functions.
I agree, I think looking at that page, PHP's integration is most similar to the Typescript description.
For the most part it should just-workβ’οΈ on any IDE that recognises the composer.json generated with the dagger module
I've been a long time PHPStorm user, but I did try Zed with a Laravel project and the auto language detection was π₯
I haven't tried Zed, I use PhpStorm and Emacs. The PHP functionality in Emacs looks to be similar to Zed (LSP and Treesitter).
Any objections are welcome but from what I've seen: pretty much every editor like Zed, Emacs, Vim, Neovim, VSCode, etc. uses LSP
This means php language detection for pretty much every editor is based on phpactor or intelephense My experience with phpactor has been that it detects all of the dagger classes and methods out of the box.
So my expectation is any editor using LSP is just going to work OOB.
The exception being PHPStorm which, ignoring how it works (I don't know), also just works OOB.
@hallow hinge can you link me to your symfony-cli work? I wanna see what docker images you're using (base docker image) π and thus what PHP extensions you're using
Feel free to commit on this branch if needed
looks like when i made this change, i missed that we needed to do this: https://github.com/dagger/dagger/pull/9589
We started relying on functionality introduced in v1.14.1 of php-graphql-client. But we failed to bump to v0.14.0.
This wasn't caught during testing, but only when upgrading an older module...
the BackedEnum support only appears in the newest version
Quick Q to anyone building with the PHP SDK: has anyone added a dependency to their composer.json other than the auto generated/added dependencies put there by codegen?
Hi PHP wizards... @summer sequoia @green otter @hallow hinge @serene light I asked the same question to the Java folks. I am very curious to see what would happen if you built a toy AI agent module with the SDK PHP, similar to my demo here: https://x.com/solomonstre/status/1891205257516003344
That demo is based on a branch of the engine (to add the navive LLM type and magic tool-calling capabilities). It should all work with any SDK.
I think the PHP community might be very excited at the idea of not only writing world-class CI pipelines in PHP, but also leapfrogging the AI engineering community, and perhaps writing world-class AI agents in PHP as well π
If you're interested in trying, we're hacking on this in #agents
The PHP SDK has liftoff!!
#announcements message
Huge thanks to the community leaders that made this SDK happen@summer sequoia @serene light @green otter congrats! π
Great to see the collab with the PHP pros on the Dagger staff as well @zealous venture @cunning pine π
Congrats all! This will help a lot to get newbies like me on board π
Its so awesome to see this all come together and launch. I am inspired by all the work that went into it from this group, amazing!

Update: today we added PHPπ support. Develop AI micro-agents in PHP, with full cross-language interop. One runtime, one ecosystem.
Are you seeing it yet? π
cc @official_php @dr4goonis
Hi PHP wizards... @Carnage @
Hey @obsidian forge we just want to quickly test the fix @summer sequoia discussed during. I ran dagger develop with this schema
{
"name": "update-minimal-dagger",
"engineVersion": "v0.15.4",
"sdk": {
"source": "github.com/carnage/dagger/sdk/php@fix-composer-lock"
}
}
We get this error
! failed to get sdk required paths: failed to call sdk module requiredPaths: select: Select: PhpSdk has no such field: "requiredPaths"
aha
okay, so requiredPaths has now been removed
what engine version are you using?
currently 0.15.4 I believe
i expect what's happening is that fix-compose-lock is based off of v0.16.0 (so has no requiredPaths), but the engine is v0.15.4 (and so needs it)
Oh, I see...
if you upgrade the engine, it should fix it
It is, yes.
Thank you, brilliant. I'll let you know how it goes and we should be able to merge that fix soon π
no worries π anytime! π
Alright, merged the branch. That should remove some a few hiccups. Thank you @summer sequoia @obsidian forge
As a side topic I've been wondering about: How do the other SDKs test actual integration with dagger?
Like, creating some test modules and calling them from dagger?
Because right now the PHP SDK has unit tests for code that can be tested independently, but integration or feature tests are basically non-existent
yeah π€
so i think probably we'll want to do similar to what @pine bridge is doing in https://github.com/dagger/dagger/blob/bf712c4d46992979e9b92a1b9728413b0565e928/core/integration/module_java_test.go#L1-L1
essentially, what you'll need to do is copy the sdk source in https://github.com/dagger/dagger/blob/bf712c4d46992979e9b92a1b9728413b0565e928/core/integration/module_java_test.go#L194-L195
then you can create modules using --sdk=./path/to/imported/sdk/source
and write tests similarly to how we do for all of our other tests
Thank you, I've made an issue on it for now: https://github.com/dagger/dagger/issues/9670
It's definitely something I want to get more of. I like tests.
The PHP SDK could use integration tests. With modules created, purely for testing, to assert PHP modules work when called through dagger. For reference: https://discord.com/channels/707636530424053...
i like tests
after my own heart π
i'm just very lazy actually, and don't like having to manually check things work
I can help looking into this if you like. I have planned to add it to Elixir as well to discover what I missed in the SDK.
You are more than welcome to help π
If you beat me to it, my only request is that you help me understand how it works so I can help maintain it π
Nice. Will looking into this weekend, hopefully that PR will be open around Tue-Wed.
I didnβt know that before so we can removing it from the SDK?
yup π although if you do that, that version will stop working on the new versions of the engine (though i think that's absolutely fine)
A bird test in the hand test suite is worth two in the bush done manually
hmmm
i feel like this might have started breaking stuff on main after it was merged
since there's a php test that does init with sdk php@main
Cannot update only a partial set of packages without a lock file present. Run
composer updateto generate a lock file.
^ this feels a bit suspicious
the tests in question that are failing: https://github.com/dagger/dagger/blob/bf712c4d46992979e9b92a1b9728413b0565e928/core/integration/module_php_test.go#L18-L31
why didn't it break on the PR?
might have to wrap that update with a if file exists (composer.lock)
revert for now and we can fix it asap
Hi everyone! Is this the correct channel regarding daggerizing a PHP (Symfony) project?
I've put my question on https://discord.com/channels/707636530424053791/1343298656417353824
These only started failing on main because these tests fetch the version of the PHP SDK from main. While these checks are somewhat important, we should probably have a test for the commit - similar to how it's done for TestJava.
(quoting myself from the pr)
just hit this on llm.2
Also, is there a way to set a default directory with the PHP SDK. Maybe I missed it in the docs? Trying to do something like this (using a default directory in the constructor):
#[DefaultPath] on the Directory parameter
You also have #[Ignore('this.txt', 'that.json', 'dont-forget-this.yaml')]
Totally forgot attributes can be used in functions! 
Also, I feel like we need to add those as examples to this page (specifically for default paths and docs) https://docs.dagger.io/api/arguments/
We have the default path one there: https://docs.dagger.io/api/default-paths
It is possible to assign a default path for a Directory or File argument in a Dagger Function. Dagger will automatically use this default path when no value is specified for the argument. The Directory or File loaded in this manner is not merely a string, but the actual filesystem state of the directory or file.
we meaning all languages, not just php
I'm not sure where Ignore is but I think we got it as well?
Yeah, that might be useful on the same page actually
yeah, I think the arguments page should also highlight some best practices - like documenting the args. Thoughts?
I think that would be a good move, or at least make a note of it within the page and point to the relevant info
Because, case and point; you went looking for how to put a default on a Directory argument and did not find it where you expected
I definitely think we should mention it, or point to it here: https://docs.dagger.io/api/arguments#default-values
I think because there's quite a lot of info to digest on default paths and inline docs, it's probably best to point to it (rather than try to wedge it all in). But a brief mention would help anyone who follows the same path through the docs that you experienced just now
mm, agreed, that is weird.
imo, arguments + default paths + directory filters are all very related?
makes sense to have them on different pages i guess, but they either need better linking, or should maybe appear one after each other?
yeah I'm always jumping between those pages
maybe @zealous venture might have some context for why it's currently like this?
There's a PR with this solution included, awaiting review: https://github.com/dagger/dagger/pull/9644/files#diff-45a8cb01feb16ff047ea22b82cecc28ca6283e36d5da48d89739d0e4e690aba7
I agree with this and it was actually set up that way until two weeks ago. We received user feedback that it was hard to find buried deep inside the default values section, so I moved it to a separate page to make it more visible. More info at https://github.com/dagger/dagger/issues/9493
It looks like this change didn't help much, so I'll open a PR to add prominent cross-links between those pages and we can see if that helps.
Open to other ideas as well ofc!
I definitely agree with it needing a dedicated page, yes some cross-links would be the ideal solution here I think
Will do today!
Thanks for the feedback!
when you have a few minutes, please check out Jason's awesome Laravel agent written with Dagger: #agents message
https://github.com/dagger/dagger/pull/9704 also fyi @cunning pine @obsidian forge
PHP SDK Integration tests
I thought I saw this, sorry for the lazy post, but in the PHP SDK are we against composer requiring dagger in projects like we documented here: https://docs.dagger.io/api/sdk/#custom-applications. I was running this in a local PHP environment in Laravel and got tripped up on the logic in this switch: https://github.com/dagger/dagger/blob/main/sdk/php/src/Connection/CliDownloader.php#L109 (darwin always contains win so it thinks its windows)
I believe we want to recommend against it. cc @summer sequoia
But yes, that switch statement is clearly never going to work for darwin.
Having a quick look at it, I think there's a better solution here by relying on PHP_OS_FAMILY instead.
it has a smaller subset of predefined values and we can match against them exactly rather than str_contains
One of 'Windows', 'BSD', 'Darwin', 'Solaris', 'Linux' or 'Unknown'. Available as of PHP 7.2.0.
Maybe we should discuss the composer require? I think embedding dagger clients in other programs is a little bit of a super power (we document how to in the other SDKs). From personal experience, that is how I deployed it with Craft Cloud (embedded dagger client in a Go application).
I might be mistaken, I just looked more closely at the docs you linked
I'm not sure why I ended up there in the first place tbh, I had dagger CLI installed and in my path (ran php artisan serve). Nothing to really worry about right now but I will look at it when I can get the time
yeah, that is probably the best option - but that class is deprecated so π€·
I don't think we are against requiring dagger in projects, I'm just not particularly accustomed with how it works and if it does
That part of the functionality was developed before I got involved, I haven't touched it too much because I didn't want to break it. π
I'm currently working on the integration tests. Once we've got a more thorough suite, it should be a bit less daunting to work on it.
My personal recommendation is that everything is a dagger module
@cunning pine is that running an LLM inside the dagger engine or making calls to ChatGPT et al?
@serene light Here is the integration tests we discussed last week https://github.com/dagger/dagger/pull/9712. It has only 1 feature, 2 tests at the moment but I think we can add more to this PR. π
NOTE: This needs to be merge after https://github.com/dagger/dagger/pull/9710 in order to make CI happy.
Brilliant Win, thank you!
I made similar refactoring to the TestInit function just now, so I think those changes can be removed.
Your addition of the TestDefaultValue and phpModule are exactly what I was considering next! I've put a few comments on the PR π
nicely done @ocean creek
@cunning pine don't forget to tag me in questions, as I might otherwise not see them.
Why do you thinkg PHP_OS_FAMILY is deprecated? where did you see that?
You can also fall back onto PHP_OS constant.
All in all we have php_uname() here, which you can write a nice quick match() statement in there.
Let me know.
All suggestions except formatting comment are addressed. πββοΈ
hi, I think there is an issue while creating a module π€
EDIT: it seems that I did not have network in docker ... my bad
is this working?
$ dagger init --sdk=github.com/dagger/dagger/sdk/php foo
The CliDownloader is deprecated so I think Jason is referring to "whether it's worth fixing"
Thank you π
I've approved your PR but I'm not sure right now if the failing pipeline parts are flakes or not? π€·
running against OpenAI, but supports multiple endpoints: https://github.com/dagger/agents?tab=readme-ov-file#2configure-llm-endpoints
@shy goblet If you have a moment, could you please have a look at this?
I noticed you've mentioned [this is a known flake](#1334452944740814931 message)
It's the same output we're getting here
I'd have assumed flake already, but since the PR changes the core/integration/module_php_test.go It's somewhat related to the jobs that are failing.
An engine to run your pipelines in containers. Contribute to dagger/dagger development by creating an account on GitHub.
Hey, I'm not sure I understand your question, the PR doesn't change anything in module_php_Test.go ?
Doh! I linked to the same PR twice.
This one: https://github.com/dagger/dagger/actions/runs/13535668132/job/37849719297?pr=9712
An engine to run your pipelines in containers. Contribute to dagger/dagger development by creating an account on GitHub.
It seems to get this error:
Run #!/bin/bash --noprofile --norc -e -o pipefail
Error: Process completed with exit code 1.
I'm not finding any useful information in the error to work out what went wrong
nothing urgent π
Also, was unclear in my statement, I meant the Dagger CLIDownloader class was deprecated.
You need to check the traces on dagger cloud directly, it seems the error isn't displayed in the action.
Do you have access to them?
@serene light what's our most basic php example we can give someone.
- Install composer
- Php ext install <--- which extensions do we choose?
- composer install
- run phpunit
https://v3.dagger.cloud/dagger/traces/c1853f2d0a02b59dda941e4144f018b4 This job is failing
Elixir tests are failing, same on my PR
And there are also some flakes with private module using SSH
I seem to be able to access it, but only via your link. I don't know how to get there normally
dagger.cloud -> dagger organisation
@zealous star Are the dagger repo traces publicly accessible?
they are, but only with a direct link, yea - you can't view the trace listing atm
Ah okay, yeah I was looking and could not find a link to the organisation page
I only have my local traces set up
@charjr what's our most basic php
Sorry for the trouble. It's me that broke the SDK T_T.
I'm working on fixing it. You can see the progress in #elixir for this fix.
From this issue, I just found that the link is in the CI summary!
@ocean creek That's fine π Also thank you for finding the link! I tried clicking it but I don't seem to be able to access it like that.
@summer sequoia @serene light about to help me before my community call?
β β β β β ! process "/src/dagger/entrypoint.php" did not complete successfully: exit code: 1
Error: failed to serve module: input: moduleSource.asModule failed to load dependencies as modules: failed to load module dependencies: select: failed to call module "php" to get functions: process "/src/dagger/entrypoint.php" did not complete successfully: exit code: 1
Existing codebase, I upgraded dagger to the latest
tried dagger develop ?
there seems to be some over zelous caching of module dependencies going on hit us earlier
Nope.
Trying
β ModuleSource.generatedContextDirectory: Directory! 1.5s
! failed to load dependencies as modules: failed to load module dependencies: select: failed to call module "php" to get functions: process "/src/dagger/entrypoint.php" did not complete successfully: exit code: 1
Error: failed to generate code: input: moduleSource.withEngineVersion.generatedContextDirectory failed to load dependencies as modules: failed to load module dependencies: select: failed to call module "php" to get functions: process "/src/dagger/entrypoint.php" did not complete successfully: exit code: 1
does the dependant module work independently?
if so; might need to a) update the engine version in the dagger.json of the module; b) update any dependencies it uses; c) remove composer.lock from the dependency repository (temp until the fix for this goes in)
you may have the same issue tbh#
if the module was created on an older version of the engine; good chance you hit the composer.lock issue with it
You might be able to get round it if you install dagger from the development branch
Ignore me, the PR isn't actually in yet
Your best bet if possible is as chris said, remove the composer.lock from the module
Please send me URLs to more examples
so I need our custom PHP module @summer sequoia @serene light
for extensions
and such
regarding extensions, I setup this module to make setting up a php environment a littler easier: https://github.com/jasonmccallister/dagger-php
we already have one for a few months now, and it's written in PHP
thanks for replying tho
@cunning pine feel free to add examples on your readme
on how to use it, from PHP
I had an example PHP module, but I've been focusing on Sai recently as a more general purpose toolkit
I don't have any example modules unfortunately
It's fine, I used my phpstan() daggerverse module, for the community call demo
return dag()->phpstan()->analyze('8.4', $this->source, './app');
PS: don't format your OS the day before you're due to do demos π
@summer sequoia can you link me to some examples of using our PHP module, for extension installations?
I'll try to find some time to document Sai to add some examples
Found some old usage of it, onan older version of the SDK
$container = $this->client->php()->cli('8.2');
$container = $this->client->php()->withExtension($container, 'pdo_mysql');
$container = $this->client->php()->withExtension($container, 'intl');
$container = $this->client->php()->withExtension($container, 'gmp');
$container = $this->client->php()->withExtension($container, 'gd');
New version should probably be something like
dag()->php()->cli('8.2')->withExtensions(['intl', 'gmp', 'gd'])
Hey Team! Here is the new "base snippet" for the PHP community - I've given it to @inner walrus to review and update our Blog Post Announcement .. and we can use this for "intro to dagger PHP" too.
https://gist.github.com/dragoonis/5e10df970f062324afbd8f549b960298
This is what we can use to teach people.
Lesson #1 of our tutorials. People can add this to ANY php project (mostly) and have it execute tests
@summer sequoia I need the URL to our PHP system builder package we worked on .. can you link me to it please? I want to review it and also bring it up to date with latest PHP SDK and test it out .. then it's ready for documentation stuff.
Do you mean this: https://github.com/carnage/dagger-php-module/blob/main/dagger/src/PHPContainer.php
aye
Usage is how you described the update you wanted
@inner walrus @cunning pine @summer sequoia @serene light
Here is the "Dagger PHP" github organisation I was talking about. I will get you guys added to it. It will be where we host our "official community dagger modules" for popular things.
Like SymfonyCli, phpstan, psalm, drupal, magento, laravel .. and so on I already have the modules on my personal github, but it shouldn't live there it should be part of the community
I have 2-3 laravel project build stuff already made, I'll publish it soon too
Symfony is in progress
QA tools are complete, need moving over to the organisation
For our modules we will have to
- Write good docs
- Tag releases so they're pinned against specific dagger engine versions. As dagger engine team try to innovate and change/break stuff, we need to allow them to do so, so we can separate by "tag"
phpstan module - discussion
Hi, how do you solve the issue with Dagger performance due to missing cache in CI? I mean, every time Dagger builds its cache in CI, so simple call takes up to 5 minutes in GitLab. I saw Depot, but it's paid (I'm doing open-source mostly, so that's not an option). Do you solve it somehow, or just doesn't care about it? Thanks in advance! If you have any examples I'd be great to see them π .
Using free GitLab runners or your own cluster?
Thread
Hey PHP Daggernauts!
If you're looking for a way to get involved, we have a number of docs issues open that we'd all be glad to review and merge PRs on.
https://github.com/dagger/dagger/issues/9790 (parent issue)
Overall the PHP docs are really solid, but this set will make it stellar. Could be a great first issue for someone. π€©
If you'd like to claim one, I'd suggest leaving a comment on the issue to say you're working on it and get a draft PR up as soon as you can with your first commit in it. Make sure to put something like fixes #9779 in the PR description so the issue and PR will be linked up. 
Then when you've got all of your commits in, you can make it ready for review and drop it in here. π
Thanks in advance! We're close to having full docs coverage for PHP. π
Hi, is there an issue/PR about daggerverse in the PHP SDK? what is the progress?
based on my test (dagger install ...) and this issue I guess this is not ready yet
What is the issue? Add PHP-specific details to https://docs.dagger.io/api/daggerverse/
You should be able to use daggerverse and install modules without issue. π
[That issue](#php message) is for being able to show examples on published modules, which is not currently ready.
TLDR; modules work fine but you can't add much documentation to them
when I try, I got an error:
$ dagger init --sdk=php .
# ok
$ dagger install github.com/sagikazarmark/daggerverse/gh@v0.11.0
Warning: Undefined array key "description" in /sdk/vendor/webonyx/graphql-php/src/Utils/BuildClientSchema.php on line 363
Warning: Undefined array key "description" in /sdk/vendor/webonyx/graphql-php/src/Utils/BuildClientSchema.php on line 363
Warning: Undefined array key "description" in /sdk/vendor/webonyx/graphql-php/src/Utils/BuildClientSchema.php on line 428
Warning: Undefined array key "description" in /sdk/vendor/webonyx/graphql-php/src/Utils/BuildClientSchema.php on line 363
Warning: Undefined array key "description" in /sdk/vendor/webonyx/graphql-php/src/Utils/BuildClientSchema.php on line 363
Warning: Undefined array key "description" in /sdk/vendor/webonyx/graphql-php/src/Utils/BuildClientSchema.php on line 363
[INFO] Generating scalar 'CacheVolumeID'
...
Fatal error: Uncaught TypeError: Nette\PhpGenerator\ClassLike::addComment(): Argument #1 ($val) must be of type string, null given, called in /sdk/src/Codegen/Introspection/EnumVisitor.php on line 20 and defined in /sdk/vendor/nette/php-generator/src/PhpGenerator/Traits/CommentAware.php:37
Stack trace:
#0 /sdk/src/Codegen/Introspection/EnumVisitor.php(20): Nette\PhpGenerator\ClassLike->addComment(NULL)
#1 /sdk/src/Codegen/Introspection/AbstractVisitor.php(20): Dagger\Codegen\Introspection\EnumVisitor->generateType(Object(GraphQL\Type\Definition\EnumType))
#2 /sdk/src/Codegen/Introspection/CodegenVisitor.php(45): Dagger\Codegen\Introspection\AbstractVisitor->visit(Object(GraphQL\Type\Definition\EnumType))
#3 /sdk/src/Codegen/Codegen.php(61): Dagger\Codegen\Introspection\CodegenVisitor->visitEnum(Object(GraphQL\Type\Definition\EnumType))
#4 /sdk/src/Command/CodegenCommand.php(61): Dagger\Codegen\Codegen->generate()
Have you encountered this issue trying to install other modules?
indeed, this works with an other module. thx
Thank you for pointing it out, there is probably an underlying issue here that we will need to check out.
Also thank you for the replicable stack trace π
Found some duplicate code between .dagger/sdk_php.go and sdk/php/dev/src/PhpSdkDev.php.
Going to try and transfer some of that code from the Go to PHP side
PHP SDK devs: just checking that you actively use the module github.com/dagger/dagger/sdk/php/dev, and it accurately represents an up-to-date toolchain? In particular that container build. Can I rely on it over the one built in sdk_php.go?
They look very very similar
You're welcome to give it a go, it's referenced in issue #8125. It's been on the backburner, I never quite got round to solving it.
sdk/php/dev is the developer module used for running unit tests and linting on the sdk itself. It hasn't been updated in a while but it is an actively used as part of development.
^ Also, if it isn't the up-to-date toolchain, it will be.
I want to make extensive use of that module for testing the SDK. π
@obsidian forge Do you have any idea how to do this bit in PHP?
dirOpts := dagger.ContainerWithDirectoryOpts{
Exclude: "*.md*",
}
I'm trying to write the filters bits of the docs. I've never used this method before.
const dirOpts = { exclude: ["*.md*"] }
Typescript just seems to be an anonymous object?
I'm assuming in PHP it's just
$dirOpts = ['exclude' => ['*.md*']];
But I'll be honest, I'm not really sure what purpose these snippets serve: https://docs.dagger.io/api/filters#post-call-filtering
When you pass a directory to a Dagger Function as argument, Dagger uploads everything in that directory tree to the Dagger Engine. For large monorepos or directories containing large-sized files, this can significantly slow down your Dagger Function while filesystem contents are transferred. To mitigate this problem, Dagger lets you apply filter...
so in php it looks like this: https://github.com/dagger/dagger/blob/e2be4eaedc36f1c65efcff760cae4d596e323b82/sdk/php/generated/Directory.php#L204-L212
it's just an optional arg
the reason it's the struct in go is because go doesn't haven't optional args
it's like that in ts, because that's a pretty common pattern
you just need to pass exclude, and override the option
Ah thank you, in that case, I think showing it as a PHP array is probably the right call.
Because you can throw that into a call like this: directory('/src', $source, ...$dirOpts)
And it would be treated as identical to directory('src/', $source, exclude: ['*.md*'])
yup, exactly
it's much neater in a language that has features (i guess the closest parallel here for you is actually python)
since it has the *args and **kwargs spread operators
Does anyone have a working php example template for container or helm chart builds?
How does one work with state / getters with the php sdk? I can add the snippet here if someone points me in the right direction π https://docs.dagger.io/api/state?sdk=java
<?php
declare(strict_types=1);
namespace DaggerModule;
use Dagger\Attribute\DaggerFunction;
use Dagger\Attribute\DaggerObject;
use Dagger\Attribute\Doc;
#[DaggerObject]
#[Doc('A module that provides greeting functionality')]
class MyModule
{
/**
* @var string
*/
#[DaggerFunction]
#[Doc('The greeting to use')]
private string $greeting;
/**
* @var string
*/
#[Doc('Who to greet')]
private string $name;
/**
* Constructor for MyModule
*
* @param string $greeting The greeting to use
* @param string $name Who to greet
*/
public function __construct(string $greeting = 'Hello', string $name = 'World')
{
$this->greeting = $greeting;
$this->name = $name;
}
#[DaggerFunction]
#[Doc('Return the greeting message')]
public function message(): string
{
return "{$this->greeting}, {$this->name}!";
}
}
I see what you mean. I couldn't get a getter by decorating with
#[DaggerFunction]
#[Doc('The greeting to use')]
private string $greeting;
nor did public work vs private.
Yeah I tried a bunch of different things and dug around in the sdk code and I think it's not supported. I left the getter getSource in the php snippet in my PR to account for that
It seemed like we need a Dagger\Attribute\DaggerField to be consistent with the other SDKs. I can open an issue. If I'm missing some current way to do this I'll close it π
@lusty grove @inner walrus Apologies, they have not been implemented yet.
cc @summer sequoia @green otter
It seemed like we need a Dagger\Attribute\DaggerField to be consistent with the other SDKs. I can open an issue.
For the PHP SDK, functions are only exposed if they are annotated with Dagger\Attribute\DaggerFunction and they have public visibility.
My inclination is to do the same for public properties.
My reasoning can be explained with this class:
class MyModule
{
#[DaggerField]
public string $greeting;
#[DaggerFunction]
public function greeting(): string
{
return "{$this->greeting}, Dagger!";
}
}
This is allowed in PHP, but to Dagger... we would expose two identically named functions. Best case scenario: it prints a meaningful error.
I suspect this will confuse users as they would seem like separate things.
My hope is, by reusing DaggerFunction , like typescript does the overlap will be clearer.
class MyModule
{
#[DaggerFunction]
public string $greeting;
#[DaggerFunction]
public function greeting(): string
{
return "{$this->greeting}, Dagger!";
}
}
Obviously; open to discussion by anyone
you might be able to expose one of the fancy getter/setter functions that have been added to PHP recently; but the SDK doesn't currently support exposing fields directly
That would be a meaningful reason for us to upgrade to PHP 8.4
mmm, couldn't remember if they were in 8.3 or 8.4
I forgot too, just checked. It's 8.4
That said, I don't think PHP is treating those getters and setters as functions is it?
Are they not just hooks on accessing/setting the property?
i.e. This is still allowed
class MyModule
{
public string $greeting {
#[DaggerFunction]
get {
return $this->greeting;
}
}
#[DaggerFunction]
public function greeting(): string
{
return "{$this->greeting}, Dagger!";
}
}
If this is allowed by PHP, then it would cause the same issue: Two identically named functions being exposed to Dagger
Yeah, I'd just return an error if there's a conflict.
In that case, keeping it simple I propose :
- Stick with 8.2 (until a meaningful reason to upgrade presents itself)
- Reuse
DaggerFunction(to hint the overlap to users) - Only expose public properties (consistent with exposing functions)
- Ensure a useful error is returned for naming conflicts.
Another issue with the getter is that the API won't call the PHP getter if there's additional logic there. It will return the value it has for the field directly.
Under the hood the engine creates a getter function for the field, without arguments, but it's executed inside the engine, not relayed to the SDK.
Ah, in other words the 8.4 property hooks would not work?
public string $greeting {
#[DaggerFunction]
get {
return $this->greeting . ", World!";
}
}
i.e. In the above case, if $greeting === "Hello" then Dagger will return "Hello"
Correct
The SDK can still support getter functions, but it's best to report them as a normal function, not as a field.
Fields are faster though, because they don't take the round trip to the SDK, so need to keep that in mind.
That's definitely food for thought.
For now, we don't support property hooks, so the simple approach above should suffice.
I won't be implementing it today, so there's still time to mull it over.
While you're around, @cobalt pelican
Is there a change log that would help SDK maintainers keep up to date with what features/changes should be implemented?
Currently, I only tend to find out when an issue arises or I happen to read part of the docs and go "Huh, I haven't added that to PHP yet"
Currently not, but it's a good idea. Haven't been able to invest time in documenting more on creating an SDK.
I would really like that, even something like a "sdk-dev announcements" on discord
Yeah, or just an #sdk-dev channel next to #engine-dev for things that touch all SDKs. We can mention for announcements. \cc @tropic whale
Hey ! Long time since I played with dagger. I am trying to get back on it for a simple usecase. But I ran into a question. If you look here https://hub.docker.com/r/composer/composer you'll see that it would be best to add volumes for composer home / cache dir and so on. But locally these are defined through env variable. Is there any way to have something like #[DefaultPath('${COMPOSER_HOME:-$HOME/.config/composer}')] ? Maybe this is global to dagger and not PHP specifically ?
Using environment variables in default paths would be global dagger functionality rather than PHP specifically.
I'm not sure it's possible, and I don't believe it will be. For security reasons: You can't provide paths outside of your dagger module
It is possible to assign a default path for a Directory or File argument in a Dagger Function. Dagger will automatically use this default path when no value is specified for the argument. The Directory or File loaded in this manner is not merely a string, but the actual filesystem state of the directory or file.
So I would presume that getting access to environment variables could be a security issue as well.
That said, if caching is your concern; Dagger will cache calls with identical arguments, so if you separate your composer step enough, it will be cached.
For instance:
private function getVendor(
File $composerJson,
File $composerLock
): Directory {
return dag()
->container()
->from('composer/composer')
->withFile('/app/composer.json', $composerJson)
->withFile('/app/composer.lock', $composerLock)
->withWorkdir('/app')
->withExec(['composer', 'install'])
->directory('/app/vendor');
}
Now you have a call to get your vendor/ directory which will be cached until you make any changes to your composer.json or composer.lock
You'll have to manually insert it into your app but the time saved on dagger calls is well worth it.
ok thanks. will check it out. but regarding caching (just tried on github action) and I thought the "load module" part would get cached or something. It takes 17s on my local machine and I think about the same time on github actions...
Ah, hmm... I'm not sure about that initial step. I expect someone from the core Dagger team would be better suited to answer that question.
cc @obsidian forge @cobalt pelican Do you have any insight on Adrien's problem? π
regarding caching (just tried on github action) and I thought the "load module" part would get cached or something. It takes 17s on my local machine and I think about the same time on github actions...
You guys need to benchmark loading a simple PHP module (without a git repo). The SDK module can perhaps be better optimized. We have a workflow that runs periodically for the 3 official SDKS: https://github.com/dagger/dagger/blob/e79b3347c89d614f9eb6677d29aa0b3cffbbc955/.github/workflows/benchmark.yml#L20-L56
If it's looking good on that end it could be that @karmic tendon is uploading more context than intended (think docker build context). Similarly to #1379046207527325746 message, try running this (assuming running from the directory where your module is):
dagger -M -c '.core | module-source . | context-directory | glob "**"'
If you see the vendor directory this could be slowing you down but I'd expect a second dagger functions would be much faster (i.e., cached). This is something the PHP SDK maintainers can try as well, and add anything that shouldn't be there in dagger.json exclude.
The DefaultPath is not a path from your host. It's relative to either your git repo root, or the module's directory if not inside a git repo.
Try adding both to exclude list like in https://github.com/dagger/dagger/blob/ae3eb2163eb4e99d9849b77951b73c109fbe2ffc/core/integration/testdata/modules/python/git-dep/dagger.json#L4-L7.
Don't include .dagger, assuming you have "source": ".dagger" in your dagger.json. Paths are relative to your source directory.
Basically anything that you have in .gitignore should be excluded in dagger.json. I want to make that automatic at some point. See https://github.com/dagger/dagger/issues/6627.
This is what I am doing at the moment : https://github.com/Jean-Beru/GotenbergBundle/pull/4/files dagger init with php sdk. it takes 18s to laod module and 22s to execute the php script. (which takes arougn 1s locally)
As Helder said, there are probably some optimizations that we could make in the PHP SDK so it is probably slower than the official SDKs
π I understand. regarding defaults. I understand defaults. Just not how to get env variables. I know that it is something that can be any input and the user provide it as an option but I wanted to make it default to not have to provide the values each time. Also I wonder how cache is handled in github action. because one of the promise of dagger was layer caching at every step but if github actions don't persist said cache then I don't see the point... And it just takes longer to run things (by far)
Don't use include, use exclude:
- "include": [
- "!.venv",
- "!sdk"
+ "exclude": [
+ ".venv",
+ "sdk"
],
Github actions caching
modified and ran dagger develop before the dagger call. It still takes around the same time
If you run this again, what do you get?
dagger -M -c '.core | module-source . | context-directory | glob "**"'
same thing as before :/
So vendor and sdk weren't excluded?
wait... when I update to exclude and run dagger develop it seems to rollback the changes
That's strange. Would need to know more, but please make sure. dagger develop shouldn't remove your manually added "exclude" field. Have you fully saved your changes before running that command?
{
"name": "GotenbergBundle",
"engineVersion": "v0.18.9",
"sdk": {
"source": "php"
},
"exclude": [
".venv",
"sdk"
],
"source": ".dagger"
}
yes I have this and it is saved
when I run dagger develop. after ~15s it rollbacks my changes back to the include
{
"name": "GotenbergBundle",
"engineVersion": "v0.18.9",
"sdk": {
"source": "php"
},
"include": [
"!.venv",
"!sdk"
],
"source": ".dagger"
}
What's your dagger version?
$ dagger version
dagger v0.18.9 (docker-image://registry.dagger.io/engine:v0.18.9) darwin/arm64
Hang on
Oh, wow, I can reproduce it. That shouldn't happen! Do you mind creating a bug report in GitHub?
sure. where ?
?
Yes
that's good yup π
Same happens in Go. I wonder if it's because of some latest changes for client generation.
Oh wait, I sort of remember @worthy ice wanting to no longer do two include + exclude. Maybe it should always be include from now on and the engine is normalizing.
even though it doesn't explain why sdk and vendor are in the context
I may be wrong but this bit may help: https://docs.dagger.io/configuration/modules/#file-and-directory-filters
Modules can be configured by editing their dagger.json file. The configuration in there contains all module metadata - from the name of the module and the SDK it uses, to the dependencies it requires. An initial configuration is automatically generated when using dagger init or dagger develop for the first time, and is kept up-to-date with dagge...
If the "context" is in the middle of your calls
Maybe the paths are relative to the root directory. Try adding .dagger/:
"include": [
"!.dagger/.venv",
"!.dagger/sdk"
],
if so that would be weird since all of this is freshly auto generated with dagger init
The "include" isn't auto generated on init. Didn't you add it manually?
nope it was automatic
If you do dagger init --sdk=php new-module are you saying there's an include in dagger.json?
I just ran dagger init --sdk=php but yes
Did you run that on an empty dir?
nope. I ran it at root of my library
ok modifying the include with .dagger/ and adding .dagger/vendor did improve things a bit. We are now at 8s instead of 17
I don't think that's doing what you think. Didn't it add a .dagger to the root of your library? Just add a new directory as in:
dagger init --sdk=php new-module
The new-module was to ensure it created the new module in a new empty dir. If you run dagger init on a dir with existing files it's doing something slightly different.
It doesn't add include on dagger init:
β― cd $(mktemp -d)
β― dagger init --sdk=php my-module
β― cat my-module/dagger.json
{
"name": "my-module",
"engineVersion": "v0.18.9",
"sdk": {
"source": "php"
}
}
tried it with plop and indeed the dagger.json is lighter
but then the dagger.json is not at the root
so any dagger call something must be done withing the plop` folder
I wasn't suggesting you moved your module's location, I was just trying to show you that dagger init doesn't generate "include".
AND you still have the vendor and sdk issue
yeah I understand. it does if you do not execute this on an empty dir
It does not:
β― cd $(mktemp -d)
β― mkdir my-proj
β― cd my-proj
β― git init
β― touch README.md
β― git add .
β― git commit -m "initial commit"
β― dagger init --sdk=php
β― cat dagger.json
{
"name": "my-proj",
"engineVersion": "v0.18.9",
"sdk": {
"source": "php"
},
"source": ".dagger"
}
weird it didn't to me either this time... But I'm sure I didn't touched this file... so which command add includes like this ?
Are you sure you didn't add them after I suggested it?
I just ran dagger develop and dagger call commands
maybe... sorry I can't remember
either way thanks to your help we reduced a bit the "load" time.
Oh, one other thing. You copied .venv which is the virtual environment from Python. You want that to be vendor. So:
{
"name": "GotenbergBundle",
"engineVersion": "v0.18.9",
"sdk": {
"source": "php"
},
"include": [
"!.dagger/vendor",
"!.dagger/sdk"
],
"source": ".dagger"
}
Is this something that should be automatically generated by the SDK? Since it does seem to make it faster.
Yeah, possibly. I was just hoping we didn't have to if we had https://github.com/dagger/dagger/issues/6627. I was working on that last year but had to move to other things. Then @worthy ice reassigned but he has other priorities rn.
@karmic tendon this is how I do composer stuff to have the composer cache mounted and kept around by dagger: https://github.com/sai-php/sai/blob/main/dagger/src/PHPContainer.php#L78
there's also a trick here: https://github.com/sai-php/sai/blob/main/dagger/src/Composer.php#L29 which makes better use of dagger's caches when installing composer dependencies
thank. will have a close look π
I think I spotted an issue with ReturnsAsList attribute and wanted to contribute. But the install with docker compose up -d fails with "./hack/dev": stat ./hack/dev: no such file or directory: unknown does that ring a bell ?
I don't think I used docker compose for the setup at all: this discussion might help: [dev instructions](#1359449990036066355 message)
I think you just use dagger to build dagger
mmm yeah the docker-compose file might need to be removed actually
i had no idea it existed, that's definitely not the intended way to get a dev setup
to build the engine, you want to just run ./hack/dev
ok so I have to fork dagger/dagger instead of dagger-php-sdk ?
OH missed it on the About section. usually it is in readme or maybe UI changed in github. didn't noticed. thanks.
so I forked and ran the hack/dev now if I make changes to the PHP sdk. waht is the procedure ?
- in dagger.json/source I must point toward myforked-dagger/sdk/php
but do I need to run hack/dev at every change ?
I am trying
"sdk": {
"source": "../dagger/sdk/php"
},
and running dagger develop but it doesn't work
I didn't find any documentation on how to set everything up locally for contribution
The "../dagger/sdk/php" SDK does not exist.
There is probably a more streamlined way, but when I want to test it with a module I push it to git and label the source as my branch
So it ends up being "source": "github.com/<my-username>/dagger/sdk/php@<my-branch>"
Or something like that. cc @obsidian forge any better methods?
you can set source to a local path
this should work?
the path is relative to your dagger.json for the module
dagger.json is at the root of my project. the project and the fork are siblings. I use "source": "../dagger/sdk/php" so it should be good ?
but it does'nt :/
Hold on.
It might need to be ../dagger/sdk/php/runtime
mm.. maybe? It's been a while.
nope :/
Yeah ignore me. I'm looking at it now. the dagger.json file is in sdk/php
and that points to runtime, so it should be fine.
Are you seeing this error?
Error: failed to get local context directory path: input: moduleSource failed to load sdk for local module source: local module dep source path "../dagger/sdk/php" escapes context
This is what I get if I try what you're doing
It seems to me, that a local path in a different directory is not allowed for security purposes
failed to load sdk for local module source: local module dep source path "../dagger/sdk/php/runtime" escapes context "/xxx/xxxx/xxxx/GotenbergBundle": unknown builtin sdk
Yeah so, it is telling you it escapes context. Which, for security, dagger can only accept paths that are at the same level or lower in the file system.
So if dagger.json is not right next to the directory you're accessing, it can't access it.
Going up a directory is not allowed in this instance
This works:
{
"name": "scratch",
"engineVersion": "v0.18.9",
"sdk": {
"source": "dagger/sdk/php"
},
"source": "scratch"
}
Where my file structure looks like this:
drwxrwxr-x 37 4.0K May 28 15:50 dagger/
-rw-r--r-- 1 124 Jun 12 14:38 dagger.json
drwxr-xr-x 5 4.0K Jun 12 14:38 scratch/
You can give it a go, I've not tried that but it might work
yup it seems to be working (no errors for the moment)
still : If I change something on the SDK shoud I run dagger develop each time ?
I think so, yes for changes to the SDK you will need to.
ok thank you
No problem, thank you for wanting to contribute π
very small fix : https://github.com/dagger/dagger/pull/10577
Ah, hmm. I think there's a reason we cannot do this
I may be mistaken, or outdated knowledge. But I believe the real issue is that dagger has no defined way to display nested arrays in stdout
@obsidian forge Does this sound correct?
I understand. but then why ReturnsListOfTypes accept a ListOfType ?
Hold on, I'll have a look at it and refresh myself
no worries. I'm done for the day π Let me know if I need to change something I'll be happy to help
you definitely can do it, it should display!
you're right though, it didn't used to
Oh I see, that is good to know!
When we implemented it, I think only flat arrays could be returned so we limited it purposefully.
Thank you π
no worries. I'm done for the day π Let
Just to double check.
Is passing nested arrays as arguments over CLI still unsupported? Last time I checked it that wasn't allowed because no format had been agreed upon for how you'd represent it.
i.e. [Int]: --my-array=1,2,3 [[Int]]: ???
I don't think it's supported on the cli, you're right
cc @cobalt pelican
but it's still possible to do so from other code or using a raw graphql query
so the sdks should ideally still support it
Yeah. I think it may be supported already. I was just curious what shiny new toys we had π€©
why not multiple --arg ? like --keyword=plop --keyword=plip ?
That might work for [[Int]], but it wouldn't work for [[[Int]]] and so on
--keyword-level0-level1=value ?
It could work, but it's a bit messy and probably a lot more work than it's worth.
We can still pass nested arrays between functions, just not over CLI.
That could be supported but in shell, probably never in dagger call.
Hello everyone
Hi everyone.
I am pleased to say I submitted a talk to SymfonyCon about dagger (PHP SDK).
Based on @green otter 's last year at Vienna, mine will be focused on a real-world use case using https://github.com/sensiolabs/GotenbergBundle/pull/168 .
I don't know yet if I'll be selected but I'd like for people in this channel to review the PR if possible and point out best practices regarding dagger. For things like performances / caches and DX.
Thank you in advance ! π
I put in a few suggestions in a review π
thanks. will have a look π sorry about the previous PR didn't find much time since then to try to contribute the tests. Hanging on until the holidays...
Not a problem. The integration tests are a WIP so I can add them during another pass anyway
Hi all ! I'm curious what you guys are using dagger for with PHP, I saw some cool examples in the introduction for the community SDK, but wondering if there's been any cool/unique/helpful ways to use it π
and on the off chance someone is using phalcon...
did the changes. Still bothered by the $result = [] which I find is not very friendly DX wise and waits for everything to finish (the whole matrix) before rendering anything.
Wouldn't there be a way to :
- do the foreach loop in parallell
- output as it goes ?
Hi ! My usecase for example is a Symfony Bundle. To properly test a bundle you should check it against several PHP / Symfony versions. But to do so locally is very cumbersome manually or to automate with a script (and error prone). With dagger, it made it easy and isolated.
Running a CI Matrix in parallel
@obsidian forge While I'm already pestering you, I've been watching enum support enthusiastically. Is it time?
yes!
ahaha sorry i so forgot to tell you about this
so. we shipped it, and also finally seem to have ironed out all the bugs that we shipped alongside it π
Nice! π
I'll have to look at what I'd done before, but i'm looking forward to adding that in π
lemme know if you hit anything - also happy to jump on a quick call or something if you want to chat through what would need doing
Brilliant will do π
π @serene light just wanted to flag https://github.com/dagger/dagger/issues/10823, in case you hadn't seen it π
seems familiar to https://github.com/dagger/dagger/pull/10577 ?
Thanks Justin, I'll help them out with that one
Just noticed there's a similar misleading error if a user passes an argument without an attribute. I'll fix that today and let you know
hi all. FYI thanks to @serene light review we finally merged and migrated officially to dagger on our Symfony Bundle : https://github.com/sensiolabs/GotenbergBundle/pull/168 . Now trying to add pie to the native dagger sdk php image so we can easily add new extensions without being too much restricted. Also I wondered... because sdk are simple strings ATM. like php. Wouldn't it make sens to have something like php:8.3 with php being equivalent to php:latest for example ? WDYT ? Should I open an issue on dagger itself to talk about this ?
The "php" string is actually just an alias for the github url that points to the the dagger php sdk. So I think changing that string isn't much of an option.
If we supported multiple versions I think it would have to be done with a new keyword. I believe Typescript did something similar to pick which package manager you wanted to use.
That's a big if though, because I suspect it would be a large task and a heavy maintenance burden as I don't believe any other SDK allows different language versions, not even the SDKs maintained by the core team.
cc @obsidian forge am I right about this?
@karmic tendon For reference, here's the alias being added https://github.com/dagger/dagger/pull/8067/files#diff-0f56671aa816ba46aa7ca99e164f99cb39d656cea7c4293b9b475b30030ea8ee
This allows users to use elixir to use the elixir SDK, and php to use the php SDK, without needing the full github.com/dagger/dagger/sdk/<sdk>/runtime@<version> URL whic...
But I think it would make totally sense. Because ATM dagger is relatively new so it is ok. But whenever a change like the PHP runtime version is done, there is a big risk that CIs will break. Thus not complying with the promise by design. WDYT ?
For the end-user, if they get CI working using Dagger version 0.18.4, which uses PHP 8.2. They can stay on version 0.18.4 forever if they want and it will not break, it will use PHP8.2 forever.
If we then upgrade the SDK to PHP 8.4, it would only affect new versions of Dagger.
So I don't think it breaks any promises in that regard.
It works similarly to other tools like PHPUnit or PHPStan, where later versions sometimes require later versions of PHP.
If we were to upgrade PHP to a version that introduced BC breaks, I would recommend we try and time the change with the next minor version (since there is no major version yet, this would be acceptable use of sem ver)
I'm not against the idea. I think if we could, it would be very cool to support multiple PHP versions. I'm just saying it's probably quite a big task
you can add php@dagger-tag in dagger.json to select a specific version of the dagger sdk
for supporting multiple versions of php, that would be neat? both typescript and python support this
they read from the package.json or pyproject.toml
Oh they do? Interesting, does it add much maintenance?
we don't bother for go, since go's backwards compatbility essentially guarantees to never break anything (and this mostly holds)
cc @shy goblet
It might break or at least causes problems because modules that you require may not be compatible. Each module should be able to require a specific PHP version IMO
yeah, each module would need to specify the version it wants
overriding globally is a big no
Wouldn't each module just be going through dagger anyway? And just use the appropriate version of the engine? (not rhetorical, genuinely curious)
so the way that ts/python work is that they read the module's package.json or whatever. then the sdk uses that python:version image to actually execute the runtime
everything still goes through the engine
but overriding globally (except for updating the default), is kinda tricky because a module might require a specific version for some reason
But what I mean is, if you have some old module using a php:8.2 image, then in the distant future use a module with a php:9.0 image... that should still work shouldn't it?
Even using both modules in tandem
yeah, they would both have separate Runtimes (as defined in the SDK)
I thought as much, since I can use a Go module inside a PHP module, it seemed natural that I could use an old PHP module inside a new PHP module
On an absolutely, completely superficial and utterly pointless, yet entirely desired, note... any chance PHP can get it's own arbitrarily coloured circle to the left of our names like other languages? π (perhaps a nice blue? https://www.elephpant.com/)
Special version:
"dagger": {
"runtime": "node@20.15.0"
}
You can also completely override the base image of the SDK runtime if you want: https://docs.dagger.io/configuration/modules/?ts_runtime=nodejs#alternative-base-images
As long as its alpine based it will work
Thanks @shy goblet it sounds like it might be worthwhile for PHP as well then. π
@karmic tendon I think if we were to implement it, we should stick closely to Tom's example. i.e. in composer.json using the extra keyword for arbitrary data
"extra": {
"dagger": {
"runtime": "php:8.4@cli-alpine"
}
}
A Dependency Manager for PHP
You could also do it from the dagger.json, we support extra configuration now
I think @pine bridge did it already for java
Ah, that would probably be much simpler, thank you!
Especially since the image is currently decided by the underlying Go module
Check the java SDK, I think there's an extra config somewhere
It's withConfig on module: https://github.com/dagger/dagger/blob/0026f7da8e5fea15daf626f08f6fce4a607b46d5/core/sdk/module.go#L98
thanks I'll take a look. So it would be a per module configuration ? If a module B is required by project A then to each their own images right ?
Yeah, each module would specify their image separately via their dagger.json
@pine bridge Does the Java SDK get affected by picking a different image?
To be clear, my concern is this:
Lets say you use new features of the Java language, then someone uses an old image, would this break the SDK?
Basically, are you limited to versions that don't break compatibility with the SDK's code?
I'm just trying to wrap my head around it
The Java SDK is providing some configuration in the dagger.json but not the java image used.
If I had to, that's where I would put it.
But yes, once you do that, you start to deal with compatibility issues.
Maybe it could be possible to check some of the components? For instance to quickly instanciate a container from the image and check things like php version (or any other component) and if that doesn't match requirements fail with an error message?
That way you can allow users to pick the image they want but guarantee it works.
(I haven't followed the whole discussion so maybe that doesn't match your needs, just thinking out loud)
Lots of things to think about ... To sum up :
- I am trying to add PHP/pie to the container so it installs PHP extensions on the fly.
- How do we ensure forward compatibility with newer modules / PHP versions
The global answer is that we could provide some configuration through the dagger.json for both some extensions / images and ensure everything is coherent with checking the composer.json file.
How do we ensure forward compatibility with newer modules / PHP versions
I think this point is already covered by Dagger's language agnostic feature, we can already use completely different languages from other modules, so using a slightly older/newer PHP is a non-issue.
The only time forward compatibility breaks is if a new version of Dagger introduced BC breaks. Which would happen no matter what the PHP SDK does.
That's brilliant thank you, exactly what I was after.
I'm weighing up the pros and cons atm
I am trying to add PHP/pie to the container so it installs PHP extensions on the fly.
I think if php/pie were introduced it would be best to just stick to composer.json since that's the advantage of it.
If we were writing it in the dagger.json we might as well use PECL, which is more mature.
PIE has not officially replaced PECL (yet) and looking at the supported libraries: PIE's <70 extensions vs. PECL's 436 I would be hesitant to introduce PIE as a core part of the SDK.
As an "opt-in" feature, it would be cool and future-proof us for when PIE does take over
But I don't think it would make sense as the default; end-users shouldn't need to know why some of their extensions installed and the rest didn't.
So a "withPie": true should have to be explicitly set by the user in their dagger.json, where the default is false.
That way, only users who know exactly what they're signing up for would use it.
Then, when PIE does fully replace PECL, we could set the default to true
Yes. What I had in mind. Trying to push pie forward but cannot solely rely on it at the moment
I agree, having it all in composer.json would really neaten things up.
And end-users getting all their extensions in for free βΊοΈ now that would be some nice UX
I'm not really sure on what the value is of being able to install extensions or specify a PHP version for dagger modules? You are mostly writing code to orchestrate containers; if you need a specific version you can just build a container with that version, the extensions you need and run your build step inside that container.
For example I tried to install pcntl to use the forking process trick to try parallel building. Not available. Seems overkill to do dagger in dagger
I do think that we need to handle parallelism better; perhaps the base image could include the pcntl extension, but if we were to do that I'd want to have some examples of how to make it work properly in the docs, cause I'm sure there will be good ways and bad ways to do it
On this, I wonder if there are other possibilities such as using curl multi to do several graphql requests at the same time; would be similar to the async options in other sdks
I assume we'd have to dig into the client code a bit more for that one?
In the other sdks, Container.sync() returns a Container. In the PHP SDK, it returns a ContainerId.
Can you help me correct the function below? It fails because of this type mismatch
#[DaggerObject]
class MyModule
{
#[DaggerFunction]
public function copyDirectoryWithExclusions(
// source directory
#[Ignore('*', '!**/*.md')]
Directory $source,
): Container {
return dag()
->container()
->from('alpine:latest')
->withDirectory('/src', $source)
->sync();
}
}
guessing the solution is to not call sync() but checking
is it mandatory for dagger functions in php to have a return type? if so, what should it be for this function?
#[DaggerFunction]
public function copyFile(
// source file
File $source
) {
$source->export('foo.txt');
// your custom logic here
// for example, read and print the file in the Dagger Engine container
echo file_get_contents('foo.txt');
}
[ERROR] DaggerFunction "copyFile" cannot be supported without a return type
void is the return type when nothing is returned.
#[DaggerFunction]
public function copyFile(
// source file
File $source
): void {
$source->export('foo.txt');
// your custom logic here
// for example, read and print the file in the Dagger Engine container
echo file_get_contents('foo.txt');
}
@zealous venture as a side note, I saw this comment: https://github.com/dagger/dagger/pull/10978#discussion_r2319799584
Returning void here since it looks like a return type is mandatory for PHP Dagger functions** (unlike other SDKs)** and this didn't work otherwise.
In what instances are return types optional in other SDKs?
I was referring to this example which has functions without a return type mentioned: https://docs.dagger.io/cookbook/filesystems?sdk=go#copy-a-file-to-the-dagger-module-runtime-container-for-custom-processing
I noted that when you run the Go function, for example, although it doesn't have a return type specified, it works and returns Void. That's different from PHP, where the function doesn't run unless the return type is explicitly specified
Go function run:
$ dagger call copy-file --source=./go.sum
βΆ connect 0.5s
βΆ load module: . 7.8s
β parsing command line arguments 0.1s
β myModule: MyModule! 0.0s
βΆ .copyFile(
β source: Host.file(path: "/home/admin/sandbox/go/go.sum"): File!
): Void 0.7s
Yeah that's good to know, thank you. π
It looks like the official SDK's, without a return type, assume 'Void'. If that is the case, PHP could support it as well.
Yeah, that's worth doing.
I will look into it. It SHOULD be fairly simple, but I'd have to be certain it prints out an incredibly clear error for users that try to return something without a return type
I would say, if possible, you should return a clear error whenever the user returns someting at runtime that doesn't match the return type, not just when no return type is defined.
Yes of course, I believe it already does so. I just need to check that the same logic applies if Void
Hello everyone. So... I am trying to implement what we talked about , Add a "config" key to allow :
- changing php version
- adding pecl modules
- and (maybe) start with pie as well...
To do so, I checked how it was impleemnted in Java and saw that I needed to add a WithConfig method and stuff like this. But now that I want to test it. dagger develop doesn't seem to be enough. So I am trying the ./hack/dev but it fails horribly with the following message
βΌ .loadToDocker(
β β docker: Host.unixSocket(path: "/Users/neirda/.docker/run/docker.sock"): Socket!
β β name: "localhost/dagger-engine.dev"
β ): DaggerEngineLoadedEngine! 9.7s ERROR
β°ββΌ Container.withExec(args: ["/bin/busybox", "--install", "-s"]): Container! 0.3s ERROR
β /bin/busybox: /usr/lib/libc.so.6: version `GLIBC_2.42' not found (required by /bin/busybox)
! process "/bin/busybox --install -s" did not complete successfully: exit code: 1
which prevents me from going further. I am new to go so I don't know if it is related to go or something else (my local machine maybe) any ideas ?
To give a bit more input : my project has a symlink to the fork of dagger and updated the dagger.json like so :
"sdk": {
"source": "dagger/sdk/php",
"config": {
"phpVersion": "8.3"
}
},
ok nevermind... the hack dev is still failing but I need to run armagedon on my docker containers for it to work it seems π
@karmic tendon personally, when I want to test a dev version of the engine, I use this (using a regular stable install of dagger):
-
dagger -c 'dev | terminal': build a complete engine + CLI, then open a terminal in the resulting environment. If I need to mount extra files or set env variables in the container, I can do that as well:dev | with-directory . ./my-test-files | with-env-variable OP_SERVICE_ACCOUNT foobar | terminal -
To run all linters:
dagger -c lint -
To run the full test suite (which is huge..)
dagger -c test | all
TLDR I personally don't use ./hack/dev but I am not a full-blown core engine developer, I contribute various PRs here and there. I know the core devs have a tighter dev loop and rely on ./hack more.
Anyway just my 2c!
Hi @radiant flume . Thank you for your input. At the moment my symlink is very easy to work with but I was a bit confused with how things works so now it should be good. Although using goland from jetbrains I didn't get breakpoints which would be very useful but didn't took the time yet to understand how to set it up properly.
on another note here is my PR https://github.com/dagger/dagger/pull/10991 about php extensions / php-pie and a few other things let me know
There's several bits:
-
The composer image and the PHP image being updated could be one PR and go in as soon as it's ready.
-
The bug fix is brilliant, thank you for spotting it. That can go in immediately as a separate PR.
-
I think installing extensions is trickier, and forgive me if I've forgotten but what user-facing problem are we trying to solve?
- It would install extensions into the SDK image itself, not into the containers you create with it.
This might confuse users a lot, if we tell them they can install extensions automatically. They install pdo_sql, then they call dag()->container() and that container does not have pdo_sql
Hey guys, I'm working on a PR (https://github.com/dagger/dagger/pull/11052) to bump the engine dependency and one of the blocker is gqlgen, they changed the way we disable some validation rules that seems required to make the PHP SDK working well.
The latest gqlgen package automatically enables either ValuesOfCorrectTypeRule or ValuesOfCorrectTypeRuleWithoutSuggestions even if we disable them on our side (see https://github.com/99designs/gqlgen/blob/522517d5cd2356fae51f9945124d2a08eb2d795e/graphql/executor/executor.go#L246-L254)
I see that our CI is green so no tests fails after the changes but I'm wondering if maybe something not tested may broke, is there any tests that we could add to prevent a surprise if we merge it?
Magical world of enums: π§΅
hello php community, any reason to not allow/use php 8.4 on pipeline execution?
Container.withExec(args: ["composer", "update", "--with-all-dependencies", "--minimal-changes", "dagger/dagger"]): Container! 1.6s ERROR
Loading composer repositories with package information
Updating dependencies
Your requirements could not be resolved to an installable set of packages.
Problem 1
- Root composer.json requires php ^8.4 but your php version (8.3.9) does not satisfy that requirement.
! process "composer update --with-all-dependencies --minimal-changes dagger/dagger" did not complete successfully: exit code: 2
any way i can hook into it or do i need to wait for a release that allow is?
hello php community, any reason to not
@serene light . Hi. Just woke up to this : https://github.com/Neirda24/GotenbergBundle/actions/runs/17992975791/job/51186788443 no worries it is nothing critical on my side... but I was wondering, are sha supposed to expire / get overwritten ? If so it makes (at least) the PHP runtime flaky at best don't you think ? Should we target a more specific version to avoid this ? Or set up a mirror somewhere ?
I am trying to regenerate the generated directory for PHP sdk. But I am having a hard time understanding how things work... there are two commands : dagger:codegen and ``dagger:schema codegenrequires theschemafirst. Butschemarequires two env variablesDAGGER_SESSION_PORT&DAGGER_SESSION_TOKENwhich should be set by dagger itself I guess... But then I am looking at where is thedagger:schemaexecuted ? Nowhere to be found in teh dagger repository. Neither in github workflows or in dagger itself... Am I missing something ? So I tried to add a newSchemagengo function asCodegen exists to try to output a file (schema.json) but it is still doesn;t work because there is a CliDownloader` in the PHP sdk which is deprecated that is trying to download the dagger cli... all of this is very confusing. Any guidance would be greatly appreciated ! I see several stuff I'd like to contribute / co-contribute :
- Fix generated classes (order or arguments required / optionals)
- Use / rework Dagger attributes to ease things a bit
- See if I can optimize other part of the code
- Fix a bad detection of windows / darwin (looking for string
winfirst creates a mismatch darwin for windows)
Contributing
someone already tried to use dagger with cypress (cypress GUI I mean) ?
I've not heard of anyone trying it yet, but maybe π€·
in general are there known example of how to forward X11 or similar using dagger ?
A quick look found this for cypress: https://daggerverse.dev/mod/github.com/quartz-technology/daggerverse/cypress@627fc4df7de8ce3bd8710fa08ea2db6cf16712b3
thanks but this seems to be running headless without gui access :/
Ah, sorry, I'm unfamiliar with Cypress
no worries
Someone may have tried it, when you say X11 are we talking about the windowing system?
yup
I'm not sure if anyone has to be honest, I could be wrong. I typically only hover in the PHP channel
cc @obsidian forge
in general are there known example of how to forward X11 or similar using dagger ?
hallo
i have been summoned
it's likely going to look similar to how you do it in docker
so starting a x11 session, and grabbing the x11 socket
but there is an siolation layer added with dagger right ?
won't that be an issue you think ?
it would be similar to what happens when you run them in docker
i think x11 maybe needs --privileged? we have a flag to AsService that does the same thing
essentially, what you'll want to do is pass the x11 unix socket as an input to a dagger function, then you can attach it using WithUnixSocket, and run operations against it using WithExec or AsService
is
#[DaggerFunction]
public function cypress(
#[DefaultPath('.')]
Directory $source,
#[DefaultPath('/tmp/.X11-unix')]
File $x11Socket,
string $display = ':0'
): Cypress {
``` the right approach ? Becaus ethe socket is just a file right ? Or should I use the Socket object from dagger ? never tried it before
I assume that was the DefaultPath attribute, which only works for File and Directory
yes
I think you'll have to pass the socket in manually
Yes. Might be worth to allow that Attribute on Socket as well to ease DX
Or create a DefaultSocket because it can be somethign else than a file I guess
[ERROR] failed to evaluate container: InvalidArgument: InvalidArgument: rpc error: code = InvalidArgument desc = not a socket: /tmp/.X11-unix
so not it apparently (macos)
trying with /X0
seems good so far. Having errors later down but not related to x11 at the moment...
Default paths on Sockets
so I managwed to make it work but clearly it is not stable and require too much work before calling dagger for it to be DX-friendly... :/ too bad
Hello PHP SDK devs π I'm refactoring codegen in our CI, and wondering if Generate() in .dagger/sdk_php.go is expected to include sdk/php/vendor, or if it's safe to exclude that?
We have a fancy new UI for code generation workflows - if your function returns the new Changeset type, the CLI will interactively show you the diff and prompt you to apply it. Sadly, with an included php/vendor directory that experience instantly becomes horrendous
cc <@&946480760016207902> π
I'd say it should be ok to exclude Solomon. vendor in the PHP sdk generally comes from the module code generation step AFAIK
So is it a bug that dagger call sdk generate exports a php vendor?
Because that should be unrelated to modules
checking. 1 sec
I think it is. Particularly because both the .gitignore and the dagger.json in the sdk/php path have the vendor folder
so it seems to me it's safe not to export that folder from the Generate function
@radiant flume Marcos beat me to it but yes, that is most likely a bug and should be removed. Thank you for catching it π
not sure if I'm relevant. but the export of the vendor directory seems to be to improve DX so we don't have to. otherwise it would require to run both dagger develop & compsoer install to make it work. But to run compsoer install we need the export of the generated parts and to generate those parts we need the composer install. am I right ?
BTW I'm happy to share that I will be speaking about dagger and PHP at symfonycon this year ! following @green otter last year at vienna
I will work on my conference and then that would be great if some of you could help me review it to make sure I'm not saying anything completely wrong π
not sure if I'm relevant.
Everyone's input is relevant π
otherwise it would require to run both dagger develop & compsoer install to make it work. But to run compsoer install we need the export of the generated parts and to generate those parts we need the composer install. am I right ?
I will double-check.
@karmic tendon post on #general to announce. Also twitter and LI. Same post. Tag Dagger and me and stuff
soon π
but the export of the vendor directory seems to be to improve DX so we don't have to.
The proposed change shouldn't affect this. AFAIK it's only to ignore local copies to avoid the whole "it works on my machine" issue.
The SDK has always needed to run composer install and include vendor/ to work. So if this change breaks that, the integration tests should fail
The change I'm making affects the generation of the php client library in the core repo. Whenever the engine API schema changes, this has to be done for all SDKs, and the output checked into git.
I am changing the generate function so that it only returns the generated client library (and php reference docs), and not the vendor directory
Does this have any effect on the SDK runtime? a.k.a. sdk/php/runtime/main.go
No
Well except that the PHP runtime imports the Go client
So if your dev version of the PHP runtime requires a new feature in the dev version of the engine, you'll need to dagger call sdk go generate (or just dagger call generate) so that the PHP runtime builds
but that's unrelated to sdk/php/vendor
My understanding is that when a user sets up a module, with "sdk: {"source": "php"} in their dagger.json, that hit's the sdk/php/runtime module which provides what end-users need.
My knowledge outside of sdk/php is fairly shallow atm, so correct me if I'm wrong: Looking at the .dagger/sdk_php.go file it looks like this is mostly for dev use,(tests, linting, doc generation) from the top-level.
If that's correct, then it should be fine to ignore vendor, especially in diffs
Yes that particular generate function is purely for sdk & engine maintainers, to re-generate official client libraries for the different SDKs. Never called by the end user
Sounds fine then, worst case scenario it affects maintainers on dev and we revert it
hey everyone. How can I access the host container image using the PHP SDK ? because dag()-> doesn't have host anymore and the auto resolution of typing Container but passing a local image doesn't work (trying to pull from docker.io)
You might be able to do it with this https://docs.dagger.io/reference/php/dagger/container#method_import
It seems like the host() function should still be there. Did it disappear on the latest tagged release?
(I can confirm it is missing for me as well, using a v0.19.6 module)
host should never been available from a module (whatever the sdk)
The main reason is if not it means any module at any point in the dependency tree could be able to access the host. And that's something quite dangerous
So communication to/from host is only at the very top level.
Ah thank you for clarifying! π
The part I find odd, is that the generated API references still mention the function
yes, because there's the SDK we can integrate as a library in any other kind of code (the "custom application" aspect, cf https://docs.dagger.io/extending/custom-applications/php), and the library that is dedicated for modules. This last one is generated on demand for the modules, as it can also contain the dependencies.
Right, okay so it's accessible through custom applications, interesting. Thank you. I think that resolves my confusion. Thank you @pine bridge
no problem, it's not always obvious π This is a point not always easy, how to allow easy interactions with the host and at the same time security.
One thing for instance on this area as we don't have access to the host, is the ChangeSet object. At any level we can create one, but it will only be the top level (the CLI roughly) that will apply it on the host. So dependencies can expose their need to create files for instance, but the modules themselves will not have access to the host to do it, only the client will do.
Okay but then I think there are a couple of things that dagger could benefit from. Because I am tryiong to migrate to dagger after I've been playing with it for quite soem time now. But :
- This is a project with multiple tests types (phpunit, cypress, phpstan, etc etc)
- a Big Dockerfile for php : the "base" image + extra stage for debug / local or for CI, or for production and also a stage for building assets.
- locally and on CI we have a traefik to replicate the same environement as production with host going through traefik, cuystom certificates for CI
- 1 compose for local, 1 compose for building, 1 compose for cypress tests
all in all it is quite heavy to migrate. So I'd like to migrate step by step and starting with the biggest pain point : cypress tests. So I am trying to migrate only the cypress compsoe file. But to do so :
- I need the docker socket for traefik (No worries I managed but I think a
DefaultSocketwould be a nice addition for DX) - I need built images from the build compose file ==> This is an issue because There is no easy way to do this at the moment. I am exploring the idea of create a new contaienr based on
docker:cliwith the socket mounted, docker save to a tarball and then trying to import fromdag()->container()->import() - Even migrating the build to dagger is not easy because Yes it provides a
Directory::dockerBuildmethod but this does not comply with all docker features : extra context for example
That's about it at the moment π
@karmic tendon I forwarded your message to #daggernauts. Not that it can't be discussed here, the feedback is absolutely welcome. πΈ
But I suspect the Dagger team's expertise might be able to alleviate some of your problems and if not, it's the right channel to discuss proposals which could alleviate your problems in the future.
good thing, especially those feedbacks are generic, they can apply to all sdks and not only php π
and they are very valuable π
thank you both. And I'm happy to try to contribute more to dagger. (I'm giving a talk next week at SymfonyCon about it and my slides are still nto ready π¬
hey all. Is there a way yet to configure function caching with php sdk ? Thanks / because of this. Directories as input are considered part of the cache key. Is there a way to automatically filter something like this
#[DefaultPath('.')]
Directory $source,
to ignore things based on the .gitignore / .dockerignore / something else ? For example we could use dagger to generate files that are ignored (code coverage) by git without having side effect on the cache key.
the next step could be to create a phpunit object that exposes several functions such as getCoverage, displayResult etc etc and cache won't be impacted so everything should run very fast without having to redo everything ?
because AFAIK there isn't a way yet to both output somehting to user and export a directory / changeset. Am I right ?
You can manually ignore things like so:
#[DefaultPath('.')]
#[Ignore(
'.phpunit.cache',
'vendor/',
)]
Directory $source,
You can also manually ignore things from the module itself, using dagger.json.
I do recall automatic ignores based on .gitignore being a frequently sought after feature. Here's the first example I found searching for it:
https://github.com/dagger/dagger/issues/11317
This can be done to take advantage of the cache, as long as the cache continues to exist between calls. i.e. Your mileage may vary between CI pipelines.
You can do something like this:
#[DaggerFunction, Doc('Generate PHPUnit report')]
public function test(): TestReport
{
return new TestReport($this->container->withExec(
args: ['vendor/bin/phpunit', '--log-junit=cov.xml'],
expect: ReturnType::ANY,
));
}
And now you have a TestReport object which has a container with everything you need:
$this->container->stdout(),$this->container->stderr(),$this->container->exitCode(),$this->container->file('cov.xml')
And every step to create the TestReport will be cached.
The most awkward part, I will admit is getting the exit code and stdout/stderr at the same time nicely printed.
This is a bit hacky, as I'm abusing internal SDK knowledge for this one:
#[DaggerFunction('Return test report')]
public function report(): string
{
$exitCode = $this->container->exitCode();
$stdout = $this->container->stdout();
$stderr = $this->container->stderr();
if ($exitCode !== 0) {
throw new QueryError(['errors' => [[
'message' => '',
'extensions' => [
'exitCode' => $exitCode,
'stdout' => $stdout,
'stderr' => $stderr,
]]]]);
}
return $stdout;
}
You can throw any exception you want and your CI will fail, but that QueryError is the exception thrown by the GraphQL library we depend on. So if it fails, it will fail just like it would if you had only just called phpunit and received a non-zero exit code.
You might also just be able to do something clever with a withExec call and echo the stdout then exit 1 but I haven't tried that.
hey. thanks. exactly my point. it is a bit hacky and DX not very great. It is very common in jobs (in pipelines) to have both outputs (plural) and a single exit code and some artifacts (plural).
I want to add some custom exceptions similar to the Python SDK. It has some base exceptions so you know it came from that library
I understand your point, it would be very convenient to get all of it in one call.
My knowledge may be outdated, but I believe that is a current limitation. You can still make several dagger calls within the same step on CI and then fetch everything from it. But as you say, it's a bit awkward.
PS: To be clear, this is a current limitation of Dagger in general, not specifically the PHP SDK.
indeed π
Checking the Github issues I've found this one by Dagger's core maintainers: https://github.com/dagger/dagger/issues/8421
It's a known limitation and there is work going towards it, but it seems to be a huge feat.
I can understand of course, because that would involve us having to return some form of data object, since PHP does not support multiple return types and neither do most of the supported languages.
php does support multiple return types
but the underlying engine does not allow it (dagger)
we could have Directory|Container
Sorry, I meant multiple return values like how Go can return a value and an error, as two separate values.
Either way, I want the feature too βΊοΈ
hmm I see. What about using yield instead then ?
It would allow us to return multiple values as well
or a Custom object dedicated for this.
either way regarding the ignore it is nice I'll probably do it like this But I think supporting external files would be useful so you don't have to repeat yourself multiple times in your dagger source files
@karmic tendon
hmm I see. What about using yield instead then ?
It's possible, but it entirely depends on how it's implemented in Dagger first.
or a Custom object dedicated for this.
That is one of the suggestions (number 3 specifically) and seems to be the preferred option currently.
I personally prefer this option as well.
I think it should also allow for example for a ChangeSet to be considered an error if not empty. Would this DaggerError allow for custom object or just raw strings ?