Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions hooks_processor/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ services:

volumes:
- .:/app
- elixir_deps:/app/deps
- elixir_build:/app/_build


db:
image: postgres:9.6
Expand Down Expand Up @@ -67,3 +70,7 @@ services:
volumes:
postgres-data:
driver: local
elixir_deps:
driver: local
elixir_build:
driver: local
56 changes: 34 additions & 22 deletions hooks_processor/lib/hooks_processor/hooks/payload/bitbucket.ex
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ defmodule HooksProcessor.Hooks.Payload.Bitbucket do
end

@doc """
Used for concluding whether branch was created, updated or deleted via given push
Used for concluding whether branch or tag was created, updated or deleted via given push
"""
def branch_action(payload) do
change = payload |> get_in(["push", "changes"]) |> Enum.at(0)
Expand Down Expand Up @@ -47,41 +47,29 @@ defmodule HooksProcessor.Hooks.Payload.Bitbucket do
"""
def extract_data(payload, hook_type, action_type)

def extract_data(payload, "tag", "deleted") do
change = payload |> get_in(["push", "changes"]) |> Enum.at(0) |> Map.get("old")
extract_tag_data_(payload, change)
end

def extract_data(payload, "tag", _action_type) do
change = payload |> get_in(["push", "changes"]) |> Enum.at(0) |> Map.get("new")
tag_name = Map.get(change, "name")
target = Map.get(change, "target")
repo_name = payload |> Map.get("repository") |> Map.get("name")
owner = payload |> get_in(["repository", "workspace", "slug"])
author = get_in(target, ["author", "user", "nickname"])

%{
branch_name: "refs/tags/" <> tag_name,
git_ref: "refs/tags/" <> tag_name,
display_name: tag_name,
owner: owner,
repo_name: repo_name,
commit_sha: Map.get(target, "hash"),
commit_message: Map.get(target, "message"),
commit_author: author,
pr_name: "",
pr_number: 0
}
extract_tag_data_(payload, change)
end

def extract_data(payload, "branch", "deleted") do
change = payload |> get_in(["push", "changes"]) |> Enum.at(0) |> Map.get("old")

extract_data_(payload, change)
extract_branch_data_(payload, change)
end

def extract_data(payload, "branch", _action_type) do
change = payload |> get_in(["push", "changes"]) |> Enum.at(0) |> Map.get("new")

extract_data_(payload, change)
extract_branch_data_(payload, change)
end

defp extract_data_(payload, change) do
defp extract_branch_data_(payload, change) do
branch_name = Map.get(change, "name")
target = Map.get(change, "target")
repo_name = payload |> Map.get("repository") |> Map.get("name")
Expand All @@ -105,6 +93,30 @@ defmodule HooksProcessor.Hooks.Payload.Bitbucket do
}
end

defp extract_tag_data_(payload, change) do
tag_name = Map.get(change, "name")
target = Map.get(change, "target")
repo_name = payload |> Map.get("repository") |> Map.get("name")
owner = payload |> get_in(["repository", "workspace", "slug"])

author =
get_in(target, ["author", "user", "nickname"]) ||
get_in(payload, ["actor", "nickname"])

%{
branch_name: "refs/tags/" <> tag_name,
git_ref: "refs/tags/" <> tag_name,
display_name: tag_name,
owner: owner,
repo_name: repo_name,
commit_sha: Map.get(target, "hash"),
commit_message: Map.get(target, "message"),
commit_author: author,
pr_name: "",
pr_number: 0
}
end

@doc """
Extracts from payload provider's id of requester
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,14 @@ defmodule HooksProcessor.Hooks.Processing.BitbucketWorker do
end

defp process_webhook("tag", webhook, repository, requester_id) do
with parsed_data <- BBPayload.extract_data(webhook.request, "tag", "push"),
with action_type <- BBPayload.branch_action(webhook.request),
parsed_data <- BBPayload.extract_data(webhook.request, "tag", action_type),
parsed_data <- Map.put(parsed_data, :yml_file, repository.pipeline_file),
parsed_data <- Map.put(parsed_data, :requester_id, requester_id),
parsed_data <- Map.put(parsed_data, :provider, "bitbucket"),
{:skip_ci, false} <- BBPayload.skip_ci_flag?(parsed_data),
{:build, true} <- should_build?(repository, parsed_data, :TAGS) do
perform_actions(webhook, parsed_data, "tag", "new")
perform_actions(webhook, parsed_data, "tag", action_type)
else
{:skip_ci, true, parsed_data} ->
HooksQueries.update_webhook(webhook, parsed_data, "skip_ci")
Expand Down Expand Up @@ -108,7 +109,7 @@ defmodule HooksProcessor.Hooks.Processing.BitbucketWorker do
schedule_workflow(webhook, parsed_data)
end

defp perform_actions(webhook, parsed_data, "branch", "deleted") do
defp perform_actions(webhook, parsed_data, hook_type, "deleted") when hook_type in ["branch", "tag"] do
update_to_deleting_branch(webhook, parsed_data)
end

Expand Down
31 changes: 28 additions & 3 deletions hooks_processor/test/hooks/payload/bitbucket_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ defmodule HooksProcessor.Hooks.Payload.BitbucketTest do

tag_hooks = [
BitbucketHooks.push_annoted_tag(),
BitbucketHooks.push_lightweight_tag()
BitbucketHooks.push_lightweight_tag(),
BitbucketHooks.tag_deletion()
]

