@opensoftware/contracts 1.6.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -2
- package/dist/formats.js +2 -0
- package/dist/formats.js.map +1 -1
- package/dist/generated/types.d.ts +568 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js.map +1 -1
- package/events/asyncapi.yaml +42 -0
- package/events/issue-labeled/issue-labeled.schema.json +128 -0
- package/events/run-started/run-started.schema.json +139 -0
- package/factory-definition/factory-definition.schema.json +9 -0
- package/openapi/openapi.json +974 -132
- package/package.json +2 -2
- package/typespec/events.tsp +47 -0
- package/typespec/factory-definition.tsp +10 -0
- package/typespec/foreman-api.tsp +45 -0
- package/typespec/foreman.tsp +110 -0
- package/typespec/intake-api.tsp +40 -0
- package/typespec/intake.tsp +52 -0
- package/typespec/main.tsp +4 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opensoftware/contracts",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"description": "The shared formats of the open software factory: JSON Schemas, TypeScript types and the osf-contracts CLI.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"@typespec/openapi": "1.17.0",
|
|
45
45
|
"@typespec/openapi3": "1.17.0",
|
|
46
46
|
"openapi-typescript": "7.13.0",
|
|
47
|
-
"@opensoftware/testkit": "0.
|
|
47
|
+
"@opensoftware/testkit": "0.23.0"
|
|
48
48
|
},
|
|
49
49
|
"scripts": {
|
|
50
50
|
"build": "node scripts/build.ts",
|
package/typespec/events.tsp
CHANGED
|
@@ -39,6 +39,9 @@ model CloudEvent<Type extends string, Data> {
|
|
|
39
39
|
/** intake: a work item was accepted. */
|
|
40
40
|
model WorkReceived is CloudEvent<"work.received@v1", WorkItem>;
|
|
41
41
|
|
|
42
|
+
/** foreman: a run started (ADR 0067). */
|
|
43
|
+
model RunStarted is CloudEvent<"run.started@v1", RunStartedData>;
|
|
44
|
+
|
|
42
45
|
/** foreman: a run ended. */
|
|
43
46
|
model RunCompleted is CloudEvent<"run.completed@v1", RunCompletedData>;
|
|
44
47
|
|
|
@@ -60,6 +63,26 @@ model PrReviewed is CloudEvent<"pr.reviewed@v1", PrReviewedData>;
|
|
|
60
63
|
/** forge adapters: a pull request was merged or closed without a merge. */
|
|
61
64
|
model PrClosed is CloudEvent<"pr.closed@v1", PrClosedData>;
|
|
62
65
|
|
|
66
|
+
/** forge adapters: a label was added to an issue. */
|
|
67
|
+
model IssueLabeled is CloudEvent<"issue.labeled@v1", IssueLabeledData>;
|
|
68
|
+
|
|
69
|
+
model RunStartedData {
|
|
70
|
+
runId: Identifier;
|
|
71
|
+
workItemId: Identifier;
|
|
72
|
+
|
|
73
|
+
/** The name of the factory. */
|
|
74
|
+
factory: Name;
|
|
75
|
+
|
|
76
|
+
factoryVersion: CommitHash;
|
|
77
|
+
|
|
78
|
+
/** The stages of the run's workflow, in order. */
|
|
79
|
+
stages: Name[];
|
|
80
|
+
|
|
81
|
+
startedAt: utcDateTime;
|
|
82
|
+
requester: Actor;
|
|
83
|
+
source: Name;
|
|
84
|
+
}
|
|
85
|
+
|
|
63
86
|
model RunCompletedData {
|
|
64
87
|
runId: Identifier;
|
|
65
88
|
workItemId: Identifier;
|
|
@@ -166,3 +189,27 @@ model PrClosedData {
|
|
|
166
189
|
|
|
167
190
|
mergeCommit?: CommitHash;
|
|
168
191
|
}
|
|
192
|
+
|
|
193
|
+
model IssueLabeledData {
|
|
194
|
+
/** The issue. */
|
|
195
|
+
url: url;
|
|
196
|
+
|
|
197
|
+
repository: url;
|
|
198
|
+
|
|
199
|
+
@minValue(1)
|
|
200
|
+
number: safeint;
|
|
201
|
+
|
|
202
|
+
@minLength(1)
|
|
203
|
+
title: string;
|
|
204
|
+
|
|
205
|
+
body?: string;
|
|
206
|
+
|
|
207
|
+
/** The person who opened the issue. */
|
|
208
|
+
author: Actor;
|
|
209
|
+
|
|
210
|
+
/** Every label of the issue after the change. */
|
|
211
|
+
labels: string[];
|
|
212
|
+
|
|
213
|
+
/** The label that was added, when the forge names it. */
|
|
214
|
+
label?: string;
|
|
215
|
+
}
|
|
@@ -126,10 +126,20 @@ model Stage {
|
|
|
126
126
|
/** The stage waits for a decision before it starts. */
|
|
127
127
|
gate?: Gate;
|
|
128
128
|
|
|
129
|
+
/**
|
|
130
|
+
* Checks that must succeed on the run's pull request before the stage starts, by their names on the forge, for
|
|
131
|
+
* example "verify" (ADR 0069).
|
|
132
|
+
*/
|
|
133
|
+
checks?: CheckName[];
|
|
134
|
+
|
|
129
135
|
/** Whether the stage must produce an evidence bundle. */
|
|
130
136
|
evidence?: EvidenceRequirement;
|
|
131
137
|
}
|
|
132
138
|
|
|
139
|
+
/** The name of a check on the forge: a commit status context. */
|
|
140
|
+
@minLength(1)
|
|
141
|
+
scalar CheckName extends string;
|
|
142
|
+
|
|
133
143
|
enum EvidenceRequirement {
|
|
134
144
|
required,
|
|
135
145
|
optional,
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// The HTTP API of `foreman serve` (ADR 0067). `pnpm build` compiles it with the OpenAPI 3 emitter and copies its paths
|
|
2
|
+
// into openapi/openapi.json, next to gatekeeper's and intake's; the models are the named models of the JSON Schema
|
|
3
|
+
// bundle.
|
|
4
|
+
import "@typespec/http";
|
|
5
|
+
import "./foreman.tsp";
|
|
6
|
+
import "./gatekeeper-api.tsp";
|
|
7
|
+
|
|
8
|
+
using TypeSpec.Http;
|
|
9
|
+
|
|
10
|
+
namespace Osf.Contracts;
|
|
11
|
+
|
|
12
|
+
namespace ForemanApi {
|
|
13
|
+
/** Start a run of the factory's workflow for a work item. The same work item again answers the run it started. */
|
|
14
|
+
@route("/v1/runs")
|
|
15
|
+
@post
|
|
16
|
+
op startRun(@body workItem: WorkItem):
|
|
17
|
+
| {
|
|
18
|
+
@statusCode statusCode: 201;
|
|
19
|
+
@body run: RunView;
|
|
20
|
+
}
|
|
21
|
+
| {
|
|
22
|
+
@statusCode statusCode: 200;
|
|
23
|
+
@body run: RunView;
|
|
24
|
+
}
|
|
25
|
+
| GatekeeperApi.Failure<400>
|
|
26
|
+
| GatekeeperApi.Failure<401>;
|
|
27
|
+
|
|
28
|
+
/** A run: its state and the state of each stage. */
|
|
29
|
+
@route("/v1/runs/{runId}")
|
|
30
|
+
@get
|
|
31
|
+
op getRun(@path runId: string): RunView | GatekeeperApi.Failure<401> | GatekeeperApi.Failure<404>;
|
|
32
|
+
|
|
33
|
+
/** Steer the running stage's agent, or cancel the run. */
|
|
34
|
+
@route("/v1/runs/{runId}/signals")
|
|
35
|
+
@post
|
|
36
|
+
op signalRun(@path runId: string, @body signal: RunSignal):
|
|
37
|
+
| {
|
|
38
|
+
@statusCode statusCode: 202;
|
|
39
|
+
@body run: RunView;
|
|
40
|
+
}
|
|
41
|
+
| GatekeeperApi.Failure<400>
|
|
42
|
+
| GatekeeperApi.Failure<401>
|
|
43
|
+
| GatekeeperApi.Failure<404>
|
|
44
|
+
| GatekeeperApi.Failure<409>;
|
|
45
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import "@typespec/json-schema";
|
|
2
|
+
import "./common.tsp";
|
|
3
|
+
import "./work-item.tsp";
|
|
4
|
+
import "./factory-definition.tsp";
|
|
5
|
+
|
|
6
|
+
using TypeSpec.JsonSchema;
|
|
7
|
+
|
|
8
|
+
namespace Osf.Contracts;
|
|
9
|
+
|
|
10
|
+
/** foreman: where a run stands (vision scenario ORCH-008). */
|
|
11
|
+
enum RunState {
|
|
12
|
+
running,
|
|
13
|
+
blocked,
|
|
14
|
+
complete,
|
|
15
|
+
failed,
|
|
16
|
+
cancelled,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** foreman: where a stage of a run stands. */
|
|
20
|
+
enum StageState {
|
|
21
|
+
pending,
|
|
22
|
+
blocked,
|
|
23
|
+
running,
|
|
24
|
+
succeeded,
|
|
25
|
+
failed,
|
|
26
|
+
rejected,
|
|
27
|
+
cancelled,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** foreman: the state of a check on the forge (forge port). */
|
|
31
|
+
enum CheckState {
|
|
32
|
+
pending,
|
|
33
|
+
success,
|
|
34
|
+
failure,
|
|
35
|
+
error,
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** foreman: a check that a stage waits for, as the foreman last read it on the run's pull request (ADR 0069). */
|
|
39
|
+
model CheckView {
|
|
40
|
+
name: CheckName;
|
|
41
|
+
state: CheckState;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** foreman: one stage of a run (ADR 0067). */
|
|
45
|
+
model StageView {
|
|
46
|
+
stage: Name;
|
|
47
|
+
|
|
48
|
+
/** The agent that runs the stage. */
|
|
49
|
+
agent: Name;
|
|
50
|
+
|
|
51
|
+
state: StageState;
|
|
52
|
+
|
|
53
|
+
/** The harness session of the stage's agent, once it started. */
|
|
54
|
+
sessionId?: string;
|
|
55
|
+
|
|
56
|
+
/** The gate that decides whether the stage starts, once it was requested. */
|
|
57
|
+
@pattern("^g[0-9a-f]{16}$")
|
|
58
|
+
gateId?: string;
|
|
59
|
+
|
|
60
|
+
/** The checks the stage waits for, once the foreman read them (ADR 0069). */
|
|
61
|
+
checks?: CheckView[];
|
|
62
|
+
|
|
63
|
+
/** Why the stage ended without success, when the foreman knows. */
|
|
64
|
+
@minLength(1)
|
|
65
|
+
reason?: string;
|
|
66
|
+
|
|
67
|
+
startedAt?: utcDateTime;
|
|
68
|
+
endedAt?: utcDateTime;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** foreman: a run of the factory's workflow for one work item, as the HTTP API shows it (ADR 0067). */
|
|
72
|
+
model RunView {
|
|
73
|
+
/** "run_" and 20 hex digits of the SHA-256 of the work item's ID. */
|
|
74
|
+
@pattern("^run_[0-9a-f]{20}$")
|
|
75
|
+
runId: string;
|
|
76
|
+
|
|
77
|
+
workItem: WorkItem;
|
|
78
|
+
|
|
79
|
+
/** The name of the factory. */
|
|
80
|
+
factory: Name;
|
|
81
|
+
|
|
82
|
+
/** The commit of the factory definition the run started with. */
|
|
83
|
+
factoryVersion: CommitHash;
|
|
84
|
+
|
|
85
|
+
state: RunState;
|
|
86
|
+
|
|
87
|
+
/** The last pull request link that an agent of the run wrote (ADR 0069). */
|
|
88
|
+
pullRequest?: url;
|
|
89
|
+
|
|
90
|
+
startedAt: utcDateTime;
|
|
91
|
+
endedAt?: utcDateTime;
|
|
92
|
+
|
|
93
|
+
/** The stages of the workflow, in order. */
|
|
94
|
+
stages: StageView[];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** foreman: what a person tells a run. */
|
|
98
|
+
enum RunSignalType {
|
|
99
|
+
steer,
|
|
100
|
+
cancel,
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** foreman: a signal to a run: "steer" with a message for the running stage's agent, or "cancel". */
|
|
104
|
+
model RunSignal {
|
|
105
|
+
type: RunSignalType;
|
|
106
|
+
|
|
107
|
+
/** The steering message. Required with "steer". */
|
|
108
|
+
@minLength(1)
|
|
109
|
+
message?: string;
|
|
110
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// The HTTP API of `intake serve` (ADR 0063). `pnpm build` compiles it with the OpenAPI 3 emitter and copies its paths
|
|
2
|
+
// into openapi/openapi.json, next to gatekeeper's; the models are the named models of the JSON Schema bundle.
|
|
3
|
+
import "@typespec/http";
|
|
4
|
+
import "./intake.tsp";
|
|
5
|
+
import "./gatekeeper-api.tsp";
|
|
6
|
+
|
|
7
|
+
using TypeSpec.Http;
|
|
8
|
+
|
|
9
|
+
namespace Osf.Contracts;
|
|
10
|
+
|
|
11
|
+
namespace IntakeApi {
|
|
12
|
+
/** Put work into the inbox. A submission with the dedupe key of a work item answers that work item. */
|
|
13
|
+
@route("/v1/work-items")
|
|
14
|
+
@post
|
|
15
|
+
op submitWork(@body submission: WorkSubmission):
|
|
16
|
+
| {
|
|
17
|
+
@statusCode statusCode: 201;
|
|
18
|
+
@body workItem: WorkItemView;
|
|
19
|
+
}
|
|
20
|
+
| {
|
|
21
|
+
@statusCode statusCode: 200;
|
|
22
|
+
@body workItem: WorkItemView;
|
|
23
|
+
}
|
|
24
|
+
| GatekeeperApi.Failure<400>
|
|
25
|
+
| GatekeeperApi.Failure<401>;
|
|
26
|
+
|
|
27
|
+
/** The work item with this dedupe key, such as an issue's link (ADR 0065). */
|
|
28
|
+
@route("/v1/work-items")
|
|
29
|
+
@get
|
|
30
|
+
op findWorkItem(@query dedupeKey: string):
|
|
31
|
+
| WorkItemView
|
|
32
|
+
| GatekeeperApi.Failure<400>
|
|
33
|
+
| GatekeeperApi.Failure<401>
|
|
34
|
+
| GatekeeperApi.Failure<404>;
|
|
35
|
+
|
|
36
|
+
/** A work item, its status and every request that asked for it. */
|
|
37
|
+
@route("/v1/work-items/{workItemId}")
|
|
38
|
+
@get
|
|
39
|
+
op getWorkItem(@path workItemId: string): WorkItemView | GatekeeperApi.Failure<401> | GatekeeperApi.Failure<404>;
|
|
40
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import "@typespec/json-schema";
|
|
2
|
+
import "./common.tsp";
|
|
3
|
+
import "./work-item.tsp";
|
|
4
|
+
|
|
5
|
+
using TypeSpec.JsonSchema;
|
|
6
|
+
|
|
7
|
+
namespace Osf.Contracts;
|
|
8
|
+
|
|
9
|
+
/** intake: work to put into the inbox, a work item without its ID (ADR 0063). */
|
|
10
|
+
model WorkSubmission {
|
|
11
|
+
/** Default: task. */
|
|
12
|
+
type?: WorkItemType;
|
|
13
|
+
|
|
14
|
+
@minLength(1)
|
|
15
|
+
@maxLength(300)
|
|
16
|
+
title: string;
|
|
17
|
+
|
|
18
|
+
description?: string;
|
|
19
|
+
requester: Actor;
|
|
20
|
+
origin: Origin;
|
|
21
|
+
|
|
22
|
+
/** Requests with the same key become one work item. Default: the origin's url, else "<source>:<externalId>". */
|
|
23
|
+
@minLength(1)
|
|
24
|
+
dedupeKey?: string;
|
|
25
|
+
|
|
26
|
+
surface?: string;
|
|
27
|
+
links?: Link[];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Where a work item stands. */
|
|
31
|
+
enum WorkItemStatus {
|
|
32
|
+
received,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** intake: one submission that asked for a work item. */
|
|
36
|
+
model WorkRequest {
|
|
37
|
+
requester: Actor;
|
|
38
|
+
origin: Origin;
|
|
39
|
+
receivedAt: utcDateTime;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** intake: a work item as the HTTP API shows it (ADR 0063). */
|
|
43
|
+
model WorkItemView {
|
|
44
|
+
/** Its ID is "wi_" and 20 hex digits of the SHA-256 of its dedupe key. */
|
|
45
|
+
workItem: WorkItem;
|
|
46
|
+
|
|
47
|
+
status: WorkItemStatus;
|
|
48
|
+
receivedAt: utcDateTime;
|
|
49
|
+
|
|
50
|
+
/** Every submission that asked for the work item, oldest first; one per origin. */
|
|
51
|
+
requests: WorkRequest[];
|
|
52
|
+
}
|
package/typespec/main.tsp
CHANGED