Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 2 additions & 26 deletions __tests__/utils/command.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -345,23 +345,8 @@ describe('getChangedFiles', () => {
commitEmail: 'example@example.com',
}))).toEqual({
files: [],
output: [
{
command: 'sudo npm install -g npm-check-updates',
stdout: [],
stderr: [],
},
{
command: 'npm install --save test1 test2',
stdout: [],
stderr: [],
},
{
command: 'npm update',
stdout: [],
stderr: [],
},
],
output: [],
aborted: true,
});
stdoutCalledWith(mockStdout, [
'::group::Fetching...',
Expand Down Expand Up @@ -392,15 +377,6 @@ describe('getChangedFiles', () => {
'::endgroup::',
'::group::Aborting merge...',
'[command]git merge --abort',
'::endgroup::',
'::group::Running commands...',
'[command]sudo npm install -g npm-check-updates',
'[command]npm install --save test1 test2',
'[command]npm update',
'::endgroup::',
'::group::Checking diff...',
'[command]git add --all',
'[command]git status --short -uno',
]);
});

Expand Down
108 changes: 107 additions & 1 deletion __tests__/utils/process2.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1289,7 +1289,7 @@ describe('execute', () => {
]);
});

it('should resolve conflicts', async() => {
it('should resolve conflicts 1', async() => {
process.env.GITHUB_WORKSPACE = workDir;
process.env.GITHUB_REPOSITORY = 'octocat/Hello-World';
process.env.INPUT_GITHUB_TOKEN = 'test-token';
Expand Down Expand Up @@ -1377,6 +1377,112 @@ describe('execute', () => {
]);
});

it('should resolve conflicts 2', async() => {
process.env.GITHUB_WORKSPACE = workDir;
process.env.INPUT_GITHUB_TOKEN = 'test-token';
const mockStdout = spyOnStdout();
setChildProcessParams({
stdout: (command: string): string => {
if (command.includes(' rev-parse')) {
return 'change/new-topic1';
}
if (command.startsWith('git merge --no-edit')) {
return 'Auto-merging merge.txt\nCONFLICT (content): Merge conflict in merge.txt\nAutomatic merge failed; fix conflicts and then commit the result.';
}
if (command.includes('--name-only')) {
return 'package.json';
}
return '';
},
});
setExists(true);

nock('https://api.github.com')
.persist()
.get('/repos/octocat/Hello-World/pulls?sort=created&direction=asc')
.reply(200, () => getApiFixture(rootDir, 'pulls.list'))
.get('/repos/octocat/Hello-World/pulls?head=' + encodeURIComponent('octocat:change/new-topic1'))
.reply(200, () => getApiFixture(rootDir, 'pulls.list.state.open'))
.get('/repos/octocat/Hello-World/pulls?head=' + encodeURIComponent('octocat:change/new-topic2'))
.reply(200, () => [])
.get('/repos/octocat/Hello-World/pulls/1347')
.reply(200, () => getApiFixture(rootDir, 'pulls.get.mergeable.false'))
.patch('/repos/octocat/Hello-World/pulls/1347')
.reply(200, () => getApiFixture(rootDir, 'pulls.update'))
.delete('/repos/octocat/Hello-World/git/refs/' + encodeURIComponent('heads/change/new-topic1'))
.reply(204);

await expect(execute(octokit, getActionContext(context('', 'schedule'), {
prBranchPrefix: 'change/',
prBranchName: 'test-${PR_ID}',
checkDefaultBranch: false,
}))).rejects.toThrow('There is a failed process.');

stdoutCalledWith(mockStdout, [
'::group::Target PullRequest Ref [change/new-topic1]',
'> Fetching...',
'[command]git remote add origin',
'[command]git fetch --no-tags origin \'refs/heads/change/new-topic1:refs/remotes/origin/change/new-topic1\'',
'[command]git reset --hard',
'> Switching branch to [change/new-topic1]...',
'[command]git checkout -b change/new-topic1 origin/change/new-topic1',
'[command]git checkout change/new-topic1',
'[command]git rev-parse --abbrev-ref HEAD',
' >> change/new-topic1',
'[command]git merge --no-edit origin/change/new-topic1',
' >> Auto-merging merge.txt',
' >> CONFLICT (content): Merge conflict in merge.txt',
' >> Automatic merge failed; fix conflicts and then commit the result.',
'[command]ls -la',
'> Merging [origin/master] branch...',
'[command]git remote add origin',
'[command]git fetch --no-tags origin \'refs/heads/master:refs/remotes/origin/master\'',
'[command]git config \'user.name\' test-actor',
'[command]git config \'user.email\' \'test-actor@users.noreply.github.com\'',
'[command]git merge --no-edit origin/master',
' >> Auto-merging merge.txt',
' >> CONFLICT (content): Merge conflict in merge.txt',
' >> Automatic merge failed; fix conflicts and then commit the result.',
'> Aborting merge...',
'[command]git merge --abort',
'> There is no diff.',
'> Checking references diff...',
'[command]git fetch --prune --no-tags --no-recurse-submodules origin +refs/heads/master:refs/remotes/origin/master',
'[command]git diff \'HEAD..origin/master\' --name-only',
'> This PR is not mergeable.',
'> Merging [origin/master] branch...',
'[command]git remote add origin',
'[command]git fetch --no-tags origin \'refs/heads/master:refs/remotes/origin/master\'',
'[command]git config \'user.name\' test-actor',
'[command]git config \'user.email\' \'test-actor@users.noreply.github.com\'',
'[command]git merge --no-edit origin/master',
' >> Auto-merging merge.txt',
' >> CONFLICT (content): Merge conflict in merge.txt',
' >> Automatic merge failed; fix conflicts and then commit the result.',
'> Initializing working directory...',
'[command]rm -rdf [Working Directory]',
'[command]git remote add origin',
'[command]git fetch --no-tags origin \'refs/heads/master:refs/remotes/origin/master\'',
'[command]git checkout -b master origin/master',
'[command]git checkout master',
'[command]git checkout -b change/new-topic1',
'> Running commands...',
'> Checking diff...',
'[command]git add --all',
'[command]git status --short -uno',
'> Closing PullRequest... [change/new-topic1]',
'> Deleting reference... [refs/heads/change/new-topic1]',
'::endgroup::',
'::group::Target PullRequest Ref [change/new-topic2]',
'::endgroup::',
'::group::Total:2 Succeeded:1 Failed:1 Skipped:0',
'> \x1b[32;40m✔\x1b[0m\t[change/new-topic1] has been closed because there is no diff',
'> \x1b[31;40m×\x1b[0m\t[change/new-topic2] not found',
'::set-output name=result::failed',
'::endgroup::',
]);
});

it('should throw error if push branch not found', async() => {
process.env.GITHUB_WORKSPACE = workDir;
process.env.INPUT_GITHUB_TOKEN = 'test-token';
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@technote-space/github-action-pr-helper",
"version": "2.0.4",
"version": "2.1.0",
"description": "PullRequest Helper for GitHub Actions.",
"keywords": [
"github",
Expand Down
7 changes: 5 additions & 2 deletions src/utils/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -325,11 +325,13 @@ const runCommands = async(helper: GitHelper, logger: Logger, context: ActionCont
export const getChangedFiles = async(helper: GitHelper, logger: Logger, octokit: Octokit, context: ActionContext): Promise<{
files: string[];
output: CommandOutput[];
aborted?: boolean;
}> => {
await clone(helper, logger, octokit, context);
if (await checkBranch(helper, logger, octokit, context)) {
if (!await merge(getContextBranch(context), helper, logger, context)) {
await abortMerge(helper, logger);
return {files: [], output: [], aborted: true};
}
}

Expand All @@ -352,7 +354,7 @@ export const getChangedFilesForRebase = async(helper: GitHelper, logger: Logger,

export const closePR = async(branchName: string, logger: Logger, context: ActionContext, message?: string): Promise<void> => getApiHelper(getOctokit(getApiToken()), context, logger).closePR(branchName, message ?? context.actionDetail.prCloseMessage);

export const resolveConflicts = async(branchName: string, helper: GitHelper, logger: Logger, octokit: Octokit, context: ActionContext): Promise<void> => {
export const resolveConflicts = async(branchName: string, helper: GitHelper, logger: Logger, octokit: Octokit, context: ActionContext): Promise<string> => {
if (await merge(getContextBranch(context), helper, logger, context)) {
// succeeded to merge
await push(branchName, helper, logger, context);
Expand All @@ -361,7 +363,7 @@ export const resolveConflicts = async(branchName: string, helper: GitHelper, log
const {files, output} = await getChangedFilesForRebase(helper, logger, octokit, context);
if (!files.length) {
await closePR(branchName, logger, context);
return;
return 'has been closed because there is no diff';
}
await commit(helper, logger, context);
await forcePush(branchName, helper, logger, context);
Expand All @@ -370,6 +372,7 @@ export const resolveConflicts = async(branchName: string, helper: GitHelper, log
body: await getPrBody(false, files, output, helper, octokit, context),
});
}
return 'updated';
};

export const getDefaultBranch = async(octokit: Octokit, context: ActionContext): Promise<string> => getCache<string>(getCacheKey('repos', {
Expand Down
2 changes: 1 addition & 1 deletion src/utils/misc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ export const isActiveTriggerWorkflow = (context: ActionContext): boolean => isSe
export const getTriggerWorkflowMessage = (context: ActionContext): string => context.actionDetail.triggerWorkflowMessage ?? DEFAULT_TRIGGER_WORKFLOW_MESSAGE;

// eslint-disable-next-line no-magic-numbers
export const getAutoMergeThresholdDays = (context: ActionContext): number => context.actionDetail.autoMergeThresholdDays && /^\d+$/.test(context.actionDetail.autoMergeThresholdDays) ? Number(context.actionDetail.autoMergeThresholdDays) : 0;
export const getAutoMergeThresholdDays = (context: ActionContext): number => context.actionDetail.autoMergeThresholdDays && /^\d+$/.test(context.actionDetail.autoMergeThresholdDays) ? Number(context.actionDetail.autoMergeThresholdDays) : -1;

type ChecksListSuitesForRefResponseItem = {
id: number;
Expand Down
11 changes: 9 additions & 2 deletions src/utils/process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ const createCommit = async(addComment: boolean, isClose: boolean, logger: Logger
const helper = getHelper(context);
const branchName = await getPrBranchName(helper, octokit, context);

const {files, output} = await getChangedFiles(helper, logger, octokit, context);
const {files, output, aborted} = await getChangedFiles(helper, logger, octokit, context);
if (!files.length) {
logger.info('There is no diff.');
if (context.isBatchProcess) {
Expand All @@ -140,6 +140,13 @@ const createCommit = async(addComment: boolean, isClose: boolean, logger: Logger
if (pr && await autoMerge(pr, logger, octokit, context)) {
return getResult('succeeded', 'has been auto merged', context);
}

if (pr && aborted && !await isMergeable(pr.number, octokit, context)) {
// not mergeable
logger.info('This PR is not mergeable.');
// Resolve conflicts if PR is not mergeable
return getResult('succeeded', await resolveConflicts(branchName, helper, logger, octokit, context), context);
}
}

return getResult('not changed', 'There is no diff', context);
Expand Down Expand Up @@ -278,7 +285,7 @@ const createPr = async(makeGroup: boolean, isClose: boolean, helper: GitHelper,

if (!mergeable) {
// Resolve conflicts if PR is not mergeable
await resolveConflicts(branchName, helper, logger, octokit, context);
detail = await resolveConflicts(branchName, helper, logger, octokit, context);
}

return getResult(result, detail, context);
Expand Down