#php
1 messages Β· Page 2 of 1
Maybe. Let's see how it evolves over time. I'll keep this in mind though, and bring it up with folks to see if it's possible to move it to /
"the customer is always right" 
I just wanted to avoid a worst of both worlds where 1) it's an extra directory layer for dagger users, and 2) it doesn't actually match php dev conventions
@radiant flume majority of all PHP users will not be making reuseable modules .. but instead just Dagger Module/Functions for their existing webapp... inside the same repo
So like
/ci/src/Build.php
/ci/src/UnitTests.php
Kind of thing.
The src directory diferentiates the user module code from the sdk directory containing the auto generated sdk and the vendor directory containing and dependencies the user needs for their module
composer might also choke on trying to point a PSR-4 namespace to the directory which contains the vendor directory as well; not sure, never tried it
that template is designed to look like something a PHP dev would expect a project to look like
And as has sort of been stated already, conventionally, PHP projects tend to keep php files in a src/ directory
Guys, I'm trying to dagger init on an existing PHP project ..
mkdir ci && cd ci
dagger init --sdk=github.com/carnage/dagger/sdk/php/runtime@add-php-runtime --name=gt
β connect 0.8s
β starting engine 0.5s
β starting session 0.1s
β ModuleSource.resolveFromCaller: ModuleSource! 0.4s
! failed to collect local module source deps: failed to get git module sdk: failed to load sdk module github.com/carnage/dagger/sdk/php/runtime@add-php-runtime: select: module name and SDK must be set
Error: failed to generate code: input: moduleSource.withName.withSDK.withSourceSubpath.resolveFromCaller resolve: failed to collect local module source deps: failed to get git module sdk: failed to load sdk module github.com/carnage/dagger/sdk/php/runtime@add-php-runtime: select: module name and SDK must be set
module name and SDK must be set
How is it not set? π€
dagger init --sdk=github.com/carnage/dagger/sdk/php/runtime@**charjr-**add-php-runtime --name=gt
It's a bit awkward because of all the git branches atm... but when initialising it, it seems you need to use the exact branch
I've just resolved that by merging your branch, my branch and toms' branch into a single linear history
it should work with the add-php-runtime branch now
ah okay, I will have to fetch the latest changes
ummm .. I am using the original branch we've been using
add-php-runtime should be correct
Yeah ignore me, I didn't know about the branches being merged
dagger init --sdk=github.com/carnage/dagger/sdk/php/runtime@add-php-runtime --name=gt
So this should work, that's a legit branch name
but it broke for me? π€
select: module name and SDK must be set
Can you see what's wrong @summer sequoia @serene light ?
Might have broken it when I did stuff to merge the branches together
@green otter dagger init --sdk=github.com/carnage/dagger/sdk/php/runtime@charjr-add-php-runtime gt works, using my branch with @shy goblet 's change cherry-picked in didn't :/
let me try
hmm, that did work :/
ohhh
didn't remove the /runtime from the git url
@green otter this works: dagger init --sdk=github.com/carnage/dagger/sdk/php@add-php-runtime gt
Hahaha. My bad. Didn't see it π
This channel is so energizing!! π π π
any ETA for module support?
hopefully a basic implementaiton next week
though you can start playing with it now using: dagger init --sdk=github.com/carnage/dagger/sdk/php@add-php-runtime mymodule
just be warned that when it's merged, you'll need to fix your module's dagger.json to point to the real repository
that command sometimes fails the first time, but rerunning works fine - I'm trying to debug that currently
@faint current give us a week
I just want to say I'm amazed by the activity in this channel, you guys are relentless!
@green otter @serene light I've Rebased the add-php-runtime branch to squash every sequential commit by the same person, so we've not got 100s of commits on the branch any more; updated your workgin copies as appropriate but that branch now contains the latest code.
Thanks
Anyone about? I'm trying some stuff and have general dagger Qs
@inner walrus hey! π
Def drop them here Paul! Then we can all chime in as weβre able π
I wanna copy code from my localhost into the dagger container ...
$dir = (new Host())->directory('./laravel-app');
$container = $this->client->container()->from('jakzal/phpqa:latest')
->withDirectory('/tools/app', $dir)
->withExec(['phpqa', '', ''])
What is the $dir line? I'm looking at the source code here (generated PHP SDK code) and trying to figure it out
With functions, you donβt have access to the host, so have to pass a Directory in to your function as a function parameter
aye
All these code examples online are taking source from the CLI (--source) and don't actually show you how to do it with code
ok this makes sense why I'm stuck π
Yep, add a param, source is popular, of type Directory and then add to Container with withMountedDirectory if you wonβt be exporting/publishing that Container, but just doing something in it. Use withDirectory if you need that source to be copied in βpermanentlyβ and show up in a published/pushed image
so if it's temporary code mounting .. just to do Linting and stuff
am I using Mounted or non-mounted ?
Mounted is fine for that
ok
Itβs not a two-way bind mount, just an ephemeral snapshot
lol. Yep. We are much more sandboxed, but there are proposals to allow that sort of thing to be possible
hmmm .. I added a new function to my local dagger module ... dagger functions isn't picking it up π
One other gotcha is, if you want something like a Directory or Container or File artifact to make it back to your actual host (laptop, CI runner, etc) then it needs to be a return value of a function.
oh, we gotta re-init the module, I guess? so dagger re-parses it all
Can i dagger init, without specifying the remote git URL? just local dir
Dagger has to re-run the code gen .. somehow π€
Any other export side effect you do with the API will put things on the βhostβ it can see, which is the runtime container (PHP, TS, Go, Python)
dagger develop
So if you run dagger functions you donβt see it? π€
Huh. I wonder if the PHP SDK needs to implement something to rerun codegen. I know we changed that a while back
I just moved my Example.php file (dagger functions file) out to /tmp/ and re-ran dagger develop && dagger functions and it still finds my 2 functions ..
so it's caching
Might need a cache buster somewhere. Worth looking in typescript or python sdk for such a thing. π€ edit: I don't see anything about that in other SDKs at a glance
ok
HEHE π
so there's a diference between
dagger init --sdk=github.com/carnage/dagger/sdk/php@add-php-runtime mymodule
and
dagger init --sdk=github.com/carnage/dagger/sdk/php@add-php-runtime --source=./mymodule
the latter brings down a '/src/ DIR and other bits .. and now I realise in our SDK golang stuff, it looks in ./src/ for the stuff to codegen
so the latter works
Ah, yes, the source there is part of init and sets the source in dagger.json so Dagger knows where to look for the module implementation, even though the module root is where the dagger.json is in "."
The default lately being ./dagger/ relative to the dagger.json
right, cool. Noted π
mymodule β€ dagger init --sdk typescript
Initialized module mymodule in .
mymodule β€ tree -L 1
.
βββ LICENSE
βββ dagger/
βββ dagger.json
2 directories, 2 files
mymodule β€ cat dagger.json
{
"name": "mymodule",
"sdk": "typescript",
"source": "dagger",
"engineVersion": "v0.11.7"
}
the most typical values for source there are . and dagger, today
mymodule β€ dagger init --sdk typescript --source .
Initialized module mymodule in .
mymodule β€ tree -L 1
.
βββ LICENSE
βββ dagger.json
βββ package.json
βββ sdk/
βββ src/
βββ tsconfig.json
3 directories, 4 files
mymodule β€ cat dagger.json
{
"name": "mymodule",
"sdk": "typescript",
"engineVersion": "v0.11.7"
}
default if you don't specify source is dagger today.
understood
it's all running π sexy
dagger call user-list --svc=tcp://localhost:3306
@inner walrus does this have to be a dagger service? or just any Daemon running on that TCP port?
It's a host service btw βοΈ
your userList func has to have an arg called svc of type Service (dagger service), but the tcp://localhost:3306 service can be anything on your host, yes.
Yup, got it. Ty
PHP 8 typically declares functions in camelCase, right? like function userList(Service $svc) {}
that's right.
going to go look at code now after guess π
@inner walrus yes .. we have our PHP PSR standards (like PEP8) for all code styling rules ... and yes in PSR we use camel case for methods/functions
I'm able to run
- unit tests
- linting checks
- static analysis checks
On the laravel framework
π
Why is dagger truncating the line length? can we fix this? It's pre-maturely wrapping lines
can you check it in Traces?
huh?
π oh, do you use https://dagger.cloud/ at all? I was just curious how it renders there.
it's free.
trying to figure out if it's the TUI or something else
I tested it out .. but not currently using it.
So yea, the terminal is wrapping the lines .. and I want it to go full width π
I'm working on some things with long lines...but I guess that's the Dagger output and not log output...hmmm
Yea
It's the STDOUT output that it's truncating, I think, coz that's the PHP runtime saying "exception found .. here is the stderr output"
can you open an issue for that π
Sure ... I'll sync with @summer sequoia to see if there's anything we're doing about it .. before raising an issue. but I will π
looking for issues...https://github.com/dagger/dagger/issues/6442
I'm gonna publish my first daggerverse module now π
This URL is very slow :/ https://daggerverse.dev/
my browser is just loading and loading ..
Every other website loads .. but that one isn't
@inner walrus is there a URL on how to publish your repo into the Daggerverse? (that's not on daggerverse.dev, as that's not loading for me) - so I can learn
Not sure why slow! Sorry about that. I let our infra folks know.
Could you try dagger publish from the root of your git repo.
If it has a git remote called origin, it should work no prob.
ok
@inner walrus I'm running dagger publish now
Error: git repository is not clean; run with --force to ignore
On branch main
Your branch is up-to-date with 'origin/main'.
nothing to commit, working tree clean
?
i have nothing to commit btw ..
@green otter dagger publish with no arguments is best avoided. Run it against a remote url, and run it from outside a local git repo for peace of mind
Ok. It didn't work anyway. Daggerverse is down.
I just checked and it seems to work for me. Are you still experiencing issues?
We now have a fork of the graphql library so the composer stuff is sorted
Hey Paul,
Let's go through a few steps and figure out why https://daggerverse.dev. is slow for you.
First of all, let's see where the TCP slowness is coming from. I find mtr best for this: https://www.tecmint.com/mtr-a-network-diagnostic-tool-for-linux/
The first screenshot is what that looks like for me: sudo mtr -brwc 10 -Z 1 daggerverse.dev (note: I am on a Mac & need to use sudo).
Based on the above, I get about 90ms of latency to the TCP endpoint that currently services daggerverse.dev. I am based in Milton Keynes. What does your result look like?
The second thing would be to check the HTTP connectivity from your end to daggerverse.dev, and understand the different segments. I find httpstat useful for this: https://github.com/davecheney/httpstat
See the second screenshot for what this looks like for me: httpstat https://daggerverse.dev. It confirms that TCP is 90ms away, and shows me how much time is spent in TLS, server processing & then the final transfer. All in all, I would expect this to complete within 1s in the UK. What do you get?
Lastly, https://worldpagespeed.fly.dev/ will show you how fast https://daggerverse.dev loads around the world. It uses chromeheadless so the total time is the full page load, including all the assets. Third screenshot is what I get.
Also, if you are in doubt whether daggerverse.dev is operational, this is the place to look: https://status.dagger.io/
Let us know what you find out!
FWIW, we monitor daggerverse.dev from all major continents. This is what the daggerverse.dev HTTP latecy looked like for the last 24h from all of Europe (there are multiple probes across all major European countries):
@summer sequoia
@tidal geyser I still can't access it π¦ timing out. I'm running mtr now to check
There is no thing in my hosts file, to make it not work
We have recently migrated the infra for Daggerverse, so the only thing that I suspect now is - you guessed it - DNS.
If you run this locally in a terminal, what do you get? dig daggerverse.dev +trace
This is what you should see:
These are the important IPs:
β― dig daggerverse.dev +short
107.20.229.45
18.211.147.51
same for me
;; ANSWER SECTION:
daggerverse.dev. 60 IN A 18.211.147.51
daggerverse.dev. 60 IN A 107.20.229.45
@tidal geyser one thing I've noticed is that I can't reach daggerverse.dev from my grandmother's apartment wifi because it says it can't establish a secure connection because of our certs and the fact that the ISP uses a particular firewall.
Hey guys, how do you define the description of a function argument in PHP? And what if you have extra metadata like "ignore" patterns for a Directory argument?
public function grepDir(
#[DaggerArgument('The directory to search')]
Directory $directory,
#[DaggerArgument('The pattern to search for')]
string $pattern
): string {
extra metadata would be extra params
On the same topic:
Currently all arguments are considered to be a DaggerArgument i.e. something that can be provided by the user.
Currently the #[DaggerArgument] attribute is optional and only used for metadata.
Suggestion:
If we want an "ignore" pattern... I think for consistency:
- Only functions with the
#[DaggerFunction]attribute are considered to be aDaggerFunctioni.e. something that can be called by the user. (this is the currently implemented behaviour) - Only arguments with the
#[DaggerArgument]attribute are considered to be aDaggerArgumenti.e. something that can be provided by the user (this is the suggested change)
The problem with ignoring an argument, is that PHP will still need to get it from somewhere and the only place it can come from is a default. In which case, you could just hard code it on the line below...
Just rebased on the latest dagger main branch & updated the engine and I'm now hitting this error when init'ing a module
Error: failed to generate code: input: moduleSource.withName.withSDK.withSourceSubpath.resolveFromCaller resolve: failed to collect local module source deps: failed to get git module sdk: failed to get sdk source for github.com/carnage/dagger/sdk/php@add-php-runtime: select: failed to resolve git src to commit: failed to update submodules for https://github.com/carnage/dagger: git error: exit status 128
stderr:
Submodule 'engine/telemetry/opentelemetry-proto' (https://github.com/open-telemetry/opentelemetry-proto) registered for path 'engine/telemetry/opentelemetry-proto'
fatal: No url found for submodule path 'telemetry/opentelemetry-proto' in .gitmodules
@shy goblet your PR added some telemetry stuff to the go.mod file; is that causing this issue?
Which PR?
Oh you mean the one I did on php?
Hmm it was working before right? That's a strange error
Maybe try to clean up the go.mod? I'm not aware of that kind of issue
hmm, removed from go.mod and now get
Error: failed to generate code: input: moduleSource.withName.withSDK.withSourceSubpath.resolveFromCaller resolve: failed to collect local module source deps: failed to get git module sdk: failed to get sdk source for github.com/carnage/dagger/sdk/php@add-php-runtime: select: failed to resolve git src to commit: failed to update submodules for https://github.com/carnage/dagger: git error: exit status 128
stderr:
fatal: No url found for submodule path 'telemetry/opentelemetry-proto' in .gitmodules
@shy goblet Do you have any time to work out why this error is occurring? Neither of us are Go developers so this error is a bit hard to look into
I'll have a look but I'm not sure what's the root of the error
Thank you, I've got a branch that should be able to dynamically handle any of the IdAble implementations, but this issue is blocking me from trying it out
Ohh, you cannot even try it locally?
I cannot, the command is failing locally so I haven't been able to try it out
Hmm okay I need to check
Ok that super weird, because I'm hitting an issue completely different when I try from my branch:
dagger init --sdk=github.com/TomChv/dagger/sdk/php@feat/local-php-runtime --name=test
Fatal error: Uncaught TypeError: GraphQL\Utils\BuildClientSchema::build(): Argument #1 ($introspectionQuery) must be of type array, null given, called in /codegen/src/Command/CodegenCommand.php on line 54 and defined in /codegen/vendor/webonyx/graphql-php/src/Utils/BuildClientSchema.php:95
Stack trace:
#0 /codegen/src/Command/CodegenCommand.php(54): GraphQL\Utils\BuildClientSchema::build(NULL)
#1 /codegen/vendor/symfony/console/Command/Command.php(279): Dagger\Command\CodegenCommand->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#2 /codegen/vendor/symfony/console/Application.php(1029): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#3 /codegen/vendor/symfony/console/Application.php(316): Symfony\Component\Console\Application->doRunCommand(Object(Dagger\Command\CodegenCommand), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#4 /codegen/vendor/symfony/console/Application.php(167): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#5 /codegen/codegen(22): Symfony\Component\Console\Application->run()
#6 {main}
thrown in /codegen/vendor/webonyx/graphql-php/src/Utils/BuildClientSchema.php on line 95
And it looks like a php error
Same on your branch
dagger init --sdk=github.com/carnage/dagger/sdk/php@add-php-runtime --name=test
Full trace at https://dagger.cloud/Quartz/traces/17c330e5caecda6730b3b69abf88f795
β ModuleSource.asModule: Module! 19.2s
! failed to create module: select: failed to update codegen and runtime: failed to generate code: failed to call sdk module codegen: select: call function "Codegen": process "/runtime" did not complete successfully: exit code: 2
Error: failed to generate code: input: moduleSource.withContextDirectory.withName.withSDK.withSourceSubpath.asModule resolve: failed to create module: select: failed to update codegen and runtime: failed to generate code: failed to call sdk module codegen: select: call function "Codegen": process "/runtime" did not complete successfully: exit code: 2
Stdout:
marshal: json: error calling MarshalJSON for type *dagger.GeneratedCode: input: container.from.withMountedDirectory.withoutEntrypoint.withWorkdir.withExec.withExec.withExec.withExec.withNewFile.withExec.directory resolve: process "./codegen dagger:codegen --schema-file schema.json" did not complete successfully: exit code: 255
Stdout:
Fatal error: Uncaught TypeError: GraphQL\Utils\BuildClientSchema::build(): Argument #1 ($introspectionQuery) must be of type array, null given, called in /codegen/src/Command/CodegenCommand.php on line 54 and defined in /codegen/vendor/webonyx/graphql-php/src/Utils/BuildClientSchema.php:95
Stack trace:
#0 /codegen/src/Command/CodegenCommand.php(54): GraphQL\Utils\BuildClientSchema::build(NULL)
#1 /codegen/vendor/symfony/console/Command/Command.php(279): Dagger\Command\CodegenCommand->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#2 /codegen/vendor/symfony/console/Application.php(1029): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#3 /codegen/vendor/symfony/console/Application.php(316): Symfony\Component\Console\Application->doRunCommand(Object(Dagger\Command\CodegenCommand), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#4 /codegen/vendor/symfony/console/Application.php(167): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#5 /codegen/codegen(24): Symfony\Component\Console\Application->run()
#6 {main}
thrown in /codegen/vendor/webonyx/graphql-php/src/Utils/BuildClientSchema.php on line 95
I do not see any go error, am I missing something?
which dagger engine version are you on?
I had that error on 0.11.0 but it went away on the latest
v0.11.8
that error confuses me; as it's basically got a schema file, passed in from the runtime and json decoded it. So to get null, the file is either empty or contains invalid json
Ahhh got a lead on it. A change last week swiched the json passed from a string to a file
hmm, I've pushed a fix, however I'm still geting the go error before it gets to that point :/
Is there a quick way to update the dagger engine to the latest version?
You just need the latest CLI, it'll provision the corresponding engine for you.
hmm, seems the go issue was specific to 11.6/11.7 it's gone on 11.8
@cobalt pelican What is the expected behaviour of the SDK if a user's module throws an error? As obviously, it can't set a result properly on the function call as the type won't match
It's simple. The entrypoint should exit with a non-zero exit code. Any output to stdout or stderr will be seen in the function's output in the logs.
That's what already happens with unhandled exceptions. Python tries to print a more user friendly error (without the traceback) when it can. Traceback is included when debug level logging is enabled or if it's an unhandled exception.
Basically there's a custom exception that the SDK re-raises for errors that it catches in several places (e.g. FatalError).
I had a good call with @summer sequoia today .. we were able to take an existing app "dagger init --source=." onto it, and start coding some dagger functions onto it..
We even took an existing dagger module that Carnage made (from github, not daggerverse) and start interacting with that as well.
It's starting to take shape! on the fundamentals at least..
@cobalt pelican @astral hollow @radiant flume I'd say we're hitting ready for merge point now .. it can still be tagged as experimental, but I'm feeling confident atm that we have a solid base to make future PRs upon (and smaller ones too, not 1 months of work π )
What do you guys think?
Of course! Iβll review it this week.
Thanks
Pasting this here so @serene light can see it too. /cc @summer sequoia
try {
$container = $container
->withExec(['./vendor/bin/phpunit']);
return $container->stdout();
} catch(\Throwable $e) {
return $e->getErrors()[0]['extensions']['stdout'];
}
This is how I had to find the internal exception thrown, from the ->withExec() call that returned an exit code of 2 when there were a few unit tests failing.
Yes the unit test suite failed, but the execution of this command was successful, from the Dagger/SDK/GraphQL perspective, so we have to doing try/catch of the output .. and return that .. instead of it bubbling up to the top.
This is probably #1 priorty to fix, for the workshop which is next week
π
Which unit tests were failing?
if you run phpunit --group=unit is it within there?
Unit tests for a project; using the SDK to make a ci pipeline
@serene light any tests .. run a bash script that does "exit 1" and it will replicate
Oh, I see! Apologies I misconstrued as the unit tests on the php sdk itself
@green otter do you have time for a call on this?
@summer sequoia yes. How abt 3pm?
π for 3PM //cc @serene light
complete successfully: exit code: 1
[ERROR] #0 /src/dagger/vendor/carnage/php-graphql-client/src/Client.php(160):
GraphQL\Results->__construct(Object(GuzzleHttp\Psr7\Response), false)
#1 /src/dagger/vendor/carnage/php-graphql-client/src/Client.php(115):
GraphQL\Client->runRawQuery('query {\nphp {\nw...', false,
Object(stdClass))
#2 /src/dagger/sdk/src/Client/AbstractClient.php(40):
GraphQL\Client->runQuery(Object(GraphQL\Query))
#3 /src/dagger/sdk/src/Client/AbstractObject.php(26):
#[DaggerFunction('phpunit')]
public function phpunit(
#[DaggerArgument('Path to your project')]
Directory $source,
): string {
return $this->client->container()
->from('php:8.3-cli-alpine')
->withMountedDirectory('/tmp/app', $source)
->withWorkdir('/tmp/app')
->withExec(['./vendor/bin/phpunit'])
->stdout();
}
dagger call phpunit --source=.
try {
$container = $container
->withExec(['./vendor/bin/phpunit']);
return $container->stdout();
} catch(\Throwable $e) {
return $e->getErrors()[0]['extensions']['stdout'];
}
Hey guys, what's the canonical PR to review? Is it Paul php runtime? Is it up to date?
It'll be this one https://github.com/dagger/dagger/pull/7493 but I need to check it's got the latest commits on it. seems to be up to date
@serene light @summer sequoia any movement on that non-caught Exception issue on withExec() / stdout() ? π
As per our call yesterday ... it is making the DX gods very sad π’
I'm looking into it atm, we know what exception is being thrown, just trying to narrow it down so we don't catch something we shouldn't
Yeah, it needs to be robust regardless of what ends up being thrown as it's a generic exception.
Okay. Got it @serene light @summer sequoia
It doesn't always contain the same data
If it fails to make a container i.e. ->from('php:8.3-cli-alpine') then getErrorsDetails()['extensions'] is not set
If it fails to execute the command i.e. ->withExec(['./vendor/bin/phpasta']) then getErrorsDetails()['extensions'] is set
array (
'_type' => 'EXEC_ERROR',
'cmd' =>
array (
0 => 'docker-php-entrypoint',
1 => './vendor/bin/phppasta',
),
'exitCode' => 127,
'stderr' => '/usr/local/bin/docker-php-entrypoint: exec: line 9: ./vendor/bin/phppasta: not found',
'stdout' => '',
)
If it phpunit fails a test then
array (
'_type' => 'EXEC_ERROR',
'cmd' =>
array (
0 => 'docker-php-entrypoint',
1 => './vendor/bin/phpunit',
),
'exitCode' => 1,
'stderr' => '',
'stdout' => 'PHPUnit 10.5.24 by Sebastian Bergmann and contributors.
Runtime: PHP 8.3.8
Configuration: /tmp/app/phpunit.xml
.........................................................F...SS 63 / 112 ( 56%)
................................................. 112 / 112 (100%)
Time: 00:00.072, Memory: 10.00 MB
There was 1 failure:
1) GraphQL\\Tests\\QueryTest::testThatFails
This test fails
/tmp/app/tests/QueryTest.php:26
FAILURES!
Tests: 112, Assertions: 139, Failures: 1, Skipped: 2.',
)
The "extensions" in errors is only set on an exec error at the moment.
It allows creating a custom exception in SDKs.
@summer sequoia ^
That's really helpful, thank you!
You can look at the "path" in a GraphQL error to see which API call raised the error.
So if it errors in "from" here: $dag->container->from('php:8.3-cli-alpine')->withExec(['./vendor/bin/phpasta']), then you should see ["container", "from"] in the error's "path".
I think ideally you store the data you get in the GraphQL error in a general custom exception, in a way that's decoded from JSON. This way you don't lose that info when debugging. Should already be done by your GraphQL client library. So a sub-exception for ExecError reads those properties to customize the error a bit further, especially allowing to catch errors coming from executing the withExec instead of something else. At the moment, the custom error types like EXEC_ERROR, aren't in codegen, so it's created manually.
Python decides which class to use based on the _type field in the extension: https://github.com/dagger/dagger/blob/5231aa7de19266430581da054604ce533cc85898/sdk/python/src/dagger/_exceptions.py#L91.
In TypeScript this is done here: https://github.com/dagger/dagger/blob/5231aa7de19266430581da054604ce533cc85898/sdk/typescript/api/utils.ts#L210
Yeah I think that's the conclusion we were coming to earlier
@green otter referring to this branch: "sdk": "github.com/carnage/dagger/sdk/php@charjr-add-php-runtime"
It now gets the proper stdout from a failed phpunit run:
imhotek@imhotek2:~/git/php-graphql-client$ dagger call phpunit --source=.
PHPUnit 10.5.24 by Sebastian Bergmann and contributors.
Runtime: PHP 8.3.8
Configuration: /tmp/app/phpunit.xml
.........................................................F...SS 63 / 112 ( 56%)
................................................. 112 / 112 (100%)
Time: 00:00.069, Memory: 10.00 MB
There was 1 failure:
1) GraphQL\Tests\QueryTest::testThatFails
This test fails
/tmp/app/tests/QueryTest.php:25
FAILURES!
Tests: 112, Assertions: 139, Failures: 1, Skipped: 2.
But it doesn't currently return the correct exit code.
imhotek@imhotek2:~/git/php-graphql-client$ echo $?
0
I know how to get the correct exit code... but when I try having the EntrypointCommand return anything other than 0 I get this:
imhotek@imhotek2:~/git/php-graphql-client$ dagger call phpunit --source=.
resolve: process "docker-php-entrypoint ./vendor/bin/phpunit" did not complete successfully: exit code: 1
imhotek@imhotek2:~/git/php-graphql-client$ echo $?
127
If I'm reading this correctly, the exit code in a withExec doesn't currently propagate to the CLI. Actually never thought about that and no one asked for it, but it's something we could do.
Needs an issue though.
@cobalt pelican well if you have a CI pipeline .. and you run a command "run unit tests" .. the pipeline should ofcourse stop and fail because of a non-zero exit code ...
Niceone @serene light for that.. at can live without the exit code for now .. until it gets fixed..
@green otter I've given it a quick test with the phpunit command... but if you happen to notice anything awry when planning your workshop please let me know π
@serene light we need this merged into Chris' main branch π
I'll ask Chris to check it shortly
It exits with a non-zero exit code of course, just not necessarily the same inside the container. So let's say phpunit return 127, then dagger call exits with code 1.
@cobalt pelican that's good and works for me π
@cobalt pelican above .. @serene light mentioned he is having a challenge with the SDK runtime ...
When we return exit 1 from our PHP entrypoint command, back to the main.go runtime we get this output ..
$ dagger call phpunit --source=.
resolve: process "docker-php-entrypoint ./vendor/bin/phpunit" did not complete successfully: exit code: 1
It no longer accepts our custom output .. it overrides/changes it with that ..
Is that right @serene light ?
@green otter @summer sequoia and I solved this just now, no longer a problem @cobalt pelican, thank you
@green otter You can point your module to the main branch add-php-runtime now
It's merged
ooh.. shiny
if I have an existing dagger.json in a repo .. and I wanna get the NEW version of our SDK code ... what's the best way to do this?
It currently looks like
{
"name": "laravel-app",
"sdk": "github.com/carnage/dagger/sdk/php@add-php-runtime",
"dependencies": [
{
"name": "php",
"source": "github.com/carnage/dagger-php-module@22aa90a967f4eef40bba1ddce096ad04e8888b33"
}
],
"source": "dagger",
"engineVersion": "v0.11.8"
}
If latest changes are in the repo referenced in "sdk", it should be automatic.
noted. so it pulls every time.
I'm giving it a spin now.
@serene light it's working π
Error: response from query: input: laravelFramework.phpunit resolve: call function "phpunit": process "/src/dagger/dagger" did not complete successfully: exit code: 255
Stdout:
An error occurred inside PHPUnit.
Message: Undefined constant PDO::MYSQL_ATTR_SSL_CA
Location: /tmp/app/tests/Database/DatabaseMariaDbSchemaStateTest.php:66
#0 /tmp/app/vendor/phpunit/phpunit/src/Metadata/Api/DataProvider.php(158): Database\DatabaseMariaDbSchemaStateTest::provider()
#1 /tmp/app/vendor/phpunit/phpunit/src/Metadata/Api/DataProvider.php(59): PHPUnit\Metadata\Api\DataProvider->dataProvidedByMethods('Database\\Databa...', 'provider', Object(PHPUnit\Metadata\MetadataCollection))
#2 /tmp/app/vendor/phpunit/phpunit/src/Framework/TestBuilder.php(41): PHPUnit\Metadata\Api\DataProvider->providedData('Database\\Databa...', 'testConnectionS...')
#3 /tmp/app/vendor/phpunit/phpunit/src/Framework/TestSuite.php(508): PHPUnit\Framework\TestBuilder->build(Object(ReflectionClass), 'testConnectionS...', Array)
@cobalt pelican so we're not getting real-time output .. it's buffering it up until the end
probably needs something such that we can stream the response from stdOut called after withExec
not sure that's possible currently
That's because you need to add OTel support in the SDK, particularly live progress. Best left for later, but at least you know why.
it's kind of underwhemling when we run 10,000 unit tests ... and see no output until the end π
Yeah, up to you guys when you want to add OTel.
Think you could add a PR to this file to add it? π https://github.com/carnage/dagger/blob/add-php-runtime/sdk/php/runtime/main.go
It needs to be done in PHP using https://opentelemetry.io/docs/languages/php/getting-started/. I can help with what's needed when you get to it. You'll basically want the SDK to make some automatic OTel instrumentation based on the existence of OTEL_ env vars, and propagate the context. For the live progress you'll need a custom span processor.
Understood.
This will give the real-time STDOUT ?
we wanna see this stuff ..or a CLI progress bar
You can try a small repro in a Go module to see how it'll look like.
@cobalt pelican I'm trying to copy a binary file from another docker image .. into my current dagger container.
I've found this example, but it's not quite there. What's the right syntax?
This is a multi-stage build question
This is the Dockerfile syntax
COPY --from=composer /usr/bin/composer /usr/bin/composer
$composer = $this->client->container()->from('composer:2');
$ctr->withFile("/usr/bin/composer", $this->client->container()->from('composer:2')->file("/usr/bin/composer"));
ty - testing
@cobalt pelican how can I make sure a step is cached? For example ..
composer install which is the same as npm install
I don't wanna run it twice.
->withExec(['composer', 'install']);
First you should add a cache volume for composer's cache. That'll avoid re-downloading packages. As for composer install, you can add another cache volume for vendor, in this case with a more specific cache key.
In general, to avoid cache invalidation you need to make sure inputs don't change.
Ok.. Do you have a good recommended URL (from the cookbook?) I can follow to try and add this
Also, for the cache volume for composer's cache, you need to know if composer allows concurrent writes to that cache or not.
It does .. because composer installs packages in parallel.
Actually .. that's for bringing in host files .. I don't have any host files .. it exists only inside the container
.withMountedCache(
"/src/node_modules",
dag.cacheVolume("node-21-myapp-myenv"),
)
This is my code:
->withMountedDirectory('/tmp/app', $source)
->withWorkdir('/tmp/app')
I'm trying this
->withMountedCache('/tmp/app/vendor', $this->client->cacheVolume('composer-volume'))
composer installs to ./vendor
Doesn't need to be an absolute url, if you put it after workdir.
cool
composer.json should be the invalidation file - if that changes then it should re-run - how to achive cache invalidation?
To invalidate the cache, it's just the opposite. Make sure you use an input that's guaranteed to be different. One simple example of forcing that is using a cache buster env var, like in https://docs.dagger.io/cookbook#invalidate-cache. In your case, composer.json does what you need already. Just needs to be added first.
I mean ->withMountedDirectory() is called first .. so ?
return $container
->withMountedDirectory('/tmp/app', $source)
->withWorkdir('/tmp/app')
->withMountedCache('/tmp/app/vendor', $this->client->cacheVolume('composer-volume'))
->withFile('/usr/bin/composer', $composer->file('/usr/bin/composer'))
->withEnvVariable('COMPOSER_ALLOW_SUPERUSER', '1');
It's a good idea to copy composer.json (and lock) first to install dependencies, then bring in the rest of the code. Otherwise any changes in code will invalidate the cache for installing the dependencies.
In composer that won't work as there can be refenreces in composer.json which point to the codebase .. such as 'plugins/hooks' .. so the codebase needs to come in
Can't you include only enough to make the install step work?
Every project will be different, so we can't recommend that as a solution, since some people will have code-base references, and some won't.
Are you making a reusable/general module for php projects?
No, I'm making workshop examples for people to learn from .. and take away to their projcets (whatever it looks like)
In that case you can afford to do what's right for your composer.json. In this case, you can follow the same best practices as in Dockerfiles it's the same cache invalidation.
ok.
I'll do this
COPY composer.json
RUN composer install
COPY . /var/www/html <-- copy all the source code
let's build that in daggerland.
Isn't there a lock file too?
Yea there is .. but you can change your .json file and composer.json will pick up that change (diff vs the .lock file) and run the 'require' command for you
require = new packages
lazy mode π
How to copy just 1 file from the host $source DIR?
basically ..
dagger call testing --source=.
From this call, it will need to bring in 'composer.json' from that source DIR
and then do composer install
and then mount the entire directory
and then run the test suite
$source->file("composer.json")
Like this?
$container->withFile($source->file('composer.json'))
Almost, first arg to withFile is the path. You can leave it empty ('') to use the same file name.
optional is no longer a thing .. it's mandatory in the PHP generated stuff ... so mayb graphql has been changed
thanks - testing
->withFile('composer.json', $source->file('composer.json'))
I meant:
$container->withFile('', $source->file('composer.json'))
ah blank string .. got it
π
Yea so this isn't gonna work .. bcoz the composer.json has application things in it
At least we tried .. in any case .. we're trying to invalidate the composer cache ..
Then just add what's needed, you can add more dirs and files, instead of the whole dir.
we need everything π it's coupled
This isn't a library it's an entire web application, that runs on top of an entire MVC framework - https://github.com/koel/koel
Yeah, that's a caveat to be aware of because any change in code invalidates the compose install step. However, with the cache volume, even though that step re-runs, it should be faster since it doesn't need to refetch everything.
Understood. We will just allow the entire app's codebase to invalidate it .. like you said.
It was a good exercise to try tho .. and I will hopefully have a simple example where I can showcase this simple composer.json / composer.lock invalidation ... on a simpler example
Another thing to be aware of is that caching works on a best effort basis. It's not guaranteed on following runs. For example, if you're low on disk space things get pruned automatically.
@cobalt pelican what do you think? π
#[DaggerFunction('phpunit')]
public function phpunit(
#[DaggerArgument('Path to your project')]
Directory $source,
): string {
return $this->base($source)
->withExec(['composer', 'install'])
->withExec(['./vendor/bin/phpunit'])
->stdout();
}
private function base(Directory $source): Container
{
$composer = $this->client->container()->from('composer:2');
$container = $this->client->php()->cli('8.1');
foreach(['pdo_mysql', 'gd', 'gmp', 'intl', 'exif', 'zip'] as $ext) {
$container = $this->client->php()->withExtension($container, $ext);
}
return $container
->withMountedDirectory('/tmp/app', $source)
->withWorkdir('/tmp/app')
->withMountedCache('/tmp/app/vendor', $this->client->cacheVolume('composer-volume'))
->withFile('/usr/bin/composer', $composer->file('/usr/bin/composer'))
->withEnvVariable('COMPOSER_ALLOW_SUPERUSER', '1');
}
base() gives the runtime for the application environment (extensions ..etc)
You're missing the cache volume for composer's cache. That's most important.
->withMountedCache('/tmp/app/vendor', $this->client->cacheVolume('composer-volume'))
That's the vendor dir for the app, not the cache dir for the tool π https://getcomposer.org/doc/06-config.md#cache-dir
As for the vender cache volume, you need a more specific cache key as you don't want another module to reuse the same vendor dir.
Okay.
And the cache key for composer's cache dir needs to be specific to what it's compatible. So for example, php's version or the tools' major version, to avoid incompatibilities in different modules. That depends on how compatible composer's cache is between which versions. Maybe it's different between alpine and ubuntu so the base image should probably be added as well. Depends.
->withExec(['apt-get', 'update'])
->withExec(['apt-get', 'install', '-y', 'nano']);
This is very cumbersome (annoying)..
Can I do the bash -c trick and make it smoother string?
@cobalt pelican π I just learned I can pass an argument to ->terminal() by default it was 'sh' and now I'm able to get 'bash' π
->terminal(['bash']);
How to make bash the default shell, after installing bash from apt-get? (general linux Q)
->withExec(['apt-get', 'update'])
->withExec(['apt-get', 'install', '-y', 'nano', 'bash'])
I tried this
->withExec(['chsh', '-s', '/bin/bash', 'root']);
and then ->terminal() but it's still defaulting to 'sh'
interesting!!
I checked this
root:x:0:0:root:/root:/bin/bash
but when i do ->terminal() I still get 'sh' π€
You mean for Terminal?
Yea, when I do ->terminal() I'm getting 'sh' shell dropped
There's a withTermalDefault.... something.
$container = $this->client->php()->cli('8.1')
->withExec(['apt-get', 'update'])
->withExec(['apt-get', 'install', '-y', 'nano', 'bash'])
->withExec(['chsh', '-s', '/bin/bash', 'root'])
->terminal();
LOL wait - wrong container and stuff.
That code wasn't running on this dagger call π
$container = $this->client->php()->cli('8.1')
->withExec(['apt-get', 'update'])
->withExec(['apt-get', 'install', '-y', 'nano', 'bash'])
->terminal(["bash"]);
or
$container = $this->client->php()->cli('8.1')
->withExec(['apt-get', 'update'])
->withExec(['apt-get', 'install', '-y', 'nano', 'bash'])
->withDefaultTerminalCmd(['bash'])
->terminal();
uhhh
#[DaggerFunction('phpunit-debug')]
public function phpunitDebug(
#[DaggerArgument('Path to your project')]
Directory $source,
): Terminal {
return $this->base($source)
->terminal();
}
private function base(Directory $source): Container
{
$composer = $this->client->container()->from('composer:2');
$container = $this->client->php()->cli('8.1')
->withExec(['apt-get', 'update'])
->withExec(['apt-get', 'install', '-y', 'nano', 'bash']);
foreach(['pdo_mysql', 'gd', 'gmp', 'intl', 'exif', 'zip'] as $ext) {
$container = $this->client->php()->withExtension($container, $ext);
}
return $container
->withMountedDirectory('/tmp/app', $source)
->withWorkdir('/tmp/app')
->withMountedCache('/tmp/app/vendor', $this->client->cacheVolume('composer-volume'))
->withFile('/usr/bin/composer', $composer->file('/usr/bin/composer'))
->withEnvVariable('COMPOSER_ALLOW_SUPERUSER', '1');
}
I'm running ->terminal() and I don't get a shell at all, I get this
β Koel.phpunitDebug(
source: β ModuleSource.resolveDirectoryFromCaller(path: "."): Directory! 0.0s
): Terminal! 3.5s
β Void.websocketEndpoint: String! 0.0s
Error: exited with code 1
Output:
You don't need a different function and return terminal. Just return Container and in the CLI add terminal. See https://docs.dagger.io/manuals/user/terminal/
I should be able to run ->terminal() in the code .. no problem ..
I'm doing it on another container, and it's working fine.
#[DaggerFunction('phpstan')]
public function phpstan_debug(
#[DaggerArgument('phpstan')]
Directory $source,
): Terminal {
return $this->client->container()
->from('jakzal/phpqa:latest')
->withExec(['apt-get', 'update'])
->withExec(['apt-get', 'install', '-y', 'nano', 'bash'])
->withMountedDirectory('/tmp/app', $source)
->withWorkdir('/tmp/app')
->terminal();
}
This works fine ..
Wait, are you using a build from main or a released version of dagger?
that image starts from jakzal/phpqa and ->terminal() works fine ..
but when I start from php:debain on the base() function it doesn't work π€
Which version are you on?
0.11.8
In main, Terminal works a bit differently, so I suggest you keep terminal to the CLI. That type is going away. See https://discord.com/channels/707636530424053791/1255401990696206357 for what's changed.
uhh - I've ran ->terminal() on some ubuntu image ... and it works
I run ->terminal() on another ubuntu image .. and it doesn't work tho
Do you get an error?
I'm surprised to see Void.terminal, what's the code you have now?
Use withoutEntrypoint to make sure the base image doesn't have something prepended to the command.
ok I figured it out
this is alpine, and I'm trying to do apt-get on it ... silly mistake .. but.. the issue here is
@cobalt pelican here
So the ->withExec() calls were failing .. but silently failing .. and when I tried to run ->terimnal() it somehow didn't handle the failures and gave empty output
ok so.. if I call ->stdout() on the container .. i see the error 'apt-get command not found' ... but if I call ->terminal() I get no output and an exit code 1
That's a known issue but I thought it was fixed. Probably fixed in main with the new changes.
I'm pulling 0.11.9 now
It's not in 0.11.9 though, the new changes are going to be in 0.12.
How can I get the latest main?
I'm installing using
curl -L https://dl.dagger.io/dagger/install.sh | BIN_DIR=$HOME/.local/bin sh
We don't have nightlies, but you can build it yourself if you have a clone of the dagger repo. I also think there's a module somewhere that does it too, but don't know where. If you have the clone it's easy enough though.
Okay. I tested with 0.11.9 and it doesn't fix this known issue. At least I know about it now. It was a hidden gotcha
you can do DAGGER_COMMIT=... in an env var
just put the commit from main that you want to download
@obsidian forge got a full CLI command I can run here? π please. (with the env var and all)
That's just the CLI right @obsidian forge? How does it handle the corresponding engine?
curl -L https://dl.dagger.io/dagger/install.sh | DAGGER_COMMIT= f39e3883718808d5e026cb7fe2c0bac72ed8dd37 BIN_DIR=$HOME/.local/bin sh
Oh, don't we have a published engine in every push to main?
yup
i've started daily driving off of main to try and find more random things when using dagger day-to-day
I've created this dagger function called base-test which does ->stdout() and will show me any errors .. so when ->terminal() fails (with this known empty output) then I can go to base-test and see exactly what's wrong... Until we're on 11.0 π
@cobalt pelican how can I see the actual output of the ->withExec() in real time? on my CLI?
For example I'm doing apt-get install and I want to watch it .. right now Dagger CLI is just showing the timer clock going up
Like I said, you need to add support for OTel in the PHP SDK.
ok fair enough .. and that'll shuttle across the STDOUT in real time π
If you expose base as a function then you can do either dagger call base stdout or dagger call base terminal. No need for the extra debug functions.
@cobalt pelican good point! π I'll consider that.
Is this safe?
private function cmd(string $cmd): array
{
return ["/bin/sh", "-c", $cmd];
}
writing this out by hand is terrible DX
->withExec(['apt-get', 'install', '-y', 'nano', 'bash']);
Yeah, that's fine. Some users do it.
I wanna do
$this->cmd('apt-get install -y nano bash')
cool. I might even include it in the PHP SDK out of the box ..
@summer sequoia what's your thoughts on adding this utility function into our PHP SDK... so when we do dagger init we have it?
Maybe we can include it as a standalone function, and import it at the top of the file?
use function Dagger\Utility\dagger_cmd
I suggest trying to keep parity with other SDKs to avoid drift.
@cobalt pelican that's a good point .. so what do the other SDK's do in this case? π
Recommendation is to embrace the array syntax because it makes it really clear what the arguments to commands are, and you don't need a shell to execute so there's less overhead. Some people add a simple function like you did for convenience when they don't care, but that's in userland. You need to know what's the available shell btw.
Understood, thanks for sharing. Insightful
I'm gonna pause for now .. Gotta get back to CEO duties but today has been great progress .. and lots of knowledge handover ..
Thanks @cobalt pelican you've been awesome π€ πͺ
Dockerfile supports both, whether you use array syntax or not but as I understand it, it's a source of complication in that code base as there's a need to handle various edge cases. Also, not viable to accomplish in withExec because of the type safety. And lastly, best to keep SDK-side utilities to a minimum to avoid maintenance burden on all SDKs in order to avoid drift. There's a general purpose with that PHP could implement though (for reference: https://archive.docs.dagger.io/0.9/592101/custom-callbacks).
Sure! Nice work π
I'll share my workshop samples soon... for peer review .. as the next thing I'm going to back asking you + the team is "what things should be in the dagger worksho" for people to start adding Dagger into their existing projects
Examples are
- Taking existing Dockerfiles, and importing them into your Dagger file, and doing docker build that way
So moving away from "building reudable modules" to "replace your current app's CI/CD shit, with Dagger sexyness" is my angle ..
Have a think and we can catch up soon .. and each scenario we think is important to teach the community, I'm make sure to have PHP samples made for this workshop .. and I think it'll be helpful for moving forward.
Cheers π
I have that in my php module and it works
Workshop Topics - Thread
I had a great call today with @obsidian forge - answering many of my open dagger core engine questions, and talking about developer flows and thus workshop things π
π Dockerize a Laravel 11 app. It would be great to make a similar "Daggerize a Laravel 11 app" and see how they compare π
What's on your mind?
@cobalt pelican all the different topics, and things to cover.
After running phpunit, and adding a withServiceBinding() for redis/mysql...
then what?
It's a 4 hour workshop, so I need plenty of materials to take them throguh
@cobalt pelican I took that Laravel 11 web page and have a functional system using it π
It's time to start adding Dagger into it π
@green otter how dod the workshop go?
@summer sequoia it went well! I learned a lot, about how people learn and interpret what Dagger is
Any pain points in the Dagger SDK we could look at addressing?
Yes. I'm back home on Thursday so we can have a sync then
@summer sequoia the number one thing right now is no real-time STDOUT output. Helder says this is OpenTelemetary related, so I think this should be our next immediate focus
@cobalt pelican @grim stump @shy goblet we should discuss on merging the current PHP SDK now .. since the PR now contains 1+ month of work.
What are good next steps? Could we have a repo such as github.com/dagger/php-sdk and then we (dagger team + me + carnage/charjr) can continue to develop on that repo, and manage future PRs from the community
LMK your thoughts
Hey! Congrats! Can I get the link of the PR so I can review it properly
Hey, sure! But it's still in draft so you need to mark it as ready for review. For follow-ups, just continue working on a fork of the dagger/dagger repo and submitting PRs.
yep, not sure how we deal with the open telemetry stuff yet
John has been adding support for arrays and objects over the past few days
is there a php library for the open telematry or do we need to write one?
There is one yes. OpenTelemetry supports several SDKs and languages. I can give guidance on what's necessary.
@summer sequoia can you update the PR to "ready for review" as it is π
We can add OTel after we get this existing PR merged (either into dagger/dagger, or into dagger/php-sdk)
Which direction do you guys want to take @cobalt pelican ? (dagger/dagger, vs dagger/php-sdk repo)
Done
I replied to that in #php message: dagger/dagger repo π
@cobalt pelican okay. Got it.
dagger functions
echo Echo the value to standard output
echo-simple-list Echo the value to standard output
grep-dir Search a directory for lines matching a pattern
Skipped 1 function(s) with unsupported types: echo-nested-list
Does dagger support nested lists? i.e. [[String!]]
Also is there somewhere in the documentation that I can refer to for what types are/aren't supported?
Not documented. Nested lists have been requested in https://github.com/dagger/dagger/issues/6834. The problem with that is just syntax. How to represent it in the command.
But should still be supported when used from another module, so it's good if the SDK can support it.
That makes sense, if it was supported, my next question was literally going to be "How do I represent it in the command?".
I think it is supported within the module, I'll see what testing I can do on it
To support enums I need to upgrade the sdk to version 0.12.0 but, when running dagger develop on my module I encounter this issue:
Error: failed to get module SDK: input: moduleSource.resolveFromCaller resolve: failed to collect local module source deps: failed to get git module sdk: failed to load sdk module github.com/carnage/dagger/sdk/php@charjr-add-php-runtime: select: failed to initialize module: failed to call module "php-sdk" to get functions: call constructor: process "go build -o /runtime ." did not complete successfully: exit code: 1
Stderr:
# php-sdk
./main.go:20:17: undefined: Directory
./main.go:22:17: undefined: Container
./main.go:28:16: undefined: Directory
./main.go:46:60: undefined: ModuleSource
./main.go:46:93: undefined: File
./main.go:46:101: undefined: GeneratedCode
./main.go:58:64: undefined: ModuleSource
./main.go:58:97: undefined: File
./main.go:58:105: undefined: Container
./main.go:125:66: undefined: ModuleSource
./main.go:125:66: too many errors
It seems that the sdk/php/runtime/main.go is unable to find the definitions that should normally be generated.
This is only an issue on 0.12.0 I can successfully call dagger/develop on 0.11.9.
I've noticed 0.12.0 does introduce breaking changes, but I'm having trouble pinpointing what change I'm butting heads with.
Any help would be greatly appreciated.
You can revert that quickly by discarding the updated engineVersion in dagger.json. To update, you need to import "main/internal/dagger" and add dagger. before every core Dagger type like Container -> dagger.Container.
Ah, I had a feeling it was to do with the Go SDK Changes, thank you. I missed the bit about needing to import
My issue currently is now this:
Stderr:
main.go:10:2: package main/internal/dagger is not in std (/usr/local/go/src/main/internal/dagger)
I've also tried internal/dagger, dagger/main/internal/dagger, dagger/php-sdk/internal/dagger, dagger/internal/dagger
that can happen if the go.mod doesn't match up your imports
or if it's happening randomly in ci, it means that you're hitting an absolutely miserable flake π
Right, I apologise, I'm quite new to Go
go.mod says php-sdk so it should be php-sdk/internal/dagger.
Ahah! Thank you @obsidian forge @cobalt pelican!
I've learned a bit more of go and you've solved my issue! Now I should be able to get Enums in π
yay π
honestly, some of the go stuff around packages is very tricky to understand, it's designed in a ... particular way
In which case, I'm thankful dagger devs are willing to help π
Niceone @serene light
I'm trying to make the changes to the sdk/php/dagger.json mentioned in the PR:
https://github.com/dagger/dagger/pull/7493#discussion_r1657470819
https://github.com/dagger/dagger/pull/7493#pullrequestreview-2186514247
I'm noticing that, no matter what I do, I can't break the module. I literally changed the sdk/php/dagger.json to this:
{
"name": "php-sdk",
"sdk": "go",
"include": [
],
"exclude": [
"."
],
"source": "runtime",
"engineVersion": "v0.12.0"
}
my natural assumption would be this would exclude everything, and it should blow up in my face. But it worked as normal, as if it had all the files in the container.
My first guess is that, I've missed a vital step in sdk/php/runtime/main.go that reads it. But I haven't had any luck discovering it. Any help would be greatly appreciated.
runtime/main.go doesn't read that. It's the engine when loading the runtime module. So that happens before loading those files. I'd just dagger call the runtime manually and in the cli, terminal into the source dir and see what files were loaded under /src.
@serene light Like this:
@serene light, note that if you increase verbosity in the TUI, you can see the complete set of include/exclude patterns.
Notice also that only src is included if I only add that. I had to exclude "vendor" because I think that's always being included by default by the Go SDK.
@serene light, basically, just continue to add only what you need in include and avoid exclude. Easier to manage.
Thank you for the help, I was able to see how it affected the files in the dagger engine. But what I'm finding is, I only need the dagger.json file, that's it
I've literally put in the following:
{
"name": "php-sdk",
"sdk": "go",
"include": [
"dagger.json"
],
"exclude": [
"src/",
"vendor/"
],
"source": "runtime",
"engineVersion": "v0.12.0"
}
then with dagger call source-dir terminal -> ls
I get the following:
dagger.json
So I've got basically nothing in there at all.
But then I initialise a new module based on this, and I can still call echo, grep-dir, no problems
What should be "breaking" when I don't include the right files?
@serene light i got your DM - let's have a sync today
@serene light @summer sequoia is there a time today that works for you guys, for a sync, on this topic?
@cobalt pelican question - why are you suggesting singleton .. is this actually so it re-uses a connection, i.e: for performance reasons? or is there another motivation about moving to Singleton .. (assuming I've interpreted everything correctly)
Just DX. As an alternative to having an instance globally available, a singleton returns the same instance from class instantiation, but could be a function or static method that is easily imported but still returns the same instance (for example, using a static variable).
Is there an example of doing something similar in a popular framework, like for example using a database connection?
@green otter We'll be having a sync at 2pm - 2:30pm, so you should be able to join then
@cobalt pelican we're already using a static - that's what Dagger::connect() does
https://github.com/carnage/dagger/blob/add-php-runtime/sdk/php/src/Dagger.php
Singleton pattern - https://github.com/carnage/dagger/blob/add-php-runtime/sdk/php/src/Connection.php#L23-L25
That doesn't look like a singleton to me. It tries to establish an EnvSession to pick up on an existing running server, and those lines are just falling back to provisioning the CLI and starting a new engine session. But it's not reusing the same client connection.
The point of this is to just not require passing that client instance around in function parameters, but the DX should be as idiomatic as possible for users, that's why I'm interested in knowing how popular PHP frameworks/libraries do something similar to this.
@cobalt pelican I understand. I'll sync with @serene light and agree on the right implementation here. Thanks for your initative, we'll work on it more π to improve DX
2pm?
@serene light @summer sequoia send me a calendar invitation, please, so it's blocked out.
done
composer.json
{
"autoload": {
"files": ["functions.php"]
}
}
dump-autoload
autoload-dump
@cobalt pelican so we're moving towards a nice and simple dag() function which returns the singleton instance π
This will make the PHP SDK user experinece the same as Golang
See the bottom right (creation of the function), and on the top left the function is imported, and then you can do dag() in your dagger module
@serene light @summer sequoia I'm out of meetings now - are there other topics we should discuss? I'm available again, now
I think we're fine at the moment, I'm just cleaning up what we discussed earlier, that should clear up every suggestion from the PR
@serene light thanks a lot. QoL improvement for sure dag()
@cobalt pelican We've got the SDK working to the best of our current knowledge and rebased to latest. Is there any pressing issues we need to resolve for this to get merged? If so I'm free to talk through them, see if we can get it over the line π
Yes, I'll take a look right now! Check if every comment has been addressed from current reviews so I can mark them as resolved.
I've looked through all the comments, and resolved everything except that last one about the dagger.json file
Iβve marked resolved what I can atm, see the remaining ones while I try it out.
I've removed the comment, I have got objects working fully in a separate branch.
The current plan is to get this merged, then follow up with a second PR supporting custom objects.
EDIT: The plan can change to include it in this PR if that is preferable, but it does make quite a few additions, so it's probably easier as a second PR
custom object support should come in a followup. I've also realised we've got a bug in the existing implementation - it'll blow up if you return a custom object which doesn't have a #[DaggerObject()] attribute on it.
Ah. Then yes, we'll keep that to a follow-up PR while we squash the bug.
What value have you been using on --sdk=?
I've been putting this in the dagger.json of modules:
"sdk": "github.com/carnage/dagger/sdk/php@add-php-runtime"
I've not been using the --sdk option itself, but I assume it takes the same value? @summer sequoia
yes
replied.
@serene light, I did a review round for now while I take a deeper look at the patterns so you can make progress while I do that.
Uh π
Oh, I think when the source is a git remote those excludes don't apply. \cc @worthy ice @ocean creek
Sorry, for the delay, something came up I had to deal with. I'm back now and will look into the review
@cobalt pelican I've never ran the SDK as a module.
We are doing
dagger init --sdk=githubUrl .
I know, but you can run the module directly to debug. That's what I did.
I didn't think it was a module.. but a runtime SDK with "generated" code instead
Anyway, I'm sure in time I'll understand why an SDK is a module
The SDK runtimes are built as normal modules. Go modules in this case.
The Go runtime is the only one that's not implemented as a module because someone needs to be the bootstrapper.
@green otter
From the sdk/php/dagger.json
{
"name": "php-sdk",
"sdk": "go",
...
}
The SDK is actually just a module built from the Go SDK, or at least, that's my understanding of it
@green otter One of the review suggestions is that we rename the dagger script to entrypoint.php. I think I've done it...
In sdk/php/main.go I changed this:
const (
...
RuntimeExecutablePath = "entrypoint.php" // was "dagger"
...
)
And when finding the src directory I changed it
private function searchDirectory(string $dir): ?string
{
return file_exists("$dir/entrypoint.php") && is_dir("$dir/src") ? // was "$dir/dagger"
"$dir/src" :
null;
}
Can you think of any other places we used the name?
I wasn't involved in its development quite as early as you were, so I'd just like to double check if that sounds about right
I agree with this change. It's the right thing to do.
Implicit vs Explicit
it will break any existing modules though as it's generated by dagger init
It hasn't been merged yet and you already worry about existing modules π
Merge it! Nobody is using the PHP module yet
Hi guys. I have a question. If I run dagger init --sdk=php in an existing PHP project, how well will the module source code co-exist with the existing project?
pretty well, by default it'll stick everything in a dagger sub directory
only a dagger.json ends up in the root
More just a warning for anyone testing it, that their modules will be broken
Hey @radiant flume
It will work like the other SDK's, and it will drop all the dagger files into standard dagger folder structure
dagger.json
dagger/
... sub dirs with SDK code, and your module code.
Does this answer your question? do you want to know?
PS: we can't do --sdk=php yet, as it's not been merged by the dagger core team, so we're using @summer sequoia's github fork, meanwhile π
we wont be able to do sdk=php once merged either -> needs to wait until php becomes an officially supported sdk or that there is agreement on how communiy skds are aliased
I'm aware.
There are no existing modules .. nothing to break.
@cobalt pelican what's outstanding for merging the current version of PHP SDK? we have new features we want to add, but are keen to have the current PR merged.
Please let me know π
Taking another look at the outstanding review comments. Some of those haven't been responded to. For any outstanding issue you guys can just add a TODO comment and follow-up later.
@cobalt pelican right. I thought @serene light and @summer sequoia said they had fixed everything.
I see changes pushed 1h ago. Is it done?
@cobalt pelican I was looking at what I needed to change to rename the "codegen/" directory to "sdk/" but overall it should be done. I'll have a quick check
I will see what I can do shortly
If you allow me to push changes to your branch, just let me know when you're done, and I'll just quickly fix the remaining things and approve the PR.
You're more than welcome to. If it requires permission to push to, then @summer sequoia will need to provide it
I think the pr allows changes by maintainers
I'm fine with it, I was still working it out, so if you know what to do I'm sure you'd get it done a lot sooner
I am done for today, so I wont be committing anything until tomorrow
For the next few hours I'll be afk, but I'll see if I can finish it up quickly.
Referring to this discussion: https://github.com/dagger/dagger/pull/7493#discussion_r1697254329
generated/(codegen should be able to run with this being empty so it generates it from a clean slate)
We completely agree with this change. But it seems the PHP SDK, in its current state, depends on an already generated Client, in order to generate the code. (We're guessing this is why the generated/directory is committed to the dagger git repository as well) .
This is the error I get if I try to call dagger functions without the generated/ directory included:
! failed to initialize module: failed to call module "potato" to get functions: call constructor: process "/src/dagger/entrypoint.php" did not complete successfully: exit code: 255
β
β Fatal error: Missing code generated dagger client in /src/dagger/sdk/src/Dagger.php on line 25
Error: input: module.withSource.initialize resolve: failed to initialize module: failed to call module "potato" to get functions: call constructor: process "/src/dagger/entrypoint.php" did not complete successfully: exit code: 255
Stdout:
Fatal error: Missing code generated dagger client in /src/dagger/sdk/src/Dagger.php on line 25
Thanks for letting me know! I made quite a few changes yesterday but there's one problem that needs fixing. I can't get into that right now but I expect it'll be done today. Let me know if you have further changes today. Best to hold on if you can.
Ah fair enough! I did push one change but it's relatively small. I changed the New function to be similar to what you wanted
func New(
// Directory with the PHP SDK source code.
// +optional
sdkSourceDir *dagger.Directory,
) *PhpSdk {
if sdkSourceDir == nil {
// TODO: Replace with a *default path from context* when
// https://github.com/dagger/dagger/pull/7744 becomes availble.
sdkSourceDir = dag.Directory().WithDirectory(
"/",
dag.CurrentModule().Source().Directory(".."),
dagger.DirectoryWithDirectoryOpts{
// NB: these patterns should match those in `dagger.json`. When `--sdk` points to a git remote
// the files aren't filtered using `dagger.json` include/exclude patterns since the whole repo is cloned.
// It's still useful to have the same patterns in `dagger.json` though, to avoid the unnecessary uploads
// when loading the SDK from a local path.
Include: []string{
"composer.json",
EntryPoint,
"generated",
"init-template.sh",
"LICENSE",
"README.md",
"src",
"template",
},
Exclude: []string{
"vendor",
},
},
)
}
I hadn't gotten round to moving the files though. I will leave that alone for now.
EDIT: I also rebased the branch to keep up with main
That's ok, I'm going to force push my changes now (rebased on top of main).
@serene light, I just pushed. Please test it out and check if everything's ok. It seems the sign-offs in your commits aren't there though.
Things are getting juicy π§
Have you guys thought about showing off the PHP SDK in our community call? \cc @tropic whale
How do we sign off our commits?
Why should the variable sdk be called m? I noticed it in Python's sdk but it made more sense to me to be called sdk since it was the sdk performing the action.
Is this a Go convention I'm unaware of?
I only ask because it might help me understand it a bit better.
Yeah, it's an unofficial convention. m stands for "module". sdk was more confusing because it seemed like it could be a Directory with the SDK's sources for example.
how do you add signoffs for existing commits? we've got 3 people who contributed to this branch so coordinating signoffs will be troublesome
You'd have to change the history and edit those commit messages. Didn't notice the DCO before, I can just push through the DCO this time, so we can get this merged.
@serene light please let me know if everything looks good on your end.
@cobalt pelican I've done some quick tests and it all seems good! Thank you for the help
Ok, PR accepted. Good to merge, right?
I think we're all good, I will make sure to sign off the custom objects one after I check it's rebased and working
Merged π₯³
Woo! That's brilliant, hopefully, many smaller PRs from now on π
Party!
@serene light, I changed the location of the codegen script but didn't consider to adjust the generate task in CI as well. I'll send a fix shortly.
out of curiosity ... this is gonna be in the next release yup?
could someone add a changelog entry if so?
Actually not a part of the release. It's used independently, but you can now tag the version in the --sdk=github.com/dagger/dagger/.... URL ref, to make sure the versions are compatible.
ahhh i see, it's not bundled
@cobalt pelican wdyt about the idea of having aliases for "sdk" - e.g. php could alias to the full github.com link
might also be nice for elixir
Yeah, I love that idea π
But we need a prefix instead of just php.
π
let's thread π§΅
@obsidian forge, https://github.com/dagger/dagger/pull/8066
@tidal geyser can we get an "SDK PHP" team in github? then we can add it to CODEOWNERS like we have for elixir/etc
(would also be nice to have "SDK Go/Python/Typescript as well)
(would also be nice to have "SDK Go/
@cobalt pelican I've put in a PR for custom objects (and signed it off)
like it
FUCK YEAAAAA
it's party time - get your daggers out π‘οΈ
we sign our commits in blood
Next steps are
- Custom object support
- migrate ci pipeline for the sdk to a dagger module
- add open telemerty for realtime feedback
I've got a speaking slot at PHP Leeds in September and plan to show off our work here
Anyone willing to demo the PHP sdk tomorrow at the Community Call?
What time is it?
Sorry, it's not tomorrow. It's next week's thursday (Aug 8th), at 17h London time: https://discord.com/events/707636530424053791/1268283758533148744/1271135836569600000
@cobalt pelican I can't make tha time, sorry. I was planning/intending to do some nice demos, but I'll be travelling on that day/time so I can't.
Happy to do another week. If Carnage wants to do the demo next week Thu, then fine by me
Next steps are
@Helder Correia I can't make tha time,
I'm trying to make a sdk/php/dev module capable of running the sdk/php tests: https://github.com/dagger/dagger/pull/8078/files
- I can run unit tests currently with :
~/git/dagger/sdk/php/dev $ dagger call unit-test --source=../ stdout- I had to add a
sourceargument as it is currently the easiest way I could think of getting thesdk/phpdirectory inside the container.
- I had to add a
- The integration tests fail. My guess being that they are not connecting to dagger properly. Could anyone point me in the right direction for getting these integration tests to connect to dagger from inside a module?
Perhaps some env vars to give access to the local dagger engine; but wondering how eg python sdk does it
Run from sdk/php with dagger call -m dev .... I'll take a look at your PR when able. π
Thank you, the tests are mostly failing like this:
5) Dagger\Tests\Integration\Connection\CliDownloaderTest::testRealCliDownload
RuntimeException: Invalid checksum : e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855, expected :
That's not me truncating the exception, that is the exception, nothing appears after the colon
So let me see if I understand. PHPUnit is successfully running, just doesn't seem to have the expected file structure?
Honestly, I'm not sure. I have a vague idea how the query builder is working, but not enough to know what would cause that.
Sorry, just to clarify, I do know PHPUnit is at least successfully running. I can run the unit tests, as they do not depend on Dagger\Client or any other generated/ classes. They failed when they were meant to and passed when they were meant to.
With the Integration tests, they depend on Dagger\Client and their failures are identical to if you run them locally through a simple $ ./vendor/bin/phpunit --group=integration. In other words, they are failing in the same way as they would if you do not run them through docker-compose
docker-compose presumably adds some setup/additional services eg a dagger engine then - replicate that in the dagger module?
You donβt need to manually add the engine to the dev module.
what about for containers spawned by the dev module?
the docker-compose file doesn't actually work atm, I'm seeing if I can fix it.
Well, seeing if I can fix it quickly, since we're planning to do away with it right now (just so I can run the tests do pass in the right env)
@cobalt pelican Would it be best if I limit this first PR to simply making a Dev module that successfully performs unit tests?
Then I can get linting, static analysis and integration tests in follow-ups
Up to you. I think when you solve the first, the others will be small changes.
By "solve the first" do you mean unit tests? If so I have that working.
If you mean integration tests... I'm a little struggling on that one a bit
Ah, I see. I'll help you. Taking a looksy.
@serene light, are all your changes pushed to the PR?
All the changes I think I needed for the PR at least.
The integration test command looked identical to the unit tests one currently though
I will put it back in.
Okay it's back in
Was the module initialized correctly? I don't see the composer.json and entrypoint.php files.
It is, sorry I'll include those... I figured they would be generated when called. Am I misunderstanding?
What shouldn't be committed to git is what the runtime adds to WithVCSIgnoredPaths, which in your case is sdk and vendor. Everything else should be committed.
The template should only be applied when the module is being created for the first time.
For now you can just check if the file exists and create it if not.
But shouldn't overwrite an existing file.
You may add entrypoint.php to WithVCSGeneratedPaths.
For composer.json you could add PHP dependencies for calling a library in your module's function, for example.
The lock is important for reproducibility.
Just call dagger develop -m dev (from sdk/php). That should update the module from codegen.
Okay, that all makes sense. I'll make those changes now
Currently, the php functions in src/ are being overwritten by the template.
But that's because you removed composer.json.
Since init-template.sh is using that to check if it's a new module or not.
Right I see, obviously it was working locally since I had the files... but simply hadn't commited them.
I see
There should also be .gitignore and .gitattributes files. It's not committed.
Added them just now
A dagger develop -m dev in a clean workdir shouldn't create new changes to commit, assuming you ran it soon before with the same dagger version.
Btw, there's a weird extra space in your indentation after the annotations ("public function" lines) π
@serene light does the unit-tests function return successfully for you?
There's 33 errors when I run it. All seem related to autoloading, basically not finding some classes.
It is running successfully for me.
Then you must have something in your host that I don't have.
Try removing your sdk/php/vendor directory
The php:8.3-cli-alpine image doesn't include composer, right?
Don't you have to get composer and composer install before running phpunit?
π€¦ββοΈ
Btw, you can create a function base that doesn't have the [#DaggerFunction] annotation, so you can just call from unitTests something like: return $this->base()->withExec(['phpunit', ...]).
Basically an internal function, not exposed to dagger.
That's a good idea, I was planning to do something like that if it turned out the logic was duplicated among each function
I will call it base()
At some point you could create a reusable php module that'll provide a base container with composer installed so it's much easier for any PHP module to get a PHP container quickly. Then you could do:
dag()->php()->withSource($source)->container()->withExec(["phpunit", ...])
The way to hook that in is, let's say you put that module in sdk/php/modules/php, then dagger install -m dev modules/php (or in another git repo).
That'll add an entry for the php module in your dev/dagger.json and the client bindings for it will automatically be generated so you'll have that dag()->php().
Alright, I have added a base() function and the unit tests now run without having vendor/ already installed.
You should add vendor and sdk to the excludes in dagger.json.
That would have caught the issue sooner for you.
Actually, scratch that, your issue comes from the Directory --source argument. That would be fixed by adding a view.
But that'll be replaced soon with context directories.
You'll need to add support for it in the PHP SDK btw.
@serene light, does the PHP SDK have support for a module constructor?
Doesn't seem like it.
I don't think we do yet
That's easy to add and adds great value.
So should I still add vendor and sdk to dagger.json excludes?
I wasn't sure what a module constructor did so had left it out so far
Needs an update to the latest sdk
I also want the functions to return an object not a container so you can do things like dag()->php()->withExtension('xdebug')->withComposer()->container()
When you don't register a constructor, you basically always assume that the instantiation of the main object doesn't have any arguments always. But if you expose the class constructor to Dagger, then its arguments will show up on the CLI and you'll be able to pass values there, including via dag()->php($version).
oh, so it's only for the module base object, not for sub objects?
Yes. For the other objects, their constructor is just a function in the chain. Basically another method in current object or another.
All you have to do is similar to the way you already register functions for an object:
$func = dag()->function(
$daggerFunction->name,
$this->getTypeDef($daggerFunction->returnType)
);
But you only need this for the main object, the name should be empty (""), and you shouldn't need the [#DaggerFunction] annotation, assuming you can easily detect if the code defines the constructor or not.
That includes registering the constructor's arguments, but that should be the same as for any other function.
we could default to using the object's construct method but that might be needed in future to pass in dependencies
Then on invocation, you need to check if the function name is "" and if so, just invoke that constructor with those arguments to get the object.
You're saying it might not be a good idea to use PHP's natural object constructor?
I'm talking about function __construct() { }.
I think the idea is, if we need to inject dependencies into objects, and those dependencies don't/shouldn't need to be provided by the user, then usually they're injected in function __construct() {}
We may be able to use the __construct method still, but it's just something to consider
Yeah, but in that case you'll probably be able to know programmatically which of the constructor args are used for dependency injection, in which case you can exclude those args from being registered to Dagger.
True, it's definitely something we'd want to add.
Obviously the list is stacking up π
Python example:
- Registration (automatically added without the decorator)
- Invocation
It's mostly like any other function, just needs small adjustments. This is just so you have an idea of the effort here, but totally up to you when to get to it.
We'll focus on this Dev module first. Once we have that running on CI, we should be able to tackle the rest of the list with more confidence π
But first, lunch π²
Of course π Just thought about the constructor because you could move the --source arg to there, so there's no need to add it to every function. Meaning also that you could include the composer install step earlier, and the result shared by all functions.
For now, I suggest you accept the $source arg in base and do those steps there.
For when you come back, I think what you need for the integration tests is to add the experimentalPriviledgedNesting option to the withExec for running phpunit. That'll give you the env vars in that exec for connecting to the engine, which Dagger::connect() should already be able to pick up on.
Hmm, you guys may need to make a breaking change in codegen. Optional arguments should be named arguments. Looks to me like they're all positional atm, is that right?
what do you mean here? named arguments in PHP only applies to calling a function, the definition is always positional
I know:
return $this->base($source)->withExec(['phpunit', '--group=integration'], experimentalPriviledgedNesting: true)
What I mean is that codegen doesn't seem to define them as named arguments:
public function withExec(
array $args,
?bool $skipEntrypoint = true,
?bool $useEntrypoint = false,
?string $stdin = '',
?string $redirectStdout = '',
?string $redirectStderr = '',
?bool $experimentalPrivilegedNesting = false,
?bool $insecureRootCapabilities = false,
): Container
Don't you need to provide all args until that option currently?
What you've posted is valid code
Oh, it works like that currently?
I was going by this: https://www.php.net/manual/en/functions.arguments.php#functions.named-arguments, which uses a different syntax.
the rational for adding it to PHP was to allow skipping over a bunch of other properties in exactly the way you defined
any property with a default in the function defintion can be excluded from a call
Can you point me to the docs where your syntax for the function definition is used instead? Just curious to know more π
see example 17 on that page
It's not the same as the way withExec is defined.
RFC has some more examples; https://wiki.php.net/rfc/named_params
Ok, looking into the other sections I can see it, like example #9.
Defined like $style = "Greek" but used like style: "natural".
Cool! π
htmlspecialchars(
string $string,
int $flags = ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401,
?string $encoding = null,
bool $double_encode = true
): string
that's the defintion for htmlspecialchars which is used in a number of the examples
There is no step to explicitly define a function as accepting named arguments. Every function can accept named arguments I believe
Yeah, that definition was simply not shown in the example.
Oh I think I misread it! In example #14 (Named argument syntax), I saw:
myFunction(paramName: $value);
But somehow read it as:
function myFunction(paramName: $value) { }
Like that had to be in the definition.
Yeah that one is a bit confusing, but basically any function at all that you define, whatever the argument's name is, you can pass it as a named argument
function myFunction(string $thisIsTheName, int $thisIsADifferentOne)
That's it, now I can refer to them by name
Pretty cool π
I wanted there to be some way of explicitly opting a param of function into being usable as a named parameter as auto opting everything in has some interesting edge cases which are not ideal but the PHP community decided to go ahead with everything everywhere being namable
In Python it was all opt-in in as well, but a few years ago they added the ability to explicitly split the arguments into required positional and/or required named.
I only added the required named to optionals, but decided to allow named for positional args.
Getting back to the issue at hand, it seems your issue is in the provisioning tests, right? Failing the checksum when downloading a dagger version.
You can skip the provision tests for this PR, and solve them later. This way you focus on the dev module and replace the docker compose completely.
I think I've got them running thanks to [your help](#php message)
There's only one test that fails and that is for something we want to deprecate: the CliDownloader
It was used before the runtime was created, in order to download dagger directly and use for cli
And then set all the environment variables manually
Whereas now the runtime sets that up for you just by creating a new module
Is there a good place to keep track of the outstanding work needed on the PHP SDK?
Should we start creating a issues for it on the main repository?
That's one potential option
Yeah, you can! I just created a label for you: https://github.com/dagger/dagger/labels/area%2Fsdk%2Fphp
Brilliant, I will get on that shortly and list the follow ups from the original runtime PR
I've updated the PR, this one should be capable of running the tests now https://github.com/dagger/dagger/pull/8078
Ok, let's hook that into CI π
So, things which need doing imo:
- Telemetry
- Module constructor
- Interfaces
- Docs for dagger.io ?
- Remove generated dir from dagger/dagger repo
- Remove deprecated process connection code & cli downloader
Oh, I ask you to make a simple change first. Rename the module from dev to php-sdk-dev please.
So it creates a dag.PhpSdkDev() instead of dag.Dev().
Ah, I did see that naming convention in the python one, I didn't realise that was what it was for
I changed the name in sdk/php/dev/dagger.json and the name of the class sdk/php/dev/src/Dev to sdk/php/dev/src/PhpSdkDev
I believe those are the only places it needed changing
Made the change anyway, thank you
I'm going to push a few changes to your PR
That's fine, I'm not changing it currently. I'm writing up the issues. I can't add labels to them though
Prefix the title with "PHP: " and we'll add the label.
Yay π
Now you need to fix those checks π
@serene light, from the root of our repo, try this:
dagger call -m dev --source=.:default sdk php test
And also:
dagger call -m dev --source=.:default sdk php lint
To generate client bindings:
dagger call -m dev --source=.:default sdk php generate export --path=.
Need to pull my changes
Learning: What does --source=.:default do?
The :default suffix is a "view", used to apply these filters: https://github.com/dagger/dagger/blob/37ae2292b0754d32565352c12053492f351121e6/dev/dagger.json#L37-L47
Right, so it avoids looking at anything in that list
Yes, those files are excluded from what will be sent to your dev module as $source.
The only one matching will be sdk/php/dev/sdk.
Right, but with anything in the :default filter excluded?
But also helps cut down on time when running the command locally because it'll avoid uploading those things in case you have them (e.g., a node_modules).
I was able to run dagger call -m dev --source=.:default sdk php test but not dagger call -m dev --source=.:default sdk php test stdout
Those are by default patterns to include, unless it's prefixed with "!", which in this case it's all of them. So yes, it's excluding those patterns.
It did run though (it took about 4 minutes)
Don't add the stdout. That function doesn't return a container.
It's not redirecting to yours. See the implementation in your PR, in /dev/php_sdk.php.
Right, I see.. so it only returns nil or error?
Only sdk php test is hooked into your dev module. Would be great to move the rest there.
Yes, if no error, it'll return nil.
Output from the test will be available from telemetry. TUI/cloud.
But it only matters if it errors, so the output should show up in your screen.
What does "client bindings" mean? That is new terminology to me.
Aka codegen. Basically dag()->..... Those are client bindings to functions in the server. With runtimes you started getting more "kinds" of codegen, not just for client bindings. So sometimes I prefer being explicit here.
Right so by performing that command I'm generating bindings to call functions from the php sdk dev module?
I see, it's generated Client, Container Directory and Function_ ... but with the correct linting.
The sdk php generate function runs the SDK's codegen: generated.
Only sdk php test is connected to sdk/php/dev.
When I wanted to generate the files before, I was calling dagger develop when inside sdk/php, what is the difference?
What difference was made to generate the code with correct linting this time, that wasn't done before?
I didn't add sdk php generate now, it's been there since the beginning of the PHP SDK. That's how we run codegen (to update bindings) for all SDKs when we make changes to the API. It's included in:
dagger call -m dev --source=.:default sdk all generate export --path=.
Yes, but the Go code that makes it possible should just call a function in sdk/php/dev for that. We didn't have it before.
Inferior how?
well, if it's exported like that you only get the base dagger functions
so you cant use modules directly
You can see Python's example: https://github.com/dagger/dagger/blob/37ae2292b0754d32565352c12053492f351121e6/dev/sdk_python.go#L120
or am I misunderstanding what the generate is doing?
You can use either. I can generate python bindings from the root of the repo with our /dev module (in Go) that puts all of it together. Or I can run the /sdk/python/dev module (in Python) if I'm in the SDK's directory. In the case of Python, the Go module just calls out to the Python module. It's what I'm saying you guys should do.
That command should just be updating the files in sdk/php/generated. Each SDK has a different target directory where the client bindings are located. These bindings only include the core API, and is what the PHP is released with to Packagist.
Modules have their own codegen and include bindings to their dependencies.
These are two different things.
I think I'm following, but I've been taking in a lot over the last hour or two (thank you for all the help! @cobalt pelican ) so I'm going to be afk while it sinks in.
I added the linting changes. The PHP tests failed in the PR but they are passing locally, I'm not sure why as I can't seem to access the trace on github :/
Probably something you have locally that's not in the remote. Try in a new clone.
There was 1 failure:
1) Dagger\Tests\Unit\Service\FindsDaggerObjectsTest::itFindsDaggerObjects with data set "test fixtures" ([Dagger\ValueObject\DaggerObject Object (...), Dagger\ValueObject\DaggerObject Object (...)], '/src/sdk/php/tests/Unit/Servi...ixture')
Failed asserting that two arrays are equal.
--- Expected
+++ Actual
@@ @@
Array (
0 => Dagger\ValueObject\DaggerObject Object (
'daggerFunctions' => Array (
- )
- 'name' => 'Dagger\Tests\Unit\Fixture\NoDaggerFunctions'
- )
- 1 => Dagger\ValueObject\DaggerObject Object (
- 'daggerFunctions' => Array (
'returnBool' => Dagger\ValueObject\DaggerFunction Object (...)
'returnInt' => Dagger\ValueObject\DaggerFunction Object (...)
'returnString' => Dagger\ValueObject\DaggerFunction Object (...)
@@ @@
'explicitlyOptionalFile' => Dagger\ValueObject\DaggerFunction Object (...)
)
'name' => 'Dagger\Tests\Unit\Fixture\DaggerObjectWithDaggerFunctions'
+ )
+ 1 => Dagger\ValueObject\DaggerObject Object (
+ 'daggerFunctions' => Array (
+ )
+ 'name' => 'Dagger\Tests\Unit\Fixture\NoDaggerFunctions'
)
)
/src/sdk/php/tests/Unit/Service/FindsDaggerObjectsTest.php:25
FAILURES!
Tests: 236, Assertions: 241, Failures: 1.
I made a fresh clone of my branch, still passes. But I can see from what you sent that all it's failing on is getting the array of objects in a different order.
So I'll see if I can make that test a bit more robust so it isn't bothered what order they come in, because that is not important to the test.
yeah, it was running fine on my local after pulling your branch as well
@summer sequoia Can you think of a quick way to make it not bothered by the order there?
EDIT: nvm, I found it. PHPUnit has assertEqualsCanonicalizing($expected, $actual) https://docs.phpunit.de/en/10.5/assertions.html#assertequalscanonicalizing
hmmm, that's new
It claims to do exactly what we're after.
Well, I think it is working now: https://github.com/dagger/dagger/pull/8078
It isn't failing on the PHP tests. It may be one of those flaky tests?
Add a module under sdk/php/dev, using the PHP SDK, to test the PHP SDK.
Fix previous refactoring oversight left in existing unit test.
Implement unit-tests function to run unit tests only
Imp...
I've updated The PhpSdkDev PR
I unified the test functions into one with an optional --group argument.
I think this PR is ready to be reviewed (and maybe merged)
Then I'm ready to add PHPCS for linting.
nicely done @serene light
feat: Add PHP SDK dev module for running...
@cobalt pelican I've added a PR for linting in the PhpSdkDev. It looks like a lot of changes but it's mostly just automated fixes from the linter.
I also copied the way the python linting command works in the Dev module so it should perform the check in CI too
https://github.com/dagger/dagger/pull/8112
The only files with significant changes are:
dev/sdk_php.go,sdk/php/dev/src/PhpSdkDev.phpcomposer.json
Everything else is linting
Just a minor issue and it's good to go.
https://github.com/dagger/dagger/pull/8112#pullrequestreview-2221860777
The codegen logic is still fairly unfamiliar to me, I'm looking at it now, but I'm not sure what I need to do to resolve this feedback.
Do I need to add a simple .WithExec() Or actually dig into the codegen a bit?
You mean the part about generate and not needing base anymore?
That part, I assume I want to replace the dagger.Source with t.Base
I meant how do I fix the potential linting error that the codegen could cause when the engine gets bumped up a version
Would I want to run PHPCBF, the automated fixer for lint errors, on the generated dir? Or do I need to dig into the codegen and fix the error wherever it is generated?
https://github.com/dagger/dagger/pull/8112#discussion_r1705925826
Sorry, specifically this comment
Oh, that's very simple. You just need to reformat this content so that the linter doesn't find anything that needs formatting: https://github.com/dagger/dagger/blob/0f8b9d58535fcf65d560448ce4e31dfebecdfdac/dev/sdk_php.go#L102-L103
It's a good idea to run the formatter after codegen. All SDKs do it. You don't want to get lint errors after sdk php generate.
Or to at least make sure that codegen produces an output that doesn't create linting errors, if that's possible.
By delegate codegen to the PhpSdkDev do you mean to replace t.PhpBase() with dag.PhpSdkDev.Base()?
No, I mean move implementation to dag.PhpSdkDev().Generate().
See Python for example.
@summer sequoia This PR has a red CI because of php linter: https://github.com/dagger/dagger/pull/8114
Could you have a look when you have a moment please, it's pretty strange because the exact same command isn't failing locally. Are you doing something special in the CI?
feat: compute file digest by TomChv Β· Pu...
Thanks for the preso today @summer sequoia πͺ
Join your fellow Daggernauts for the latest Dagger product updates, community demos, and more.
Do you use a JetBrains IDE? Guessing maybe the best one for PHP?
Yeah, I was using PHPStorm π
hi @summer sequoia, thx for the demo! I tried to replicate your commands but it failed:
$ dagger version
dagger v0.12.4 (registry.dagger.io/engine:v0.12.4) linux/amd64
$ dagger init --sdk=github.com/dagger/dagger/sdk/php demo
β connect 1.1s
β moduleSource(refString: "demo"): ModuleSource! 0.0s
β ModuleSource.kind: ModuleSourceKind! 0.0s
β ModuleSource.resolveContextPathFromCaller: String! 0.0s
β ModuleSource.withName(name: "demo"): ModuleSource! 0.0s
β ModuleSource.withSDK(sdk: "github.com/dagger/dagger/sdk/php"): ModuleSource! 0.0s
β ModuleSource.withSourceSubpath(path: "."): ModuleSource! 0.0s
β ModuleSource.resolveFromCaller: ModuleSource! 9.7s
! failed to collect local module source deps: failed to get git module sdk: failed to get sdk source for github.com/dagger/dagger/sdk/php: select: determine default branch: failed to run git: exit status 128
Error: failed to generate code: input: moduleSource.withName.withSDK.withSourceSubpath.resolveFromCaller resolve: failed to collect local module source deps: failed to get git module sdk: failed to get sdk source for github.com/dagger/dagger/sdk/php: select: determine default branch: failed to run git: exit status 128
any idea what is wrong or what should I do?
hmmm...not sure. Just worked for me
dagger version dagger v0.12.4 (registry.dagger.io/engine:v0.12.4) darwin/arm64
@slim thistle most sources suggest it looks like a git problem.
Wondering if you have a firewall or something that is blocking the anonymous git clone.
Ok... I reboot and retried, it works π
I've made a format function for PhpSdkDev.
The only gripe I have is it relies on shoving a small shell script in just to circumvent PHPCBF's unconventional exit codes.
#[DaggerFunction('Format the source directory')]
public function format(Directory $source): Directory
{
$scriptPath = '/usr/bin/format';
$script = <<<SH
#!/bin/sh
phpcbf
if [ $? != 3 ]
then
exit 0
fi
SH;
$original = $this->base($source)->directory(self::SDK_ROOT);
$formatted = $this->base($source)
->withNewFile($scriptPath, $script)
->withExec(['chmod', '+x', $scriptPath])
->withExec([$scriptPath])
->directory(self::SDK_ROOT);
return $original->diff($formatted);
}
If an exit code of 0 is not received by the withExec call, then execution stops there and it wont return the diff.
Is there a better way to handle this that I'm not taking advantage of?
π question - any ideas why https://github.com/dagger/dagger/pull/8158 is failing?
locally, i ran dagger call --source=.:default sdk php generate -o ., and it looks like it's out of date
however, when i pr this in, it looks like ci fails?
cc @sudden shuttle
I'm not sure about the generate command currently, I haven't touched that one yet
hm, well the generated code was modified in https://github.com/dagger/dagger/pull/8078
It looks like the generated files in your PR have linting errors, example:
?string $owner = '',
?int $mode = 256,
): Container
{
Yeah, were they caused by the generate function?
well apparently
but the issue is that this seems to pass locally
What is it passing locally?
Right apologies, should have looked.
So to be clear, for my sake as I'm still quite new to Dagger: you're calling something like dagger call -m dev sdk php lint?
yeah, i'm calling dagger -m . call --source=.:default sdk php lint
i can't quite tell, but it seems like the codegen is doing different locally vs in ci? i don't really know how that's possible π’
I'm not quite sure atm, the quick fix is just to remove the generated directory from your PR and then it should pass.
I'll need to consider why it might be different.
yes - but if i remove the generated directory, then it fails locally
I forked your branch and called dagger -m . call --source=.:default sdk php lint
I'm got the following:
Stdout:
invoke: input: dirdiff.assertEqual resolve: call function "AssertEqual": process "/runtime" did not complete successfully: exit code: 2
Stdout:
invoke: input: container.import.withMountedTemp.withMountedTemp.withWorkdir.withMountedDirectory.withMountedDirectory.withWorkdir.withExec.sync resolve: process "diff -r a/sdk/php/generated b/sdk/php/generated" did not complete successfully: exit code: 1
Stdout:
diff -r a/sdk/php/generated/Client.php b/sdk/php/generated/Client.php
149,150c149
< ): GitRepository
< {
---
... and so on.
My local output matched what came through on CI
However I did not call generate first or anything. So maybe my local branch doesn't match yours
no i'm working from a clean state
hmm, i wonder if it might have something to do with sdk/php/vendor/?
removing that now, trying again
lint shouldn't touch vendor/ at all
yeah, cool @sudden shuttle that did it
hm, i removed it and now linting passes on main π
when before it didn't
could it have had some old deps in it?
That is surprising! It's passing on CI by removing vendor locally?
I'm glad it worked, but I am curious why
the pr i opened was just to demonstrate the issue - what was happening was that running lint locally was failing, because generate was making changes to the generated code
this seemed to be because i had a vendor/ directory, which was somehow influencing the codegen (i guess from an old dep in there?)
Yes that is strange, we include the composer.lock which should dictate the versions of each dependency. I would have expected that to blow up.
@obsidian forge In case it happens again, we've figured out why this issue is occurring.
Too Long Didn't Read: If you encounter issues again, delete sdk/php/dev/composer.lock and try again.
Too Short Want To Read: The sdk/php/dev/composer.lock takes the sdk/php directory, but it doesn't realise when sdk/php has changed because it's just a local path. This is mostly an issue during development as the dependencies of the sdk change rapidly, but we may develop a composer plugin to solve that in the future. For now, it's on the ever increasing back log.
cc @summer sequoia if you can double-check I've got the facts straight here, thank you π
is there something we need to fix in the engine php pipeline to prevent this from happening in the future? It was certainly something that it wasn't obvious at all
@summer sequoia @serene light ping
@sudden shuttle It is something that needs fixing in the PhpDevSDK.
The /sdk/php/dev/composer.lock file tracks the PhpSDK as a relative file path. It doesn't notice when the PhpSdk updates its dependencies
@summer sequoia @serene light can we arrange a call for next week sometime? Such as Wed or Thu to discuss outstanding things with PHP SDK?
Such as, blockers, open discussions, release plan ..etc
You don't have to prepare anything in advance, just some topics.
there are a few issues in github regarding things that are still to do; interfaces, constructors and telemetry are the main ones i think
@Carnage @charjr can we arrange a call
@cobalt pelican Quick question: When it comes to enums what should the value look like when returned?
Lets say I'm looking at the NetworkProtocol enum
enum NetworkProtocol: string
{
case TCP = 'TCP';
case UDP = 'UDP';
}
Should I get back "TCP" or TCP ?
EDIT: More precisely, should I get back the case's name or value?
If for instance we had a case
case Name = 'Value'
What should I be seeing as a result?
In GraphQL enums are enumerations of values. The βname" is only used by the SDK. When serialized, it should be a string because enums are based on string scalars.
Right, so to be clear. The values I should expect would be "TCP" and "Value" in the above examples?
Specifically, inside double quotes
π Just submit a PR to uses context directory here https://github.com/dagger/dagger/pull/8369
@ocean creek hey π π
Lots of good feedback/comments on your PR here - https://github.com/dagger/dagger/pull/8369
@zealous star hey! π let us know once you've given your opinion on these changes π /cc @tidal geyser
@shy goblet First; Thank you for getting context directories in, they will certainly make calls simpler. I had a couple of questions about supporting them in PHP.
-
The PHP SDK piggybacks off the Go SDK, I'm assuming your work makes them immediately accessible to the SDK with the use of the annotations in Win's PR. If I'm wrong, please let me know. I'd love to understand it more.
-
What, if anything, needs to be done to support context directories for modules built using the PHP SDK?
replied!
@green otter Hi π Will looking suggestions on that PR tonight.
Cool
@shy goblet @cobalt pelican I have a question about +ignore on https://github.com/dagger/dagger/pull/8369.
I try with with-dev dagger call -m github.com/wingyplus/dagger/sdk/php/runtime@cd3a3e724aa5a2ce259fe6b217f0efe5abaaabcb source-dir (it is the latest commit on that PR) and found that ignore does't work as I expected because it returns:
_type: Directory
digest: sha256:4efcbbc3978405e30f078b41ff5acb6a0d1f6084906a42d3cf32d4377190a414
entries:
- .changes
- .changie.yaml
- .gitattributes
- .gitignore
- .php-cs-fixer.dist.php
- CHANGELOG.md
- LICENSE
- README.md
- composer.json
- composer.lock
- dev
- docker
- docker-compose.yml
- generated
- phpcs.xml
- phpunit.xml.dist
- psalm.xml
- runtime
- scripts
- src
- tests
But if I change defaultPath to ".." I got:
_type: Directory
digest: sha256:87f768c76fbf1901d1b036461fc9207d82f7eccfc26d892540ef276e332aafbb
entries:
- LICENSE
- README.md
- composer.json
- composer.lock
- generated
- scripts
- src
I'm unsure what I am missing on the ignore configuration. But why does it act differently?
The value for defaultPath is relative to the directory where dagger.json is.
Why don't you use it locally?
with-dev dagger call -m runtime source-dir
If the path is relative
From https://github.com/dagger/dagger/pull/8369/files#diff-0586053a20f05d1973e9fafdb90d0e09153f7943df4f7983b78f88e0338a5beeR28-R29. I change the defaultPath to /sdk/php, If I call against local runtime directory, I got:
_type: Directory
digest: sha256:87f768c76fbf1901d1b036461fc9207d82f7eccfc26d892540ef276e332aafbb
entries:
- LICENSE
- README.md
- composer.json
- composer.lock
- generated
- scripts
- src
That looks very similar to defaultPath .. but when I call on module remote path, I got all files unlike the local one. So I'm unsure I set the ignore configuration correctly because the behaviour is not the same.
I see. Yeah, that's because at the moment the // +ignore only applies to local sources. Not to git remotes.
Do we need to keep https://github.com/dagger/dagger/blob/main/sdk/php/runtime/main.go#L33-L55 if it's not support git remote?
@ocean creek, I know I'm the one that asked you to move dagger.json back into runtime but I'm having second thoughts. The problem is we want to avoid having to have <...>/runtime at the end of the git URL for --sdk, but we also want to avoid having to -m dev every time while developing .We can't have both though.
One possible idea is that the runtime module is the module of sdk/php. Basically, make sure that the SDK's dir (i.e., sdk/<sdk>) is that module and can be used directly with dagger init --sdk=. Then, for the dev module, it's possible to merge it in the "runtime", the problem is that it would have to be in Go, meaning that you lose the dogfooding opportunity of having the dev module in the SDK's own language.
So I'm torn between these:
- Not having end users point an SDK to
<...>/runtime - Not having maintainers type
-m devwhile developing - Keeping the dev module in non-Go SDKs in their own language
@cobalt pelican what about the reverse, developing the whole SDK in its own language, including the runtime? You mentioned performance reasons for using Go, maybe those are fixable? There might also be a bootstrap problem? But I guess that might apply to the dev module as well (can't test the php module because the php module is broken etc)
That's not feasible anytime soon. The problem is bootstrapping. Last year right around this time we were battling with this same issue. We got around it by giving up the idea of having a normal Go module defining the runtime container for Go Modules. What you have now is that Go's runtime is defined with lower level core code, and hardcoded in core. It's not using a sdk/go/runtime or anything. And so Go is managed in a more lower level and core native way, but it allows using Go modules to define other runtime modules. It's possible someone has a fresh new idea though, I'd be interested in what Justin can think of.
However, I think it's a good idea to keep the runtime module in Go. The more hops you have, the longer it'll take to initialize, not to mention probably a slower language. Unless we pre-build these runtimes or something, and even then what does that mean when it's a non-compiled language?
@green otter @summer sequoia would love your review on the upcoming docs PHP integration page. We are hoping to merge it soon - https://github.com/dagger/dagger/pull/8321
@tropic whale don't merge that work please. It's duplicating the other work I'm already doing, and Vikram and levelaz are working in isolation from Carnage, Charjr, and myself .. and it's the first I've heard of this work going on ..
My 4 hour PHP dagger workshop already has all the PHP sample codes that reflect the SDK, daggerizing existing PHP apps.
The plan here between Carnage and I is to start to lift and shift my existing work across, to the dagger docs.
Carnage, Charjr and I have a team call scheduled for this coming Friday to go over the Dagger PHP state of play, what's missing over all.
I'll raise the question of Docs on that meeting and we can circle back with a good plan.
Is this okay?
sounds great!
Expect a report/notes from me on Friday, on outstanding items and when/how we plan to have them solved by.
/cc @summer sequoia @serene light
awesome. Just keep in mind that we are trying to keep all of our "integration" pages in the same format. Thanks again for all your contributions!
You can find the integration page template here: https://github.com/dagger/dagger/blob/main/docs/current_docs/integrations/_integration.mdx.template
Not a problem. We will take a look on Friday to understand it
@tropic whale @green otter instead of above, any objections to merging the current version asis and then iterating on it? We can ofc add more examples as they arrive and the PHP SDK becomes more stable?.
Just wait until after Friday. We will review it, collectively, in the meeting and come back. π
Let's not rush a merge through
option 4; have sdk/php for the runtime and dev/php for the dev module
The readme that is generated by dagger init --sdk=php is fairly comprehensive on how to use the PHP SDK
Looking at the contents of the various sdk/X/dev modules I may have a suggestion
which we can discuss later, I just want to write it down before I forget π
context: I am refactoring our CI and my last obstacle is integrating the SDKs...
option 5: move runtime to runtime folder and in the alias (php), point to runtime instead.
@cobalt pelican what do you think of revert move dagger.json on that PR? So we can push context directory setup forward without any blocking.
Are there any plans to allow for extending dagger objects (especially core ones) in modules? I'm thinking I'd like to extend Container to make a PHPContainer, which along with all the existing container functions also has some additional php specific things, like composer commands added as additional functions. As is I can create a dagger object which has all of those things, but it can't be passed to other functions which want a Dagger Container object without unwrapping it first
I added a fix to apply ignore on context directory git source too: https://github.com/dagger/dagger/pull/8430
Thanks @cobalt pelican for your help
Fixe based #8369 and @helderco feedbacks
Without this fix
dagger call -m github.com/wingyplus/dagger/sdk/php/runtime@cd3a3e724aa5a2ce259fe6b217f0efe5abaaabcb source-dir
_type: Directory
digest: sh...
wingyplus@WINGYMOMO ~/s/g/d/d/s/php (php-context-dir)> with-dev dagger call -m github.com/wingyplus/dagger/sdk/php/runtime@cd3a3e724aa5a2ce259fe6b217f0efe5abaaabcb source-dir
β connect 0.3s
β initialize 5.6s
β prepare 0.0s
β phpSdk: PhpSdk! 0.6s
β PhpSdk.sourceDir: Directory! 0.0s
β Directory.digest: String! 0.1s
β Directory.entries: [String!]! 0.1s
Setup tracing at https://dagger.cloud/traces/setup. To hide: export NOTHANKS=1
_type: Directory
digest: sha256:87f768c76fbf1901d1b036461fc9207d82f7eccfc26d892540ef276e332aafbb
entries:
- LICENSE
- README.md
- composer.json
- composer.lock
- generated
- scripts
- src
π
Yeah, just do it on top of Tom's PR for git remote, and don't forget to limit what's loaded with dagger.json now that you don't need to load the SDKs files from there (to get them in dag.CurrentModule().Source()). π
So I can drop all include/exclude in dagger.json?
https://github.com/dagger/dagger/pull/8369 Done! π
https://github.com/dagger/dagger/pull/8411 (shouldn't conflict with Win's PR)
Add support for default path and ignore in modules created using the PHP SDK.
I'm having a confusing issue with setting up a constructor:
We've decided, if the PHP magic method __construct is exposed as a DaggerFunction then it is the constructor for the module.
I have this module:
#[DaggerFunction]
public function __construct(
private Directory $source,
) {
}
#[DaggerFunction('Retrieve a base PHP CLI Container')]
public function php(): PhpContainer
{
return new PhpContainer($this->source);
}
and call
dagger call --source=. php
This works fine.
Then I try running a DaggerFunction on my PhpContainer called test
dagger call --source=. php test
This blows up:
[ERROR] Method DaggerModule\MyModule::() does not exist
Is this an error anyone recognises? Or is this a quirk of me having not gotten it quite working?
I've put up a draft PR if anyone has the time to help π
https://github.com/dagger/dagger/pull/8437
We've decided, if the PHP magic method
__constructis exposed as aDaggerFunctionthen it is theconstructorfor the module.
Thatβs not necessary. As constructors go, only the main objectβs constructor can be registered. So just register it if itβs defined. Not necessary for other object types, just the main one.
It's merged now: https://github.com/dagger/dagger/pull/8430 π
Fixe based #8369 and @helderco feedbacks
Without this fix
dagger call -m github.com/wingyplus/dagger/sdk/php/runtime@cd3a3e724aa5a2ce259fe6b217f0efe5abaaabcb source-dir
_type: Directory
digest: sh...
Nice! The PR https://github.com/dagger/dagger/pull/8369 is now rebased against main branch. π
π
just noticed that the sdk_php.go Test function doesn't spin up a dev engine π€
which means it's querying against the main engine - so if new apis are added, which @cloud trench has hit, then we're testing against the wrong engine
does it make sense to alter the test function to take a service? and then have something like the installer function?
@obsidian forge that's one thing I caught in my CI cleanup. Would love to enroll you & @cobalt pelican so we can get that done together, it massively simplifies our CI in general, and will clarify the contract between core and SDK pipelines, in a much needed way (it's a mess at the moment)
among other things we have drift between sdk dev modules (not used in CI with the exception of python) and core sdk_xxx.go functions which reimplement the same stuff, slightly differently, in Go, and are called in CI (but perhaps not used by SDK devs upstream?)
think an interface would be good for this - we could have an Installer interface that has an Install method. then we implement that on the DaggerDev top-level, and pass that into the sdk modules
I think we added the php dev module into CI? it was certainally the plan to do that
definitely a smart idea. Why wouldn't we? π
It is in CI. But It may not be spinning up a dev engine. I think that was an issue @cobalt pelican asked for a follow up on:
https://github.com/dagger/dagger/pull/8112#pullrequestreview-2221860777
I may be mistaken on the issue, but that's what it is sounding like to me.
FYI @zealous venture and @tropic whale ..etc
We had our PHP group call today (@carnage, @serene light) We spent the 1hr only discussing the documentation stuff, and he have conclusions drawn on, and positive improvements to make.
@serene light is prepping some functional examples, and give me over the weekend to write up the meeting minutes and conclusions.
I'm focusing on some dagger tutorials stuff with @pure lodge atm, so prioritizing and will circle back.
Cheers π
Thanks for the update and taking the time to discuss this! Could you please clarify when you think the examples would be ready? Also, do you plan to push them to the same PR or how should we review your proposed improvements?
Probably before the end of Tuesday. It shouldn't be too hard (famous last words) but I try to spend less time at the keyboard on weekends.
I can push them to the same PR if that is the most convenient way to do it, if you would prefer to receive them separately let me know π
Yes, that should be fine. Thanks
Hi, everyone.
Welcome @hidden cairn
Nice ElePHPant photo
Yes @zealous venture give me at some point today to write an update.
Charjr (john) is going to do the work and PR to you, but my message will make more sense in context.
Speak soon. Thanks
Nice to meet you, @green otter .
@serene light change the code so it doesn't git clone a repo, but mounts the source code.
Update the command to do --source=.
withDirectory()
We can't do --source=., default paths havent been merged yet
Can you take my phpstan code too? Add that as another test.
Lemme get you the code from my workshop.
Add support for default path and ignore in modules created using the PHP SDK.
@serene light you're not understanding me π .. we can already bring code into the container. This was possible from day 1.. You're thinking of something else.
Add the Directory argument and call it $source
Are we making examples expecting them to supply their own project, and not with an example project?
If that's the case we can probably go back to the original suggestion of just reusing code from PhpSdkDev.php
the bitnami:laravel container means we don't need certain lines like: ->withEnvVariable('COMPOSER_ALLOW_SUPERUSER', '1') but as it turns out that's because that docker image already does it and uses root as the user
But if we're using the code from PhpSdkDev then I already have functional examples of running PHPUnit, PHPCS, PHPCBF and PHPStan from any generic php container
I understand if we make any complex examples in the future of setting up nginx then bitnami:laravel would be handy. But for running basic CLI tools it might be more convenient simply to use a framework-agnostic container since we run a composer install anyway
And obviously saves time since I can just reuse code
@serene light hey! ping my name when you reply, so I see it π
@green otter I've reused the PhpSdkDev but reworked it to avoid that allow_superuser stuff
@serene light
- The example approach is for you to let them add Dagger to their existing project. They will have a project already, and we want to get Dagger on to it.
So that's why you're doing ->withDirectory()
- Stick with the bitnami laravel image. It's strategically being used here. Add on the phpcs and phpstan calls onto this example, and that's fit for purpose.
In the future more things will come, that we want to use the laravel image for
@green otter Playing Devil's advocate a little: Why not both?
We could have the framework-agnostic tests and static analysis etc.
then framework-specific example for the framework-specific publishing and what not
If they're used as separate examples, built from separate containers.
The only downside I suppose is based on having to have 2 different build function examples
For now, let's just stick to the plan π please
There's good reasons for it, but we can talk about it more over a call, soon.
Fair enough π
I'm going to DM you a link to some of my workshop code.
I would like to understand the examples that you are working on @serene light . We currently have two docs:
- the previous guide which used a Laravel app: https://archive.docs.dagger.io/0.9/128409/build-test-publish-php
- the current revision which uses a Slim app (and is simpler): https://github.com/dagger/dagger/pull/8321
Are you adapting one of these?
Hey @zealous venture
Here is the update from Friday's call and stuff. Sorry for the delay in replying.
Integrations PHP page - current examples on the site doesn't reflect real life of a PHP developer.
-
The changes in your current PR are to remove the apache webserver from the docker image, and to bring in Slim Framework.
-
Having a docker image without a webserver isn't reflecting real life in PHP, so we need the webserver back in there, but not apache as nobody uses apache anymore.
-
Using Slim isn't a good choice either as it's super niche and not reflective of the real life of PHP developer, and they can't relate.
I asked myself what is the purpose of this page? What should user experience be?
The answer is it should outline examples of things in the day and life of a PHP developer, so that is what Chris, John, and I discussed on the call, that we will bring to the table some real-life-like samples and scenarios of a PHP developer, that they can relate to and immediately pick up, an start using Dagger on their PHP projects.
Lots of this content is already on my Dagger PHP workshop, so we can quickly lift them across.
Note: We're going to add the "PHP" tab here, too, on this page only, and have a note that it's "experimental" and not official PHP SDK, yet, but at least the PHP people can read PHP code (upon page load), but they can switch to the other languages on the tabs, too.
As for your question about your current PR, which strips out Apache.. We will come up with new page content for PHP, and file a PR for it, you can expect this later today π
Thanks for the info, that helps. One comment: regarding adding a PHP tab to the page, we decided some time ago not to document experimental SDKs in code listings. So I would skip that atm and only have the code in the officially supported languages.
@zealous venture I understand, and I understand why that decision is made across the entire dagger.io website
I'm not suggesting you revert on that decision, but given we're on a language-specific page, then we should have it here, as the exception to the rule, so that it makes sense.
If I land on a PHP page and don't see PHP code, then it will feel confusing, coz they are PHP developers, not Golang developers.
Outside of this 1 page, then these factors don't exist
@serene light your pr here https://github.com/dagger/dagger/pull/8478
reminded me of something i hit about a couple years ago in docker - turns out all the docker build tools used to produce 3-space indented json everywhere, and there were critical tooling pieces that relied on it...
insane indent levels, always good fun π
That is irritating! Especially because it's only off by 1, I never notice it when it's first generated. Then I start editing it and am confused why my indentation is off by 1...
It took me a long while to realise it was the template itself causing the issue! π€¦ββοΈ
Has anything changed between 0.12 and 0.13 regarding AbstractScalars and enums?
I'm running into these errors:
Error: get module name: input: failed to get schema: failed to get schema for module "test-everything": failed to create function "testBuiltinAbstractScalar": failed to find mod type for function "testBuiltinAbstractScalar" return type: "Json!"
I don't think so? do you have a snippet of code?
abstract scalars aren't a dagger thing as far as i'm aware though, so not entirely sure
I don't fully understand how the automatically generated code works yet, but the PHP SDK generates an AbstractScalar interface.
abstract readonly class AbstractScalar implements Stringable
{
public function __construct(private string $value)
{
}
public function getValue(): string
{
return $this->value;
}
public function __toString(): string
{
return $this->value;
}
public static function from(string $value): static
{
return new static($value);
}
}
Which is implemented by things like IDs, Platform and Json
/**
* The platform config OS and architecture in a Container.
*
* The format is [os]/[platform]/[version] (e.g., "darwin/arm64/v7", "windows/amd64", "linux/arm64").
*/
readonly class Platform extends Client\AbstractScalar
{
}
It's basically a fancy wrapper around a string
Basically, I had enums and abstract scalars working as far as I was aware, but now they only work in limited instances and I've been struggling to fix it
Sorry forgot to make them replies @obsidian forge
Either way, thank you for the input. It is probably a change I made, I'll just have to keep digging.
Hey @serene light @green otter, hope you guys are doing well!
There's an issue with the PHP SDK generator on that PR: https://github.com/dagger/dagger/pull/8427#pullrequestreview-2324715836
Could you have a look so we can merge it, it's the last thing that hold the PR π
It's quite a strange issue though.
/cc @cloud trench
@obsidian forge In reference to #1288075868073234494 message
Pointing to the specific commit hash would be quite annoying for development. As dagger moves fast π
I end up rebasing my PRs incredibly frequently and would have to update this every time. It would be a pain and also a mistake waiting to happen.
Are there any alternatives that might work?
is the dev module always using the latest and greatest features? i think the options probably are:
- leave it as implicit/explicit main - if we ever make backwards incompat changes to the php sdk, old engines will fail to build - this is pretty bad
- leave it as implicit current engine tag - this means, that like the python/typescript dev modules, you can't use features that have been merged to main and haven't been released
- pin to a specific commit on main (but how to make sure it doesn't lag too far behind, etc, is tricky)
personally, i'd be happiest with the 2nd option, but means that for example, you wouldn't be able to use constructors in the php dev module until v0.13.4 is released
(which is no worse than the other dev sdks)
That is a bit awkward as it sounds like we wouldn't be able to test new SDK features until after they've been merged for a while.
Do other SDKs have a way around this? Or do new feature tests have a delay?
@obsidian forge
for tests imo, it doesn't matter hugely - but for the dev module (which is imported into the core ci), it does
fyi @cobalt pelican
@cobalt pelican @obsidian forge I think the best solution sounds like we fix it at 0.13.4 once that's released. That way we wont break anything currently, and then bump it to the latest version during any PR
Yeah, for Python's dev module (or any CI module) I need to keep it compatible between dev and stable. You need to make sure the engineVersion in dagger.json points to a released version of dagger, and not a dev build.
It's just because our CI runs with both, in order to catch possible regressions in a change, earlier.
@cobalt pelican Would it be possible to get https://github.com/dagger/dagger/pull/8411 re-reviewed please? I think I've addressed all feedback π
I just need to double check on the isOptional thing, but I need to take care of something else now. Will get back to it after.
public function isOptional(): bool
{
return $this->type->nullable
|| $this->default !== null
|| $this->defaultPath !== null;
}
Basically it's optional if the type has been specified as nullable OR has a default value OR has a defaultPath
Then I tested the function here:
#[Test]
#[DataProvider('providePropertiesThatMakeArgumentsOptional')]
public function itMayBeOptional(
bool $expected,
Type $type,
?Json $default,
?string $defaultPath,
): void {
$sut = new Argument('sut', '', $type, $default, $defaultPath);
self::assertSame($expected, $sut->isOptional());
}
And no worries, take your time. Thank you very much for taking the time to review it today π
That's the thing, isOptional isn't necessarily true if there's a default value.
isOptional actually means "does it take a null"?
So an argument on the language side that has a default, but that default being a complex type that can't be registered to dagger, you need to force it with withOptional even though it doesn't take a null. But at runtime the SDK needs to detect this so that if the engine sends a null, the SDK actually needs to omit it so the default value gets triggered.
Today, the engine never sends a null, but that could change so it's good to prepare for it.
Summary While documenting optional and default values in Python functions I came upon some inconsistencies in implementations due to different assumptions. The term βOptionalβ thatβs used in module...
Right, it is a bit confusing.
So it is only optional if it's nullable. however I should force the engine to see it as optional if there's a default path?
I'll read the context more thoroughly shortly, when I have the time. Thank you for your input
isOptional should really only be forced when the function has a default value but can't be reported to dagger (e.g., complex type). I think when it's a defaultPath it's the engine that should force that in, rather than continue to make SDKs do it.
That is fair enough, so put simply, within the PHP SDK:
Optional means nullable, that's it.
Hi. We've been having a few discussions on docs internally so I'd like to provide a quick update related to the PHP page.
- PHP "integration" page in docs - We're pushing a big docs change later today and we would like to include this page in it. So we're planning to merge the page in its current state, but ofc it's totally fine for you to send a PR with new examples etc once they're ready. https://github.com/dagger/dagger/pull/8321
- PHP code tab - Yes to this with some qualifications. We're going to try it as an experiment only on this PHP page as you suggested earlier. We will however need to highlight that the PHP SDK is experimental, both in the tab label eg.
PHP (Experimental)and as a callout box in the tab content. We're also assuming that as maintainers of the PHP SDK, you'll take care of keeping the example code in the PHP tab sync with future changes in the SDK.
Thank you for all your hard work on the SDK and for all the feedback as well!
Makes sense to me. I'll try to keep the page in mind during PRs
Thank you
π Hi @cobalt pelican We've noticed a bug with enum support for the PHP SDK.
I've been working on it here.
Looking at our implementation, it seems identical to the typescript implementation:
// Register all enums defined by this modules
Object.values(module.enums).forEach((enum_) => {
let typeDef = dag.typeDef().withEnum(enum_.name, {
description: enum_.description,
})
Object.values(enum_.values).forEach((value) => {
typeDef = typeDef.withEnumValue(value.value, {
description: value.description,
})
})
mod = mod.withEnum(typeDef)
})
foreach ($daggerObjects as $daggerObject) {
if ($daggerObject instanceof Dagger\ValueObject\DaggerEnum) {
$enumTypeDef = dag()
->typeDef()
->withEnum(
$daggerObject->getNormalisedName(),
$daggerObject->getDescription(),
);
foreach ($daggerObject->getCases() as $case => $description) {
$enumTypeDef->withEnumValue($case, $description);
}
$daggerModule = $daggerModule->withEnum($enumTypeDef);
continue;
}
My implementation works for built in enums. But it is failing on user-defined enums with this error:
Error: invalid argument "hello" for "--arg" flag: value should be one of
It's just empty after that... so presumably my implementation is failing to register the values properly.
As a separate issue, some of the scalar types work and some don't.
For instance, I can pass Platform as an argument and return it.
I cannot pass Json as an argument nor can I return it.
Something very odd is happening with php codegen locally for me (running dagger call sdk php generate export --path .). When I run locally on main with no changes I get this diff: https://github.com/sipsma/dagger/commit/7f15a0020fc89ff912a56af3ed4b01580492f02b
Consists of moving some curly braces from one line to the line below it.
But in our CI that never happens and checks pass.
It's a problem because I have to hand edit the generated files or else CI in my PRs fails after regenning SDKs.
Any idea what could be happening? Seems extremely odd it's different locally and in CI (I'm on arm64 linux if that somehow matters due to a platform specfic container image at a different version from x86 or something like that)
cc @cobalt pelican @obsidian forge in case this rings any bells
Ah... on a hunch I just ran git clean -d -f -x ., saw that sdk/php/vendor got removed, and now when I run codegen that diff goes away...
So I guess a stale vendor dir broke it somehow? Either way, not a huge deal, just a big gotcha laying around to be aware of
some of us have been bitten by this in the past, @serene light any ideas how we could potentially avoid users tripping into this?
@cobalt pelican @obsidian forge I'm noticing the php integration tests, that were passing on 0.13.3 are failing on 0.13.4.
Has something changed that might break them? None of the breaking changes look related to the issue:
π₯ Breaking Changes
Changed behavior of Git to default keep the .git directory by @obsidian forge in #8318
This can be disabled with tree's new discardGitDir option. Modules with
older engineVersions will keep the old behavior.
Deprecated git's keepGitDir argument by @obsidian forge in #8318
Looking at the tests, they seem to assert that basic functionality works as expected, making a file, directory or container.
I haven't yet learned the nitty gritty part of how the PHP SDK integrates with dagger, so any insight would be appreciated.