Skip to content
Open
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
5 changes: 5 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ inputs:
maintainer-can-modify:
description: 'Indicates whether maintainers can modify the pull request.'
default: true
skip-if-commits-from-other-authors:
description: >
Skip updating the pull request branch if it contains commits from authors other than the configured action author/committer.
This prevents overwriting changes made by other users to the branch.
default: false
outputs:
pull-request-number:
description: 'The pull request number'
Expand Down
71 changes: 67 additions & 4 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,8 @@ function splitLines(multilineString) {
.map(s => s.trim())
.filter(x => x !== '');
}
function createOrUpdateBranch(git, commitMessage, base, branch, branchRemoteName, signoff, addPaths) {
return __awaiter(this, void 0, void 0, function* () {
function createOrUpdateBranch(git_1, commitMessage_1, base_1, branch_1, branchRemoteName_1, signoff_1, addPaths_1) {
return __awaiter(this, arguments, void 0, function* (git, commitMessage, base, branch, branchRemoteName, signoff, addPaths, skipIfCommitsFromOtherAuthors = false, authorEmail = '', committerEmail = '') {
// Get the working base.
// When a ref, it may or may not be the actual base.
// When a commit, we must rebase onto the actual base.
Expand Down Expand Up @@ -268,6 +268,52 @@ function createOrUpdateBranch(git, commitMessage, base, branch, branchRemoteName
core.info(`Pull request branch '${branch}' already exists as remote branch '${branchRemoteName}/${branch}'`);
// Checkout the pull request branch
yield git.checkout(branch);
// Check if the branch has commits from other authors
if (skipIfCommitsFromOtherAuthors && authorEmail && committerEmail) {
core.info('Checking if branch has commits from other authors...');
const branchCommitsAheadCount = yield commitsAhead(git, base, branch);
if (branchCommitsAheadCount > 0) {
try {
const commitAuthors = yield git.getCommitAuthors(`${base}..${branch}`);
const hasOtherAuthors = commitAuthors.some(commit => commit.authorEmail !== authorEmail &&
commit.committerEmail !== committerEmail);
if (hasOtherAuthors) {
core.info(`Branch '${branch}' has commits from other authors. Skipping update to prevent overwriting their changes.`);
core.info(`Configured author: ${authorEmail}, committer: ${committerEmail}`);
const otherAuthors = commitAuthors.filter(commit => commit.authorEmail !== authorEmail ||
commit.committerEmail !== committerEmail);
core.info(`Found commits from: ${otherAuthors.map(c => `${c.authorEmail} (committer: ${c.committerEmail})`).join(', ')}`);
action = 'not-updated';
hasDiffWithBase = yield isAhead(git, base, branch);
const baseSha = yield git.revParse(base);
const baseCommit = yield git.getCommit(baseSha);
const headSha = yield git.revParse(branch);
let branchCommits = [];
if (hasDiffWithBase) {
branchCommits = yield buildBranchCommits(git, base, branch);
}
yield git.exec(['branch', '--delete', '--force', tempBranch]);
yield git.checkout(workingBase);
if (stashed) {
yield git.stashPop();
}
return {
action: action,
base: base,
hasDiffWithBase: hasDiffWithBase,
baseCommit: baseCommit,
headSha: headSha,
branchCommits: branchCommits
};
}
core.info('No commits from other authors found. Proceeding with update.');
}
catch (error) {
core.warning(`Failed to check commit authors: ${utils.getErrorMessage(error)}`);
core.info('Proceeding with update despite check failure.');
}
}
}
// Reset the branch if one of the following conditions is true.
// - If the branch differs from the recreated temp branch.
// - If the number of commits ahead of the base branch differs between the branch and
Expand Down Expand Up @@ -505,7 +551,7 @@ function createPullRequest(inputs) {
outputs.set('pull-request-operation', 'none');
// Create or update the pull request branch
core.startGroup('Create or update the pull request branch');
const result = yield (0, create_or_update_branch_1.createOrUpdateBranch)(git, inputs.commitMessage, inputs.base, inputs.branch, branchRemoteName, inputs.signoff, inputs.addPaths);
const result = yield (0, create_or_update_branch_1.createOrUpdateBranch)(git, inputs.commitMessage, inputs.base, inputs.branch, branchRemoteName, inputs.signoff, inputs.addPaths, inputs.skipIfCommitsFromOtherAuthors, parsedAuthor.email, parsedCommitter.email);
outputs.set('pull-request-head-sha', result.headSha);
// Set the base. It would have been '' if not specified as an input
inputs.base = result.base;
Expand Down Expand Up @@ -815,6 +861,22 @@ class GitCommandManager {
};
});
}
getCommitAuthors(commitRange) {
return __awaiter(this, void 0, void 0, function* () {
const output = yield this.exec(['log', '--format=%ae%n%ce%n###COMMIT###', commitRange], { suppressGitCmdOutput: true });
const commits = [];
const lines = output.stdout.split('\n').filter(x => x !== '');
for (let i = 0; i < lines.length; i += 3) {
if (lines[i + 2] === '###COMMIT###') {
commits.push({
authorEmail: lines[i],
committerEmail: lines[i + 1]
});
}
}
return commits;
});
}
getConfigValue(configKey_1) {
return __awaiter(this, arguments, void 0, function* (configKey, configValue = '.') {
const output = yield this.exec([
Expand Down Expand Up @@ -1654,7 +1716,8 @@ function run() {
teamReviewers: utils.getInputAsArray('team-reviewers'),
milestone: Number(core.getInput('milestone')),
draft: getDraftInput(),
maintainerCanModify: core.getBooleanInput('maintainer-can-modify')
maintainerCanModify: core.getBooleanInput('maintainer-can-modify'),
skipIfCommitsFromOtherAuthors: core.getBooleanInput('skip-if-commits-from-other-authors')
};
core.debug(`Inputs: ${(0, util_1.inspect)(inputs)}`);
if (!inputs.token) {
Expand Down
67 changes: 66 additions & 1 deletion src/create-or-update-branch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,10 @@ export async function createOrUpdateBranch(
branch: string,
branchRemoteName: string,
signoff: boolean,
addPaths: string[]
addPaths: string[],
skipIfCommitsFromOtherAuthors = false,
authorEmail = '',
committerEmail = ''
): Promise<CreateOrUpdateBranchResult> {
// Get the working base.
// When a ref, it may or may not be the actual base.
Expand Down Expand Up @@ -294,6 +297,68 @@ export async function createOrUpdateBranch(
// Checkout the pull request branch
await git.checkout(branch)

// Check if the branch has commits from other authors
if (skipIfCommitsFromOtherAuthors && authorEmail && committerEmail) {
core.info('Checking if branch has commits from other authors...')
const branchCommitsAheadCount = await commitsAhead(git, base, branch)
if (branchCommitsAheadCount > 0) {
try {
const commitAuthors = await git.getCommitAuthors(`${base}..${branch}`)
const hasOtherAuthors = commitAuthors.some(
commit =>
commit.authorEmail !== authorEmail &&
commit.committerEmail !== committerEmail
)
if (hasOtherAuthors) {
core.info(
`Branch '${branch}' has commits from other authors. Skipping update to prevent overwriting their changes.`
)
core.info(
`Configured author: ${authorEmail}, committer: ${committerEmail}`
)
const otherAuthors = commitAuthors.filter(
commit =>
commit.authorEmail !== authorEmail ||
commit.committerEmail !== committerEmail
)
core.info(
`Found commits from: ${otherAuthors.map(c => `${c.authorEmail} (committer: ${c.committerEmail})`).join(', ')}`
)
action = 'not-updated'
hasDiffWithBase = await isAhead(git, base, branch)
const baseSha = await git.revParse(base)
const baseCommit = await git.getCommit(baseSha)
const headSha = await git.revParse(branch)
let branchCommits: Commit[] = []
if (hasDiffWithBase) {
branchCommits = await buildBranchCommits(git, base, branch)
}
await git.exec(['branch', '--delete', '--force', tempBranch])
await git.checkout(workingBase)
if (stashed) {
await git.stashPop()
}
return {
action: action,
base: base,
hasDiffWithBase: hasDiffWithBase,
baseCommit: baseCommit,
headSha: headSha,
branchCommits: branchCommits
}
}
core.info(
'No commits from other authors found. Proceeding with update.'
)
} catch (error) {
core.warning(
`Failed to check commit authors: ${utils.getErrorMessage(error)}`
)
core.info('Proceeding with update despite check failure.')
}
}
}

// Reset the branch if one of the following conditions is true.
// - If the branch differs from the recreated temp branch.
// - If the number of commits ahead of the base branch differs between the branch and
Expand Down
6 changes: 5 additions & 1 deletion src/create-pull-request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export interface Inputs {
always: boolean
}
maintainerCanModify: boolean
skipIfCommitsFromOtherAuthors: boolean
}

export async function createPullRequest(inputs: Inputs): Promise<void> {
Expand Down Expand Up @@ -194,7 +195,10 @@ export async function createPullRequest(inputs: Inputs): Promise<void> {
inputs.branch,
branchRemoteName,
inputs.signoff,
inputs.addPaths
inputs.addPaths,
inputs.skipIfCommitsFromOtherAuthors,
parsedAuthor.email,
parsedCommitter.email
)
outputs.set('pull-request-head-sha', result.headSha)
// Set the base. It would have been '' if not specified as an input
Expand Down
20 changes: 20 additions & 0 deletions src/git-command-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,26 @@ export class GitCommandManager {
}
}

async getCommitAuthors(
commitRange: string
): Promise<{authorEmail: string; committerEmail: string}[]> {
const output = await this.exec(
['log', '--format=%ae%n%ce%n###COMMIT###', commitRange],
{suppressGitCmdOutput: true}
)
const commits: {authorEmail: string; committerEmail: string}[] = []
const lines = output.stdout.split('\n').filter(x => x !== '')
for (let i = 0; i < lines.length; i += 3) {
if (lines[i + 2] === '###COMMIT###') {
commits.push({
authorEmail: lines[i],
committerEmail: lines[i + 1]
})
}
}
return commits
}

async getConfigValue(configKey: string, configValue = '.'): Promise<string> {
const output = await this.exec([
'config',
Expand Down
5 changes: 4 additions & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ async function run(): Promise<void> {
teamReviewers: utils.getInputAsArray('team-reviewers'),
milestone: Number(core.getInput('milestone')),
draft: getDraftInput(),
maintainerCanModify: core.getBooleanInput('maintainer-can-modify')
maintainerCanModify: core.getBooleanInput('maintainer-can-modify'),
skipIfCommitsFromOtherAuthors: core.getBooleanInput(
'skip-if-commits-from-other-authors'
)
}
core.debug(`Inputs: ${inspect(inputs)}`)

Expand Down