tag_hooks
Expand All @@ -48,7 +49,9 @@ defmodule HooksProcessor.Hooks.Payload.BitbucketTest do
test "branch_action() returns proper action type for all types of hooks" do
branch_hooks = [
BitbucketHooks.push_new_branch_with_commits(),
BitbucketHooks.push_new_branch_no_commits()
BitbucketHooks.push_new_branch_no_commits(),
BitbucketHooks.push_annoted_tag(),
BitbucketHooks.push_lightweight_tag()
]

branch_hooks
Expand All @@ -66,7 +69,15 @@ defmodule HooksProcessor.Hooks.Payload.BitbucketTest do
assert BBPayload.branch_action(hook) == "push"
end)

assert BitbucketHooks.branch_deletion() |> BBPayload.branch_action() == "deleted"
branch_hooks = [
BitbucketHooks.branch_deletion(),
BitbucketHooks.tag_deletion()
]

branch_hooks
|> Enum.each(fn hook ->
assert BBPayload.branch_action(hook) == "deleted"
end)
end

test "extract_data() returns valid data set for each type of the hook" do
Expand Down Expand Up @@ -96,6 +107,18 @@ defmodule HooksProcessor.Hooks.Payload.BitbucketTest do
assert data.pr_name == ""
assert data.pr_number == 0

data = BitbucketHooks.tag_deletion() |> BBPayload.extract_data("tag", "deleted")
assert data.branch_name == "refs/tags/v1.0-alpha"
assert data.git_ref == "refs/tags/v1.0-alpha"
assert data.display_name == "v1.0-alpha"
assert data.owner == "fake-test-user-1234"
assert data.repo_name == "fake-test-repo-2025"
assert data.commit_sha == "86efd1e2f788d237a9b8d6da5c04683d289ad805"
assert data.commit_message == "README.md created online with Bitbucket"
assert data.commit_author == "fake-test-user-1234"
assert data.pr_name == ""
assert data.pr_number == 0

# Branches

data = BitbucketHooks.push_new_branch_with_commits() |> BBPayload.extract_data("branch", "new")
Expand Down Expand Up @@ -194,6 +217,8 @@ defmodule HooksProcessor.Hooks.Payload.BitbucketTest do
assert BBPayload.extract_actor_id(BitbucketHooks.push_lightweight_tag()) ==
"{53c5afd4-936e-4ded-9b8a-398f527a33c9}"

assert BBPayload.extract_actor_id(BitbucketHooks.tag_deletion()) == "{00000000-6000-4000-9000-000000000012}"

assert BBPayload.extract_actor_id(BitbucketHooks.pull_request_open()) == "{53c5afd4-936e-4ded-9b8a-398f527a33c9}"
assert BBPayload.extract_actor_id(BitbucketHooks.pull_request_closed()) == "{53c5afd4-936e-4ded-9b8a-398f527a33c9}"
end
Expand Down
78 changes: 78 additions & 0 deletions hooks_processor/test/hooks/processing/bitbucket_worker_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,84 @@ defmodule HooksProcessor.Hooks.Processing.BitbucketWorkerTest do
GrpcMock.verify!(WorkflowServiceMock)
end

test "valid tag-deleted hook => tag is archived" do
params = %{
received_at: DateTime.utc_now(),
webhook: BitbucketHooks.tag_deletion(),
repository_id: UUID.uuid4(),
project_id: UUID.uuid4(),
organization_id: UUID.uuid4(),
provider: "bitbucket"
}

assert {:ok, webhook} = HooksQueries.insert(params)

# setup mocks

ProjectHubServiceMock
|> GrpcMock.expect(:describe, fn req, _ ->
assert req.id == webhook.project_id

%Projecthub.DescribeResponse{
project: %{
metadata: %{
id: req.id,
org_id: UUID.uuid4()
},
spec: %{
repository: %{
pipeline_file: ".semaphore/semaphore.yml",
run_on: [:BRANCHES, :TAGS],
whitelist: %{tags: ["/v1.*/", "/release-.*/"]}
}
}
},
metadata: %{status: %{code: :OK}}
}
end)

AdminServiceMock
|> GrpcMock.expect(:terminate_all, fn req, _ ->
assert req.project_id == webhook.project_id
assert req.branch_name == "refs/tags/v1.0-alpha"
assert req.reason == :BRANCH_DELETION

%TerminateAllResponse{response_status: %{code: :OK}}
end)

BranchServiceMock
|> GrpcMock.expect(:describe, fn req, _ ->
assert req.project_id == webhook.project_id
assert req.branch_name == "refs/tags/v1.0-alpha"

%DescribeResponse{branch: %{id: webhook.id, name: "refs/tags/v1.0-alpha"}, status: %{code: :OK}}
end)
|> GrpcMock.expect(:archive, fn req, _ ->
assert req.branch_id == webhook.id

%ArchiveResponse{status: %{code: :OK, message: "Success"}}
end)

# wait for worker to finish and check results

assert {:ok, pid} = WorkersSupervisor.start_worker_for_webhook(webhook.id)

Test.Helpers.wait_for_worker_to_finish(pid, 15_000)

assert {:ok, webhook} = HooksQueries.get_by_id(webhook.id)
assert webhook.state == "deleting_branch"
assert webhook.result == "OK"
assert webhook.wf_id == nil
assert webhook.ppl_id == nil
assert webhook.branch_id == webhook.id
assert webhook.commit_sha == "86efd1e2f788d237a9b8d6da5c04683d289ad805"
assert webhook.commit_author == "fake-test-user-1234"
assert webhook.git_ref == "refs/tags/v1.0-alpha"

GrpcMock.verify!(ProjectHubServiceMock)
GrpcMock.verify!(BranchServiceMock)
end

test "[skip ci] flag in branch-push hook => hook in skip_ci state" do
params = %{
received_at: DateTime.utc_now(),
Expand Down
Loading