Smart pipelines plugin
The Bitbucket Cloud smart pipelines plugin
brings all the flexibility and versatility of
Flowie to Bitbucket Pipelines. You define your pipelines as usual in your bitbucket-pipelines.yml,
and use Flowie to trigger them, which gives you the following advantages:
- Use conditions to define which and when pipelines are triggered
- Trigger pipelines using different events as triggers. e.g., source or/and event updated
- Easily run custom pipelines for pull requests
- No trigger for conflicted pull requests
- Trigger multiple pipelines for an event
Triggering pipelines
Flowie can trigger pull-requests and custom pipelines.
import {const configure: (config: Config | (() => Config)) => voidconfigure} from "flowie.app"
import {const pipelines: OptionsPluginNoDefault<PipelinesPluginOptions, false>pipelines} from "flowie.app/plugins"
function configure(config: Config | (() => Config)): voidconfigure({
Config.plugins?: PluginDef<unknown>[] | undefinedplugins: [
function pipelines(options: PipelinesPluginOptions): PluginDef<PipelinesPluginOptions> (+1 overload)pipelines({
run: "custom:integration_tests"run: "custom:integration_tests",
trigger?: RunTriggerEvent[] | undefinedtrigger: ["source_new_updated", "destination_updated"],
}),
],
})
Select which pipeline from bitbucket-pipelines.yml should be triggered using the run property.
The trigger property defines when the pipeline will run.
Currently, it supports source_new_updated and destination_updated.
Differently from Bitbucket Cloud standard functionality, it also lets you trigger the pipeline when
the pull request destination is updated.
Triggering based on the destination branch
By using conditions you can
define to which pull requests the pipeline should be applied.
For instance, it can be defined to only trigger the pipeline for a pull request
targeting main as destination.
import {const configure: (config: Config | (() => Config)) => voidconfigure} from "flowie.app"
import {const pipelines: OptionsPluginNoDefault<PipelinesPluginOptions, false>pipelines} from "flowie.app/plugins"
import {function target(...branches: Array<string | RegExp> & NonEmptyArray): ChainableConditiontarget} from "flowie.app/conditions"
function configure(config: Config | (() => Config)): voidconfigure({
Config.plugins?: PluginDef<unknown>[] | undefinedplugins: [
function pipelines(...rules: Rules<PipelinesPluginOptions | undefined>): PluginDef<PipelinesPluginOptions> (+1 overload)pipelines([
function target(...branches: Array<string | RegExp> & NonEmptyArray): ChainableConditiontarget("main"),
{
run: "custom:integration_tests"run: "custom:integration_tests",
trigger?: RunTriggerEvent[] | undefinedtrigger: ["source_new_updated", "destination_updated"],
variables?: Record<string, string | number> | undefinedvariables: {my_var: stringmy_var: "my_custom_value"},
},
]),
],
})
You can define different pipelines based on different conditions:
import {const configure: (config: Config | (() => Config)) => voidconfigure} from "flowie.app"
import {const pipelines: OptionsPluginNoDefault<PipelinesPluginOptions, false>pipelines} from "flowie.app/plugins"
import {function source(...branches: Array<string | RegExp> & NonEmptyArray): ChainableConditionsource, function target(...branches: Array<string | RegExp> & NonEmptyArray): ChainableConditiontarget, const labels: Labelslabels, const changeset: ChangesetConditionschangeset} from "flowie.app/conditions"
function configure(config: Config | (() => Config)): voidconfigure({
Config.plugins?: PluginDef<unknown>[] | undefinedplugins: [
function pipelines(...rules: Rules<PipelinesPluginOptions | undefined>): PluginDef<PipelinesPluginOptions> (+1 overload)pipelines(
[
function target(...branches: Array<string | RegExp> & NonEmptyArray): ChainableConditiontarget("main").ChainableCondition.and: (also: Condition<boolean>) => ChainableConditionand(const labels: Labelslabels.Labels.has(label: string | LabelRef): ChainableCondition (+1 overload)has("CI ready")),
{
run: "custom:sonar"run: "custom:sonar",
trigger?: RunTriggerEvent[] | undefinedtrigger: ["destination_updated", "source_new_updated"],
variables?: Record<string, string | number> | undefinedvariables: {type MY_MAIN_VAR: stringMY_MAIN_VAR: "MY_MAIN_VALUE"},
},
],
[
function target(...branches: Array<string | RegExp> & NonEmptyArray): ChainableConditiontarget(/release.*/).ChainableCondition.and: (also: Condition<boolean>) => ChainableConditionand(function source(...branches: Array<string | RegExp> & NonEmptyArray): ChainableConditionsource(/hotfix.*/)),
{
run: "custom:quick_integration_tests"run: "custom:quick_integration_tests",
trigger?: RunTriggerEvent[] | undefinedtrigger: ["source_new_updated"],
},
],
[
function target(...branches: Array<string | RegExp> & NonEmptyArray): ChainableConditiontarget("main").ChainableCondition.and: (also: Condition<boolean>) => ChainableConditionand(const changeset: ChangesetConditionschangeset.ChangesetConditions.matches: (glob: string) => ChainableConditionmatches("src/docs/*")),
{
run: "custom:build_docs"run: "custom:build_docs",
trigger?: RunTriggerEvent[] | undefinedtrigger: ["source_new_updated"],
variables?: Record<string, string | number> | undefinedvariables: {my_var: stringmy_var: "my_custom_value"},
},
]
),
],
})
Triggering custom pipelines
Custom pipelines support variables and are triggered using the custom prefix
on the run property:
import {const configure: (config: Config | (() => Config)) => voidconfigure} from "flowie.app"
import {const pipelines: OptionsPluginNoDefault<PipelinesPluginOptions, false>pipelines} from "flowie.app/plugins"
function configure(config: Config | (() => Config)): voidconfigure({
Config.plugins?: PluginDef<unknown>[] | undefinedplugins: [
function pipelines(options: PipelinesPluginOptions): PluginDef<PipelinesPluginOptions> (+1 overload)pipelines({
run: "custom:sonar"run: "custom:sonar",
trigger?: RunTriggerEvent[] | undefinedtrigger: ["source_new_updated"],
}),
],
})
Merge pull request destination
Flowie makes it easy to merge the pull request destination branch into your working branch when running custom pipelines, the same way pull-requests work.
Simply add eval $MERGE_PULL_REQUEST_CMD as the first step of your script.
# bitbucket-pipelines.yaml
pipelines:
custom: # Pipelines that are triggered manually
sonar: # The name that is displayed in the list in the Bitbucket Cloud GUI
- step:
script:
- eval $MERGE_PULL_REQUEST_CMD
- echo "Manual triggers for Sonar are awesome!"
Alternatively,
you can use $REBASE_PULL_REQUEST_CMD instead if you use a rebase workflow.
Variables
Flowie injects the BITBUCKET_PR_DESTINATION_BRANCH,
BITBUCKET_PR_DESTINATION_COMMIT and BITBUCKET_PR_ID variables.
Additional variables can be specified using the variables property.
import {const configure: (config: Config | (() => Config)) => voidconfigure} from "flowie.app"
import {const pipelines: OptionsPluginNoDefault<PipelinesPluginOptions, false>pipelines} from "flowie.app/plugins"
function configure(config: Config | (() => Config)): voidconfigure({
Config.plugins?: PluginDef<unknown>[] | undefinedplugins: [
function pipelines(options: PipelinesPluginOptions): PluginDef<PipelinesPluginOptions> (+1 overload)pipelines({
run: "custom:sonar"run: "custom:sonar",
trigger?: RunTriggerEvent[] | undefinedtrigger: ["source_new_updated"],
variables?: Record<string, string | number> | undefinedvariables: {type MY_VAR: stringMY_VAR: "MY_VALUE"},
}),
],
})
Pipelines UI limitation
Custom pipelines are triggered using the branch target, since Bitbucket does not support using a pull request as target. This means that the pull request won’t be displayed at the pipelines UI, only the pull request associated branch.
You can use pull-requests pipelines
to be able to show the associated pull request instead.
Triggering pull-requests pipelines
Pull-request based pipelines are referenced
using the pull-requests prefix on the run property.
The main difference from custom pipelines triggered for pull requests is that
pull-requests pipelines are able
to show the associated pull request in the pipelines view as explained above.
import {const configure: (config: Config | (() => Config)) => voidconfigure} from "flowie.app"
import {const pipelines: OptionsPluginNoDefault<PipelinesPluginOptions, false>pipelines} from "flowie.app/plugins"
import {function target(...branches: Array<string | RegExp> & NonEmptyArray): ChainableConditiontarget} from "flowie.app/conditions"
function configure(config: Config | (() => Config)): voidconfigure({
Config.plugins?: PluginDef<unknown>[] | undefinedplugins: [
function pipelines(...rules: Rules<PipelinesPluginOptions | undefined>): PluginDef<PipelinesPluginOptions> (+1 overload)pipelines([
function target(...branches: Array<string | RegExp> & NonEmptyArray): ChainableConditiontarget("main"),
{
run: "pull-requests:to_main"run: "pull-requests:to_main",
trigger?: RunTriggerEvent[] | undefinedtrigger: ["source_new_updated", "destination_updated"],
},
]),
],
})
# bitbucket-pipelines.yaml
pipelines:
pull-requests:
to_main/**:
- step:
script:
# Clean up dynamically generated branch
- git push origin --delete $BITBUCKET_BRANCH
- ./build.sh
Note that instead of specifying the source branch pattern, you specify a placeholder.
The placeholder can be any arbitrary name.
In the example we used to_main.
The example is also using conditions to limit this pipeline only to pull requests
targeting main as destination.
Flowie will create the source branch dynamically for Bitbucket
to be able to match against it and run the pipeline.
After Bitbucket clones it, this generated branch can be discarded.
You should do this
by adding the git push origin --delete $BITBUCKET_BRANCH command to your
pipeline as shown above.
Triggering multiple pipelines
import {const configure: (config: Config | (() => Config)) => voidconfigure} from "flowie.app"
import {const pipelines: OptionsPluginNoDefault<PipelinesPluginOptions, false>pipelines} from "flowie.app/plugins"
import {function target(...branches: Array<string | RegExp> & NonEmptyArray): ChainableConditiontarget} from "flowie.app/conditions"
function configure(config: Config | (() => Config)): voidconfigure({
Config.plugins?: PluginDef<unknown>[] | undefinedplugins: [
function pipelines(...rules: Rules<PipelinesPluginOptions | undefined>): PluginDef<PipelinesPluginOptions> (+1 overload)pipelines([
function target(...branches: Array<string | RegExp> & NonEmptyArray): ChainableConditiontarget("main"),
[
{
run: "custom:pipeline_1"run: "custom:pipeline_1",
trigger?: RunTriggerEvent[] | undefinedtrigger: ["source_new_updated"],
},
{
run: "custom:pipeline_2"run: "custom:pipeline_2",
trigger?: RunTriggerEvent[] | undefinedtrigger: ["source_new_updated"],
},
],
]),
],
})