tylersong 1.0.10 → 1.0.12
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/SECURITY_CHECK.md +121 -0
- package/dist/index.js +159 -29
- package/dist/lib/date.d.ts +8 -0
- package/dist/lib/date.js +52 -0
- package/dist/lib/dateUtils.d.ts +26 -0
- package/dist/lib/dateUtils.js +185 -0
- package/dist/lib/sanity.d.ts +26 -0
- package/dist/lib/sanity.js +146 -0
- package/dist/types/experience.d.ts +12 -0
- package/dist/types/experience.js +2 -0
- package/package.json +6 -4
- package/.cursor/plans/-----------8c733d2f.plan.md +0 -158
- package/.editorconfig +0 -15
- package/.eslintrc.json +0 -33
- package/.github/actions/discord-notify/action.yml +0 -119
- package/.github/actions/setup-runtime/action.yml +0 -41
- package/.github/workflows/ci.yml +0 -79
- package/.github/workflows/deploy.yml +0 -164
- package/.github/workflows/publish.yml +0 -53
- package/.prettierrc +0 -13
- package/bun.lock +0 -212
- package/bunfig.toml +0 -16
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/docs/auto-deployment.md +0 -191
- package/docs/deployment.md +0 -82
- package/docs/development.md +0 -394
- package/docs/direct-deployment.md +0 -116
- package/docs/discord-setup.md +0 -158
- package/docs/github-actions-fixes.md +0 -142
- package/docs/improvements.md +0 -287
- package/docs/pipeline.md +0 -228
- package/docs/testing.md +0 -173
- package/docs/usage.md +0 -112
- package/docs/workflows.md +0 -176
- package/src/index.ts +0 -141
- package/test/index.test.ts +0 -167
- package/tsconfig.eslint.json +0 -9
- package/tsconfig.json +0 -20
- package/vitest.config.ts +0 -22
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { createClient } from "@sanity/client";
|
|
2
|
+
import { readFileSync } from "fs";
|
|
3
|
+
import { join, dirname } from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = dirname(__filename);
|
|
7
|
+
/**
|
|
8
|
+
* .env 파일에서 환경 변수를 읽어옵니다
|
|
9
|
+
*/
|
|
10
|
+
const loadEnvConfig = () => {
|
|
11
|
+
try {
|
|
12
|
+
const envPath = join(__dirname, "..", "..", ".env");
|
|
13
|
+
const envContent = readFileSync(envPath, "utf-8");
|
|
14
|
+
const config = {};
|
|
15
|
+
envContent.split("\n").forEach((line) => {
|
|
16
|
+
const trimmedLine = line.trim();
|
|
17
|
+
if (trimmedLine && !trimmedLine.startsWith("#")) {
|
|
18
|
+
const [key, ...valueParts] = trimmedLine.split("=");
|
|
19
|
+
const value = valueParts.join("=").replace(/^["']|["']$/g, "");
|
|
20
|
+
switch (key.trim()) {
|
|
21
|
+
case "SANITY_PROJECT_ID":
|
|
22
|
+
config.projectId = value;
|
|
23
|
+
break;
|
|
24
|
+
case "SANITY_DATASET":
|
|
25
|
+
config.dataset = value;
|
|
26
|
+
break;
|
|
27
|
+
case "SANITY_API_VERSION":
|
|
28
|
+
config.apiVersion = value;
|
|
29
|
+
break;
|
|
30
|
+
case "SANITY_API_TOKEN":
|
|
31
|
+
config.token = value;
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
if (!config.projectId || !config.dataset || !config.apiVersion) {
|
|
37
|
+
throw new Error("필수 Sanity 환경 변수가 누락되었습니다: SANITY_PROJECT_ID, SANITY_DATASET, SANITY_API_VERSION");
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
projectId: config.projectId,
|
|
41
|
+
dataset: config.dataset,
|
|
42
|
+
apiVersion: config.apiVersion,
|
|
43
|
+
token: config.token,
|
|
44
|
+
useCdn: false, // 읽기 전용이므로 CDN 사용 안 함
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
// .env 파일이 없거나 읽을 수 없는 경우 process.env에서 시도
|
|
49
|
+
const projectId = process.env.SANITY_PROJECT_ID;
|
|
50
|
+
const dataset = process.env.SANITY_DATASET;
|
|
51
|
+
const apiVersion = process.env.SANITY_API_VERSION;
|
|
52
|
+
const token = process.env.SANITY_API_TOKEN;
|
|
53
|
+
if (!projectId || !dataset || !apiVersion) {
|
|
54
|
+
throw new Error("Sanity 환경 변수를 찾을 수 없습니다. .env 파일을 확인해주세요.");
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
projectId,
|
|
58
|
+
dataset,
|
|
59
|
+
apiVersion,
|
|
60
|
+
token,
|
|
61
|
+
useCdn: false,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Sanity 클라이언트 인스턴스를 생성합니다
|
|
67
|
+
*/
|
|
68
|
+
const createSanityClient = () => {
|
|
69
|
+
const config = loadEnvConfig();
|
|
70
|
+
return createClient({
|
|
71
|
+
projectId: config.projectId,
|
|
72
|
+
dataset: config.dataset,
|
|
73
|
+
apiVersion: config.apiVersion,
|
|
74
|
+
token: config.token,
|
|
75
|
+
useCdn: config.useCdn,
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
// Sanity 클라이언트 인스턴스
|
|
79
|
+
const client = createSanityClient();
|
|
80
|
+
/**
|
|
81
|
+
* 모든 Experience(경력) 데이터를 조회합니다
|
|
82
|
+
*/
|
|
83
|
+
export const getExperiences = async () => {
|
|
84
|
+
try {
|
|
85
|
+
const query = `*[_type == "experience"] | order(startDate asc) {
|
|
86
|
+
_id,
|
|
87
|
+
company,
|
|
88
|
+
position,
|
|
89
|
+
startDate,
|
|
90
|
+
endDate,
|
|
91
|
+
description,
|
|
92
|
+
technologies,
|
|
93
|
+
location
|
|
94
|
+
}`;
|
|
95
|
+
const experiences = await client.fetch(query);
|
|
96
|
+
return experiences;
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
throw new Error(`경력 데이터를 조회하는 중 오류가 발생했습니다: ${error instanceof Error ? error.message : String(error)}`);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* 특정 ID의 Experience를 조회합니다
|
|
104
|
+
*/
|
|
105
|
+
export const getExperienceById = async (id) => {
|
|
106
|
+
try {
|
|
107
|
+
const query = `*[_type == "experience" && _id == $id][0] {
|
|
108
|
+
_id,
|
|
109
|
+
company,
|
|
110
|
+
position,
|
|
111
|
+
startDate,
|
|
112
|
+
endDate,
|
|
113
|
+
description,
|
|
114
|
+
technologies,
|
|
115
|
+
location
|
|
116
|
+
}`;
|
|
117
|
+
const experience = await client.fetch(query, { id });
|
|
118
|
+
return experience;
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
throw new Error(`경력 데이터를 조회하는 중 오류가 발생했습니다: ${error instanceof Error ? error.message : String(error)}`);
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
export const getPortfolio = async (name) => {
|
|
125
|
+
try {
|
|
126
|
+
// name이 제공된 경우 author의 name과 일치하는 portfolio만 조회
|
|
127
|
+
const query = `*[_type == "portfolio" && author->name == $name][0] {
|
|
128
|
+
"author": author-> {
|
|
129
|
+
name,
|
|
130
|
+
email
|
|
131
|
+
}
|
|
132
|
+
}`;
|
|
133
|
+
const portfolio = name
|
|
134
|
+
? await client.fetch(query, { name })
|
|
135
|
+
: await client.fetch(query);
|
|
136
|
+
return portfolio;
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
throw new Error(`포트폴리오 데이터를 조회하는 중 오류가 발생했습니다: ${error instanceof Error ? error.message : String(error)}`);
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* Sanity 클라이언트 인스턴스를 반환합니다 (필요한 경우)
|
|
144
|
+
*/
|
|
145
|
+
export const getSanityClient = () => client;
|
|
146
|
+
//# sourceMappingURL=sanity.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface Experience {
|
|
2
|
+
_id: string;
|
|
3
|
+
company: string;
|
|
4
|
+
position: string;
|
|
5
|
+
startDate: string;
|
|
6
|
+
endDate?: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
technologies?: string[];
|
|
9
|
+
location?: string;
|
|
10
|
+
[key: string]: unknown;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=experience.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tylersong",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.12",
|
|
4
4
|
"description": "나의 CLI 자기소개 도구",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
"scripts": {
|
|
16
16
|
"build": "tsc",
|
|
17
17
|
"build:bun": "bun build src/index.ts --outdir dist --target node",
|
|
18
|
-
"dev": "
|
|
19
|
-
"dev:
|
|
18
|
+
"dev": "bun run src/index.ts",
|
|
19
|
+
"dev:tsx": "tsx src/index.ts",
|
|
20
20
|
"start": "node dist/index.js",
|
|
21
21
|
"start:bun": "bun run dist/index.js",
|
|
22
22
|
"test": "vitest run",
|
|
@@ -27,11 +27,13 @@
|
|
|
27
27
|
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
|
28
28
|
"format:check": "prettier --check \"src/**/*.ts\" \"test/**/*.ts\"",
|
|
29
29
|
"typecheck": "tsc --noEmit",
|
|
30
|
-
"prepublishOnly": "
|
|
30
|
+
"prepublishOnly": "bun run build"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
+
"@sanity/client": "^7.13.2",
|
|
33
34
|
"chalk": "^5.4.1",
|
|
34
35
|
"commander": "^13.1.0",
|
|
36
|
+
"date-fns": "^4.1.0",
|
|
35
37
|
"inquirer": "^12.4.2"
|
|
36
38
|
},
|
|
37
39
|
"devDependencies": {
|
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
<!-- 8c733d2f-63d8-4158-aa6e-255c23deedca 77c7f805-6518-4181-90b0-4dff17016b38 -->
|
|
2
|
-
# 프로젝트 품질 개선 계획
|
|
3
|
-
|
|
4
|
-
## 📊 현재 프로젝트 분석
|
|
5
|
-
|
|
6
|
-
### ✅ 장점
|
|
7
|
-
|
|
8
|
-
1. **깔끔한 코드 구조**: TypeScript 기반의 명확한 단일 파일 구조
|
|
9
|
-
2. **타입 안정성**: TypeScript 사용으로 인터페이스 정의 및 strict 모드 활성화
|
|
10
|
-
3. **Bun 지원**: 최신 런타임 지원으로 성능 최적화 가능
|
|
11
|
-
4. **풍부한 문서화**: docs 폴더에 배포, 사용법 등 상세 문서 작성됨
|
|
12
|
-
5. **사용자 친화적**: Commander.js, Inquirer.js로 직관적인 CLI 경험 제공
|
|
13
|
-
6. **크로스 플랫폼**: Windows, macOS, Linux 모두 지원하는 URL 열기 기능
|
|
14
|
-
|
|
15
|
-
### ❌ 단점 및 개선 필요 사항
|
|
16
|
-
|
|
17
|
-
#### 1. **테스트 코드 부재** (Critical)
|
|
18
|
-
|
|
19
|
-
- 현재 `package.json`에 "No test specified"로 테스트 미구현
|
|
20
|
-
- 사용자 규칙에 따라 Vitest 사용 필요
|
|
21
|
-
|
|
22
|
-
#### 2. **에러 처리 부족** (High)
|
|
23
|
-
|
|
24
|
-
- `exec()` 함수의 에러 핸들링 없음
|
|
25
|
-
- URL 열기 실패 시 사용자 피드백 없음
|
|
26
|
-
- 프로미스 거부(rejection) 처리가 `.catch(console.error)`로만 처리
|
|
27
|
-
|
|
28
|
-
#### 3. **린팅/포맷팅 설정 없음** (Medium)
|
|
29
|
-
|
|
30
|
-
- ESLint, Prettier 등 코드 품질 도구 미설정
|
|
31
|
-
- 일관된 코드 스타일 관리 어려움
|
|
32
|
-
|
|
33
|
-
#### 4. **CI/CD 파이프라인 없음** (High)
|
|
34
|
-
|
|
35
|
-
- docs에 워크플로우 문서는 있으나 실제 `.github/workflows` 폴더 없음
|
|
36
|
-
- 자동 테스트, 빌드, 배포 검증 불가
|
|
37
|
-
|
|
38
|
-
#### 5. **버전 중복 관리** (Low)
|
|
39
|
-
|
|
40
|
-
- `package.json`과 `src/index.ts`에 버전이 각각 하드코딩됨
|
|
41
|
-
- 버전 업데이트 시 두 곳을 수정해야 함
|
|
42
|
-
|
|
43
|
-
#### 6. **Bun 우선 정책 미준수** (Medium)
|
|
44
|
-
|
|
45
|
-
- `prepublishOnly` 스크립트가 `npm run build` 사용
|
|
46
|
-
- 사용자 규칙에 따라 bun 사용 필요
|
|
47
|
-
|
|
48
|
-
#### 7. **Git 관리 개선 필요** (Low)
|
|
49
|
-
|
|
50
|
-
- `.gitignore`에 `dist/`, `*.log` 등 명시 필요
|
|
51
|
-
- `node_modules` 제외 확인 필요
|
|
52
|
-
|
|
53
|
-
#### 8. **보안 및 의존성 관리** (Medium)
|
|
54
|
-
|
|
55
|
-
- 의존성 취약점 자동 검사 없음
|
|
56
|
-
- 정기적인 업데이트 메커니즘 부재
|
|
57
|
-
|
|
58
|
-
#### 9. **환경별 설정 분리 없음** (Low)
|
|
59
|
-
|
|
60
|
-
- 개인정보(GitHub URL, 이메일)가 하드코딩됨
|
|
61
|
-
- 설정 파일로 분리하면 재사용성 향상
|
|
62
|
-
|
|
63
|
-
## 🔧 개선 작업 항목
|
|
64
|
-
|
|
65
|
-
### 1. 테스트 환경 구축 (`test/` 폴더)
|
|
66
|
-
|
|
67
|
-
- **파일**: `test/index.test.ts`
|
|
68
|
-
- Vitest 설치 및 설정
|
|
69
|
-
- 주요 함수(`openUrl`, `main`) 단위 테스트 작성
|
|
70
|
-
- CLI 옵션별 통합 테스트 작성
|
|
71
|
-
|
|
72
|
-
### 2. 에러 처리 강화 (`src/index.ts`)
|
|
73
|
-
|
|
74
|
-
```typescript
|
|
75
|
-
// openUrl 함수 개선
|
|
76
|
-
const openUrl = (url: string): void => {
|
|
77
|
-
exec(`${command} ${url}`, (error) => {
|
|
78
|
-
if (error) {
|
|
79
|
-
console.error(chalk.red('❌ 브라우저를 열 수 없습니다.'));
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
};
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
### 3. 린팅/포맷팅 설정
|
|
86
|
-
|
|
87
|
-
- **파일**: `.eslintrc.json`, `.prettierrc`, `.editorconfig`
|
|
88
|
-
- ESLint + TypeScript 플러그인 설치
|
|
89
|
-
- Prettier 설정
|
|
90
|
-
- pre-commit 훅 설정 (husky)
|
|
91
|
-
|
|
92
|
-
### 4. CI/CD 파이프라인 구축
|
|
93
|
-
|
|
94
|
-
- **파일**: `.github/workflows/ci.yml`, `.github/workflows/publish.yml`
|
|
95
|
-
- Pull Request 시 자동 테스트/린트
|
|
96
|
-
- main 브랜치 머지 시 자동 빌드 검증
|
|
97
|
-
- 태그 푸시 시 NPM 자동 배포
|
|
98
|
-
|
|
99
|
-
### 5. 버전 관리 개선
|
|
100
|
-
|
|
101
|
-
- `src/index.ts`에서 버전 하드코딩 제거
|
|
102
|
-
- `package.json` 버전을 동적으로 읽어오기
|
|
103
|
-
|
|
104
|
-
### 6. 프로젝트 설정 개선
|
|
105
|
-
|
|
106
|
-
- **파일**: `.gitignore`, `vitest.config.ts`
|
|
107
|
-
- Bun 우선 스크립트 수정
|
|
108
|
-
- Git ignore 규칙 추가
|
|
109
|
-
|
|
110
|
-
### 7. 문서 업데이트
|
|
111
|
-
|
|
112
|
-
- **파일**: `docs/testing.md`, `docs/development.md`
|
|
113
|
-
- 테스트 실행 방법 문서화
|
|
114
|
-
- 개발 환경 설정 가이드 추가
|
|
115
|
-
- 파이프라인 다이어그램 (Mermaid 그래프)
|
|
116
|
-
|
|
117
|
-
## 📝 생성/수정될 파일 목록
|
|
118
|
-
|
|
119
|
-
### 새로 생성
|
|
120
|
-
|
|
121
|
-
- `test/index.test.ts` - 테스트 코드
|
|
122
|
-
- `vitest.config.ts` - Vitest 설정
|
|
123
|
-
- `.eslintrc.json` - ESLint 설정
|
|
124
|
-
- `.prettierrc` - Prettier 설정
|
|
125
|
-
- `.gitignore` - Git ignore 규칙
|
|
126
|
-
- `.github/workflows/ci.yml` - CI 워크플로우
|
|
127
|
-
- `.github/workflows/publish.yml` - 배포 워크플로우
|
|
128
|
-
- `docs/testing.md` - 테스트 가이드
|
|
129
|
-
- `docs/pipeline.md` - CI/CD 파이프라인 설명 (Mermaid 그래프 포함)
|
|
130
|
-
|
|
131
|
-
### 수정
|
|
132
|
-
|
|
133
|
-
- `src/index.ts` - 에러 처리 강화, 버전 동적 로딩
|
|
134
|
-
- `package.json` - 테스트 스크립트 추가, bun 우선 스크립트 수정
|
|
135
|
-
- `README.md` - 테스트, 린팅 배지 추가
|
|
136
|
-
|
|
137
|
-
## 🎯 우선순위
|
|
138
|
-
|
|
139
|
-
1. **테스트 환경 구축** (가장 중요)
|
|
140
|
-
2. **에러 처리 강화**
|
|
141
|
-
3. **CI/CD 파이프라인**
|
|
142
|
-
4. **린팅/포맷팅 설정**
|
|
143
|
-
5. **기타 개선 사항**
|
|
144
|
-
|
|
145
|
-
### To-dos
|
|
146
|
-
|
|
147
|
-
- [ ] Vitest 설치 및 설정 파일 생성 (vitest.config.ts)
|
|
148
|
-
- [ ] test/index.test.ts 파일 작성 (주요 기능 테스트)
|
|
149
|
-
- [ ] src/index.ts의 에러 처리 강화 (openUrl, main 함수)
|
|
150
|
-
- [ ] ESLint, Prettier 설정 파일 생성
|
|
151
|
-
- [ ] .github/workflows/ci.yml 생성 (테스트, 린트 자동화)
|
|
152
|
-
- [ ] .github/workflows/publish.yml 생성 (NPM 자동 배포)
|
|
153
|
-
- [ ] src/index.ts에서 버전을 package.json에서 동적으로 읽어오기
|
|
154
|
-
- [ ] .gitignore 파일 생성 또는 개선
|
|
155
|
-
- [ ] package.json의 테스트/린트 스크립트 추가, bun 우선 수정
|
|
156
|
-
- [ ] docs/testing.md 문서 작성
|
|
157
|
-
- [ ] docs/pipeline.md 작성 (Mermaid 그래프 포함)
|
|
158
|
-
- [ ] README.md에 테스트, 린팅 배지 및 정보 추가
|
package/.editorconfig
DELETED
package/.eslintrc.json
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"env": {
|
|
3
|
-
"node": true,
|
|
4
|
-
"es2021": true
|
|
5
|
-
},
|
|
6
|
-
"extends": [
|
|
7
|
-
"eslint:recommended",
|
|
8
|
-
"plugin:@typescript-eslint/recommended",
|
|
9
|
-
"plugin:@typescript-eslint/recommended-requiring-type-checking"
|
|
10
|
-
],
|
|
11
|
-
"parser": "@typescript-eslint/parser",
|
|
12
|
-
"parserOptions": {
|
|
13
|
-
"ecmaVersion": "latest",
|
|
14
|
-
"sourceType": "module",
|
|
15
|
-
"project": "./tsconfig.eslint.json"
|
|
16
|
-
},
|
|
17
|
-
"plugins": ["@typescript-eslint"],
|
|
18
|
-
"rules": {
|
|
19
|
-
"@typescript-eslint/no-unused-vars": [
|
|
20
|
-
"error",
|
|
21
|
-
{
|
|
22
|
-
"argsIgnorePattern": "^_",
|
|
23
|
-
"varsIgnorePattern": "^_"
|
|
24
|
-
}
|
|
25
|
-
],
|
|
26
|
-
"@typescript-eslint/explicit-function-return-type": "warn",
|
|
27
|
-
"@typescript-eslint/no-explicit-any": "warn",
|
|
28
|
-
"@typescript-eslint/no-floating-promises": "error",
|
|
29
|
-
"no-console": "off"
|
|
30
|
-
},
|
|
31
|
-
"ignorePatterns": ["dist", "node_modules", "*.config.ts", "*.config.js", "**/*.d.ts"]
|
|
32
|
-
}
|
|
33
|
-
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
name: "Discord Notification"
|
|
2
|
-
description: "Send notification to Discord webhook"
|
|
3
|
-
|
|
4
|
-
inputs:
|
|
5
|
-
webhook-url:
|
|
6
|
-
description: "Discord webhook URL"
|
|
7
|
-
required: true
|
|
8
|
-
status:
|
|
9
|
-
description: "Status of the workflow (success, failure, cancelled)"
|
|
10
|
-
required: true
|
|
11
|
-
title:
|
|
12
|
-
description: "Notification title"
|
|
13
|
-
required: true
|
|
14
|
-
description:
|
|
15
|
-
description: "Notification description"
|
|
16
|
-
required: false
|
|
17
|
-
default: ""
|
|
18
|
-
color:
|
|
19
|
-
description: "Embed color (hex without #)"
|
|
20
|
-
required: false
|
|
21
|
-
default: "5865F2"
|
|
22
|
-
fields:
|
|
23
|
-
description: "Additional fields in JSON format"
|
|
24
|
-
required: false
|
|
25
|
-
default: "[]"
|
|
26
|
-
|
|
27
|
-
runs:
|
|
28
|
-
using: "composite"
|
|
29
|
-
steps:
|
|
30
|
-
- name: Set color based on status
|
|
31
|
-
shell: bash
|
|
32
|
-
id: color
|
|
33
|
-
run: |
|
|
34
|
-
case "${{ inputs.status }}" in
|
|
35
|
-
success)
|
|
36
|
-
echo "color=00FF00" >> $GITHUB_OUTPUT
|
|
37
|
-
echo "emoji=✅" >> $GITHUB_OUTPUT
|
|
38
|
-
;;
|
|
39
|
-
failure)
|
|
40
|
-
echo "color=FF0000" >> $GITHUB_OUTPUT
|
|
41
|
-
echo "emoji=❌" >> $GITHUB_OUTPUT
|
|
42
|
-
;;
|
|
43
|
-
cancelled)
|
|
44
|
-
echo "color=FFA500" >> $GITHUB_OUTPUT
|
|
45
|
-
echo "emoji=⚠️" >> $GITHUB_OUTPUT
|
|
46
|
-
;;
|
|
47
|
-
*)
|
|
48
|
-
echo "color=${{ inputs.color }}" >> $GITHUB_OUTPUT
|
|
49
|
-
echo "emoji=ℹ️" >> $GITHUB_OUTPUT
|
|
50
|
-
;;
|
|
51
|
-
esac
|
|
52
|
-
|
|
53
|
-
- name: Send Discord notification
|
|
54
|
-
shell: bash
|
|
55
|
-
env:
|
|
56
|
-
WEBHOOK_URL: ${{ inputs.webhook-url }}
|
|
57
|
-
STATUS: ${{ inputs.status }}
|
|
58
|
-
TITLE: ${{ inputs.title }}
|
|
59
|
-
DESCRIPTION: ${{ inputs.description }}
|
|
60
|
-
COLOR: ${{ steps.color.outputs.color }}
|
|
61
|
-
EMOJI: ${{ steps.color.outputs.emoji }}
|
|
62
|
-
FIELDS: ${{ inputs.fields }}
|
|
63
|
-
run: |
|
|
64
|
-
# 16진수 색상을 10진수로 변환
|
|
65
|
-
COLOR_DEC=$((16#$COLOR))
|
|
66
|
-
|
|
67
|
-
# 안전한 JSON 페이로드 생성 (임시 파일 사용)
|
|
68
|
-
TEMP_FILE=$(mktemp)
|
|
69
|
-
|
|
70
|
-
# 기본 구조 생성
|
|
71
|
-
jq -n \
|
|
72
|
-
--arg emoji "$EMOJI" \
|
|
73
|
-
--arg title "$TITLE" \
|
|
74
|
-
--arg description "$DESCRIPTION" \
|
|
75
|
-
--argjson color "$COLOR_DEC" \
|
|
76
|
-
'{
|
|
77
|
-
embeds: [{
|
|
78
|
-
title: ($emoji + " " + $title),
|
|
79
|
-
description: $description,
|
|
80
|
-
color: $color,
|
|
81
|
-
footer: {
|
|
82
|
-
text: "GitHub Actions",
|
|
83
|
-
icon_url: "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png"
|
|
84
|
-
},
|
|
85
|
-
timestamp: (now | strftime("%Y-%m-%dT%H:%M:%S.000Z"))
|
|
86
|
-
}]
|
|
87
|
-
}' > "$TEMP_FILE"
|
|
88
|
-
|
|
89
|
-
# fields가 비어있지 않으면 추가
|
|
90
|
-
if [ "$FIELDS" != "[]" ] && [ -n "$FIELDS" ]; then
|
|
91
|
-
jq --argjson fields "$FIELDS" '.embeds[0].fields = $fields' "$TEMP_FILE" > "${TEMP_FILE}.tmp" && mv "${TEMP_FILE}.tmp" "$TEMP_FILE"
|
|
92
|
-
fi
|
|
93
|
-
|
|
94
|
-
# Discord 웹훅으로 전송 (디버그 정보 포함)
|
|
95
|
-
echo "Sending payload:"
|
|
96
|
-
cat "$TEMP_FILE"
|
|
97
|
-
echo ""
|
|
98
|
-
|
|
99
|
-
RESPONSE=$(curl -s -w "%{http_code}" -H "Content-Type: application/json" \
|
|
100
|
-
-d @"$TEMP_FILE" \
|
|
101
|
-
"$WEBHOOK_URL")
|
|
102
|
-
|
|
103
|
-
HTTP_CODE="${RESPONSE: -3}"
|
|
104
|
-
RESPONSE_BODY="${RESPONSE%???}"
|
|
105
|
-
|
|
106
|
-
echo "HTTP Status: $HTTP_CODE"
|
|
107
|
-
echo "Response: $RESPONSE_BODY"
|
|
108
|
-
|
|
109
|
-
# 임시 파일 정리
|
|
110
|
-
rm -f "$TEMP_FILE"
|
|
111
|
-
|
|
112
|
-
# 상태 코드 확인
|
|
113
|
-
if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 300 ]; then
|
|
114
|
-
echo "✅ Discord 알림 전송 성공"
|
|
115
|
-
else
|
|
116
|
-
echo "❌ Discord 알림 전송 실패: HTTP $HTTP_CODE"
|
|
117
|
-
echo "Response: $RESPONSE_BODY"
|
|
118
|
-
exit 1
|
|
119
|
-
fi
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
name: "Setup Runtime Environment"
|
|
2
|
-
description: "Setup Node.js or Bun runtime with dependencies"
|
|
3
|
-
|
|
4
|
-
inputs:
|
|
5
|
-
runtime:
|
|
6
|
-
description: "Runtime to setup (node or bun)"
|
|
7
|
-
required: true
|
|
8
|
-
node-version:
|
|
9
|
-
description: "Node.js version"
|
|
10
|
-
required: false
|
|
11
|
-
default: "20.x"
|
|
12
|
-
bun-version:
|
|
13
|
-
description: "Bun version"
|
|
14
|
-
required: false
|
|
15
|
-
default: "latest"
|
|
16
|
-
|
|
17
|
-
runs:
|
|
18
|
-
using: "composite"
|
|
19
|
-
steps:
|
|
20
|
-
- name: Setup Node.js
|
|
21
|
-
if: inputs.runtime == 'node'
|
|
22
|
-
uses: actions/setup-node@v4
|
|
23
|
-
with:
|
|
24
|
-
node-version: ${{ inputs.node-version }}
|
|
25
|
-
cache: "npm"
|
|
26
|
-
|
|
27
|
-
- name: Setup Bun
|
|
28
|
-
if: inputs.runtime == 'bun'
|
|
29
|
-
uses: oven-sh/setup-bun@v1
|
|
30
|
-
with:
|
|
31
|
-
bun-version: ${{ inputs.bun-version }}
|
|
32
|
-
|
|
33
|
-
- name: Install dependencies (Node.js)
|
|
34
|
-
if: inputs.runtime == 'node'
|
|
35
|
-
shell: bash
|
|
36
|
-
run: npm ci
|
|
37
|
-
|
|
38
|
-
- name: Install dependencies (Bun)
|
|
39
|
-
if: inputs.runtime == 'bun'
|
|
40
|
-
shell: bash
|
|
41
|
-
run: bun install
|
package/.github/workflows/ci.yml
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
name: CI
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [main, develop]
|
|
6
|
-
pull_request:
|
|
7
|
-
branches: [main, develop]
|
|
8
|
-
|
|
9
|
-
jobs:
|
|
10
|
-
test:
|
|
11
|
-
name: Test & Lint
|
|
12
|
-
runs-on: ubuntu-latest
|
|
13
|
-
|
|
14
|
-
strategy:
|
|
15
|
-
matrix:
|
|
16
|
-
node-version: [18.x, 20.x]
|
|
17
|
-
|
|
18
|
-
steps:
|
|
19
|
-
- name: 코드 체크아웃
|
|
20
|
-
uses: actions/checkout@v4
|
|
21
|
-
|
|
22
|
-
- name: Bun 설치
|
|
23
|
-
uses: oven-sh/setup-bun@v1
|
|
24
|
-
with:
|
|
25
|
-
bun-version: latest
|
|
26
|
-
|
|
27
|
-
- name: 의존성 캐시
|
|
28
|
-
uses: actions/cache@v3
|
|
29
|
-
with:
|
|
30
|
-
path: ~/.bun/install/cache
|
|
31
|
-
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
|
|
32
|
-
restore-keys: |
|
|
33
|
-
${{ runner.os }}-bun-
|
|
34
|
-
|
|
35
|
-
- name: 의존성 설치
|
|
36
|
-
run: bun install
|
|
37
|
-
|
|
38
|
-
- name: 타입 체크
|
|
39
|
-
run: bun run build
|
|
40
|
-
|
|
41
|
-
- name: 린트 실행
|
|
42
|
-
run: bun run lint
|
|
43
|
-
|
|
44
|
-
- name: 테스트 실행
|
|
45
|
-
run: bun run test
|
|
46
|
-
|
|
47
|
-
- name: 테스트 커버리지 업로드
|
|
48
|
-
if: matrix.node-version == '20.x'
|
|
49
|
-
uses: codecov/codecov-action@v3
|
|
50
|
-
with:
|
|
51
|
-
files: ./coverage/coverage-final.json
|
|
52
|
-
flags: unittests
|
|
53
|
-
name: codecov-umbrella
|
|
54
|
-
|
|
55
|
-
build:
|
|
56
|
-
name: Build
|
|
57
|
-
runs-on: ubuntu-latest
|
|
58
|
-
needs: test
|
|
59
|
-
|
|
60
|
-
steps:
|
|
61
|
-
- name: 코드 체크아웃
|
|
62
|
-
uses: actions/checkout@v4
|
|
63
|
-
|
|
64
|
-
- name: Bun 설치
|
|
65
|
-
uses: oven-sh/setup-bun@v1
|
|
66
|
-
with:
|
|
67
|
-
bun-version: latest
|
|
68
|
-
|
|
69
|
-
- name: 의존성 설치
|
|
70
|
-
run: bun install
|
|
71
|
-
|
|
72
|
-
- name: Bun으로 빌드
|
|
73
|
-
run: bun run build:bun
|
|
74
|
-
|
|
75
|
-
- name: 빌드 결과물 업로드
|
|
76
|
-
uses: actions/upload-artifact@v3
|
|
77
|
-
with:
|
|
78
|
-
name: dist
|
|
79
|
-
path: dist/
|