Skip to content

Commit

Permalink
introduce hypersonic
Browse files Browse the repository at this point in the history
  • Loading branch information
tnm committed Dec 27, 2024
1 parent 6f89eb7 commit f78f793
Show file tree
Hide file tree
Showing 12 changed files with 139 additions and 165 deletions.
19 changes: 13 additions & 6 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,23 @@ module.exports = {
plugins: ['@typescript-eslint'],
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'prettier',
'plugin:@typescript-eslint/recommended'
],
env: {
node: true,
jest: true,
jest: true
},
rules: {
'@typescript-eslint/explicit-function-return-type': 'warn',
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-var-requires': 'off'
},
overrides: [
{
files: ['**/__tests__/**/*'],
rules: {
'@typescript-eslint/no-unused-vars': 'off'
}
}
]
};
4 changes: 4 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
dist
node_modules
coverage
*.d.ts
2 changes: 1 addition & 1 deletion examples/basic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"start": "ts-node test-hypersonic.ts"
},
"dependencies": {
"@runcased/hypersonic": "^0.2.3"
"@runcased/hypersonic": "^0.3.0"
},
"devDependencies": {
"typescript": "^5.3.0",
Expand Down
29 changes: 23 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
{
"name": "@runcased/hypersonic",
"version": "0.2.3",
"version": "0.3.0",
"description": "Streamlined GitHub PR automation for modern TypeScript applications",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc",
"test": "jest",
"lint": "eslint src/**/*.ts",
"lint": "eslint 'src/**/*.{js,ts}'",
"clean": "rimraf dist",
"format": "prettier --write \"src/**/*.{js,ts}\"",
"format:check": "prettier --check \"src/**/*.{js,ts}\"",
"prepublishOnly": "npm run clean && npm run build"
},
"dependencies": {
Expand All @@ -24,9 +26,10 @@
"glob": "^10.3.10",
"jest": "^29.7.0",
"lru-cache": "^10.2.0",
"prettier": "^3.2.5",
"rimraf": "^5.0.5",
"ts-jest": "^29.1.2",
"typescript": "^5.3.3"
"typescript": "5.5.3"
},
"peerDependencies": {
"@octokit/rest": ">=18.0.0"
Expand Down
26 changes: 12 additions & 14 deletions src/__tests__/config.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { DEFAULT_PR_CONFIG, DEFAULT_CONFIG, MergeStrategy } from '../core/config';
import { DEFAULT_PR_CONFIG, MergeStrategy } from '../core/config';

describe('Configuration', () => {
describe('DEFAULT_PR_CONFIG', () => {
test('has all required fields', () => {
expect(DEFAULT_PR_CONFIG).toEqual(expect.objectContaining({
describe('DEFAULT_PR_CONFIG', () => {
test('has all required fields', () => {
expect(DEFAULT_PR_CONFIG).toEqual(
expect.objectContaining({
title: expect.any(String),
baseBranch: expect.any(String),
draft: expect.any(Boolean),
Expand All @@ -12,14 +12,12 @@ describe('Configuration', () => {
teamReviewers: expect.any(Array),
mergeStrategy: expect.any(String),
deleteBranchOnMerge: expect.any(Boolean),
autoMerge: expect.any(Boolean)
}));
});

test('uses valid merge strategy', () => {
expect(Object.values(MergeStrategy)).toContain(DEFAULT_PR_CONFIG.mergeStrategy);
});
autoMerge: expect.any(Boolean),
})
);
});

// ... more tests
});
test('uses valid merge strategy', () => {
expect(Object.values(MergeStrategy)).toContain(DEFAULT_PR_CONFIG.mergeStrategy);
});
});
58 changes: 22 additions & 36 deletions src/__tests__/github.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,26 @@ describe('GitHubAPI', () => {

beforeEach(() => {
jest.clearAllMocks();

// Create base mock Octokit instance
mockOctokit = {
git: {
getRef: jest.fn(),
createRef: jest.fn()
createRef: jest.fn(),
},
repos: {
getContent: jest.fn(),
createOrUpdateFileContents: jest.fn(),
get: jest.fn()
get: jest.fn(),
},
pulls: {
create: jest.fn(),
requestReviewers: jest.fn(),
updateBranch: jest.fn()
updateBranch: jest.fn(),
},
issues: {
addLabels: jest.fn()
}
addLabels: jest.fn(),
},
} as unknown as Octokit;

(Octokit as jest.MockedClass<typeof Octokit>).mockImplementation(() => mockOctokit);
Expand All @@ -39,7 +39,7 @@ describe('GitHubAPI', () => {
describe('createBranch', () => {
test('creates branch from base', async () => {
jest.spyOn(mockOctokit.git, 'getRef').mockResolvedValue({
data: { object: { sha: 'test-sha' } }
data: { object: { sha: 'test-sha' } },
} as any);

await github.createBranch('user/repo', 'new-branch', 'main');
Expand All @@ -48,32 +48,24 @@ describe('GitHubAPI', () => {
owner: 'user',
repo: 'repo',
ref: 'refs/heads/new-branch',
sha: 'test-sha'
sha: 'test-sha',
});
});

test('handles errors', async () => {
jest.spyOn(mockOctokit.git, 'getRef').mockRejectedValue(new Error('API error'));

await expect(
github.createBranch('user/repo', 'branch', 'main')
).rejects.toThrow(GitHubError);
await expect(github.createBranch('user/repo', 'branch', 'main')).rejects.toThrow(GitHubError);
});
});

describe('updateFile', () => {
test('updates existing file', async () => {
jest.spyOn(mockOctokit.repos, 'getContent').mockResolvedValue({
data: { sha: 'existing-sha' }
data: { sha: 'existing-sha' },
} as any);

await github.updateFile(
'user/repo',
'test.txt',
'content',
'update message',
'main'
);
await github.updateFile('user/repo', 'test.txt', 'content', 'update message', 'main');

expect(mockOctokit.repos.createOrUpdateFileContents).toHaveBeenCalledWith({
owner: 'user',
Expand All @@ -82,36 +74,30 @@ describe('GitHubAPI', () => {
message: 'update message',
content: expect.any(String),
branch: 'main',
sha: 'existing-sha'
sha: 'existing-sha',
});
});

test('creates new file', async () => {
jest.spyOn(mockOctokit.repos, 'getContent').mockRejectedValue({ status: 404 });

await github.updateFile(
'user/repo',
'new.txt',
'content',
'create message',
'main'
);
await github.updateFile('user/repo', 'new.txt', 'content', 'create message', 'main');

expect(mockOctokit.repos.createOrUpdateFileContents).toHaveBeenCalledWith({
owner: 'user',
repo: 'repo',
path: 'new.txt',
message: 'create message',
content: expect.any(String),
branch: 'main'
branch: 'main',
});
});
});

describe('createPullRequest', () => {
test('creates PR successfully', async () => {
jest.spyOn(mockOctokit.pulls, 'create').mockResolvedValue({
data: { html_url: 'https://github.com/user/repo/pull/1' }
data: { html_url: 'https://github.com/user/repo/pull/1' },
} as any);

const url = await github.createPullRequest(
Expand All @@ -130,7 +116,7 @@ describe('GitHubAPI', () => {
body: 'Test description',
head: 'feature-branch',
base: 'main',
draft: false
draft: false,
});
expect(url).toBe('https://github.com/user/repo/pull/1');
});
Expand All @@ -144,7 +130,7 @@ describe('GitHubAPI', () => {
owner: 'user',
repo: 'repo',
pull_number: 123,
reviewers: ['reviewer1', 'reviewer2']
reviewers: ['reviewer1', 'reviewer2'],
});
});
});
Expand All @@ -157,23 +143,23 @@ describe('GitHubAPI', () => {
owner: 'user',
repo: 'repo',
issue_number: 123,
labels: ['bug', 'enhancement']
labels: ['bug', 'enhancement'],
});
});
});

describe('getDefaultBranch', () => {
test('gets default branch', async () => {
jest.spyOn(mockOctokit.repos, 'get').mockResolvedValue({
data: { default_branch: 'main' }
data: { default_branch: 'main' },
} as any);

const branch = await github.getDefaultBranch('user/repo');

expect(branch).toBe('main');
expect(mockOctokit.repos.get).toHaveBeenCalledWith({
owner: 'user',
repo: 'repo'
repo: 'repo',
});
});
});
Expand All @@ -200,8 +186,8 @@ describe('GitHubAPI', () => {
jest.spyOn(mockOctokit.repos, 'get').mockRejectedValue({ status: 404 });

await expect(github.getDefaultBranch('user/repo')).rejects.toMatchObject({
status: 404
status: 404,
});
});
});
});
});
Loading

0 comments on commit f78f793

Please sign in to comment.