Pull request policy plugin NEW

The Bitbucket Cloud pull request policy plugin validates pull request attributes against different rules and creates merge checks for them.

It can be used for compliance and enforce several aspects of your pull request, e.g., title, description and branches conventions.

A policy is made of a list of rules.

Custom rule

A powerful rule that allows you to write your own validation logic.

import {const configure: (config: Config | (() => Config)) => voidconfigure} from "flowie.app"
import {const pullRequestPolicy: OptionsPluginNoDefault<PullRequestPolicyPluginOptions, false>pullRequestPolicy} from "flowie.app/plugins"

function function isSentenceCase(str: string): booleanisSentenceCase(str: stringstr: string) {
  return /^[A-Z][^A-Z]*$/.RegExp.test(string: string): boolean
Returns a Boolean value that indicates whether or not a pattern exists in a searched string.
@paramstring String on which to perform the search.
test
(str: stringstr)
} function configure(config: Config | (() => Config)): voidconfigure({ Config.plugins?: PluginDef<unknown>[] | undefinedplugins: [ function pullRequestPolicy(options: PullRequestPolicyPluginOptions): PluginDef<PullRequestPolicyPluginOptions> (+1 overload)pullRequestPolicy([ { name: string
The name of the policy.
name
: "sentence-case-title",
check: (context: PullRequestContextData) => CustomPullRequestRuleResult | undefinedcheck: ({pullRequest: PullRequestpullRequest}) => ({ title: stringtitle: "Tile must be sentence case", conclusion: boolean | "FAILED" | "SUCCESS" | "IGNORED"
"IGNORED" will be skipped, and the result won't be reported in the checks. 'true' is the same as "SUCCESS" and 'false' is the same as "FAILED"
conclusion
: function isSentenceCase(str: string): booleanisSentenceCase(pullRequest: PullRequestpullRequest.PullRequest.title: stringtitle),
}), }, ]), ], })

The check is a function that takes the pullRequest as an argument and returns a check result.

The conclusion can be either "FAILED", "SUCCESS" or "IGNORED". For convenience, true and false can also be use for "SUCCESS" and "FAILED" respectively.

When "IGNORED", the check will not be added to the pull request.

You can choose to report only on failure by returning "IGNORED" when success:

conclusion: isSentenceCase(pullRequest.title) ? "IGNORED" : "FAILED"

Displaying check results

The title is required, and you can also provide additional details using summary. Both properties accept Markdown syntax! 📄✨

Branch rules example:

The policy below contains three rules that ensure the following:

  • The source branch name follows the naming convention.
  • The correct branching model is used, not merging features directly into ‘main’ for instance.
  • The source branch references a Jira ticket.
import {const configure: (config: Config | (() => Config)) => voidconfigure} from "flowie.app"
import {const pullRequestPolicy: OptionsPluginNoDefault<PullRequestPolicyPluginOptions, false>pullRequestPolicy} from "flowie.app/plugins"

