Refactor: Move util commands to appropriate directories and update command.dart
This commit is contained in:
parent
6210ab09ad
commit
144f46bf65
8 changed files with 121 additions and 123 deletions
|
|
@ -29,10 +29,10 @@ import 'package:oto_cli/oto/commands/jira/jira.dart';
|
|||
import 'package:oto_cli/oto/commands/process/process.dart';
|
||||
import 'package:oto_cli/oto/commands/proto/protobuf.dart';
|
||||
import 'package:oto_cli/oto/commands/util/json.dart';
|
||||
import 'package:oto_cli/oto/commands/util/mattermost.dart';
|
||||
import 'package:oto_cli/oto/commands/notification/mattermost.dart';
|
||||
import 'package:oto_cli/oto/commands/util/print.dart';
|
||||
import 'package:oto_cli/oto/commands/util/set_value.dart';
|
||||
import 'package:oto_cli/oto/commands/util/smb_authorize.dart';
|
||||
import 'package:oto_cli/oto/commands/infra/smb_authorize.dart';
|
||||
import 'package:oto_cli/oto/commands/util/string_util.dart';
|
||||
import 'package:oto_cli/oto/commands/util/timer.dart';
|
||||
import 'package:oto_cli/oto/commands/web/web.dart';
|
||||
|
|
@ -42,9 +42,9 @@ import 'package:oto_cli/oto/commands/file/delete.dart';
|
|||
import 'package:oto_cli/oto/commands/file/rename.dart';
|
||||
import 'package:oto_cli/oto/commands/shell/shell.dart';
|
||||
import 'package:oto_cli/oto/commands/file/copy.dart';
|
||||
import 'package:oto_cli/oto/commands/util/publish_ios.dart';
|
||||
import 'package:oto_cli/oto/commands/util/slack.dart';
|
||||
import 'package:oto_cli/oto/commands/util/zip.dart';
|
||||
import 'package:oto_cli/oto/commands/build/publish_ios.dart';
|
||||
import 'package:oto_cli/oto/commands/notification/slack.dart';
|
||||
import 'package:oto_cli/oto/commands/file/zip.dart';
|
||||
import 'package:oto_cli/oto/commands/ftp/upload.dart';
|
||||
import 'package:oto_cli/oto/pipeline/pipeline_exe_handle.dart';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,118 +0,0 @@
|
|||
// ignore_for_file: prefer_function_declarations_over_variables, avoid_init_to_null
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:dart_framework/utils/slack/slack_data.dart';
|
||||
import 'package:dart_framework/utils/system_util.dart';
|
||||
import 'package:oto_cli/oto/application.dart';
|
||||
import 'package:oto_cli/oto/commands/command.dart';
|
||||
import 'package:oto_cli/oto/data/command_data.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:oto_cli/oto/data/jira_data.dart';
|
||||
|
||||
class Jira extends Command {
|
||||
String? findContent(DataJiraContent? data) {
|
||||
if (data != null) {
|
||||
if (data.text != null) {
|
||||
return data.text;
|
||||
} else {
|
||||
if (data.content != null && data.content!.isNotEmpty) {
|
||||
return findContent(data.content!.first);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future execute(DataCommand command) async {
|
||||
var data = DataJira.fromJson(command.param);
|
||||
var text = '${data.id}:${data.token}';
|
||||
var base64 = base64Encode(utf8.encode(text));
|
||||
var header = {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Basic $base64'
|
||||
};
|
||||
var url = 'https://${data.domain}/rest/api/3/issue/${data.issue}';
|
||||
Application.log(url);
|
||||
var response = await http.get(Uri.parse(url), headers: header);
|
||||
|
||||
if (response.statusCode < 300 && response.statusCode >= 200) {
|
||||
Application.log(response.body);
|
||||
var issue = DataJiraIssue.fromJson(jsonDecode(response.body));
|
||||
var targetUser = issue.fields?.assignee?.emailAddress;
|
||||
if (targetUser != null) {
|
||||
var slackID = '';
|
||||
for (var user in data.users) {
|
||||
if (targetUser.contains(user.mail!)) {
|
||||
slackID = user.slackID!;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (slackID.isNotEmpty) {
|
||||
var arr = issue.fields?.description?.content;
|
||||
var summary = issue.fields?.summary;
|
||||
if ((arr != null && arr.isNotEmpty) || summary != null) {
|
||||
String? content = "";
|
||||
if (arr != null && arr.isNotEmpty) {
|
||||
content = findContent(arr.first);
|
||||
content ??= summary!;
|
||||
} else {
|
||||
content = summary!;
|
||||
}
|
||||
var browseUrl = 'https://${data.domain}/browse/${data.issue}';
|
||||
DataSlack Function(String) getData = (channel) {
|
||||
var slackData = DataSlack(channel);
|
||||
|
||||
slackData.attachments = [];
|
||||
var attachment = SlackAttachment();
|
||||
slackData.blocks = [];
|
||||
var blockSection = SlackBlockSection();
|
||||
blockSection.text = SlackBlockText();
|
||||
blockSection.text!.text = ':jira: 새 Jira 업무가 할당되었습니다.';
|
||||
slackData.blocks!.add(blockSection);
|
||||
|
||||
attachment.blocks = [];
|
||||
|
||||
blockSection = SlackBlockSection();
|
||||
blockSection.text = SlackBlockText();
|
||||
blockSection.text!.type = SlackTextType.mrkdwn;
|
||||
blockSection.text!.text =
|
||||
'*<$browseUrl|${data.issue}> ${issue.fields?.summary}*';
|
||||
attachment.blocks!.add(blockSection);
|
||||
|
||||
blockSection = SlackBlockSection();
|
||||
blockSection.text = SlackBlockText();
|
||||
blockSection.text!.text = content;
|
||||
blockSection.accessory = SlackAccessory();
|
||||
blockSection.accessory!.type = SlackActionType.button;
|
||||
blockSection.accessory!.url = browseUrl;
|
||||
blockSection.accessory!.text = SlackBlockText();
|
||||
blockSection.accessory!.text!.type = SlackTextType.plain_text;
|
||||
blockSection.accessory!.text!.text = 'Open';
|
||||
attachment.blocks!.add(blockSection);
|
||||
|
||||
slackData.attachments!.add(attachment);
|
||||
return slackData;
|
||||
};
|
||||
// setReturn(data.return_slack_data, getData(slackID));
|
||||
|
||||
// if(data.sub_channel != null) {
|
||||
// setReturn(data.return_slack_channel, getData(data.sub_channel!));
|
||||
// }
|
||||
}
|
||||
} else {
|
||||
Application.log('User not found');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw Exception('Request Jira API Faile: $url');
|
||||
}
|
||||
|
||||
return simpleFuture;
|
||||
}
|
||||
}
|
||||
116
refactoring/to-do.md
Normal file
116
refactoring/to-do.md
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
# AI-Friendly Refactoring To-Do
|
||||
|
||||
AI(Claude 등)가 코드베이스를 더 잘 이해하고 수정할 수 있도록 하는
|
||||
리팩토링 작업 목록. 우선순위 순으로 정렬.
|
||||
|
||||
---
|
||||
|
||||
## ✅ 완료
|
||||
|
||||
### 1. command_data.dart 도메인별 분리
|
||||
- **작업**: 1300줄짜리 단일 파일을 9개 도메인 파일로 분리
|
||||
- **결과**: AI가 특정 커맨드 수정 시 읽어야 할 코드량 대폭 감소
|
||||
- **상세**: `refactoring/history_001.md` 참조
|
||||
|
||||
### 2. commands/util/ 폴더 정리 — 잘못 배치된 커맨드 이동
|
||||
- **작업**: `util/`의 도메인 혼재 파일 5개 이동, 중복 파일 1개 삭제
|
||||
- **결과**:
|
||||
- `util/slack.dart` → `notification/slack.dart`
|
||||
- `util/mattermost.dart` → `notification/mattermost.dart`
|
||||
- `util/publish_ios.dart` → `build/publish_ios.dart`
|
||||
- `util/zip.dart` → `file/zip.dart`
|
||||
- `util/smb_authorize.dart` → `infra/smb_authorize.dart`
|
||||
- `util/jira.dart` → 삭제 (`jira/jira.dart`와 중복, import 없음)
|
||||
- `command.dart` import 경로 5곳 수정
|
||||
|
||||
---
|
||||
|
||||
## 📋 할 일
|
||||
|
||||
---
|
||||
|
||||
### 3. Self-registering Command 패턴
|
||||
**우선순위: 최고 / 난이도: 높음**
|
||||
|
||||
2번 작업(util/ 정리)과 연계. `commands/` 구조 개편의 마무리 단계.
|
||||
현재 새 커맨드 추가 시 두 곳을 수정해야 한다:
|
||||
1. 도메인 데이터 파일 — 데이터 클래스 추가
|
||||
2. `commands/command.dart` — 130+ case factory switch에 추가
|
||||
|
||||
각 Command 클래스가 자신을 등록하는 패턴으로 변경하면
|
||||
새 커맨드 추가 시 해당 파일 하나만 수정하면 된다.
|
||||
|
||||
작업 내용:
|
||||
- `Command` 클래스에 `registerFactory()` static 메서드 추가
|
||||
- 각 커맨드 파일에 `static void register()` 메서드 추가
|
||||
- `application.dart` 또는 별도 registry 파일에서 모든 커맨드 등록
|
||||
- 기존 switch factory 제거
|
||||
|
||||
> ⚠️ 변경 범위가 크므로 2번 완료 후 진행 권장
|
||||
|
||||
---
|
||||
|
||||
### 4. 태그 시스템 중앙화
|
||||
**우선순위: 중간 / 난이도: 낮음**
|
||||
|
||||
현재 태그 처리 로직(`<!property.key>` 등)이 `commands/command.dart` 내부에
|
||||
흩어져 있다. 별도 파일로 분리하면 AI가 "어떤 태그를 쓸 수 있나?" 질문에
|
||||
코드 한 곳만 읽어도 답할 수 있다.
|
||||
|
||||
작업 내용:
|
||||
- `lib/oto/core/tag_system.dart` 파일 생성
|
||||
- 태그 파싱/치환 로직을 `command.dart`에서 이동
|
||||
- 태그 종류 명세를 주석으로 정리 (`property`, `state`, `common` 등)
|
||||
- `command.dart`는 `tag_system.dart`를 import해서 사용
|
||||
|
||||
---
|
||||
|
||||
### 5. Pipeline Executor에 YAML 예제 주석 추가
|
||||
**우선순위: 중간 / 난이도: 낮음**
|
||||
|
||||
현재 `assets/yaml/example/` 폴더에 예제가 따로 있어 코드-예제 매핑이 안 된다.
|
||||
각 PipelineExecutor 클래스 상단에 인라인 YAML 예제를 주석으로 추가하면
|
||||
AI가 파이프라인 구조를 한 파일만 읽어도 파악할 수 있다.
|
||||
|
||||
대상 파일:
|
||||
- `lib/oto/pipeline/pipeline_exe.dart`
|
||||
- `lib/oto/pipeline/pipeline_if.dart`
|
||||
- `lib/oto/pipeline/pipeline_foreach.dart`
|
||||
- `lib/oto/pipeline/pipeline_while.dart`
|
||||
- `lib/oto/pipeline/pipeline_switch.dart`
|
||||
- `lib/oto/pipeline/pipeline_exe_handle.dart`
|
||||
- `lib/oto/pipeline/pipeline_wait_until.dart`
|
||||
|
||||
예시:
|
||||
```dart
|
||||
/// Example YAML:
|
||||
/// ```yaml
|
||||
/// - if:
|
||||
/// equal-string: "<!property.env>"
|
||||
/// value: "prod"
|
||||
/// on-true:
|
||||
/// - exe: deployProd
|
||||
/// on-false:
|
||||
/// - exe: deployDev
|
||||
/// ```
|
||||
class PipelineIf extends PipelineExecutor { ... }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6. CLAUDE.md 작성 — 마지막에 작성
|
||||
**우선순위: 높음 / 난이도: 낮음 / 시점: 모든 리팩토링 완료 후**
|
||||
|
||||
> ⚠️ 리팩토링이 진행되면 구조가 계속 바뀌므로 반드시 마지막에 작성한다.
|
||||
|
||||
프로젝트 루트에 `CLAUDE.md`를 두면 Claude가 대화 시작 시 자동으로 읽는다.
|
||||
매 대화마다 프로젝트 구조를 다시 파악하는 비용을 없앨 수 있다.
|
||||
|
||||
포함할 내용:
|
||||
- 프로젝트 개요 (Dart CLI, Jenkins 연동 빌드 자동화)
|
||||
- 최종 디렉토리 구조 요약
|
||||
- 새 커맨드 추가 방법 (단계별)
|
||||
- 새 도메인 데이터 클래스 추가 방법 (`build_runner` 실행 포함)
|
||||
- 태그 문법 레퍼런스 (`<!property.key>`, `<!state.cmdId>`, `<!common.field>`)
|
||||
- 에러 핸들링 패턴 (`application.dart` catch 구조)
|
||||
- 주의사항 (xcworkspace/xcodeproj `??` 패턴 등)
|
||||
Loading…
Reference in a new issue