docs: publish one column of implemented operations and nothing else

This commit is contained in:
Julian Sommer
2026-09-15 11:27:17 +10:00
parent 881a66ab57
commit c0d54e6131
5 changed files with 125 additions and 140 deletions
+21 -35
View File
@@ -30,38 +30,24 @@ Registry replication is a stub for the same kind of reason: a deployment is a si
### Operations
| Operation | Status |
|---|---|
| `BatchCheckLayerAvailability` | 🟡 Stub |
| `BatchDeleteImage` | ✅ Implemented |
| `BatchGetImage` | ✅ Implemented |
| `CompleteLayerUpload` | 🟡 Stub |
| `CreateRepository` | ✅ Implemented |
| `DeleteLifecyclePolicy` | ✅ Implemented |
| `DeleteRepository` | ✅ Implemented |
| `DeleteRepositoryPolicy` | ✅ Implemented |
| `DescribeImages` | ✅ Implemented |
| `DescribeRegistry` | 🟡 Stub |
| `DescribeRepositories` | ✅ Implemented |
| `GetAuthorizationToken` | ✅ Implemented |
| `GetDownloadUrlForLayer` | 🟡 Stub |
| `GetLifecyclePolicy` | ✅ Implemented |
| `GetLifecyclePolicyPreview` | ✅ Implemented |
| `GetRegistryPolicy` | 🟡 Stub |
| `GetRepositoryPolicy` | ✅ Implemented |
| `InitiateLayerUpload` | 🟡 Stub |
| `ListImages` | ✅ Implemented |
| `ListTagsForResource` | ✅ Implemented |
| `PutImage` | ✅ Implemented |
| `PutImageTagMutability` | ✅ Implemented |
| `PutLifecyclePolicy` | ✅ Implemented |
| `PutRegistryPolicy` | 🟡 Stub |
| `PutReplicationConfiguration` | 🟡 Stub |
| `SetRepositoryPolicy` | ✅ Implemented |
| `StartLifecyclePolicyPreview` | ✅ Implemented |
| `TagResource` | 🟡 Stub |
| `UntagResource` | 🟡 Stub |
| `UploadLayerPart` | 🟡 Stub |
| `GetImageScanningConfiguration` | 🔒 Outside the pinned model |
| `ListRepositories` | 🔒 Outside the pinned model |
| `ReplicateImage` | 🔒 Outside the pinned model |
| Operation |
|---|
| `BatchDeleteImage` |
| `BatchGetImage` |
| `CreateRepository` |
| `DeleteLifecyclePolicy` |
| `DeleteRepository` |
| `DeleteRepositoryPolicy` |
| `DescribeImages` |
| `DescribeRepositories` |
| `GetAuthorizationToken` |
| `GetLifecyclePolicy` |
| `GetLifecyclePolicyPreview` |
| `GetRepositoryPolicy` |
| `ListImages` |
| `ListTagsForResource` |
| `PutImage` |
| `PutImageTagMutability` |
| `PutLifecyclePolicy` |
| `SetRepositoryPolicy` |
| `StartLifecyclePolicyPreview` |
+33 -38
View File
@@ -26,41 +26,36 @@ Clusters, services and tasks run on EC2 container instances. There is no Fargate
### Operations
| Operation | Status |
|---|---|
| `CreateCapacityProvider` | ✅ Implemented |
| `CreateCluster` | ✅ Implemented |
| `CreateService` | ✅ Implemented |
| `DeleteCapacityProvider` | ✅ Implemented |
| `DeleteCluster` | ✅ Implemented |
| `DeleteService` | ✅ Implemented |
| `DeregisterContainerInstance` | ✅ Implemented |
| `DeregisterTaskDefinition` | ✅ Implemented |
| `DescribeCapacityProviders` | ✅ Implemented |
| `DescribeClusters` | ✅ Implemented |
| `DescribeContainerInstances` | ✅ Implemented |
| `DescribeServices` | ✅ Implemented |
| `DescribeTaskDefinition` | ✅ Implemented |
| `DescribeTasks` | ✅ Implemented |
| `ListAccountSettings` | 🟡 Stub |
| `ListClusters` | ✅ Implemented |
| `ListContainerInstances` | ✅ Implemented |
| `ListServices` | ✅ Implemented |
| `ListServicesByNamespace` | 🟡 Stub |
| `ListTagsForResource` | ✅ Implemented |
| `ListTaskDefinitionFamilies` | 🟡 Stub |
| `ListTaskDefinitions` | ✅ Implemented |
| `ListTasks` | ✅ Implemented |
| `PutAccountSetting` | 🟡 Stub |
| `PutClusterCapacityProviders` | ✅ Implemented |
| `RegisterContainerInstance` | ✅ Implemented |
| `RegisterTaskDefinition` | ✅ Implemented |
| `RunTask` | ✅ Implemented |
| `StartTask` | ✅ Implemented |
| `StopTask` | ✅ Implemented |
| `SubmitTaskStateChange` | ✅ Implemented |
| `TagResource` | ✅ Implemented |
| `UntagResource` | ✅ Implemented |
| `UpdateCluster` | 🟡 Stub |
| `UpdateContainerInstancesState` | ✅ Implemented |
| `UpdateService` | ✅ Implemented |
| Operation |
|---|
| `CreateCapacityProvider` |
| `CreateCluster` |
| `CreateService` |
| `DeleteCapacityProvider` |
| `DeleteCluster` |
| `DeleteService` |
| `DeregisterContainerInstance` |
| `DeregisterTaskDefinition` |
| `DescribeCapacityProviders` |
| `DescribeClusters` |
| `DescribeContainerInstances` |
| `DescribeServices` |
| `DescribeTaskDefinition` |
| `DescribeTasks` |
| `ListClusters` |
| `ListContainerInstances` |
| `ListServices` |
| `ListTagsForResource` |
| `ListTaskDefinitions` |
| `ListTasks` |
| `PutClusterCapacityProviders` |
| `RegisterContainerInstance` |
| `RegisterTaskDefinition` |
| `RunTask` |
| `StartTask` |
| `StopTask` |
| `SubmitTaskStateChange` |
| `TagResource` |
| `UntagResource` |
| `UpdateContainerInstancesState` |
| `UpdateService` |
+36 -38
View File
@@ -26,41 +26,39 @@ The data plane is a system-managed load balancer VM, launched automatically duri
### Operations
| Operation | Status |
|---|---|
| `AddListenerCertificates` | ✅ Implemented |
| `AddTags` | ✅ Implemented |
| `CreateListener` | ✅ Implemented |
| `CreateLoadBalancer` | ✅ Implemented |
| `CreateRule` | ✅ Implemented |
| `CreateTargetGroup` | ✅ Implemented |
| `DeleteListener` | ✅ Implemented |
| `DeleteLoadBalancer` | ✅ Implemented |
| `DeleteRule` | ✅ Implemented |
| `DeleteTargetGroup` | ✅ Implemented |
| `DeregisterTargets` | ✅ Implemented |
| `DescribeAccountLimits` | ✅ Implemented |
| `DescribeListenerCertificates` | ✅ Implemented |
| `DescribeListeners` | ✅ Implemented |
| `DescribeLoadBalancerAttributes` | ✅ Implemented |
| `DescribeLoadBalancers` | ✅ Implemented |
| `DescribeRules` | ✅ Implemented |
| `DescribeSSLPolicies` | ✅ Implemented |
| `DescribeTags` | ✅ Implemented |
| `DescribeTargetGroupAttributes` | ✅ Implemented |
| `DescribeTargetGroups` | ✅ Implemented |
| `DescribeTargetHealth` | ✅ Implemented |
| `ModifyListener` | ✅ Implemented |
| `ModifyLoadBalancerAttributes` | ✅ Implemented |
| `ModifyRule` | ✅ Implemented |
| `ModifyTargetGroup` | ✅ Implemented |
| `ModifyTargetGroupAttributes` | ✅ Implemented |
| `RegisterTargets` | ✅ Implemented |
| `RemoveListenerCertificates` | ✅ Implemented |
| `RemoveTags` | ✅ Implemented |
| `SetIpAddressType` | ✅ Implemented |
| `SetRulePriorities` | ✅ Implemented |
| `SetSecurityGroups` | ✅ Implemented |
| `SetSubnets` | ✅ Implemented |
| `DescribeListenerAttributes` | 🔒 Outside the pinned model |
| `ModifyListenerAttributes` | 🔒 Outside the pinned model |
| Operation |
|---|
| `AddListenerCertificates` |
| `AddTags` |
| `CreateListener` |
| `CreateLoadBalancer` |
| `CreateRule` |
| `CreateTargetGroup` |
| `DeleteListener` |
| `DeleteLoadBalancer` |
| `DeleteRule` |
| `DeleteTargetGroup` |
| `DeregisterTargets` |
| `DescribeAccountLimits` |
| `DescribeListenerCertificates` |
| `DescribeListeners` |
| `DescribeLoadBalancerAttributes` |
| `DescribeLoadBalancers` |
| `DescribeRules` |
| `DescribeSSLPolicies` |
| `DescribeTags` |
| `DescribeTargetGroupAttributes` |
| `DescribeTargetGroups` |
| `DescribeTargetHealth` |
| `ModifyListener` |
| `ModifyLoadBalancerAttributes` |
| `ModifyRule` |
| `ModifyTargetGroup` |
| `ModifyTargetGroupAttributes` |
| `RegisterTargets` |
| `RemoveListenerCertificates` |
| `RemoveTags` |
| `SetIpAddressType` |
| `SetRulePriorities` |
| `SetSecurityGroups` |
| `SetSubnets` |
+22 -25
View File
@@ -11,8 +11,9 @@ import (
"unicode/utf8"
)
// Published operation states. The symbol carries the status at a glance and the
// label disambiguates it; the docs site escapes inline SVG, so these are runes.
// Operation states. Only Implemented reaches a published page; the rest sort
// the internal report. The symbol carries the status at a glance and the label
// disambiguates it; the docs site escapes inline SVG, so these are runes.
const (
StatusImplemented = "✅ Implemented"
StatusStub = "🟡 Stub"
@@ -104,11 +105,21 @@ func (c OperationCoverage) OperationStatuses(page PageMetadata) ([]OperationStat
}
statuses = append(statuses, OperationStatus{Operation: operation, Status: status})
}
// A route outside the pinned model is still only as real as its handler, so
// its dispatch state wins: being absent from the model says nothing about
// whether the platform answers it.
for _, operation := range c.Extra {
if internal[operation] {
continue
}
statuses = append(statuses, OperationStatus{Operation: operation, Status: StatusOutsideModel})
status := StatusOutsideModel
switch {
case stubbed[operation]:
status = StatusStub
case unsupported[operation]:
status = StatusNotImplemented
}
statuses = append(statuses, OperationStatus{Operation: operation, Status: status})
}
return statuses, nil
}
@@ -327,32 +338,18 @@ func RenderServicePage(coverage OperationCoverage, pages PageSet, intro string)
return body.String(), nil
}
// writeOperations publishes one row per operation the platform serves. A gap is
// left out, and so is an operation the platform will never offer: the page says
// what is there, and the internal report carries everything that is not. The
// status column is written only where a row needs it, because a table whose
// every cell reads "Implemented" says nothing the heading has not.
// writeOperations publishes one row per operation the platform implements from
// the pinned model, and nothing else. There is no status column because every
// row carries the same status: a gap, a stub, a route the model does not
// describe and an operation the platform will never offer are all the internal
// report's to carry.
func writeOperations(body *strings.Builder, statuses []OperationStatus) {
rows := make([]OperationStatus, 0, len(statuses))
uniform := true
body.WriteString("### Operations\n\n| Operation |\n|---|\n")
for _, status := range statuses {
if status.Status == StatusNotImplemented || status.Status == StatusNotApplicable {
if status.Status != StatusImplemented {
continue
}
uniform = uniform && status.Status == StatusImplemented
rows = append(rows, status)
}
if uniform {
body.WriteString("### Operations\n\n| Operation |\n|---|\n")
for _, row := range rows {
fmt.Fprintf(body, "| `%s` |\n", row.Operation)
}
return
}
body.WriteString("### Operations\n\n| Operation | Status |\n|---|---|\n")
for _, row := range rows {
fmt.Fprintf(body, "| `%s` | %s |\n", row.Operation, row.Status)
fmt.Fprintf(body, "| `%s` |\n", status.Operation)
}
}
+13 -4
View File
@@ -65,7 +65,7 @@ func TestParsePageSetRejectsUnpublishableMetadata(t *testing.T) {
}
}
func TestRenderServicePageCarriesEveryPublishedStatus(t *testing.T) {
func TestRenderServicePagePublishesOnlyImplementedOperations(t *testing.T) {
pages := testPageSet(t)
coverage, err := CompareOperations(STS, DispatchInventory{
Registered: []string{"AssumeRole", "GetCallerIdentity", "GetSessionToken", "PublishInternal"},
@@ -87,14 +87,23 @@ func TestRenderServicePageCarriesEveryPublishedStatus(t *testing.T) {
"# STS API Coverage\n\n## Overview\n",
"Spinifex implements **1 operation** in the STS `2011-06-15` API model.",
"### Scope\n\nHand-written prose.",
"| `AssumeRole` | " + StatusImplemented + " |",
"| `GetSessionToken` | " + StatusStub + " |",
"| `PublishInternal` | " + StatusOutsideModel + " |",
"### Operations\n\n| Operation |\n|---|\n| `AssumeRole` |\n",
} {
if !strings.Contains(page, want) {
t.Errorf("page does not contain %q:\n%s", want, page)
}
}
// Everything other than an implemented operation from the pinned model is
// the internal report's: a stub answers with an error, a refusal serves
// nothing, and a route the model does not describe has no page to sit on.
for _, absent := range []string{
"GetSessionToken", "GetCallerIdentity", "PublishInternal",
StatusStub, StatusOutsideModel, StatusNotImplemented, "Status",
} {
if strings.Contains(page, absent) {
t.Errorf("page publishes %q:\n%s", absent, page)
}
}
if strings.Contains(page, "<details") || strings.Contains(page, "<summary") {
t.Errorf("page contains raw HTML the docs site would escape:\n%s", page)
}