@markjaquith/agency 2.10.0 → 2.12.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.
@@ -15,6 +15,7 @@ import {
15
15
  formatMarkdownDocument,
16
16
  parseFrontmatter,
17
17
  } from "../workbase/frontmatter"
18
+ import { canTransitionStatus } from "../readiness"
18
19
 
19
20
  class PhaseError extends Data.TaggedError("PhaseError")<{
20
21
  readonly message: string
@@ -340,6 +341,11 @@ export class PhaseService extends Effect.Service<PhaseService>()(
340
341
  const service = yield* PhaseService
341
342
  const validStatus = yield* decodeStatus(status)
342
343
  const record = yield* service.show(taskId, id, startPath)
344
+ if (!canTransitionStatus(record.data.status, validStatus)) {
345
+ return yield* new PhaseError({
346
+ message: `Cannot transition phase '${id}' from ${record.data.status} to ${validStatus}; reopen it first`,
347
+ })
348
+ }
343
349
  const parsed = yield* parseFrontmatter(record.content, record.path)
344
350
  const data = { ...record.data, status: validStatus }
345
351
  const content = formatMarkdownDocument(data, parsed.body)
@@ -244,6 +244,22 @@ describe("task and phase services", () => {
244
244
  expect(task.data.status).toBe("delegated")
245
245
  expect(task.content).toContain("status: delegated")
246
246
  expect(task.content).toContain("Describe the task outcome.")
247
+ await runTestEffect(
248
+ TaskService.pipe(
249
+ Effect.flatMap((service) =>
250
+ service.setStatus("single-status", "done", root),
251
+ ),
252
+ ),
253
+ )
254
+ await expect(
255
+ runTestEffect(
256
+ TaskService.pipe(
257
+ Effect.flatMap((service) =>
258
+ service.setStatus("single-status", "dropped", root),
259
+ ),
260
+ ),
261
+ ),
262
+ ).rejects.toThrow("reopen it first")
247
263
 
248
264
  await runTestEffect(
249
265
  TaskService.pipe(
@@ -283,6 +299,33 @@ describe("task and phase services", () => {
283
299
  ),
284
300
  )
285
301
  expect(phase.data.status).toBe("dropped")
302
+ await expect(
303
+ runTestEffect(
304
+ PhaseService.pipe(
305
+ Effect.flatMap((service) =>
306
+ service.setStatus("multi-status", "implementation", "done", root),
307
+ ),
308
+ ),
309
+ ),
310
+ ).rejects.toThrow("reopen it first")
311
+ await runTestEffect(
312
+ PhaseService.pipe(
313
+ Effect.flatMap((service) =>
314
+ service.setStatus("multi-status", "implementation", "open", root),
315
+ ),
316
+ ),
317
+ )
318
+ expect(
319
+ (
320
+ await runTestEffect(
321
+ PhaseService.pipe(
322
+ Effect.flatMap((service) =>
323
+ service.setStatus("multi-status", "implementation", "done", root),
324
+ ),
325
+ ),
326
+ )
327
+ ).data.status,
328
+ ).toBe("done")
286
329
  await expect(
287
330
  runTestEffect(
288
331
  TaskService.pipe(
@@ -15,6 +15,7 @@ import {
15
15
  formatMarkdownDocument,
16
16
  parseFrontmatter,
17
17
  } from "../workbase/frontmatter"
18
+ import { canTransitionStatus } from "../readiness"
18
19
 
19
20
  class TaskError extends Data.TaggedError("TaskError")<{
20
21
  readonly message: string
@@ -212,6 +213,11 @@ export class TaskService extends Effect.Service<TaskService>()("TaskService", {
212
213
  message: `Task '${id}' has multiple phases; set status on a phase instead`,
213
214
  })
214
215
  }
216
+ if (!canTransitionStatus(record.data.status, validStatus)) {
217
+ return yield* new TaskError({
218
+ message: `Cannot transition task '${id}' from ${record.data.status} to ${validStatus}; reopen it first`,
219
+ })
220
+ }
215
221
  const parsed = yield* parseFrontmatter(record.content, record.path)
216
222
  const data = { ...record.data, status: validStatus }
217
223
  const content = formatMarkdownDocument(data, parsed.body)
package/src/test-utils.ts CHANGED
@@ -14,6 +14,7 @@ import { PullRequestService } from "./services/PullRequestService"
14
14
  import { ArchiveService } from "./services/ArchiveService"
15
15
  import { IntegrationService } from "./services/IntegrationService"
16
16
  import { ContextService } from "./services/ContextService"
17
+ import { GraphService } from "./services/GraphService"
17
18
 
18
19
  export const createTempDir = () => mkdtemp(join(tmpdir(), "agency-test-"))
19
20
 
@@ -32,6 +33,7 @@ const TestLayer = Layer.mergeAll(
32
33
  ArchiveService.Default,
33
34
  IntegrationService.Default,
34
35
  ContextService.Default,
36
+ GraphService.Default,
35
37
  )
36
38
 
37
39
  export async function runTestEffect<A, E>(