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)) => void
configure} from "flowie.app"
import {const pipelines: OptionsPluginNoDefault<PipelinesPluginOptions, false>
pipelines} from "flowie.app/plugins"
function configure(config: Config | (() => Config)): void
configure({
Config.plugins?: PluginDef<unknown>[] | undefined
plugins: [
function pipelines(options: PipelinesPluginOptions): PluginDef<PipelinesPluginOptions> (+1 overload)
pipelines({
run: "custom:integration_tests"
run: "custom:integration_tests",
trigger?: RunTriggerEvent[] | undefined
trigger: ["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)) => void
configure} from "flowie.app"
import {const pipelines: OptionsPluginNoDefault<PipelinesPluginOptions, false>
pipelines} from "flowie.app/plugins"
import {function target(...branches: Array<string | RegExp> & NonEmptyArray): ChainableCondition
target} from "flowie.app/conditions"
function configure(config: Config | (() => Config)): void
configure({
Config.plugins?: PluginDef<unknown>[] | undefined
plugins: [
function pipelines(...rules: Rules<PipelinesPluginOptions | undefined>): PluginDef<PipelinesPluginOptions> (+1 overload)
pipelines([
function target(...branches: Array<string | RegExp> & NonEmptyArray): ChainableCondition
target("main"),
{
run: "custom:integration_tests"
run: "custom:integration_tests",
trigger?: RunTriggerEvent[] | undefined
trigger: ["source_new_updated", "destination_updated"],
variables?: Record<string, string | number> | undefined
variables: {my_var: string
my_var: "my_custom_value"},
},
]),
],
})
You can define different pipelines based on different conditions:
import {const configure: (config: Config | (() => Config)) => void
configure} from "flowie.app"
import {const pipelines: OptionsPluginNoDefault<PipelinesPluginOptions, false>
pipelines} from "flowie.app/plugins"
import {function source(...branches: Array<string | RegExp> & NonEmptyArray): ChainableCondition
source, function target(...branches: Array<string | RegExp> & NonEmptyArray): ChainableCondition
target, const labels: Labels
labels, const changeset: ChangesetConditions
changeset} from "flowie.app/conditions"
function configure(config: Config | (() => Config)): void
configure({
Config.plugins?: PluginDef<unknown>[] | undefined
plugins: [
function pipelines(...rules: Rules<PipelinesPluginOptions | undefined>): PluginDef<PipelinesPluginOptions> (+1 overload)
pipelines(
[
function target(...branches: Array<string | RegExp> & NonEmptyArray): ChainableCondition
target("main").ChainableCondition.and: (also: Condition<boolean>) => ChainableCondition
and(const labels: Labels
labels.Labels.has(label: string | LabelRef): ChainableCondition (+1 overload)
has("CI ready")),
{
run: "custom:sonar"
run: "custom:sonar",
trigger?: RunTriggerEvent[] | undefined
trigger: ["destination_updated", "source_new_updated"],
variables?: Record<string, string | number> | undefined
variables: {type MY_MAIN_VAR: string
MY_MAIN_VAR: "MY_MAIN_VALUE"},
},
],
[
function target(...branches: Array<string | RegExp> & NonEmptyArray): ChainableCondition
target(/release.*/).ChainableCondition.and: (also: Condition<boolean>) => ChainableCondition
and(function source(...branches: Array<string | RegExp> & NonEmptyArray): ChainableCondition
source(/hotfix.*/)),
{
run: "custom:quick_integration_tests"
run: "custom:quick_integration_tests",
trigger?: RunTriggerEvent[] | undefined
trigger: ["source_new_updated"],
},
],
[
function target(...branches: Array<string | RegExp> & NonEmptyArray): ChainableCondition
target("main").ChainableCondition.and: (also: Condition<boolean>) => ChainableCondition
and(const changeset: ChangesetConditions
changeset.ChangesetConditions.matches: (glob: string) => ChainableCondition
matches("src/docs/*")),
{
run: "custom:build_docs"
run: "custom:build_docs",
trigger?: RunTriggerEvent[] | undefined
trigger: ["source_new_updated"],
variables?: Record<string, string | number> | undefined
variables: {my_var: string
my_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)) => void
configure} from "flowie.app"
import {const pipelines: OptionsPluginNoDefault<PipelinesPluginOptions, false>
pipelines} from "flowie.app/plugins"
function configure(config: Config | (() => Config)): void
configure({
Config.plugins?: PluginDef<unknown>[] | undefined
plugins: [
function pipelines(options: PipelinesPluginOptions): PluginDef<PipelinesPluginOptions> (+1 overload)
pipelines({
run: "custom:sonar"
run: "custom:sonar",
trigger?: RunTriggerEvent[] | undefined
trigger: ["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)) => void
configure} from "flowie.app"
import {const pipelines: OptionsPluginNoDefault<PipelinesPluginOptions, false>
pipelines} from "flowie.app/plugins"
function configure(config: Config | (() => Config)): void
configure({
Config.plugins?: PluginDef<unknown>[] | undefined
plugins: [
function pipelines(options: PipelinesPluginOptions): PluginDef<PipelinesPluginOptions> (+1 overload)
pipelines({
run: "custom:sonar"
run: "custom:sonar",
trigger?: RunTriggerEvent[] | undefined
trigger: ["source_new_updated"],
variables?: Record<string, string | number> | undefined
variables: {type MY_VAR: string
MY_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)) => void
configure} from "flowie.app"
import {const pipelines: OptionsPluginNoDefault<PipelinesPluginOptions, false>
pipelines} from "flowie.app/plugins"
import {function target(...branches: Array<string | RegExp> & NonEmptyArray): ChainableCondition
target} from "flowie.app/conditions"
function configure(config: Config | (() => Config)): void
configure({
Config.plugins?: PluginDef<unknown>[] | undefined
plugins: [
function pipelines(...rules: Rules<PipelinesPluginOptions | undefined>): PluginDef<PipelinesPluginOptions> (+1 overload)
pipelines([
function target(...branches: Array<string | RegExp> & NonEmptyArray): ChainableCondition
target(/main.*/),
{
run: "pull-requests:to_main"
run: "pull-requests:to_main",
trigger?: RunTriggerEvent[] | undefined
trigger: ["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)) => void
configure} from "flowie.app"
import {const pipelines: OptionsPluginNoDefault<PipelinesPluginOptions, false>
pipelines} from "flowie.app/plugins"
import {function target(...branches: Array<string | RegExp> & NonEmptyArray): ChainableCondition
target} from "flowie.app/conditions"
function configure(config: Config | (() => Config)): void
configure({
Config.plugins?: PluginDef<unknown>[] | undefined
plugins: [
function pipelines(...rules: Rules<PipelinesPluginOptions | undefined>): PluginDef<PipelinesPluginOptions> (+1 overload)
pipelines([
function target(...branches: Array<string | RegExp> & NonEmptyArray): ChainableCondition
target("main"),
[
{
run: "custom:pipeline_1"
run: "custom:pipeline_1",
trigger?: RunTriggerEvent[] | undefined
trigger: ["source_new_updated"],
},
{
run: "custom:pipeline_2"
run: "custom:pipeline_2",
trigger?: RunTriggerEvent[] | undefined
trigger: ["source_new_updated"],
},
],
]),
],
})