Duplicate builds when pushing to branch with open pull request

Is there any way to prevent Drone from building for both the pull request and the push event?

My main use case is to prevent duplicate messages in Slack, which I’ve been able to partially solve using a lot of when: clauses, but the builds are still showing up in Drone’s UI.

This is what I’m trying to do:

  • When there is a push only to master, build it, report status to Slack.
    • Works with event: push and branch: master in a when: clause for a “build_master” pipeline step, which seems seems OK.
  • When there is a tag only in master, build and publish it, report status to Slack.
    • Works with event: tag and branch: master in a when: clause for a “publish” pipeline step, which also seems OK.
  • When there is a push to a pull request, build it, report status to Slack (and PR).
    • Always appears to build twice, once for the PR and once for the push.
    • The PR build incorrectly reports the branch as “master” in the Slack template.
    • The push build does not have the PR number available in the Slack template.
    • The push and PR builds share the same commit SHA.
    • I can filter out the push build using when: event: pull_request, but that reports the wrong branch name to Slack (always master), and silences Slack messages (using that same step) for the “build_master” and “publish” pipeline steps.
    • I can filter out the PR build likewise, but that doesn’t allow me to link the PR directly in the slack template.
    • Even when filtering out the Slack messages, there’s still builds in Drone.

Is there any good way to resolve this and just get a single build in every situation?

I can see in the PR there are two checks being made, which corresponds to the two events and builds:

Here’s a anonymized version of the template I’m using with org/repo substituted.

