@ffflorian/auto-merge 1.2.1 → 1.3.1

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.
@@ -1,8 +1,9 @@
1
1
  import type { AutoMergeConfig, ActionResult, Repository, RepositoryResult } from './types/index.js';
2
2
  export declare class AutoMerge {
3
- private readonly apiClient;
3
+ private readonly baseHeaders;
4
4
  private readonly config;
5
5
  private readonly logger;
6
+ private readonly baseURL;
6
7
  constructor(config: AutoMergeConfig);
7
8
  private checkConfig;
8
9
  private checkRepositorySlug;
package/dist/AutoMerge.js CHANGED
@@ -1,6 +1,5 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
- import axios from 'axios';
4
3
  import logdown from 'logdown';
5
4
  const __dirname = import.meta.dirname;
6
5
  const packageJsonPath = path.join(__dirname, '../package.json');
@@ -14,14 +13,12 @@ export class AutoMerge {
14
13
  markdown: false,
15
14
  });
16
15
  this.logger.state.isEnabled = true;
17
- this.apiClient = axios.create({
18
- baseURL: 'https://api.github.com',
19
- headers: {
20
- Accept: 'application/vnd.github+json',
21
- Authorization: `token ${this.config.authToken}`,
22
- 'User-Agent': `${toolName} v${toolVersion}`,
23
- },
24
- });
16
+ this.baseURL = 'https://api.github.com';
17
+ this.baseHeaders = {
18
+ Accept: 'application/vnd.github+json',
19
+ Authorization: `token ${this.config.authToken}`,
20
+ 'User-Agent': `${toolName} v${toolVersion}`,
21
+ };
25
22
  this.checkConfig(this.config);
26
23
  }
