Skip to content

Commit

Permalink
feat: auto-detect the value of the no-squash option
Browse files Browse the repository at this point in the history
  • Loading branch information
earl-warren committed Apr 3, 2024
1 parent 0a07bf3 commit b2554a6
Show file tree
Hide file tree
Showing 15 changed files with 128 additions and 47 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ This tool comes with some inputs that allow users to override the default behavi
| Backport Branch Names | --bp-branch-name | N | Comma separated lists of the backporting pull request branch names, if they exceeds 250 chars they will be truncated | bp-{target-branch}-{sha1}...{shaN} |
| Labels | --labels | N | Provide custom labels to be added to the backporting pull request | [] |
| Inherit labels | --inherit-labels | N | If enabled inherit lables from the original pull request | false |
| No squash | --no-squash | N | If provided the backporting will try to backport all pull request commits without squashing | false |
| No squash | --no-squash | N | If false only cherry-pick the merged commit, if true cherry-pick all the commits from the pull request. Always true if the pull request has not been merged. | true if the pull request was merged, false if it was squashed |
| Strategy | --strategy | N | Cherry pick merging strategy, see [git-merge](https://git-scm.com/docs/git-merge#_merge_strategies) doc for all possible values | "recursive" |
| Strategy Option | --strategy-option | N | Cherry pick merging strategy option, see [git-merge](https://git-scm.com/docs/git-merge#_merge_strategies) doc for all possible values | "theirs" |
| Cherry-pick Options | --cherry-pick-options | N | Additional cherry-pick options, see [git-cherry-pick](https://git-scm.com/docs/git-cherry-pick) doc for all possible values | "theirs" |
Expand Down
6 changes: 3 additions & 3 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,10 @@ inputs:
default: "false"
no-squash:
description: >
If set to true the tool will backport all commits as part of the pull request
instead of the suqashed one
If false only cherry-pick the merged commit, if true cherry-pick all the commits from the pull request.
Always true if the pull request has not been merged.
Defaults to true if the pull request was merged, false if it was squashed.
required: false
default: "false"
strategy:
description: Cherry-pick merge strategy
required: false
Expand Down
41 changes: 34 additions & 7 deletions dist/cli/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class ArgsParser {
inheritReviewers: this.getOrDefault(args.inheritReviewers, true),
labels: this.getOrDefault(args.labels, []),
inheritLabels: this.getOrDefault(args.inheritLabels, false),
squash: this.getOrDefault(args.squash, true),
squash: this.getOrDefault(args.squash),
strategy: this.getOrDefault(args.strategy),
strategyOption: this.getOrDefault(args.strategyOption),
cherryPickOptions: this.getOrDefault(args.cherryPickOptions),
Expand Down Expand Up @@ -107,7 +107,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
return result;
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.getAsBooleanOrDefault = exports.getAsSemicolonSeparatedList = exports.getAsCommaSeparatedList = exports.getAsCleanedCommaSeparatedList = exports.getOrUndefined = exports.readConfigFile = exports.parseArgs = void 0;
exports.getAsInvertedBooleanOrUndefined = exports.getAsBooleanOrDefault = exports.getAsSemicolonSeparatedList = exports.getAsCommaSeparatedList = exports.getAsCleanedCommaSeparatedList = exports.getOrUndefined = exports.readConfigFile = exports.parseArgs = void 0;
const fs = __importStar(__nccwpck_require__(7147));
/**
* Parse the input configuation string as json object and
Expand Down Expand Up @@ -163,6 +163,11 @@ function getAsBooleanOrDefault(value) {
return trimmed !== "" ? trimmed.toLowerCase() === "true" : undefined;
}
exports.getAsBooleanOrDefault = getAsBooleanOrDefault;
function getAsInvertedBooleanOrUndefined(value) {
const trimmed = value.trim();
return trimmed !== "" ? !(trimmed.toLowerCase() === "true") : undefined;
}
exports.getAsInvertedBooleanOrUndefined = getAsInvertedBooleanOrUndefined;


/***/ }),
Expand Down Expand Up @@ -203,7 +208,7 @@ class CLIArgsParser extends args_parser_1.default {
.option("--no-inherit-reviewers", "if provided and reviewers option is empty then inherit them from original pull request")
.option("--labels <labels>", "comma separated list of labels to be assigned to the backported pull request", args_utils_1.getAsCommaSeparatedList)
.option("--inherit-labels", "if true the backported pull request will inherit labels from the original one")
.option("--no-squash", "if provided the tool will backport all commits as part of the pull request")
.option("--no-squash", "If false only cherry-pick the merged commit, if true cherry-pick all the commits from the pull request. Always true if the pull request has not been merged. Defaults to true if the pull request was merged, false if it was squashed", undefined)
.option("--strategy <strategy>", "cherry-pick merge strategy, default to 'recursive'", undefined)
.option("--strategy-option <strategy-option>", "cherry-pick merge strategy option, default to 'theirs'")
.option("--cherry-pick-options <options>", "additional cherry-pick options")
Expand Down Expand Up @@ -803,13 +808,34 @@ class GitHubClient {
getDefaultGitEmail() {
return "noreply@github.com";
}
async getPullRequest(owner, repo, prNumber, squash = true) {
async getPullRequest(owner, repo, prNumber, squash) {
this.logger.debug(`Fetching pull request ${owner}/${repo}/${prNumber}`);
const { data } = await this.octokit.rest.pulls.get({
owner: owner,
repo: repo,
pull_number: prNumber,
});
if (data.state == "open") {
if (squash == true) {
this.logger.debug(`no-squash force to true because the pull request is open`);
}
squash = false;
}
else if (squash === undefined) {
const commit_sha = data.merge_commit_sha;
let commit = await this.octokit.rest.git.getCommit({
owner: owner,
repo: repo,
commit_sha: commit_sha,
});
squash = commit.data.parents.length == 1;
if (squash === true) {
this.logger.debug(`no-squash set to false because the pull request was merged as ${commit_sha} which is a not a merge commit (one parent)`);
}
else {
this.logger.debug(`no-squash set to true because the pull request was merged as ${commit_sha} which is a merge commit (more than one parent)`);
}
}
const commits = [];
if (!squash) {
// fetch all commits
Expand All @@ -827,7 +853,7 @@ class GitHubClient {
}
return this.mapper.mapPullRequest(data, commits);
}
async getPullRequestFromUrl(prUrl, squash = true) {
async getPullRequestFromUrl(prUrl, squash) {
const { owner, project, id } = this.extractPullRequestData(prUrl);
return this.getPullRequest(owner, project, id, squash);
}
Expand Down Expand Up @@ -1038,9 +1064,10 @@ class GitLabClient {
}
// READ
// example: <host>/api/v4/projects/<namespace>%2Fbackporting-example/merge_requests/1
async getPullRequest(namespace, repo, mrNumber, squash = true) {
async getPullRequest(namespace, repo, mrNumber, squash) {
const projectId = this.getProjectId(namespace, repo);
const { data } = await this.client.get(`/projects/${projectId}/merge_requests/${mrNumber}`);
// TBD ???
const commits = [];
if (!squash) {
// fetch all commits
Expand All @@ -1055,7 +1082,7 @@ class GitLabClient {
}
return this.mapper.mapPullRequest(data, commits);
}
getPullRequestFromUrl(mrUrl, squash = true) {
getPullRequestFromUrl(mrUrl, squash) {
const { namespace, project, id } = this.extractMergeRequestData(mrUrl);
return this.getPullRequest(namespace, project, id, squash);
}
Expand Down
41 changes: 34 additions & 7 deletions dist/gha/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class ArgsParser {
inheritReviewers: this.getOrDefault(args.inheritReviewers, true),
labels: this.getOrDefault(args.labels, []),
inheritLabels: this.getOrDefault(args.inheritLabels, false),
squash: this.getOrDefault(args.squash, true),
squash: this.getOrDefault(args.squash),
strategy: this.getOrDefault(args.strategy),
strategyOption: this.getOrDefault(args.strategyOption),
cherryPickOptions: this.getOrDefault(args.cherryPickOptions),
Expand Down Expand Up @@ -107,7 +107,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
return result;
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.getAsBooleanOrDefault = exports.getAsSemicolonSeparatedList = exports.getAsCommaSeparatedList = exports.getAsCleanedCommaSeparatedList = exports.getOrUndefined = exports.readConfigFile = exports.parseArgs = void 0;
exports.getAsInvertedBooleanOrUndefined = exports.getAsBooleanOrDefault = exports.getAsSemicolonSeparatedList = exports.getAsCommaSeparatedList = exports.getAsCleanedCommaSeparatedList = exports.getOrUndefined = exports.readConfigFile = exports.parseArgs = void 0;
const fs = __importStar(__nccwpck_require__(7147));
/**
* Parse the input configuation string as json object and
Expand Down Expand Up @@ -163,6 +163,11 @@ function getAsBooleanOrDefault(value) {
return trimmed !== "" ? trimmed.toLowerCase() === "true" : undefined;
}
exports.getAsBooleanOrDefault = getAsBooleanOrDefault;
function getAsInvertedBooleanOrUndefined(value) {
const trimmed = value.trim();
return trimmed !== "" ? !(trimmed.toLowerCase() === "true") : undefined;
}
exports.getAsInvertedBooleanOrUndefined = getAsInvertedBooleanOrUndefined;


/***/ }),
Expand Down Expand Up @@ -206,7 +211,7 @@ class GHAArgsParser extends args_parser_1.default {
inheritReviewers: !(0, args_utils_1.getAsBooleanOrDefault)((0, core_1.getInput)("no-inherit-reviewers")),
labels: (0, args_utils_1.getAsCommaSeparatedList)((0, core_1.getInput)("labels")),
inheritLabels: (0, args_utils_1.getAsBooleanOrDefault)((0, core_1.getInput)("inherit-labels")),
squash: !(0, args_utils_1.getAsBooleanOrDefault)((0, core_1.getInput)("no-squash")),
squash: (0, args_utils_1.getAsInvertedBooleanOrUndefined)((0, core_1.getInput)("no-squash")),
strategy: (0, args_utils_1.getOrUndefined)((0, core_1.getInput)("strategy")),
strategyOption: (0, args_utils_1.getOrUndefined)((0, core_1.getInput)("strategy-option")),
cherryPickOptions: (0, args_utils_1.getOrUndefined)((0, core_1.getInput)("cherry-pick-options")),
Expand Down Expand Up @@ -770,13 +775,34 @@ class GitHubClient {
getDefaultGitEmail() {
return "noreply@github.com";
}
async getPullRequest(owner, repo, prNumber, squash = true) {
async getPullRequest(owner, repo, prNumber, squash) {
this.logger.debug(`Fetching pull request ${owner}/${repo}/${prNumber}`);
const { data } = await this.octokit.rest.pulls.get({
owner: owner,
repo: repo,
pull_number: prNumber,
});
if (data.state == "open") {
if (squash == true) {
this.logger.debug(`no-squash force to true because the pull request is open`);
}
squash = false;
}
else if (squash === undefined) {
const commit_sha = data.merge_commit_sha;
let commit = await this.octokit.rest.git.getCommit({
owner: owner,
repo: repo,
commit_sha: commit_sha,
});
squash = commit.data.parents.length == 1;
if (squash === true) {
this.logger.debug(`no-squash set to false because the pull request was merged as ${commit_sha} which is a not a merge commit (one parent)`);
}
else {
this.logger.debug(`no-squash set to true because the pull request was merged as ${commit_sha} which is a merge commit (more than one parent)`);
}
}
const commits = [];
if (!squash) {
// fetch all commits
Expand All @@ -794,7 +820,7 @@ class GitHubClient {
}
return this.mapper.mapPullRequest(data, commits);
}
async getPullRequestFromUrl(prUrl, squash = true) {
async getPullRequestFromUrl(prUrl, squash) {
const { owner, project, id } = this.extractPullRequestData(prUrl);
return this.getPullRequest(owner, project, id, squash);
}
Expand Down Expand Up @@ -1005,9 +1031,10 @@ class GitLabClient {
}
// READ
// example: <host>/api/v4/projects/<namespace>%2Fbackporting-example/merge_requests/1
async getPullRequest(namespace, repo, mrNumber, squash = true) {
async getPullRequest(namespace, repo, mrNumber, squash) {
const projectId = this.getProjectId(namespace, repo);
const { data } = await this.client.get(`/projects/${projectId}/merge_requests/${mrNumber}`);
// TBD ???
const commits = [];
if (!squash) {
// fetch all commits
Expand All @@ -1022,7 +1049,7 @@ class GitLabClient {
}
return this.mapper.mapPullRequest(data, commits);
}
getPullRequestFromUrl(mrUrl, squash = true) {
getPullRequestFromUrl(mrUrl, squash) {
const { namespace, project, id } = this.extractMergeRequestData(mrUrl);
return this.getPullRequest(namespace, project, id, squash);
}
Expand Down
2 changes: 1 addition & 1 deletion src/service/args/args-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export default abstract class ArgsParser {
inheritReviewers: this.getOrDefault(args.inheritReviewers, true),
labels: this.getOrDefault(args.labels, []),
inheritLabels: this.getOrDefault(args.inheritLabels, false),
squash: this.getOrDefault(args.squash, true),
squash: this.getOrDefault(args.squash),
strategy: this.getOrDefault(args.strategy),
strategyOption: this.getOrDefault(args.strategyOption),
cherryPickOptions: this.getOrDefault(args.cherryPickOptions),
Expand Down
7 changes: 6 additions & 1 deletion src/service/args/args-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,9 @@ export function getAsSemicolonSeparatedList(value: string): string[] | undefined
export function getAsBooleanOrDefault(value: string): boolean | undefined {
const trimmed = value.trim();
return trimmed !== "" ? trimmed.toLowerCase() === "true" : undefined;
}
}

export function getAsInvertedBooleanOrUndefined(value: string): boolean | undefined {
const trimmed = value.trim();
return trimmed !== "" ? !(trimmed.toLowerCase() === "true") : undefined;
}
2 changes: 1 addition & 1 deletion src/service/args/args.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export interface Args {
inheritReviewers?: boolean, // if true and reviewers == [] then inherit reviewers from original pr
labels?: string[], // backport pr labels
inheritLabels?: boolean, // if true inherit labels from original pr
squash?: boolean, // if false use squashed/merged commit otherwise backport all commits as part of the pr
squash?: boolean,
strategy?: string, // cherry-pick merge strategy
strategyOption?: string, // cherry-pick merge strategy option
cherryPickOptions?: string, // additional cherry-pick options
Expand Down
2 changes: 1 addition & 1 deletion src/service/args/cli/cli-args-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default class CLIArgsParser extends ArgsParser {
.option("--no-inherit-reviewers", "if provided and reviewers option is empty then inherit them from original pull request")
.option("--labels <labels>", "comma separated list of labels to be assigned to the backported pull request", getAsCommaSeparatedList)
.option("--inherit-labels", "if true the backported pull request will inherit labels from the original one")
.option("--no-squash", "if provided the tool will backport all commits as part of the pull request")
.option("--no-squash", "If false only cherry-pick the merged commit, if true cherry-pick all the commits from the pull request. Always true if the pull request has not been merged. Defaults to true if the pull request was merged, false if it was squashed", undefined)
.option("--strategy <strategy>", "cherry-pick merge strategy, default to 'recursive'", undefined)
.option("--strategy-option <strategy-option>", "cherry-pick merge strategy option, default to 'theirs'")
.option("--cherry-pick-options <options>", "additional cherry-pick options")
Expand Down
4 changes: 2 additions & 2 deletions src/service/args/gha/gha-args-parser.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import ArgsParser from "@bp/service/args/args-parser";
import { Args } from "@bp/service/args/args.types";
import { getInput } from "@actions/core";
import { getAsBooleanOrDefault, getAsCleanedCommaSeparatedList, getAsCommaSeparatedList, getAsSemicolonSeparatedList, getOrUndefined, readConfigFile } from "@bp/service/args/args-utils";
import { getAsBooleanOrDefault, getAsInvertedBooleanOrUndefined, getAsCleanedCommaSeparatedList, getAsCommaSeparatedList, getAsSemicolonSeparatedList, getOrUndefined, readConfigFile } from "@bp/service/args/args-utils";

export default class GHAArgsParser extends ArgsParser {

Expand Down Expand Up @@ -31,7 +31,7 @@ export default class GHAArgsParser extends ArgsParser {
inheritReviewers: !getAsBooleanOrDefault(getInput("no-inherit-reviewers")),
labels: getAsCommaSeparatedList(getInput("labels")),
inheritLabels: getAsBooleanOrDefault(getInput("inherit-labels")),
squash: !getAsBooleanOrDefault(getInput("no-squash")),
squash: getAsInvertedBooleanOrUndefined(getInput("no-squash")),
strategy: getOrUndefined(getInput("strategy")),
strategyOption: getOrUndefined(getInput("strategy-option")),
cherryPickOptions: getOrUndefined(getInput("cherry-pick-options")),
Expand Down
4 changes: 2 additions & 2 deletions src/service/git/git-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@ import { BackportPullRequest, GitClientType, GitPullRequest } from "@bp/service/
* @param squash if true keep just one single commit, otherwise get the full list
* @returns {Promise<PullRequest>}
*/
getPullRequest(owner: string, repo: string, prNumber: number, squash: boolean): Promise<GitPullRequest>;
getPullRequest(owner: string, repo: string, prNumber: number, squash: boolean | undefined): Promise<GitPullRequest>;

/**
* Get a pull request object from the underneath git service
* @param prUrl pull request html url
* @param squash if true keep just one single commit, otherwise get the full list
* @returns {Promise<PullRequest>}
*/
getPullRequestFromUrl(prUrl: string, squash: boolean): Promise<GitPullRequest>;
getPullRequestFromUrl(prUrl: string, squash: boolean | undefined): Promise<GitPullRequest>;

// WRITE

Expand Down
Loading

0 comments on commit b2554a6

Please sign in to comment.