fix(deploy): persist the artifact deployment record before the best-effort site stamp
Both repositories are scoped over one DbContext, so a failed stamp save left the Site entries tracked as Modified and the deployment record's (uncaught) SaveChangesAsync rethrew it — losing the audit row and failing a deploy in which every site succeeded. Ordering rule now: audit row first, stamp after, inside its own try/catch. Same in RetryForSiteAsync, where the site load is caught too so nothing on the stamp path can reach the method's catch. Also: the method-definitions canonicaliser matches the name property case-insensitively (a naming-policy change at the producer would otherwise silently turn the sort into a no-op), and ComputeCurrentArtifactHashesAsync documents that a per-site query failure aborts the whole batch by design. Claude-Session: https://claude.ai/code/session_01Y5ef34iUUMjmwnMpL9xgmB
This commit is contained in:
+33
@@ -103,6 +103,39 @@ public class ArtifactRevisionHashServiceTests
|
||||
Assert.Equal(_sut.ComputeHash(a), _sut.ComputeHash(b));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ComputeHash_ReorderedCamelCaseMethodNames_ProducesSameHash()
|
||||
{
|
||||
// The method-name lookup is case-insensitive so that a naming-policy change at the
|
||||
// producer (PascalCase anonymous type today) cannot silently degrade the sort into a
|
||||
// no-op and let repository row order move the hash again.
|
||||
var a = Command(externalSystems:
|
||||
[
|
||||
new ExternalSystemArtifact("Mes", "https://mes", "ApiKey", null,
|
||||
"[{\"name\":\"MoveOut\"},{\"name\":\"MoveIn\"}]")
|
||||
]);
|
||||
var b = Command(externalSystems:
|
||||
[
|
||||
new ExternalSystemArtifact("Mes", "https://mes", "ApiKey", null,
|
||||
"[{\"name\":\"MoveIn\"},{\"name\":\"MoveOut\"}]")
|
||||
]);
|
||||
|
||||
Assert.Equal(_sut.ComputeHash(a), _sut.ComputeHash(b));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ComputeHash_UnparseableMethodDefinitions_StillParticipatesInTheHash()
|
||||
{
|
||||
// Non-array / non-JSON payloads pass through verbatim: the order guarantee is lost
|
||||
// (there is nothing to sort), but a content change must still move the hash.
|
||||
var a = Command(externalSystems:
|
||||
[new ExternalSystemArtifact("Mes", "https://mes", "ApiKey", null, "not json")]);
|
||||
var b = Command(externalSystems:
|
||||
[new ExternalSystemArtifact("Mes", "https://mes", "ApiKey", null, "not json either")]);
|
||||
|
||||
Assert.NotEqual(_sut.ComputeHash(a), _sut.ComputeHash(b));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ComputeHash_DifferentDeploymentIdAndTimestamp_ProducesSameHash()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user