function configure(config: Config | (() => Config)): voidconfigure({
  Config.plugins?: PluginDef<unknown>[] | undefinedplugins: [
    function pullRequestPolicy(options: PullRequestPolicyPluginOptions): PluginDef<PullRequestPolicyPluginOptions> (+1 overload)pullRequestPolicy([
      {
        name: string
The name of the policy.
name
: "branch-naming-conventions",
check: (context: PullRequestContextData) => CustomPullRequestRuleResult | undefinedcheck: ({pullRequest: PullRequestpullRequest}) => { const const sourceBranch: stringsourceBranch = pullRequest: PullRequestpullRequest.PullRequest.source: PullRequestSourcesource.
PullRequestEndpoint.branch: {
    readonly name: string;
}
branch
.name: stringname
const const isValidSource: booleanisValidSource = /^(hotfix|feature|bugfix|release)\//.RegExp.test(string: string): boolean
Returns a Boolean value that indicates whether or not a pattern exists in a searched string.
@paramstring String on which to perform the search.
test
(
const sourceBranch: stringsourceBranch ) return { title: stringtitle: `Invalid source branch naming: *${const sourceBranch: stringsourceBranch}*`, summary?: string | undefinedsummary: "See [naming conventions](https://docs.myorg.com/branching-policy#naming-conventions)", conclusion: boolean | "IGNORED" | "FAILED" | "SUCCESS"
"IGNORED" will be skipped, and the result won't be reported in the checks. 'true' is the same as "SUCCESS" and 'false' is the same as "FAILED"
conclusion
: const isValidSource: booleanisValidSource ? "IGNORED" : "FAILED",
} }, }, { name: string
The name of the policy.
name
: "branch-valid-source-for-target",
check: (context: PullRequestContextData) => CustomPullRequestRuleResult | undefinedcheck: ({pullRequest: PullRequestpullRequest}) => { const const destinationBranch: stringdestinationBranch = pullRequest: PullRequestpullRequest.PullRequest.destination: PullRequestDestinationdestination.
PullRequestEndpoint.branch: {
    readonly name: string;
}
branch
.name: stringname
const const sourceBranch: stringsourceBranch = pullRequest: PullRequestpullRequest.PullRequest.source: PullRequestSourcesource.
PullRequestEndpoint.branch: {
    readonly name: string;
}
branch
.name: stringname
if (const destinationBranch: stringdestinationBranch === "main") { const const isValidSource: booleanisValidSource = const sourceBranch: stringsourceBranch.String.startsWith(searchString: string, position?: number): boolean
Returns true if the sequence of elements of searchString converted to a String is the same as the corresponding elements of this object (converted to a String) starting at position. Otherwise returns false.
startsWith
("hotfix/") || const sourceBranch: stringsourceBranch === "staging"
return { title: stringtitle: "Source branch for *main* must be *staging* or *hotfix/**", conclusion: boolean | "IGNORED" | "FAILED" | "SUCCESS"
"IGNORED" will be skipped, and the result won't be reported in the checks. 'true' is the same as "SUCCESS" and 'false' is the same as "FAILED"
conclusion
: const isValidSource: booleanisValidSource ? "IGNORED" : "FAILED",
} } else if (const destinationBranch: stringdestinationBranch === "develop") { const const isValidSource: booleanisValidSource = const sourceBranch: stringsourceBranch.String.startsWith(searchString: string, position?: number): boolean
Returns true if the sequence of elements of searchString converted to a String is the same as the corresponding elements of this object (converted to a String) starting at position. Otherwise returns false.
startsWith
("feature/") ||
const sourceBranch: stringsourceBranch.String.startsWith(searchString: string, position?: number): boolean
Returns true if the sequence of elements of searchString converted to a String is the same as the corresponding elements of this object (converted to a String) starting at position. Otherwise returns false.
startsWith
("bugfix/")
return { title: stringtitle: "Source branch for *develop* must be *feature/** or *bugfix/**", conclusion: boolean | "IGNORED" | "FAILED" | "SUCCESS"
"IGNORED" will be skipped, and the result won't be reported in the checks. 'true' is the same as "SUCCESS" and 'false' is the same as "FAILED"
conclusion
: const isValidSource: booleanisValidSource ? "IGNORED" : "FAILED",
} } }, }, { name: string
The name of the policy.
name
: "branch-must-reference-jira",
check: (context: PullRequestContextData) => CustomPullRequestRuleResult | undefinedcheck: ({pullRequest: PullRequestpullRequest}) => { const const sourceBranch: stringsourceBranch = pullRequest: PullRequestpullRequest.PullRequest.source: PullRequestSourcesource.
PullRequestEndpoint.branch: {
    readonly name: string;
}
branch
.name: stringname
const const hasJira: booleanhasJira = /^.*\/PRJ-\d+$/.RegExp.test(string: string): boolean
Returns a Boolean value that indicates whether or not a pattern exists in a searched string.
@paramstring String on which to perform the search.
test
(const sourceBranch: stringsourceBranch)
// Only show an example if failing const const summary: "" | "Example: feature/PRJ-123"summary = const hasJira: booleanhasJira ? "" : "Example: feature/PRJ-123" return { title: stringtitle: "Source branch must reference Jira ticket", summary?: string | undefinedsummary, conclusion: boolean | "IGNORED" | "FAILED" | "SUCCESS"
"IGNORED" will be skipped, and the result won't be reported in the checks. 'true' is the same as "SUCCESS" and 'false' is the same as "FAILED"
conclusion
: const hasJira: booleanhasJira,
} }, }, ]), ], })

The policy above is displayed as per below when failing:

Branch rules check example