Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ Task 간 “선후 관계”를 관리합니다.
* `GET /v1/members/now` 현재 진행 중인 일정 ID
* `GET /v1/statistics` 주간 통계 조회
* Task 응답에 의존성 메타(`previousTaskIds`,`nextTaskIds`) 포함
* Task 의존성 페이로드: **생성 시** 각 의존 관계마다 `fromId` 또는 `toId` 중 하나는 반드시 `0`(새로 생성될 자기 자신)이어야 하며, `removeDependencies`는 비워두어야
합니다. **수정 시에는 0을 사용할 수 없습니다.**
* **작업 → 일정 복사**: `POST /v1/tasks/{taskId}/schedules`로 기존 작업을 지정 시각에 일정으로 등록할 수 있습니다.
Comment on lines +84 to 86

Copilot AI Jan 22, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(1) 문제점: 문서의 설명이 불완전합니다. "removeDependencies는 비워두어야"로 끝나서 문장이 완결되지 않았습니다.

(2) 영향: API 사용자가 removeDependencies 필드의 정확한 사용 방법을 이해하기 어렵습니다.

(3) 수정 제안: 문장을 완성하여 "removeDependencies는 비워두어야 합니다" 또는 "removeDependencies는 생성 시 지원되지 않습니다"와 같이 명확하게 작성하세요.

Suggested change
* Task 의존성 페이로드: **생성 시** 각 의존 관계마다 `fromId` 또는 `toId` 중 하나는 반드시 `0`(새로 생성될 자기 자신)이어야 하며, `removeDependencies`는 비워두어야
합니다. **수정 시에는 0을 사용할 수 없습니다.**
* **작업 → 일정 복사**: `POST /v1/tasks/{taskId}/schedules`로 기존 작업을 지정 시각에 일정으로 등록할 수 있습니다.
* Task 의존성 페이로드: **생성 시** 각 의존 관계마다 `fromId` 또는 `toId` 중 하나는 반드시 `0`(새로 생성될 자기 자신)이어야 하며, `removeDependencies`는 비워두어야 합니다. **수정 시에는 0을 사용할 수 없습니다.**
* **작업 → 일정 복사**: `POST /v1/tasks/{taskId}/schedules`로 기존 작업을 지정 시각에 일정으로 등록할 수 있습니다.

Copilot uses AI. Check for mistakes.
* **삭제 플래그**: `DELETE /v1/tasks/{taskId}?deleteSchedules=` 혹은 `DELETE /v0|v1/schedules/{scheduleId}?deleteTaskAlso=` 로
연관 삭제 여부를 선택합니다(미설정 시 연관만 해제).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,21 @@ public TaskPatch getTaskPatch() {
.setDifficulty(difficulty);
}

/**
* 업데이트 요청에서는 0 플레이스홀더 사용을 금지한다.
* (0은 새 Task 생성 시 자기 자신을 의미하므로 create 전용)
*/
public void validateNoPlaceholderForUpdate() {
if (taskId == null) {
return;
}
boolean hasPlaceholder = addDependencies.stream().anyMatch(this::hasPlaceholder)
|| removeDependencies.stream().anyMatch(this::hasPlaceholder);
if (hasPlaceholder) {
throw new IllegalArgumentException("수정 요청에서는 fromId/toId에 0을 사용할 수 없습니다.");
}
}