# Pipeline for multistage Dockerfile that includes tests
pipeline:
  # Build Dockerfile for master to report breakage in Slack
  build_master:
    dry_run: true  # Prevents publishing
    image: plugins/docker
    repo: org/repo
    when:
      branch: master
      event: push
  # Build Dockerfile for PRs to get status on PR and in Slack
  build_pull_request:
    dry_run: true  # Prevents publishing
    image: plugins/docker
    repo: org/repo
    when:
      branch:
        excludes: master
      event: pull_request
  # Build Dockerfile to publish to Docker Hub when tagging
  publish:
    image: plugins/docker
    secrets:
      - docker_username
      - docker_password
    repo: org/repo
    tags:
      - ${DRONE_COMMIT_SHA:0:8}
      - ${DRONE_COMMIT_BRANCH}
      - ${DRONE_TAG}
      - latest
    when:
      event: tag
  # Report status to Slack
  slack:
    image: plugins/slack
    webhook: ${SLACK_WEBHOOK}
    channel: drone-ci
    username: drone
    when:
      status:
        - success
        - failure
    template: >
      {{#success build.status}}
      :white_check_mark: Success!
      {{else}}
      :x: Failure:
      {{/success}}
      Build <{{build.link}}|#{{build.number}}> for 
      <https://github.com/{{repo.owner}}/{{repo.name}}|{{repo.name}}>
      {{#pull_request build.event}}
      (<https://github.com/{{repo.owner}}/{{repo.name}}/pull/{{build.pull}}|{{truncate build.commit 8}}>)
      {{else}}
      (<https://github.com/{{repo.owner}}/{{repo.name}}/commit/{{build.commit}}|{{truncate build.commit 8}}>)
      {{/pull_request}}
      (<https://github.com/{{repo.owner}}/{{repo.name}}/tree/{{build.branch}}|{{build.branch}}>) 
      by <https://github.com/{{build.author}}|{{build.author}}>
      in {{since build.started}}
2 Likes

Update:

We ended up just dropping builds on PRs entirely, and only using the Push event hook. It would be great if there was a way to make the above workflow work, but it seems like it’s not possible currently.

Please let me know if it is actually feasible.

We’re having a similar issue here, however, we’ve configured all build steps with this condition:
when:
branch: master
event:
- pull_request
- push

As a result, we do get our pull requests built, however, we also get an empty pipeline (except clone step) on the push action due to there being no other steps to perform.

My question is - is there a way to avoid publishing two branches. Let’s say, if PR is open, original branch would not show up in the UI.

2 Likes

If anyone else got here, you can use triggers to filter entire pipelines: https://docs.drone.io/user-guide/pipeline/triggers/

Unfortunately, last link from @rohit-smpx is broken.

Updated link: https://docs.drone.io/pipeline/digitalocean/syntax/trigger/

Example confs (in case this link also stops working):

  • By event, this would only run the push build for the branch
kind: pipeline
type: docker
name: default

steps:
- name: build
  image: golang
  commands:
  - go build
  - go test

trigger:
  event:
    exclude:
    - pull_request

Or by branch:
This would run on push events on the master branch and on pull requests with base branch master (AFAIK).

kind: pipeline
type: docker
name: default

steps:
- name: build
  image: golang
  commands:
  - go build
  - go test

trigger:
  branch:
    - master

Hi,

I’m trying to execute a build every time a PR is created/updated

As already explained by the author a duplicate build is created everytime and the event is triggered even when I push on a branch that it isnt related to the PR.

This is what I tried so far:

trigger:
  event:
  - pull_request
trigger:
  branch:
    - master
  event:
  - pull_request
trigger:
  branch:
    - ${DRONE_SOURCE_BRANCH}
  event:
  - pull_request

By the way Im using gitea platform with drone.

Drone cannot execute duplicate builds unless it receives two hooks from Gitea. You should therefore inspect your Gitea webhooks to understand why two hooks are being triggered for the same event. You should also check your version of Gitea as there have been regressions in the past.

You can expect Drone to execute two builds when you push to a branch with an open pull request because Gitea sends two webhooks – a push webhook for the branch and a pull_request synchronization webhook. As mentioned above, you can use the triggers section to limit this behavior.

Thanks. I will inspect Gitea to understand why it’s sending 2 hooks for the event pull_request.

Gitea sends two webhooks – a push webhook for the branch and a pull_request synchronization webhook.

I’m already using the triggers to focus only on event pull_request so I dont understand how a push event is able to trigger my build.

By the way as already said the problem happens event with a push event in a branch which isnt related to the PR.

Another question: does the triggers section apply only on pipeline execution? If not how can I define it to apply only on pipeline and not on single step?

Drone triggers a build for each webhook it receives from Gitea. If multiple build are triggered it means multiple webhooks are being sent from Gitea. Make sure only a single webhook is configured for your repository in Gitea and remove any duplicates. Also make sure Gitea is only sending a single webhook (check webhook history in Gitea to learn more). If the issue persists and Gitea continues sending duplicate hooks, please consider contacting Gitea support.

If you post here for additional help, we would need to see more details including copies of the (multiple) webhooks being triggered by Gitea, a copy of your Drone server logs with debug logs enabled, and a copy of your yaml.

The trigger stanza is used to limit overall pipeline execution [1]. The when stanza is used to limit individual step execution [2].

[1] https://docs.drone.io/pipeline/docker/syntax/trigger/
[2] https://docs.drone.io/pipeline/docker/syntax/conditions/

Make sure only a single webhook is configured for your repository in Gitea and remove any duplicates

I found out that a single webhook is configured and the configuration to trigger is:

To me this is perfectly right. The webhook must be triggered in push and pull_request event.
Now I think is normal that multiple webhook are sended because when I push on the branch of the PR Gitea send 2 requests to drone, one for push and another for pull_request. In the end with the triggers section I filter out the one with push event but that doesnt work.

Is this something you want help with? If yes, you need to post a copy of your yaml and a copy of your server logs. You can also see real world examples of how triggers are successfully used to limit execution here: https://github.com/drone/drone/blob/master/.drone.yml#L70:L73

I dont have access to the server because it is managed by privileged person who he is in holyday. I will reach you again when he returns. Thanks! @ashwilliams1
For the time being I will investigate Gitea issues with duplicate webhooks.

@ashwilliams1 After discussing in my company we found out that the problem is related to the configuration of the .drone.yml. In my case when the PR was created the file .drone.yml was missing the trigger section and Drone seems to consider the .drone.yml related when opening the PR. Each new push with updated configuration seems to be ignored.
In conclusion to solve my problem I updated the .drone.yml in each branch (master and branch to merge) and recreated the PR and now all works. Sorry for the trouble.

Is there a solution for this case, I think that there is even not solution as each event trigger very different behavior:

  • push: runs the build/tests as it is on a particular branch
  • pull_request: tries to merge the PR to target branch and then it runs build/tests in the resulted state after merging

So even the very same commit with a unique hash has two different results depending on the event perspective… Only if we assume that PR is built/tested without merging then we may consider duplicate build status between these events…

we’re struggling with the same. For now we’re running with

trigger:
  event:
    exclude:
    - pull_request #avoid double build on PRs

But this causes PR merges to not trigger builds.
I get the impression that 95% of us have similar use cases (trigger on pushes and PRs, avoid duplicate builds), so it would be good if the official documentation stated how to set up this in a clear and concise manner.