diff --git a/internal/sync/api/manifest.go b/internal/sync/api/manifest.go index a80f21fa..8086b11f 100644 --- a/internal/sync/api/manifest.go +++ b/internal/sync/api/manifest.go @@ -18,15 +18,15 @@ type SyncManifest struct { Items []SyncManifestResource `json:"items"` } -// SyncManifestResource is one versioned baseline entry. +// SyncManifestResource is one versioned baseline entry. The remote manifest +// records the fingerprint and the version of each entry. The descriptor +// metadata of a linked resource, such as its reference digest, lives in the +// sync.lock file only, and the API rejects it. type SyncManifestResource struct { ResourceKind syncdomain.Kind `json:"resourceKind"` ResourceLookupKey string `json:"resourceLookupKey"` Fingerprint string `json:"fingerprint"` Version int `json:"version"` - FingerprintSchema string `json:"fingerprintSchema,omitempty"` - ReferenceDigest string `json:"referenceDigest,omitempty"` - AdapterBehavior string `json:"adapterBehavior,omitempty"` } // SyncManifestUpsert creates an entry, or updates the entry at Version. @@ -35,9 +35,6 @@ type SyncManifestUpsert struct { ResourceLookupKey string `json:"resourceLookupKey"` Fingerprint string `json:"fingerprint"` Version int `json:"version"` - FingerprintSchema string `json:"fingerprintSchema,omitempty"` - ReferenceDigest string `json:"referenceDigest,omitempty"` - AdapterBehavior string `json:"adapterBehavior,omitempty"` } // SyncManifestDeletion removes the entry at Version. diff --git a/internal/sync/manifest/store.go b/internal/sync/manifest/store.go index 0ebed1d4..701461d3 100644 --- a/internal/sync/manifest/store.go +++ b/internal/sync/manifest/store.go @@ -147,14 +147,11 @@ func (store Store) resourcesFromRemote(projectKey string, remote syncapi.SyncMan ) } resources = append(resources, Resource{ - ResourceKind: item.ResourceKind, - ProjectKey: projectKey, - LookupKey: item.ResourceLookupKey, - Fingerprint: item.Fingerprint, - Version: item.Version, - FingerprintSchema: item.FingerprintSchema, - ReferenceDigest: item.ReferenceDigest, - AdapterBehavior: item.AdapterBehavior, + ResourceKind: item.ResourceKind, + ProjectKey: projectKey, + LookupKey: item.ResourceLookupKey, + Fingerprint: item.Fingerprint, + Version: item.Version, }) } return resources, nil @@ -180,9 +177,6 @@ func changes(before, after []Resource) ([]syncapi.SyncManifestUpsert, []syncapi. ResourceLookupKey: resource.LookupKey, Fingerprint: resource.Fingerprint, Version: current.Version, - FingerprintSchema: resource.FingerprintSchema, - ReferenceDigest: resource.ReferenceDigest, - AdapterBehavior: resource.AdapterBehavior, }) } @@ -199,11 +193,12 @@ func changes(before, after []Resource) ([]syncapi.SyncManifestUpsert, []syncapi. return upserts, deletions } +// sameManifestContent reports whether two entries are the same to the remote +// manifest, which records only the fingerprint. The descriptor metadata of a +// linked resource stays in the sync.lock file, so a change to it alone sends +// nothing. func sameManifestContent(left, right Resource) bool { - return left.Fingerprint == right.Fingerprint && - left.FingerprintSchema == right.FingerprintSchema && - left.ReferenceDigest == right.ReferenceDigest && - left.AdapterBehavior == right.AdapterBehavior + return left.Fingerprint == right.Fingerprint } // changesApplied reports whether the remote manifest contains every change. diff --git a/internal/sync/manifest/store_test.go b/internal/sync/manifest/store_test.go index aad16e27..0017c87d 100644 --- a/internal/sync/manifest/store_test.go +++ b/internal/sync/manifest/store_test.go @@ -101,12 +101,7 @@ func TestStoreUpdatesWithRemoteVersions(t *testing.T) { client := &manifestClient{patchResponses: []syncapi.SyncManifest{{ Source: "git:example/repo", Items: []syncapi.SyncManifestResource{ - { - ResourceKind: syncdomain.KindVariation, ResourceLookupKey: "config/existing", - Fingerprint: fingerprint("c"), Version: 4, - FingerprintSchema: syncdomain.ProjectionFingerprintSchema, ReferenceDigest: fingerprint("e"), - AdapterBehavior: "markdown/1", - }, + {ResourceKind: syncdomain.KindVariation, ResourceLookupKey: "config/existing", Fingerprint: fingerprint("c"), Version: 4}, {ResourceKind: syncdomain.KindTool, ResourceLookupKey: "search", Fingerprint: fingerprint("d"), Version: 1}, }, }}} @@ -131,18 +126,36 @@ func TestStoreUpdatesWithRemoteVersions(t *testing.T) { require.Len(t, client.patches, 1) assert.Equal(t, []syncapi.SyncManifestUpsert{ {ResourceKind: syncdomain.KindTool, ResourceLookupKey: "search", Fingerprint: fingerprint("d"), Version: 0}, - { - ResourceKind: syncdomain.KindVariation, ResourceLookupKey: "config/existing", - Fingerprint: fingerprint("c"), Version: 3, - FingerprintSchema: syncdomain.ProjectionFingerprintSchema, ReferenceDigest: fingerprint("e"), - AdapterBehavior: "markdown/1", - }, - }, client.patches[0].upserts) + {ResourceKind: syncdomain.KindVariation, ResourceLookupKey: "config/existing", Fingerprint: fingerprint("c"), Version: 3}, + }, client.patches[0].upserts, "the upsert carries the fingerprint and the version, and no descriptor metadata") assert.Equal(t, []syncapi.SyncManifestDeletion{{ ResourceKind: syncdomain.KindSkill, ResourceLookupKey: "old", Version: 2, }}, client.patches[0].deletions) assert.Equal(t, 4, updated.Resources[1].Version) - assert.Equal(t, syncdomain.ProjectionFingerprintSchema, updated.Resources[1].FingerprintSchema) + assert.Empty(t, updated.Resources[1].FingerprintSchema, "the remote state has no descriptor metadata") +} + +// The remote manifest records only the fingerprint, so a change to the +// descriptor metadata of a linked resource with the same fingerprint sends +// nothing. The sync.lock file keeps that metadata. +func TestStoreSendsNothingForADescriptorMetadataChange(t *testing.T) { + client := &manifestClient{patchResponses: []syncapi.SyncManifest{{Source: "git:example/repo"}}} + store := NewStore(client, "git:example/repo") + previous := Manifest{Resources: []Resource{{ + ResourceKind: syncdomain.KindVariation, ProjectKey: "project", LookupKey: "config/linked", + Fingerprint: fingerprint("a"), Version: 3, + }}} + next := Manifest{Resources: []Resource{{ + ResourceKind: syncdomain.KindVariation, ProjectKey: "project", LookupKey: "config/linked", + Fingerprint: fingerprint("a"), Version: 3, + FingerprintSchema: syncdomain.ProjectionFingerprintSchema, ReferenceDigest: fingerprint("e"), + AdapterBehavior: "markdown/1", + }}} + + _, err := store.Update(previous, next) + + require.NoError(t, err) + assert.Empty(t, client.patches, "no patch for a change that the remote manifest cannot record") } func TestStoreReportsOptimisticConflict(t *testing.T) {