public List<Dependency> getRemoveDependencies(Long selfId) {
return removeDependencies.stream()
.map(d -> new Dependency(ownerId, resolveId(d.getFromId(), selfId), resolveId(d.getToId(), selfId)))
Expand All @@ -77,9 +92,14 @@ public List<Dependency> getAddDependencies(Long selfId) {
}

private Long resolveId(Long rawId, Long selfId) {
if (rawId == null) {
if (rawId == 0L) {
return selfId;
}
return rawId;
Comment on lines 94 to 98

Copilot AI Jan 22, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(1) 문제점: null 값 처리가 누락되어 있습니다. rawId가 null인 경우 NullPointerException이 발생할 수 있습니다.

(2) 영향: DependencyDto의 fromId 또는 toId가 null일 경우 런타임 예외가 발생하여 애플리케이션이 중단될 수 있습니다.

(3) 수정 제안: null 체크를 추가해야 합니다. rawId가 null인 경우를 먼저 확인한 후 0L과 비교하도록 수정하세요.

Copilot uses AI. Check for mistakes.
}

private boolean hasPlaceholder(DependencyDto dto) {
return dto.getFromId() != null && dto.getFromId() == 0L
|| dto.getToId() != null && dto.getToId() == 0L;
Comment on lines +102 to +103

Copilot AI Jan 22, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(1) 문제점: 연산자 우선순위 문제로 인해 의도와 다르게 동작할 수 있습니다. || 연산자가 && 연산자보다 낮은 우선순위를 가지므로, 현재 코드는 (dto.getFromId() != null && dto.getFromId() == 0L) || (dto.getToId() != null && dto.getToId() == 0L)로 해석되지만 가독성이 떨어집니다.

(2) 영향: 코드 리뷰어나 유지보수 담당자가 의도를 오해할 수 있으며, 향후 수정 시 논리 오류가 발생할 가능성이 있습니다.

(3) 수정 제안: 명확성을 위해 괄호를 추가하여 의도를 명확히 표현하세요. 예: return (dto.getFromId() != null && dto.getFromId() == 0L) || (dto.getToId() != null && dto.getToId() == 0L);

Suggested change
return dto.getFromId() != null && dto.getFromId() == 0L
|| dto.getToId() != null && dto.getToId() == 0L;
return (dto.getFromId() != null && dto.getFromId() == 0L)
|| (dto.getToId() != null && dto.getToId() == 0L);

Copilot uses AI. Check for mistakes.
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public Task updateTask(Long memberId, TaskDependencyAdjustCommand command) {
if (taskId == null) {
throw new IllegalArgumentException("taskId는 null일 수 없습니다.");
}
command.validateNoPlaceholderForUpdate();
List<Dependency> removedDependencies = command.getRemoveDependencies(taskId);
List<Dependency> addedDependencies = command.getAddDependencies(taskId);
dependencyService.assertNoCycle(memberId, removedDependencies, addedDependencies);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@

public record DependencyRequest(
@NotNull
@Schema(description = "선행 일정 ID", example = "1")
@Schema(description = "선행 작업 ID (새 작업 생성 시 자기 자신은 0, 수정 시 0 금지)", example = "1")
Long fromId,
@NotNull
@Schema(description = "후행 일정 ID", example = "2")
@Schema(description = "후행 작업 ID (새 작업 생성 시 자기 자신은 0, 수정 시 0 금지)", example = "2")
Long toId
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package me.gg.pinit.pinittask.interfaces.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import me.gg.pinit.pinittask.application.datetime.DateTimeUtils;
import me.gg.pinit.pinittask.application.schedule.dto.DependencyDto;
import me.gg.pinit.pinittask.application.task.dto.TaskDependencyAdjustCommand;
import me.gg.pinit.pinittask.interfaces.utils.FibonacciDifficulty;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

public record TaskCreateRequest(
@NotBlank
@Schema(description = "작업 제목", example = "스터디 준비")
String title,
@NotBlank
@Schema(description = "작업 설명", example = "다음 주 발표 자료 정리")
String description,
@NotNull
@Schema(description = "마감 기한", example = "{\"dateTime\":\"2024-03-01T18:00:00\",\"zoneId\":\"Asia/Seoul\"}")
@Valid
DateTimeWithZone dueDate,
@NotNull
@Min(1)
@Max(9)
@Schema(description = "중요도 (1~9)", example = "5")
Integer importance,
@NotNull
@FibonacciDifficulty
@Schema(description = "난이도 (피보나치 수: 1,2,3,5,8,13,21)", example = "5")
Integer difficulty,
@Schema(description = "추가할 의존 관계 목록 (생성 시 각 항목에 fromId 또는 toId 중 하나는 0)")
List<@Valid DependencyRequest> addDependencies
) {
public TaskDependencyAdjustCommand toCommand(Long taskId, Long ownerId, DateTimeUtils dateTimeUtils) {
validateMustContainSelfPlaceholder(addDependencies);
List<DependencyDto> remove = List.of(); // 생성 시 remove는 허용하지 않음
List<DependencyDto> add = toDependencyDtos(addDependencies);
return new TaskDependencyAdjustCommand(
taskId,
ownerId,
title,
description,
dateTimeUtils.toZonedDateTime(dueDate.dateTime(), dueDate.zoneId()),
importance,
difficulty,
remove,
add
);
}

private List<DependencyDto> toDependencyDtos(List<DependencyRequest> requests) {
return Optional.ofNullable(requests)
.orElseGet(ArrayList::new)
.stream()
.map(request -> new DependencyDto(null, request.fromId(), request.toId()))
.toList();
}

private void validateMustContainSelfPlaceholder(List<DependencyRequest> dependencies) {
Optional.ofNullable(dependencies)
.orElseGet(ArrayList::new)
Comment on lines +59 to +68

Copilot AI Jan 22, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(1) 문제점: TaskCreateRequest와 TaskUpdateRequest 사이에 중복된 코드가 존재합니다. toDependencyDtos 메서드가 두 클래스에서 동일하게 구현되어 있습니다.

(2) 영향: 코드 중복으로 인해 유지보수성이 저하되고, 한쪽만 수정될 경우 불일치가 발생할 수 있습니다.

(3) 수정 제안: 공통 유틸리티 클래스나 헬퍼 메서드로 추출하여 재사용하도록 리팩토링하세요.

Suggested change
return Optional.ofNullable(requests)
.orElseGet(ArrayList::new)
.stream()
.map(request -> new DependencyDto(null, request.fromId(), request.toId()))
.toList();
}
private void validateMustContainSelfPlaceholder(List<DependencyRequest> dependencies) {
Optional.ofNullable(dependencies)
.orElseGet(ArrayList::new)
return emptyIfNull(requests)
.stream()
.map(request -> new DependencyDto(null, request.fromId(), request.toId()))
.toList();
}
private static <T> List<T> emptyIfNull(List<T> list) {
return Optional.ofNullable(list)
.orElseGet(ArrayList::new);
}
private void validateMustContainSelfPlaceholder(List<DependencyRequest> dependencies) {
emptyIfNull(dependencies)

Copilot uses AI. Check for mistakes.
.forEach(dep -> {
if (dep.fromId() != 0L && dep.toId() != 0L) {
throw new IllegalArgumentException("작업 생성 시 의존 관계에는 fromId 또는 toId 중 하나가 0이어야 합니다.");
Comment on lines +70 to +71

Copilot AI Jan 22, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(1) 문제점: validateMustContainSelfPlaceholder의 로직이 부정확합니다. 현재 코드는 "fromId와 toId가 모두 0이 아닌 경우" 예외를 던지지만, 이는 "둘 다 0인 경우"를 허용하게 됩니다.

(2) 영향: fromId=0, toId=0인 의존성이 허용되어 자기 자신에서 자기 자신으로의 의존성이 생성될 수 있습니다. 이는 의미 없는 관계를 생성하게 됩니다.

(3) 수정 제안: 로직을 수정하여 "정확히 하나만 0이어야 함"을 검증하도록 변경하세요. 조건을 (dep.fromId() == 0L) XOR (dep.toId() == 0L)로 검증하거나, 둘 다 0인 경우와 둘 다 0이 아닌 경우 모두 예외를 던지도록 수정하세요.

Suggested change
if (dep.fromId() != 0L && dep.toId() != 0L) {
throw new IllegalArgumentException("작업 생성 시 의존 관계에는 fromId 또는 toId 중 하나가 0이어야 합니다.");
boolean hasFromPlaceholder = dep.fromId() == 0L;
boolean hasToPlaceholder = dep.toId() == 0L;
if (!(hasFromPlaceholder ^ hasToPlaceholder)) {
throw new IllegalArgumentException("작업 생성 시 의존 관계에는 fromId 또는 toId 중 정확히 하나만 0이어야 합니다.");

Copilot uses AI. Check for mistakes.
}
});
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import java.util.List;
import java.util.Optional;

public record TaskRequest(
public record TaskUpdateRequest(
@NotBlank
@Schema(description = "작업 제목", example = "스터디 준비")
String title,
Expand All @@ -35,12 +35,14 @@ public record TaskRequest(
@FibonacciDifficulty
@Schema(description = "난이도 (피보나치 수: 1,2,3,5,8,13,21)", example = "5")
Integer difficulty,
@Schema(description = "제거할 의존 관계 목록")
@Schema(description = "제거할 의존 관계 목록 (수정 시 0 사용 금지)")
List<@Valid DependencyRequest> removeDependencies,
@Schema(description = "추가할 의존 관계 목록")
@Schema(description = "추가할 의존 관계 목록 (수정 시 0 사용 금지)")
List<@Valid DependencyRequest> addDependencies
) {
public TaskDependencyAdjustCommand toCommand(Long taskId, Long ownerId, DateTimeUtils dateTimeUtils) {
validateNoPlaceholder(removeDependencies);
validateNoPlaceholder(addDependencies);
List<DependencyDto> remove = toDependencyDtos(removeDependencies);
List<DependencyDto> add = toDependencyDtos(addDependencies);
return new TaskDependencyAdjustCommand(
Expand All @@ -56,6 +58,16 @@ public TaskDependencyAdjustCommand toCommand(Long taskId, Long ownerId, DateTime
);
}

private void validateNoPlaceholder(List<DependencyRequest> dependencies) {
Optional.ofNullable(dependencies)
.orElseGet(ArrayList::new)
.forEach(dep -> {
if (dep.fromId() == 0L || dep.toId() == 0L) {
throw new IllegalArgumentException("수정 요청에서는 의존 관계 ID에 0을 사용할 수 없습니다.");
}
});
}

private List<DependencyDto> toDependencyDtos(List<DependencyRequest> requests) {
return Optional.ofNullable(requests)
.orElseGet(ArrayList::new)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public class TaskControllerV1 {
@PostMapping
@Operation(summary = "작업 생성", description = "새 작업과 의존 관계를 등록합니다.")
public ResponseEntity<TaskResponse> createTask(@Parameter(hidden = true) @MemberId Long memberId,
@Valid @RequestBody TaskRequest request) {
@Valid @RequestBody TaskCreateRequest request) {
Task saved = taskAdjustmentService.createTask(memberId, request.toCommand(null, memberId, dateTimeUtils));
return ResponseEntity.status(HttpStatus.CREATED).body(TaskResponse.from(saved));
}
Expand All @@ -56,7 +56,7 @@ public ResponseEntity<TaskResponse> createTask(@Parameter(hidden = true) @Member
@Operation(summary = "작업 수정", description = "작업 본문과 의존 관계를 함께 수정합니다.")
public ResponseEntity<TaskResponse> updateTask(@Parameter(hidden = true) @MemberId Long memberId,
@PathVariable Long taskId,
@Valid @RequestBody TaskRequest request) {
@Valid @RequestBody TaskUpdateRequest request) {
Task updated = taskAdjustmentService.updateTask(memberId, request.toCommand(taskId, memberId, dateTimeUtils));
return ResponseEntity.ok(TaskResponse.from(updated));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package me.gg.pinit.pinittask.application.task.dto;

import me.gg.pinit.pinittask.application.schedule.dto.DependencyDto;
import me.gg.pinit.pinittask.domain.dependency.model.Dependency;
import org.junit.jupiter.api.Test;

import java.time.ZonedDateTime;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

class TaskDependencyAdjustCommandTest {

@Test
void resolvesSelfPlaceholderForZeroIds() {
Long ownerId = 1L;
Long selfId = 99L;

Copilot AI Jan 22, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable 'selfId' is only assigned values of primitive type and is never 'null', but it is declared with the boxed type 'Long'.

Suggested change
Long selfId = 99L;
long selfId = 99L;

Copilot uses AI. Check for mistakes.
TaskDependencyAdjustCommand command = new TaskDependencyAdjustCommand(
null,
ownerId,
"t",
"d",
ZonedDateTime.now(),
5,
3,
List.of(),
List.of(
new DependencyDto(null, 0L, 5L), // fromId=0 -> self
new DependencyDto(null, 4L, 0L) // toId=0 -> self
)
);

List<Dependency> deps = command.getAddDependencies(selfId);

assertThat(deps)
.extracting(Dependency::getFromId, Dependency::getToId)
.containsExactly(
org.assertj.core.groups.Tuple.tuple(selfId, 5L),
org.assertj.core.groups.Tuple.tuple(4L, selfId)
);
}

@Test
void validateNoPlaceholderForUpdate_rejectsZeroIds() {
TaskDependencyAdjustCommand command = new TaskDependencyAdjustCommand(
10L,
1L,
"t",
"d",
ZonedDateTime.now(),
5,
3,
List.of(),
List.of(new DependencyDto(null, 0L, 2L))
);

org.junit.jupiter.api.Assertions.assertThrows(IllegalArgumentException.class, command::validateNoPlaceholderForUpdate);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.when;
Expand Down Expand Up @@ -168,6 +169,26 @@ void updateTask_checksCycleAndAdjustsDependenciesAroundUpdate() {
assertThat(savedDependenciesCaptor.getValue()).isSameAs(addedDependencies);
}

@Test
@DisplayName("updateTask에서 0 플레이스홀더 사용 시 예외")
void updateTask_rejectsPlaceholderZero() {
Long memberId = 1L;
Long taskId = 10L;
TaskDependencyAdjustCommand command = new TaskDependencyAdjustCommand(
taskId,
memberId,
"title",
"desc",
ZonedDateTime.now(),
5,
5,
List.of(),
List.of(new DependencyDto(null, 0L, 2L))
);

assertThrows(IllegalArgumentException.class, () -> taskAdjustmentService.updateTask(memberId, command));
}

@SuppressWarnings("unchecked")
private ArgumentCaptor<List<Dependency>> dependencyListCaptor() {
return ArgumentCaptor.forClass(List.class);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package me.gg.pinit.pinittask.interfaces.dto;

import me.gg.pinit.pinittask.application.datetime.DateTimeUtils;
import org.junit.jupiter.api.Test;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertThrows;

class TaskCreateRequestTest {

@Test
void toCommand_requiresPlaceholderZeroForEachDependency() {
TaskCreateRequest req = new TaskCreateRequest(
"t",
"d",
new DateTimeWithZone(LocalDateTime.now(), ZoneId.of("UTC")),
5,
3,
List.of(new DependencyRequest(10L, 20L)) // neither is 0
);

assertThrows(IllegalArgumentException.class,
() -> req.toCommand(null, 1L, new DateTimeUtils()));
}
Comment on lines +14 to +27

Copilot AI Jan 22, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(1) 문제점: 테스트가 fromId와 toId가 모두 0인 경우를 검증하지 않습니다. 현재 validateMustContainSelfPlaceholder 로직의 버그로 인해 이 케이스가 허용될 수 있습니다.

(2) 영향: 자기 자신에서 자기 자신으로의 의존성이 생성되는 잘못된 케이스를 탐지하지 못합니다.

(3) 수정 제안: fromId=0, toId=0인 의존성에 대한 테스트 케이스를 추가하여 예외가 발생하는지 검증하세요.

Copilot uses AI. Check for mistakes.
Comment on lines +14 to +27

Copilot AI Jan 22, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(1) 문제점: 테스트가 생성 시 의존성이 비어있는 경우를 검증하지 않습니다. addDependencies가 빈 리스트이거나 null인 경우에도 정상 동작해야 하는지 확인이 필요합니다.

(2) 영향: 엣지 케이스에 대한 검증이 부족하여 예상치 못한 동작이 발생할 수 있습니다.

(3) 수정 제안: addDependencies가 비어있거나 null인 경우의 테스트 케이스를 추가하여 정상 동작을 검증하세요.

Copilot uses AI. Check for mistakes.
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import me.gg.pinit.pinittask.domain.schedule.model.ScheduleType;
import me.gg.pinit.pinittask.infrastructure.events.RabbitEventPublisher;
import me.gg.pinit.pinittask.interfaces.dto.DateTimeWithZone;
import me.gg.pinit.pinittask.interfaces.dto.TaskRequest;
import me.gg.pinit.pinittask.interfaces.dto.TaskCreateRequest;
import me.gg.pinit.pinittask.interfaces.dto.TaskScheduleRequest;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -59,13 +59,12 @@ void setUpMember() {

@Test
void taskLifecycle_create_retrieve_list_cursor_complete_reopen_delete() throws Exception {
TaskRequest createRequest = new TaskRequest(
TaskCreateRequest createRequest = new TaskCreateRequest(
"리포트 작성",
"주간 리포트 초안 작성",
new DateTimeWithZone(LocalDateTime.of(2024, 4, 1, 18, 0), MEMBER_ZONE),
5,
3,
List.of(),
List.of()
);
Comment on lines +62 to 69

Copilot AI Jan 22, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(1) 문제점: 통합 테스트가 작업 생성 시 의존성에 0을 사용하는 핵심 기능을 검증하지 않습니다. 현재 테스트는 빈 의존성 리스트만 사용하고 있습니다.

(2) 영향: PR의 주요 기능인 "작업 생성 시 0을 자기 자신의 플레이스홀더로 사용"하는 기능이 통합 테스트로 검증되지 않아, 실제 환경에서의 동작을 보장할 수 없습니다.

(3) 수정 제안: addDependencies에 fromId 또는 toId가 0인 의존성을 포함하는 테스트 케이스를 추가하여 실제로 생성된 작업의 ID로 치환되는지 검증하세요.

Copilot uses AI. Check for mistakes.

Expand Down Expand Up @@ -168,7 +167,6 @@ void createTask_validationErrors_returnDetailedErrors() throws Exception {
"dueDate": null,
"importance": 0,
"difficulty": 4,
"removeDependencies": [],
"addDependencies": []
}
""";
Expand Down
Loading