Detailed description
Right now every published port has to be written as an object, even when the only thing I'm setting is the port number:
service:
ports:
web:
port: 8080
targetPort already defaults to port, and protocol already defaults to TCP, so for the common case that nested object isn't carrying any information I didn't already give it. I keep writing three lines where one would do.
#196 added a string shorthand for files and volumes, and mentioned in passing that a few other properties could get the same treatment. service.ports feels like the most obvious next one:
service:
ports:
web: 8080
Same idea as the files shorthand: the full object form stays exactly as it is, this is just an extra accepted form for the simple single-port case. web: 8080 would mean the same thing as web: { port: 8080 }.
I think resources could take the same treatment (db: postgres instead of db: { type: postgres }), but that one is less clear-cut because the shorthand would drop class/id/params. I've left it as an open question at the bottom instead of bundling it in here.
Context
Most of the Score files I write are small, and the ports block is one of the spots where the boilerplate-to-content ratio is worst. A single published port is by far the common case, so this shorthand would cover the majority of real files people write.
It also lines up with the v1b1 to v1 ergonomics direction: keep the simple cases short, and only reach for the full object form when you actually need protocol or a different targetPort.
It's low risk for existing users. The object form keeps working unchanged, so nobody has to touch their files. This is purely an additional way to express the simple case, the same way files and volumes behave after #196.
Possible implementation
Same mechanism as #198: wrap the existing additionalProperties in a oneOf and add a scalar branch. For ports the scalar is an integer in the valid port range, and it maps to { port: <n> }.
"additionalProperties": {
"oneOf": [
{ "$ref": "#/$defs/servicePort" },
{
"description": "Shorthand for the published port. Equivalent to '{ port: <value> }'.",
"type": "integer",
"minimum": 1,
"maximum": 65535
}
]
}
One nice property here: servicePort is an object and the shorthand is an integer, so the two oneOf branches can never both match. There's no ambiguity to guard against, which means this doesn't even need the not/required guard that files and volumes need to keep their deprecated array form out.
Rollout would follow the same path as #196:
One alternative I considered and would lean against: also accepting a quoted string like "8080" to match how Compose writes ports. servicePort.port is an integer today, so keeping the shorthand an integer stays consistent and avoids two spellings of the same number.
Additional information
Prior art in the repo: #123 (map form for files/volumes) and #198 (the string shorthand this is modeled on).
The one thing I'd like to settle before writing a PR is whether resources should get the same shorthand:
mapping to { type: postgres }. It reads well and matches the "I want a database of type X" framing in the README. Unlike ports, though, it loses information: class, id, params, and metadata all disappear in the short form (the same tradeoff as files only carrying content). So two things worth deciding:
- Do we want the resource shorthand in v1 at all, or keep this to
service.ports for now?
- If we do want it, should the string be allowed to carry a class too (e.g.
postgres.large), or strictly type only?
Happy to walk through this at a community meeting first. I can start on the service.ports PR right away if the approach looks right, and we can treat resources as a separate follow-up once the question above is settled.
Detailed description
Right now every published port has to be written as an object, even when the only thing I'm setting is the port number:
targetPortalready defaults toport, andprotocolalready defaults to TCP, so for the common case that nested object isn't carrying any information I didn't already give it. I keep writing three lines where one would do.#196 added a string shorthand for
filesandvolumes, and mentioned in passing that a few other properties could get the same treatment.service.portsfeels like the most obvious next one:Same idea as the files shorthand: the full object form stays exactly as it is, this is just an extra accepted form for the simple single-port case.
web: 8080would mean the same thing asweb: { port: 8080 }.I think
resourcescould take the same treatment (db: postgresinstead ofdb: { type: postgres }), but that one is less clear-cut because the shorthand would dropclass/id/params. I've left it as an open question at the bottom instead of bundling it in here.Context
Most of the Score files I write are small, and the ports block is one of the spots where the boilerplate-to-content ratio is worst. A single published port is by far the common case, so this shorthand would cover the majority of real files people write.
It also lines up with the v1b1 to v1 ergonomics direction: keep the simple cases short, and only reach for the full object form when you actually need
protocolor a differenttargetPort.It's low risk for existing users. The object form keeps working unchanged, so nobody has to touch their files. This is purely an additional way to express the simple case, the same way
filesandvolumesbehave after #196.Possible implementation
Same mechanism as #198: wrap the existing
additionalPropertiesin aoneOfand add a scalar branch. For ports the scalar is an integer in the valid port range, and it maps to{ port: <n> }.One nice property here:
servicePortis an object and the shorthand is an integer, so the twooneOfbranches can never both match. There's no ambiguity to guard against, which means this doesn't even need thenot/requiredguard thatfilesandvolumesneed to keep their deprecated array form out.Rollout would follow the same path as #196:
samples/score-full.yamlscore-goto parse the shorthand into the existing structscore-composeandscore-k8sto handle it (should mostly fall out of thescore-gochange)One alternative I considered and would lean against: also accepting a quoted string like
"8080"to match how Compose writes ports.servicePort.portis an integer today, so keeping the shorthand an integer stays consistent and avoids two spellings of the same number.Additional information
Prior art in the repo: #123 (map form for
files/volumes) and #198 (the string shorthand this is modeled on).The one thing I'd like to settle before writing a PR is whether
resourcesshould get the same shorthand:mapping to
{ type: postgres }. It reads well and matches the "I want a database of type X" framing in the README. Unlike ports, though, it loses information:class,id,params, andmetadataall disappear in the short form (the same tradeoff asfilesonly carryingcontent). So two things worth deciding:service.portsfor now?postgres.large), or strictlytypeonly?Happy to walk through this at a community meeting first. I can start on the
service.portsPR right away if the approach looks right, and we can treatresourcesas a separate follow-up once the question above is settled.