Open allenjzhang opened 2 weeks ago
Problems with versioning today:
@added
decorator(or others if changes are not just additive)Other problems that this proposal doesn't cover:
Azure services use api versioning in a specific way that a lot of other services do not. The versioning library needs to be able to accommodate both. We can see versioning of a service as the following:
v1/v2
sub path). In those apis a client would call the same api and get the new data but as it is additive it wouldn't break. The versioning decorators would be mostly for documentation purposes.v2
instead of trying to represent breaking change with decorators.For this we would want 2 things potentially:
For 1.
we should be able to use a new @prerelease
or @preview
decorator on a version enum member to mark it as a preview version. Additionally we could auto detect a preview version if the service use some semver
enum Versions {
`1.0`, // stable
@prerelease
`2.0-preview.1`, // Explicitly marked as a preview
`2.0-beta.1`, // Implicitly inferred as a semver prerelease.
`2.0` // stable
}
For 2.
it is a bit more tricky, this introduce a complex branching system that would be quite hard to reason about. What preview features made it to the next stable version? One potential solution would be that any versioning annotation about a preview version do not apply towards the next stable version. This would mean you need to be explicit about the branching of a preview feature.
enum Versions {
`1.0`, // stable
@preview(Versions.`1.0`)
`2.0-preview.feat1`,
@preview(Versions.`1.0`)
`2.0-preview.feat2`,
`2.0` // stable
}
model Pet {
name: string;
@added(Versions.`2.0-preview.feat1`)
age: number;
@added(Versions.`2.0-preview.feat2`)
@added(Versions.`2.0`) // Here we say in v2 we actually picked this property
dob: plainDate;
}
This approach might sound intresting but it also brings quite some complexity to the table and using versioning for a flag based feature branching might not be the most appropriate.
Another approach could be to use copy of a spec for preview versioning and merging back into the stable folder when moving out of preview. This would keep the main branch clean of preview versioning and would allow to have a clear view of what is in the next stable version without needing immediate cleanup(as the next section describe).
Depending on how preview version evolve they can result in a lot of unnecessary noise in the spec when the next stable is reached. We should provide a way to patch a spec and remove any preview version from a spec.
The tool would automatically updated versioning decorators accordingly.
In the case of 2.
we would also most likely want a tool to apply the annotations to the next stable version.
In the ideal scenario where you are just doing additive change you should just be able to use the @added
decorator. However depending on the size of the new version it might become tedious to apply @added
to every new property, model, etc.
One suggestion was to allow using versioning decorators on namespace to apply to all children.
namespace MyService {
model Cat {}
@added(Versions.v2)
namespace V2 {
model Dog {}
}
}
I think the main problem with this is you are structuring your service according to versioning which could cause issues in emitters that use the namespace as a way to structure the output. Additionally it is quite unlikely that the version change are contained within a single namespace and that would still require a lot of @added
decorators in other places.
Another alternative that was suggested was to infer versioning attributes automatically
model Pet {
adddress: Address;
}
@added(Versions.v2)
model Address {}
in the example above we could argue that address: Address
should be considered as a v2 change automatically. I think this might also sound helpful until you look at Pet and don't understand why address is not in v1
unless you start to see that this model was added in v2
.
That in more complex scenarios would make it much harder to differentiate user errors from versioning done on purpose.
This is a similar approach to 1.
but would mean adding a new language feature that would allow decorating an block code expression
namespace MyService {
model Cat {}
@added(Versions.v2)
{
model Dog {}
}
}
The way this would work is applying the decorators to each elements in the code block. We'd have to decide what happens if the decorator doesn't apply to some of the elements inside. Does it ignore or it errors out.
Versioning feels like a detective's case map