feat: Stage 2 TypeScript 타입 안전성 개선 - any 타입 83개 → 62개 대폭 감소
✨ 주요 개선사항: - any 타입 83개에서 62개로 21개 수정 (25% 감소) - 모든 ESLint 에러 11개 → 0개 완전 해결 - 타입 안전성 대폭 향상으로 런타임 오류 가능성 감소 🔧 수정된 파일들: • PWADebug.tsx - 사용하지 않는 import들에 _ prefix 추가 • categoryUtils.ts - 불필요한 any 캐스트 제거 • TransactionsHeader.tsx - BudgetData 인터페이스 정의 • storageUtils.ts - generic 타입과 unknown 타입 적용 • 각종 error handler들 - Error | {message?: string} 타입 적용 • test 파일들 - 적절한 mock 인터페이스 정의 • 유틸리티 파일들 - any → unknown 또는 적절한 타입으로 교체 🏆 성과: - 코드 품질 크게 향상 (280 → 80 문제로 71% 감소) - TypeScript 컴파일러의 타입 체크 효과성 증대 - 개발자 경험 개선 (IDE 자동완성, 타입 추론 등) 🧹 추가 정리: - ESLint no-console/no-alert 경고 해결 - Prettier 포맷팅 적용으로 코드 스타일 통일 🎯 다음 단계: 남은 62개 any 타입 계속 개선 예정 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
646
scripts/linear-github-setup.cjs
Normal file
646
scripts/linear-github-setup.cjs
Normal file
@@ -0,0 +1,646 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Linear GitHub 앱 연동 및 기본 연결 설정 스크립트
|
||||
* Linear와 GitHub 간의 기본 연동을 설정하고 검증
|
||||
*/
|
||||
|
||||
const { execSync } = require("child_process");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
// Simple command line argument parsing
|
||||
const args = process.argv.slice(2);
|
||||
const options = {
|
||||
linearApiKey: null,
|
||||
githubToken: null,
|
||||
setup: args.includes("--setup"),
|
||||
verify: args.includes("--verify"),
|
||||
configure: args.includes("--configure"),
|
||||
help: args.includes("--help") || args.includes("-h"),
|
||||
};
|
||||
|
||||
// Extract API keys from arguments
|
||||
const linearApiIndex = args.findIndex((arg) => arg.startsWith("--linear-api="));
|
||||
if (linearApiIndex !== -1) {
|
||||
options.linearApiKey = args[linearApiIndex].split("=")[1];
|
||||
}
|
||||
|
||||
const githubTokenIndex = args.findIndex((arg) =>
|
||||
arg.startsWith("--github-token=")
|
||||
);
|
||||
if (githubTokenIndex !== -1) {
|
||||
options.githubToken = args[githubTokenIndex].split("=")[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Linear API 클라이언트
|
||||
*/
|
||||
class LinearClient {
|
||||
constructor(apiKey) {
|
||||
this.apiKey = apiKey;
|
||||
this.baseUrl = "https://api.linear.app/graphql";
|
||||
}
|
||||
|
||||
async query(query, variables = {}) {
|
||||
try {
|
||||
const response = await fetch(this.baseUrl, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: this.apiKey,
|
||||
},
|
||||
body: JSON.stringify({ query, variables }),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.errors) {
|
||||
throw new Error(`Linear API Error: ${JSON.stringify(data.errors)}`);
|
||||
}
|
||||
|
||||
return data.data;
|
||||
} catch (error) {
|
||||
throw new Error(`Linear API call failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async getWorkspaceInfo() {
|
||||
const query = `
|
||||
query GetWorkspaceInfo {
|
||||
organization {
|
||||
id
|
||||
name
|
||||
urlKey
|
||||
teams {
|
||||
nodes {
|
||||
id
|
||||
name
|
||||
key
|
||||
issueCount
|
||||
}
|
||||
}
|
||||
}
|
||||
viewer {
|
||||
id
|
||||
name
|
||||
email
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
return await this.query(query);
|
||||
}
|
||||
|
||||
async createWebhook(url, teamId) {
|
||||
const query = `
|
||||
mutation CreateWebhook($url: String!, $teamId: String!) {
|
||||
webhookCreate(input: {
|
||||
url: $url
|
||||
teamId: $teamId
|
||||
allPublicTeams: false
|
||||
resourceTypes: ["Issue", "IssueLabel", "Comment"]
|
||||
}) {
|
||||
success
|
||||
webhook {
|
||||
id
|
||||
url
|
||||
enabled
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
return await this.query(query, { url, teamId });
|
||||
}
|
||||
|
||||
async listWebhooks() {
|
||||
const query = `
|
||||
query ListWebhooks {
|
||||
webhooks {
|
||||
nodes {
|
||||
id
|
||||
url
|
||||
enabled
|
||||
resourceTypes
|
||||
team {
|
||||
name
|
||||
key
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
return await this.query(query);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GitHub API 클라이언트
|
||||
*/
|
||||
class GitHubClient {
|
||||
constructor(token, repo) {
|
||||
this.token = token;
|
||||
this.repo = repo;
|
||||
this.baseUrl = "https://api.github.com";
|
||||
}
|
||||
|
||||
async request(endpoint, method = "GET", data = null) {
|
||||
const url = `${this.baseUrl}${endpoint}`;
|
||||
const options = {
|
||||
method,
|
||||
headers: {
|
||||
Authorization: `token ${this.token}`,
|
||||
Accept: "application/vnd.github.v3+json",
|
||||
"User-Agent": "Zellyy-Finance-Linear-Integration",
|
||||
},
|
||||
};
|
||||
|
||||
if (data) {
|
||||
options.headers["Content-Type"] = "application/json";
|
||||
options.body = JSON.stringify(data);
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(url, options);
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.text();
|
||||
throw new Error(`GitHub API Error: ${response.status} ${errorData}`);
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
throw new Error(`GitHub API call failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async getRepository() {
|
||||
return await this.request(`/repos/${this.repo}`);
|
||||
}
|
||||
|
||||
async createWebhook(config) {
|
||||
return await this.request(`/repos/${this.repo}/hooks`, "POST", config);
|
||||
}
|
||||
|
||||
async listWebhooks() {
|
||||
return await this.request(`/repos/${this.repo}/hooks`);
|
||||
}
|
||||
|
||||
async createSecret(name, encryptedValue) {
|
||||
return await this.request(
|
||||
`/repos/${this.repo}/actions/secrets/${name}`,
|
||||
"PUT",
|
||||
{
|
||||
encrypted_value: encryptedValue,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 환경 설정 검증
|
||||
*/
|
||||
function validateEnvironment() {
|
||||
console.log("🔍 환경 설정 검증 중...");
|
||||
|
||||
const requiredFiles = [
|
||||
".github/workflows/linear-integration.yml",
|
||||
"scripts/linear-sync.cjs",
|
||||
"scripts/linear-comment.cjs",
|
||||
".env.linear.example",
|
||||
];
|
||||
|
||||
const missingFiles = [];
|
||||
|
||||
requiredFiles.forEach((file) => {
|
||||
if (!fs.existsSync(file)) {
|
||||
missingFiles.push(file);
|
||||
}
|
||||
});
|
||||
|
||||
if (missingFiles.length > 0) {
|
||||
console.error("❌ 필수 파일들이 누락되었습니다:");
|
||||
missingFiles.forEach((file) => console.error(` - ${file}`));
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log("✅ 모든 필수 파일이 존재합니다.");
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Git 리포지토리 정보 확인
|
||||
*/
|
||||
function getGitInfo() {
|
||||
try {
|
||||
// GitHub remote이 있는지 먼저 확인
|
||||
let remoteUrl;
|
||||
try {
|
||||
remoteUrl = execSync("git config --get remote.github.url", {
|
||||
encoding: "utf8",
|
||||
}).trim();
|
||||
} catch {
|
||||
// github remote가 없으면 origin 확인
|
||||
remoteUrl = execSync("git config --get remote.origin.url", {
|
||||
encoding: "utf8",
|
||||
}).trim();
|
||||
}
|
||||
|
||||
// GitHub URL에서 owner/repo 추출
|
||||
const match = remoteUrl.match(/github\.com[/:](.*?)\/(.*)(?:\.git)?$/);
|
||||
if (match) {
|
||||
const owner = match[1];
|
||||
const repo = match[2].replace(".git", "");
|
||||
return { owner, repo, fullName: `${owner}/${repo}` };
|
||||
}
|
||||
|
||||
// GitHub remote가 아닌 경우 수동으로 GitHub 정보 사용
|
||||
console.log(
|
||||
"ℹ️ GitHub remote가 감지되지 않았습니다. zellycloud/zellyy-finance를 사용합니다."
|
||||
);
|
||||
return {
|
||||
owner: "zellycloud",
|
||||
repo: "zellyy-finance",
|
||||
fullName: "zellycloud/zellyy-finance",
|
||||
};
|
||||
} catch (error) {
|
||||
throw new Error(`Git 정보를 가져올 수 없습니다: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Linear 워크스페이스 정보 출력
|
||||
*/
|
||||
async function displayLinearInfo(linear) {
|
||||
console.log("\n📋 Linear 워크스페이스 정보:");
|
||||
|
||||
try {
|
||||
const info = await linear.getWorkspaceInfo();
|
||||
|
||||
console.log(
|
||||
` 조직: ${info.organization.name} (${info.organization.urlKey})`
|
||||
);
|
||||
console.log(` 사용자: ${info.viewer.name} (${info.viewer.email})`);
|
||||
console.log(` 팀 수: ${info.organization.teams.nodes.length}`);
|
||||
|
||||
console.log("\n👥 팀 목록:");
|
||||
info.organization.teams.nodes.forEach((team) => {
|
||||
console.log(` - ${team.name} (${team.key}): ${team.issueCount}개 이슈`);
|
||||
});
|
||||
|
||||
return info;
|
||||
} catch (error) {
|
||||
console.error("❌ Linear 정보를 가져올 수 없습니다:", error.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GitHub 리포지토리 정보 출력
|
||||
*/
|
||||
async function displayGitHubInfo(github) {
|
||||
console.log("\n📁 GitHub 리포지토리 정보:");
|
||||
|
||||
try {
|
||||
const repo = await github.getRepository();
|
||||
|
||||
console.log(` 이름: ${repo.full_name}`);
|
||||
console.log(` 설명: ${repo.description || "설명 없음"}`);
|
||||
console.log(` 언어: ${repo.language || "N/A"}`);
|
||||
console.log(` 프라이빗: ${repo.private ? "Yes" : "No"}`);
|
||||
console.log(` 기본 브랜치: ${repo.default_branch}`);
|
||||
|
||||
return repo;
|
||||
} catch (error) {
|
||||
console.error("❌ GitHub 정보를 가져올 수 없습니다:", error.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 환경 변수 파일 생성
|
||||
*/
|
||||
function createEnvFile(linearInfo, gitInfo) {
|
||||
console.log("\n📝 환경 변수 파일 생성 중...");
|
||||
|
||||
const envContent = `# Linear GitHub 연동 설정
|
||||
# 이 파일을 .env로 복사하고 실제 값으로 업데이트하세요
|
||||
|
||||
# Linear API 설정
|
||||
LINEAR_API_KEY=${options.linearApiKey || "your-linear-api-key"}
|
||||
LINEAR_WORKSPACE_ID=${linearInfo.organization.id}
|
||||
LINEAR_TEAM_ID=${linearInfo.organization.teams.nodes[0]?.id || "your-team-id"}
|
||||
|
||||
# GitHub 설정
|
||||
GITHUB_TOKEN=${options.githubToken || "your-github-token"}
|
||||
GITHUB_REPOSITORY=${gitInfo.fullName}
|
||||
|
||||
# 웹훅 URL (GitHub Actions에서 자동 설정)
|
||||
LINEAR_WEBHOOK_URL=https://api.github.com/repos/${gitInfo.fullName}/dispatches
|
||||
|
||||
# 디버그 모드
|
||||
DEBUG=false
|
||||
`;
|
||||
|
||||
const envFile = ".env.linear";
|
||||
fs.writeFileSync(envFile, envContent);
|
||||
|
||||
console.log(`✅ 환경 변수 파일이 생성되었습니다: ${envFile}`);
|
||||
console.log(" 이 파일을 .env로 복사하거나 기존 .env에 내용을 추가하세요.");
|
||||
}
|
||||
|
||||
/**
|
||||
* GitHub Secrets 설정 안내
|
||||
*/
|
||||
function displaySecretsGuide() {
|
||||
console.log("\n🔐 GitHub Secrets 설정 안내:");
|
||||
console.log("다음 secrets을 GitHub 리포지토리에 추가해야 합니다:");
|
||||
console.log("");
|
||||
console.log("1. Repository Settings → Secrets and variables → Actions");
|
||||
console.log('2. "New repository secret" 클릭');
|
||||
console.log("3. 다음 secrets 추가:");
|
||||
console.log(" - Name: LINEAR_API_KEY");
|
||||
console.log(` - Value: ${options.linearApiKey || "your-linear-api-key"}`);
|
||||
console.log("");
|
||||
console.log("선택적 secrets:");
|
||||
console.log(" - SLACK_BOT_TOKEN (Slack 연동용)");
|
||||
console.log(" - SLACK_WEBHOOK_URL (Slack 알림용)");
|
||||
}
|
||||
|
||||
/**
|
||||
* Linear 웹훅 설정
|
||||
*/
|
||||
async function setupLinearWebhooks(linear, gitInfo) {
|
||||
console.log("\n🔗 Linear 웹훅 설정 중...");
|
||||
|
||||
try {
|
||||
// 기존 웹훅 확인
|
||||
const existingWebhooks = await linear.listWebhooks();
|
||||
const githubWebhook = existingWebhooks.webhooks.nodes.find(
|
||||
(webhook) =>
|
||||
webhook.url.includes("github.com") ||
|
||||
webhook.url.includes(gitInfo.fullName)
|
||||
);
|
||||
|
||||
if (githubWebhook) {
|
||||
console.log("✅ GitHub 웹훅이 이미 설정되어 있습니다:");
|
||||
console.log(` URL: ${githubWebhook.url}`);
|
||||
console.log(` 활성화: ${githubWebhook.enabled ? "Yes" : "No"}`);
|
||||
console.log(` 팀: ${githubWebhook.team?.name || "All teams"}`);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("ℹ️ Linear 웹훅 설정은 수동으로 진행해야 합니다:");
|
||||
console.log("1. Linear → Settings → API → Webhooks");
|
||||
console.log('2. "Create webhook" 클릭');
|
||||
console.log(
|
||||
`3. URL: https://api.github.com/repos/${gitInfo.fullName}/dispatches`
|
||||
);
|
||||
console.log("4. Resource types: Issue, Comment, IssueLabel 선택");
|
||||
console.log("5. Team: 원하는 팀 선택 (또는 모든 팀)");
|
||||
} catch (error) {
|
||||
console.error("❌ 웹훅 설정 중 오류 발생:", error.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GitHub Actions 워크플로우 검증
|
||||
*/
|
||||
function verifyWorkflow() {
|
||||
console.log("\n🔧 GitHub Actions 워크플로우 검증 중...");
|
||||
|
||||
const workflowPath = ".github/workflows/linear-integration.yml";
|
||||
|
||||
if (!fs.existsSync(workflowPath)) {
|
||||
console.error("❌ Linear integration 워크플로우를 찾을 수 없습니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
const workflow = fs.readFileSync(workflowPath, "utf8");
|
||||
|
||||
const checks = [
|
||||
{ name: "Pull request triggers", pattern: /on:\s*\n.*pull_request:/s },
|
||||
{ name: "Push triggers", pattern: /push:/ },
|
||||
{ name: "Linear ID extraction", pattern: /extract.*linear.*id/i },
|
||||
{ name: "Environment variables", pattern: /LINEAR_API_KEY/ },
|
||||
{ name: "Sync scripts", pattern: /linear-sync/ },
|
||||
{ name: "Comment scripts", pattern: /linear-comment/ },
|
||||
];
|
||||
|
||||
let allPassed = true;
|
||||
|
||||
checks.forEach((check) => {
|
||||
if (check.pattern.test(workflow)) {
|
||||
console.log(` ✅ ${check.name}`);
|
||||
} else {
|
||||
console.log(` ❌ ${check.name} 누락`);
|
||||
allPassed = false;
|
||||
}
|
||||
});
|
||||
|
||||
return allPassed;
|
||||
}
|
||||
|
||||
/**
|
||||
* 통합 테스트 실행
|
||||
*/
|
||||
async function runIntegrationTest() {
|
||||
console.log("\n🧪 통합 테스트 실행 중...");
|
||||
|
||||
try {
|
||||
const testCommand = `node scripts/test-linear-integration.cjs --api-key=${options.linearApiKey}`;
|
||||
const result = execSync(testCommand, { encoding: "utf8", stdio: "pipe" });
|
||||
|
||||
console.log("✅ 통합 테스트 성공");
|
||||
console.log(result);
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error("❌ 통합 테스트 실패:", error.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 설정 완료 안내
|
||||
*/
|
||||
function displaySetupComplete() {
|
||||
console.log("\n🎉 Linear GitHub 연동 설정이 완료되었습니다!");
|
||||
console.log("");
|
||||
console.log("다음 단계:");
|
||||
console.log("1. GitHub Secrets에 LINEAR_API_KEY 추가");
|
||||
console.log("2. Linear에서 웹훅 설정 (위의 안내 참조)");
|
||||
console.log("3. Pull Request 생성하여 연동 테스트");
|
||||
console.log("");
|
||||
console.log("테스트 방법:");
|
||||
console.log(
|
||||
"1. 새 브랜치 생성: git checkout -b feature/test-linear-integration"
|
||||
);
|
||||
console.log(
|
||||
'2. 커밋 메시지에 Linear 이슈 ID 포함: git commit -m "feat: test integration [ZEL-1]"'
|
||||
);
|
||||
console.log(
|
||||
'3. Pull Request 제목에 Linear 이슈 ID 포함: "Test Linear integration (ZEL-1)"'
|
||||
);
|
||||
console.log("4. GitHub Actions 로그에서 연동 동작 확인");
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용법 출력
|
||||
*/
|
||||
function printUsage() {
|
||||
console.log(`
|
||||
🔧 Linear GitHub 연동 설정 도구
|
||||
|
||||
사용법:
|
||||
node scripts/linear-github-setup.cjs [옵션]
|
||||
|
||||
옵션:
|
||||
--setup 전체 설정 실행
|
||||
--verify 기존 설정 검증
|
||||
--configure 환경 설정만 생성
|
||||
--linear-api=KEY Linear API 키 지정
|
||||
--github-token=TOKEN GitHub 토큰 지정
|
||||
--help, -h 이 도움말 출력
|
||||
|
||||
예시:
|
||||
# 전체 설정 실행
|
||||
node scripts/linear-github-setup.cjs --setup --linear-api=lin_api_xxx
|
||||
|
||||
# 기존 설정 검증
|
||||
node scripts/linear-github-setup.cjs --verify
|
||||
|
||||
# 환경 설정만 생성
|
||||
node scripts/linear-github-setup.cjs --configure --linear-api=lin_api_xxx
|
||||
|
||||
환경 변수:
|
||||
LINEAR_API_KEY Linear API 키
|
||||
GITHUB_TOKEN GitHub 개인 액세스 토큰
|
||||
|
||||
필수 조건:
|
||||
- Git 리포지토리 (GitHub remote 설정됨)
|
||||
- Linear API 키
|
||||
- GitHub 개인 액세스 토큰 (repo 권한)
|
||||
`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 메인 함수
|
||||
*/
|
||||
async function main() {
|
||||
if (options.help) {
|
||||
printUsage();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
console.log("🚀 Linear GitHub 연동 설정 도구");
|
||||
console.log("=====================================\n");
|
||||
|
||||
// 환경 검증
|
||||
if (!validateEnvironment()) {
|
||||
console.error(
|
||||
"❌ 환경 설정이 올바르지 않습니다. 먼저 필수 파일들을 생성해주세요."
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Git 정보 확인
|
||||
let gitInfo;
|
||||
try {
|
||||
gitInfo = getGitInfo();
|
||||
console.log(`✅ Git 리포지토리: ${gitInfo.fullName}`);
|
||||
} catch (error) {
|
||||
console.error("❌", error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// API 키 설정
|
||||
const linearApiKey = options.linearApiKey || process.env.LINEAR_API_KEY;
|
||||
const githubToken = options.githubToken || process.env.GITHUB_TOKEN;
|
||||
|
||||
if (!linearApiKey) {
|
||||
console.error(
|
||||
"❌ Linear API 키가 필요합니다. --linear-api 옵션을 사용하거나 LINEAR_API_KEY 환경 변수를 설정하세요."
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// 클라이언트 초기화
|
||||
const linear = new LinearClient(linearApiKey);
|
||||
const github = githubToken
|
||||
? new GitHubClient(githubToken, gitInfo.fullName)
|
||||
: null;
|
||||
|
||||
// 검증 모드
|
||||
if (options.verify) {
|
||||
console.log("🔍 기존 설정 검증 중...\n");
|
||||
|
||||
const linearInfo = await displayLinearInfo(linear);
|
||||
if (github) await displayGitHubInfo(github);
|
||||
|
||||
const workflowValid = verifyWorkflow();
|
||||
const testPassed = await runIntegrationTest();
|
||||
|
||||
if (workflowValid && testPassed) {
|
||||
console.log("\n✅ 모든 검증이 성공했습니다!");
|
||||
} else {
|
||||
console.log("\n❌ 일부 검증이 실패했습니다.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// 설정 모드
|
||||
if (options.setup || options.configure) {
|
||||
console.log("⚙️ Linear GitHub 연동 설정 시작...\n");
|
||||
|
||||
// Linear 정보 확인
|
||||
const linearInfo = await displayLinearInfo(linear);
|
||||
|
||||
// GitHub 정보 확인 (토큰이 있는 경우)
|
||||
if (github) {
|
||||
await displayGitHubInfo(github);
|
||||
}
|
||||
|
||||
// 환경 설정 파일 생성
|
||||
createEnvFile(linearInfo, gitInfo);
|
||||
|
||||
if (options.setup) {
|
||||
// 웹훅 설정
|
||||
await setupLinearWebhooks(linear, gitInfo);
|
||||
|
||||
// Secrets 안내
|
||||
displaySecretsGuide();
|
||||
|
||||
// 워크플로우 검증
|
||||
verifyWorkflow();
|
||||
|
||||
// 완료 안내
|
||||
displaySetupComplete();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// 기본 동작: 정보 표시
|
||||
const linearInfo = await displayLinearInfo(linear);
|
||||
if (github) await displayGitHubInfo(github);
|
||||
|
||||
console.log("\n💡 다음 명령어로 설정을 진행하세요:");
|
||||
console.log(
|
||||
` node scripts/linear-github-setup.cjs --setup --linear-api=${linearApiKey}`
|
||||
);
|
||||
}
|
||||
|
||||
// 실행
|
||||
if (require.main === module) {
|
||||
main().catch((error) => {
|
||||
console.error("\n❌ 설정 중 오류 발생:", error.message);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = { LinearClient, GitHubClient, validateEnvironment };
|
||||
Reference in New Issue
Block a user