27
24
  checkConfig(config) {
@@ -67,9 +64,12 @@ export class AutoMerge {
67
64
  return matchingRepositories;
68
65
  }
69
66
  async isPullRequestMergeable(repositorySlug, pullNumber) {
70
- const resourceUrl = `/repos/${repositorySlug}/pulls/${pullNumber}`;
71
- const response = await this.apiClient.get(resourceUrl);
72
- return response.data.mergeable_state === 'clean';
67
+ const resourceUrl = new URL(`/repos/${repositorySlug}/pulls/${pullNumber}`, this.baseURL);
68
+ const response = await fetch(resourceUrl, { headers: this.baseHeaders });
69
+ if (!response.ok) {
70
+ throw new Error(`Error while checking merge request: ${response.statusText}`);
71
+ }
72
+ return (await response.json()).mergeable_state === 'clean';
73
73
  }
74
74
  async mergeByMatch(regex, repositories) {
75
75
  const allRepositories = repositories || (await this.getRepositoriesWithOpenPullRequests());
@@ -137,18 +137,31 @@ export class AutoMerge {
137
137
  }
138
138
  /** @see https://docs.github.com/en/rest/reference/pulls#create-a-review-for-a-pull-request */
139
139
  async postReview(repositorySlug, pullNumber) {
140
- const resourceUrl = `/repos/${repositorySlug}/pulls/${pullNumber}/reviews`;
141
- await this.apiClient.post(resourceUrl, { event: 'APPROVE' });
140
+ const resourceUrl = new URL(`/repos/${repositorySlug}/pulls/${pullNumber}/reviews`, this.baseURL);
141
+ resourceUrl.search = new URLSearchParams({ event: 'APPROVE' }).toString();
142
+ const response = await fetch(resourceUrl, { headers: this.baseHeaders, method: 'POST' });
143
+ if (!response.ok) {
144
+ throw new Error(`Error while approving pull request: ${response.statusText}`);
145
+ }
142
146
  }
143
147
  /** @see https://docs.github.com/en/rest/reference/issues#create-an-issue-comment */
144
148
  async putMerge(repositorySlug, pullNumber, squash) {
145
- const resourceUrl = `/repos/${repositorySlug}/pulls/${pullNumber}/merge`;
146
- await this.apiClient.put(resourceUrl, squash ? { merge_method: 'squash' } : undefined);
149
+ const resourceUrl = new URL(`/repos/${repositorySlug}/pulls/${pullNumber}/merge`, this.baseURL);
150
+ if (squash) {
151
+ resourceUrl.search = new URLSearchParams({ merge_method: 'squash' }).toString();
152
+ }
153
+ const response = await fetch(resourceUrl, { headers: this.baseHeaders, method: 'PUT' });
154
+ if (!response.ok) {
155
+ throw new Error(`Error while merging pull request: ${response.statusText}`);
156
+ }
147
157
  }
148
158
  async getPullRequestsBySlug(repositorySlug) {
149
- const resourceUrl = `/repos/${repositorySlug}/pulls`;
150
- const params = { per_page: 100, state: 'open' };
151
- const response = await this.apiClient.get(resourceUrl, { params });
152
- return response.data;
159
+ const resourceUrl = new URL(`/repos/${repositorySlug}/pulls`, this.baseURL);
160
+ resourceUrl.search = new URLSearchParams({ per_page: '100', state: 'open' }).toString();
161
+ const response = await fetch(resourceUrl, { headers: this.baseHeaders });
162
+ if (!response.ok) {
163
+ throw new Error(`Error while fetching pull requests: ${response.statusText}`);
164
+ }
165
+ return response.json();
153
166
  }
154
167
  }
package/package.json CHANGED
@@ -2,7 +2,6 @@
2
2
  "author": "Florian Imdahl <git@ffflorian.de>",
3
3
  "bin": "dist/cli.js",
4
4
  "dependencies": {
5
- "axios": "1.13.2",
6
5
  "commander": "14.0.2",
7
6
  "cosmiconfig": "9.0.0",
8
7
  "logdown": "3.3.1"
@@ -32,13 +31,13 @@
32
31
  "name": "@ffflorian/auto-merge",
33
32
  "repository": "https://github.com/ffflorian/node-packages/tree/main/packages/auto-merge",
34
33
  "scripts": {
35
- "build": "tsc -p tsconfig.json",
34
+ "build": "tsc -p tsconfig.build.json",
36
35
  "clean": "rimraf dist",
37
36
  "dist": "yarn clean && yarn build",
38
37
  "start": "tsx src/cli.ts",
39
38
  "test": "vitest run"
40
39
  },
41
40
  "type": "module",
42
- "version": "1.2.1",
43
- "gitHead": "eedb2984fd69190a0b69a992d18fe451e714e04d"
41
+ "version": "1.3.1",
42
+ "gitHead": "624bfac36e769ed7157fe9a9ada1c3e5443745ff"
44
43
  }
@@ -1 +0,0 @@
1
- export {};
@@ -1,109 +0,0 @@
1
- import { expect, describe, test, beforeEach, afterEach, vi } from 'vitest';
2
- import nock from 'nock';
3
- import { StatusCodes as HTTP_STATUS } from 'http-status-codes';
4
- import { AutoMerge } from './AutoMerge.js';
5
- describe('AutoMerge', () => {
6
- describe('checkRepository', () => {
7
- let autoMerge;
8
- const validRepositoryNames = ['ffflorian/example-project-1', 'my-name/my_great-project42342'];
9
- const repositories = [
10
- {
11
- pullRequests: [
12
- {
13
- draft: false,
14
- head: {
15
- ref: 'dependabot/npm_and_yarn/eslint-plugin-typescript-sort-keys-1.5.0',
16
- sha: 'cd3ae10104a2ed9d937869b892457003ad68df74',
17
- },
18
- number: 253,
19
- title: 'chore: bump eslint-plugin-typescript-sort-keys from 1.3.0 to 1.5.0',
20
- },
21
- ],
22
- repositorySlug: validRepositoryNames[0],
23
- },
24
- {
25
- pullRequests: [
26
- {
27
- draft: false,
28
- head: {
29
- ref: 'dependabot/npm_and_yarn/typescript-4.0.3',
30
- sha: 'e59a374b357763fab5d3e61b0fdab66f4746b097',
31
- },
32
- number: 252,
33
- title: 'chore: bump typescript from 4.0.2 to 4.0.3',
34
- },
35
- ],
36
- repositorySlug: validRepositoryNames[1],
37
- },
38
- ];
39
- beforeEach(() => {
40
- autoMerge = new AutoMerge({
41
- authToken: 'example-token',
42
- projects: {
43
- gitHub: validRepositoryNames,
44
- },
45
- });
46
- nock(autoMerge['apiClient'].defaults.baseURL)
47
- .post(/^\/repos\/.+?\/.+?\/pulls\/\d+\/reviews\/?$/)
48
- .reply(HTTP_STATUS.OK, { data: 'not-used' })
49
- .persist();
50
- nock(autoMerge['apiClient'].defaults.baseURL)
51
- .get(/^\/repos\/.+?\/.+?\/pulls\/\d+\/?$/)
52
- .reply(HTTP_STATUS.OK, { data: 'not-used' })
53
- .persist();
54
- nock(autoMerge['apiClient'].defaults.baseURL)
55
- .put(/^\/repos\/.+?\/.+?\/pulls\/\d+\/merge\/?$/)
56
- .reply(HTTP_STATUS.OK, { data: 'not-used' })
57
- .persist();
58
- });
59
- afterEach(() => {
60
- nock.cleanAll();
61
- });
62
- test('detects valid repository names', () => {
63
- validRepositoryNames.forEach(repositoryName => {
64
- const checkResult = autoMerge['checkRepositorySlug'](repositoryName);
65
- expect(checkResult).toBe(true);
66
- });
67
- });
68
- test('detects invalid repository names', () => {
69
- const invalidRepositoryNames = [
70
- 'invalid-username--/valid-project-name',
71
- 'valid-username/invalid-project-name-',
72
- 'no-project-name',
73
- 'in(valid-username/valid-project-name',
74
- 'valid-username/invalid!project-name',
75
- ];
76
- invalidRepositoryNames.forEach(repositoryName => {
77
- const checkResult = autoMerge['checkRepositorySlug'](repositoryName);
78
- expect(checkResult).toBe(false);
79
- });
80
- });
81
- describe('getMatchingRepositories', () => {
82
- test('matches repositories', () => {
83
- const expectedESLint = [repositories[0]];
84
- const actualESLint = autoMerge['getMatchingRepositories'](repositories, /eslint/gi);
85
- expect(actualESLint).toEqual(expectedESLint);
86
- const expectedTypeScript = [repositories[1]];
87
- const actualTypeScript = autoMerge['getMatchingRepositories'](repositories, /typescript-4.0.3/gi);
88
- expect(actualTypeScript).toEqual(expectedTypeScript);
89
- const expectedAll = repositories;
90
- const actualAll = autoMerge['getMatchingRepositories'](repositories, /typescript/gi);
91
- expect(actualAll).toEqual(expectedAll);
92
- const expectedNone = [];
93
- const actualNone = autoMerge['getMatchingRepositories'](repositories, /no-match/gi);
94
- expect(actualNone).toEqual(expectedNone);
95
- });
96
- });
97
- describe('mergeByMatch', () => {
98
- test('merge matching PRs', async () => {
99
- vi.spyOn(autoMerge, 'putMerge');
100
- await autoMerge.mergeByMatch(/eslint/gi, repositories);
101
- const expectedRepositoryESLint = repositories[0];
102
- expect(autoMerge['putMerge']).toHaveBeenCalledWith(expectedRepositoryESLint.repositorySlug, expectedRepositoryESLint.pullRequests[0].number, false);
103
- await autoMerge.mergeByMatch(/typescript-4.0.3/gi, repositories);
104
- const expectedRepositoryTypescript = repositories[1];
105
- expect(autoMerge['putMerge']).toHaveBeenCalledWith(expectedRepositoryTypescript.repositorySlug, expectedRepositoryTypescript.pullRequests[0].number, false);
106
- });
107
- });
108
- });
109
- });