@opensoftware/contracts 1.6.0 → 1.7.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opensoftware/contracts",
3
- "version": "1.6.0",
3
+ "version": "1.7.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.16.0"
47
+ "@opensoftware/testkit": "0.23.0"
48
48
  },
49
49
  "scripts": {
50
50
  "build": "node scripts/build.ts",
@@ -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
+ }
@@ -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,84 @@
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
+ /** foreman: where a run stands (vision scenario ORCH-008). */
10
+ enum RunState {
11
+ running,
12
+ blocked,
13
+ complete,
14
+ failed,
15
+ cancelled,
16
+ }
17
+
18
+ /** foreman: where a stage of a run stands. */
19
+ enum StageState {
20
+ pending,
21
+ blocked,
22
+ running,
23
+ succeeded,
24
+ failed,
25
+ rejected,
26
+ cancelled,
27
+ }
28
+
29
+ /** foreman: one stage of a run (ADR 0067). */
30
+ model StageView {
31
+ stage: Name;
32
+
33
+ /** The agent that runs the stage. */
34
+ agent: Name;
35
+
36
+ state: StageState;
37
+
38
+ /** The harness session of the stage's agent, once it started. */
39
+ sessionId?: string;
40
+
41
+ /** The gate that decides whether the stage starts, once it was requested. */
42
+ @pattern("^g[0-9a-f]{16}$")
43
+ gateId?: string;
44
+
45
+ startedAt?: utcDateTime;
46
+ endedAt?: utcDateTime;
47
+ }
48
+
49
+ /** foreman: a run of the factory's workflow for one work item, as the HTTP API shows it (ADR 0067). */
50
+ model RunView {
51
+ /** "run_" and 20 hex digits of the SHA-256 of the work item's ID. */
52
+ @pattern("^run_[0-9a-f]{20}$")
53
+ runId: string;
54
+
55
+ workItem: WorkItem;
56
+
57
+ /** The name of the factory. */
58
+ factory: Name;
59
+
60
+ /** The commit of the factory definition the run started with. */
61
+ factoryVersion: CommitHash;
62
+
63
+ state: RunState;
64
+ startedAt: utcDateTime;
65
+ endedAt?: utcDateTime;
66
+
67
+ /** The stages of the workflow, in order. */
68
+ stages: StageView[];
69
+ }
70
+
71
+ /** foreman: what a person tells a run. */
72
+ enum RunSignalType {
73
+ steer,
74
+ cancel,
75
+ }
76
+
77
+ /** foreman: a signal to a run: "steer" with a message for the running stage's agent, or "cancel". */
78
+ model RunSignal {
79
+ type: RunSignalType;
80
+
81
+ /** The steering message. Required with "steer". */
82
+ @minLength(1)
83
+ message?: string;
84
+ }
@@ -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
@@ -10,4 +10,8 @@ import "./score.tsp";
10
10
  import "./events.tsp";
11
11
  import "./gatekeeper.tsp";
12
12
  import "./gatekeeper-api.tsp";
13
+ import "./intake.tsp";
14
+ import "./intake-api.tsp";
15
+ import "./foreman.tsp";
16
+ import "./foreman-api.tsp";
13
17
  import "./sandbox.tsp";