diff --git a/package-lock.json b/package-lock.json index 288a66ddb..f008adbb5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1612,9 +1612,9 @@ } }, "node_modules/@semantic-release/commit-analyzer": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-11.1.0.tgz", - "integrity": "sha512-cXNTbv3nXR2hlzHjAMgbuiQVtvWHTlwwISt60B+4NZv01y/QRY7p2HcJm8Eh2StzcTJoNnflvKjHH/cjFS7d5g==", + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-12.0.0.tgz", + "integrity": "sha512-qG+md5gdes+xa8zP7lIo1fWE17zRdO8yMCaxh9lyL65TQleoSv8WHHOqRURfghTytUh+NpkSyBprQ5hrkxOKVQ==", "dev": true, "dependencies": { "conventional-changelog-angular": "^7.0.0", @@ -1626,7 +1626,7 @@ "micromatch": "^4.0.2" }, "engines": { - "node": "^18.17 || >=20.6.1" + "node": ">=20.8.1" }, "peerDependencies": { "semantic-release": ">=20.1.0" @@ -2425,9 +2425,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.11.28", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.28.tgz", - "integrity": "sha512-M/GPWVS2wLkSkNHVeLkrF2fD5Lx5UC4PxA0uZcKc6QqbIQUJyW1jVjueJYi1z8n0I5PxYrtpnPnWglE+y9A0KA==", + "version": "20.11.30", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.30.tgz", + "integrity": "sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw==", "dev": true, "dependencies": { "undici-types": "~5.26.4" @@ -2467,16 +2467,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.2.0.tgz", - "integrity": "sha512-mdekAHOqS9UjlmyF/LSs6AIEvfceV749GFxoBAjwAv0nkevfKHWQFDMcBZWUiIC5ft6ePWivXoS36aKQ0Cy3sw==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.3.1.tgz", + "integrity": "sha512-STEDMVQGww5lhCuNXVSQfbfuNII5E08QWkvAw5Qwf+bj2WT+JkG1uc+5/vXA3AOYMDHVOSpL+9rcbEUiHIm2dw==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "7.2.0", - "@typescript-eslint/type-utils": "7.2.0", - "@typescript-eslint/utils": "7.2.0", - "@typescript-eslint/visitor-keys": "7.2.0", + "@typescript-eslint/scope-manager": "7.3.1", + "@typescript-eslint/type-utils": "7.3.1", + "@typescript-eslint/utils": "7.3.1", + "@typescript-eslint/visitor-keys": "7.3.1", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -2485,7 +2485,7 @@ "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -2502,19 +2502,19 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.2.0.tgz", - "integrity": "sha512-5FKsVcHTk6TafQKQbuIVkXq58Fnbkd2wDL4LB7AURN7RUOu1utVP+G8+6u3ZhEroW3DF6hyo3ZEXxgKgp4KeCg==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.3.1.tgz", + "integrity": "sha512-Rq49+pq7viTRCH48XAbTA+wdLRrB/3sRq4Lpk0oGDm0VmnjBrAOVXH/Laalmwsv2VpekiEfVFwJYVk6/e8uvQw==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.2.0", - "@typescript-eslint/types": "7.2.0", - "@typescript-eslint/typescript-estree": "7.2.0", - "@typescript-eslint/visitor-keys": "7.2.0", + "@typescript-eslint/scope-manager": "7.3.1", + "@typescript-eslint/types": "7.3.1", + "@typescript-eslint/typescript-estree": "7.3.1", + "@typescript-eslint/visitor-keys": "7.3.1", "debug": "^4.3.4" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -2530,16 +2530,16 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.2.0.tgz", - "integrity": "sha512-Qh976RbQM/fYtjx9hs4XkayYujB/aPwglw2choHmf3zBjB4qOywWSdt9+KLRdHubGcoSwBnXUH2sR3hkyaERRg==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.3.1.tgz", + "integrity": "sha512-fVS6fPxldsKY2nFvyT7IP78UO1/I2huG+AYu5AMjCT9wtl6JFiDnsv4uad4jQ0GTFzcUV5HShVeN96/17bTBag==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.2.0", - "@typescript-eslint/visitor-keys": "7.2.0" + "@typescript-eslint/types": "7.3.1", + "@typescript-eslint/visitor-keys": "7.3.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -2547,18 +2547,18 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.2.0.tgz", - "integrity": "sha512-xHi51adBHo9O9330J8GQYQwrKBqbIPJGZZVQTHHmy200hvkLZFWJIFtAG/7IYTWUyun6DE6w5InDReePJYJlJA==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.3.1.tgz", + "integrity": "sha512-iFhaysxFsMDQlzJn+vr3OrxN8NmdQkHks4WaqD4QBnt5hsq234wcYdyQ9uquzJJIDAj5W4wQne3yEsYA6OmXGw==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.2.0", - "@typescript-eslint/utils": "7.2.0", + "@typescript-eslint/typescript-estree": "7.3.1", + "@typescript-eslint/utils": "7.3.1", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -2574,12 +2574,12 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.2.0.tgz", - "integrity": "sha512-XFtUHPI/abFhm4cbCDc5Ykc8npOKBSJePY3a3s+lwumt7XWJuzP5cZcfZ610MIPHjQjNsOLlYK8ASPaNG8UiyA==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.3.1.tgz", + "integrity": "sha512-2tUf3uWggBDl4S4183nivWQ2HqceOZh1U4hhu4p1tPiIJoRRXrab7Y+Y0p+dozYwZVvLPRI6r5wKe9kToF9FIw==", "dev": true, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -2587,13 +2587,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.2.0.tgz", - "integrity": "sha512-cyxS5WQQCoBwSakpMrvMXuMDEbhOo9bNHHrNcEWis6XHx6KF518tkF1wBvKIn/tpq5ZpUYK7Bdklu8qY0MsFIA==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.3.1.tgz", + "integrity": "sha512-tLpuqM46LVkduWP7JO7yVoWshpJuJzxDOPYIVWUUZbW+4dBpgGeUdl/fQkhuV0A8eGnphYw3pp8d2EnvPOfxmQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.2.0", - "@typescript-eslint/visitor-keys": "7.2.0", + "@typescript-eslint/types": "7.3.1", + "@typescript-eslint/visitor-keys": "7.3.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2602,7 +2602,7 @@ "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -2615,21 +2615,21 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.2.0.tgz", - "integrity": "sha512-YfHpnMAGb1Eekpm3XRK8hcMwGLGsnT6L+7b2XyRv6ouDuJU1tZir1GS2i0+VXRatMwSI1/UfcyPe53ADkU+IuA==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.3.1.tgz", + "integrity": "sha512-jIERm/6bYQ9HkynYlNZvXpzmXWZGhMbrOvq3jJzOSOlKXsVjrrolzWBjDW6/TvT5Q3WqaN4EkmcfdQwi9tDjBQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "7.2.0", - "@typescript-eslint/types": "7.2.0", - "@typescript-eslint/typescript-estree": "7.2.0", + "@typescript-eslint/scope-manager": "7.3.1", + "@typescript-eslint/types": "7.3.1", + "@typescript-eslint/typescript-estree": "7.3.1", "semver": "^7.5.4" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -2640,16 +2640,16 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.2.0.tgz", - "integrity": "sha512-c6EIQRHhcpl6+tO8EMR+kjkkV+ugUNXOmeASA1rlzkd8EPIriavpWoiEz1HR/VLhbVIdhqnV6E7JZm00cBDx2A==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.3.1.tgz", + "integrity": "sha512-9RMXwQF8knsZvfv9tdi+4D/j7dMG28X/wMJ8Jj6eOHyHWwDW4ngQJcqEczSsqIKKjFiLFr40Mnr7a5ulDD3vmw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.2.0", + "@typescript-eslint/types": "7.3.1", "eslint-visitor-keys": "^3.4.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -11032,12 +11032,12 @@ } }, "node_modules/semantic-release": { - "version": "23.0.4", - "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-23.0.4.tgz", - "integrity": "sha512-UlcgO6SEcFtwSF/JMVXKswK+4Af2ypu55WRdLL6IhnKHPCZ9Zap7CV8PN2+wmvAdAPTI76CqouJyGZyb1fp9VA==", + "version": "23.0.5", + "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-23.0.5.tgz", + "integrity": "sha512-4eZG/vRTV8E7rw5oHPv2Fht5qx6ITemE/b1vzG42ayYVcffJqXYy40nP4bHEPWX1/kleJWWrlPVDt1hSYVlpKQ==", "dev": true, "dependencies": { - "@semantic-release/commit-analyzer": "^11.0.0", + "@semantic-release/commit-analyzer": "^12.0.0", "@semantic-release/error": "^4.0.0", "@semantic-release/github": "^10.0.0", "@semantic-release/npm": "^12.0.0", @@ -12355,9 +12355,9 @@ } }, "node_modules/typescript": { - "version": "5.4.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", - "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.3.tgz", + "integrity": "sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==", "dev": true, "bin": { "tsc": "bin/tsc", diff --git a/src/commands/__snapshots__/list-issues.test.ts.snap b/src/commands/__snapshots__/list-issues.test.ts.snap index 5c6f29fcd..58a30c053 100644 --- a/src/commands/__snapshots__/list-issues.test.ts.snap +++ b/src/commands/__snapshots__/list-issues.test.ts.snap @@ -4,11 +4,11 @@ exports[`list-issue command should list issues when the command is invoked 1`] = [MockFunction] { "calls": [ [ - "╔══════════════╤═════════════╤═══════════╤═══════════╗ -║ issue Number │ issue Title │ Owner │ Repo Name ║ -╟──────────────┼─────────────┼───────────┼───────────╢ -║ undefined │ undefined │ undefined │ undefined ║ -╚══════════════╧═════════════╧═══════════╧═══════════╝ + "╔══════════════╤═════════════╤════════════╤════════╤═══════════╗ +║ issue Number │ issue Title │ Owner │ status │ Repo Name ║ +╟──────────────┼─────────────┼────────────┼────────┼───────────╢ +║ 3 │ new title │ Nerdwallet │ closed │ shepherd ║ +╚══════════════╧═════════════╧════════════╧════════╧═══════════╝ ", ], ], diff --git a/src/commands/issue.test.ts b/src/commands/issue.test.ts index 566ce4fd8..d34706f2e 100644 --- a/src/commands/issue.test.ts +++ b/src/commands/issue.test.ts @@ -11,7 +11,7 @@ describe('issue command', () => { let mockContext: IMigrationContext; let mockContext1: IMigrationContext; let mockContext2: IMigrationContext; - + let mockContext3: IMigrationContext; beforeEach(() => { jest.clearAllMocks(); mockContext = { @@ -88,6 +88,34 @@ describe('issue command', () => { adapter: mockAdapter, logger: mockLogger, }; + mockContext3 = { + shepherd: { + workingDirectory: 'workingDirectory', + }, + migration: { + migrationDirectory: 'migrationDirectory', + spec: { + id: 'id', + title: 'title', + adapter: { + type: 'adapter', + }, + hooks: {}, + issues: { + title: 'this is issue', + description: 'issue description', + state_reason: 'not_planned', + labels: ['bug'], + }, + }, + workingDirectory: 'workingDirectory', + selectedRepos: [{ name: 'selectedRepos' }], + repos: [{ name: 'selectedRepos' }], + upstreamOwner: 'upstreamOwner', + }, + adapter: mockAdapter, + logger: mockLogger, + }; }); it('create issue if the issue doesnt exists in tracker', async () => { @@ -153,4 +181,24 @@ describe('issue command', () => { await issue(mockContext2); expect(mockSpinner.fail).toHaveBeenCalledWith('No issues in the shepherd yml to post'); }); + it('should catch error when issue with no title command is accessed', async () => { + (getIssueListsFromTracker as jest.Mock).mockResolvedValueOnce([ + { + issueNumber: '7', + title: 'this is my first updated issue', + owner: 'newowner', + status: 'open', + repo: 'newrepo', + }, + { + issueNumber: '0', + title: 'this is my first updated issue', + owner: 'newowner4', + status: 'open', + repo: 'newrepo4', + }, + ]); + await issue(mockContext3); + expect(mockContext3.adapter.createIssue).toHaveBeenCalled(); + }); }); diff --git a/src/commands/issue.ts b/src/commands/issue.ts index 258e833d3..392ea4bc2 100644 --- a/src/commands/issue.ts +++ b/src/commands/issue.ts @@ -19,7 +19,11 @@ export default async (context: IMigrationContext) => { try { const title = spec.issues.title; const issuesList: IssueTracker[] = await getIssueListsFromTracker(context); + let status = spec.issues.state; + if (!status) { + status = 'open'; + } await forEachRepo(context, async (repo) => { logger.spinner('Posting an issue'); @@ -39,6 +43,7 @@ export default async (context: IMigrationContext) => { issueNumber, title, owner: repo.owner, + status, repo: repo.name, }); spinner.succeed('Issue posted in the repository'); diff --git a/src/commands/list-issues.test.ts b/src/commands/list-issues.test.ts index b82c891ce..e3db5c762 100644 --- a/src/commands/list-issues.test.ts +++ b/src/commands/list-issues.test.ts @@ -7,11 +7,16 @@ import { getIssueTrackerFile } from '../util/persisted-data'; jest.mock('fs-extra', () => { return { // Mock other methods as needed - readFile: jest.fn().mockResolvedValue('[{"issue Number": "3", "issue Title": "new title"}]'), + readFile: jest + .fn() + .mockResolvedValue( + '[{"issueNumber": "3", "title": "new title", "owner": "Nerdwallet", "status": "closed", "repo": "shepherd"}]' + ), }; }); jest.mock('../util/persisted-data'); + jest.spyOn(process.stdout, 'write').mockImplementation(function () { return true; }); @@ -58,12 +63,14 @@ describe('list-issue command', () => { issueNumber: '7', title: 'this is my first updated issue', owner: 'upstreamOwner', + status: 'open', repo: 'selectedRepos', }, { issueNumber: '8', title: 'this is my first updated issue', owner: 'newOwner1', + status: 'open', repo: 'newRepo1', }, ]); diff --git a/src/commands/list-issues.ts b/src/commands/list-issues.ts index 6fc786717..76d337842 100644 --- a/src/commands/list-issues.ts +++ b/src/commands/list-issues.ts @@ -6,13 +6,13 @@ import { table } from 'table'; export default async (context: IMigrationContext) => { const rows: any = []; - const columns = ['issue Number', 'issue Title', 'Owner', 'Repo Name']; + const columns = ['issue Number', 'issue Title', 'Owner', 'status', 'Repo Name']; const issuesList = JSON.parse(await fs.readFile(getIssueTrackerFile(context), 'utf8')); - + console.log(issuesList); for (let i = 0; i < issuesList.length; i++) { const issue: any = issuesList[i]; - rows.push([issue.issueNumber, issue.title, issue.owner, issue.repo]); + rows.push([issue.issueNumber, issue.title, issue.owner, issue.status, issue.repo]); } process.stdout.write(table([columns, ...rows])); diff --git a/src/migration-context.ts b/src/migration-context.ts index 953cb01bd..e6680f6a1 100644 --- a/src/migration-context.ts +++ b/src/migration-context.ts @@ -21,15 +21,3 @@ export interface IMigrationContext { adapter: IRepoAdapter; logger: ILogger; } - -export enum state { - open, - closed, -} - -export enum state_reason { - completed, - not_planned, - reopened, - null, -} diff --git a/src/util/migration-spec.ts b/src/util/migration-spec.ts index 610ee12e5..727a4d583 100644 --- a/src/util/migration-spec.ts +++ b/src/util/migration-spec.ts @@ -16,14 +16,10 @@ export interface IMigrationIssues { title?: string | number; description?: string; labels?: string[]; - state?: string; - state_reason?: string; + state?: 'open' | 'closed'; + state_reason?: 'completed' | 'not_planned' | 'reopened' | null; } -const state = ['open', 'closed']; - -const state_reason = ['completed', 'not_planned', 'reopened']; - export type MigrationPhase = [keyof IMigrationHooks]; export interface IMigrationSpec { @@ -85,12 +81,8 @@ export function validateSpec(spec: any) { issues: Joi.object({ title: Joi.any().required(), description: Joi.string().required(), - state: Joi.string() - .valid(...state) - .optional(), - state_reason: Joi.string() - .valid(...state_reason) - .optional(), + state: Joi.string().optional(), + state_reason: Joi.string().optional(), labels: hookSchema.optional(), }).optional(), });