Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
adding README.md and unit tests
  • Loading branch information
abikouo authored and Qalthos committed Apr 5, 2023
commit 8c20b094a6907be74631b19ef91046f4ca8810b0
53 changes: 53 additions & 0 deletions .github/actions/checkout_repository/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Checkout_repository

This action checks-out your repository under the specified destination directory using the action actions/checkout. Use the `depends-On: repository/pull/xx` to override the reference to checkout.

# Usage

<!-- start usage -->

```yaml
- uses: ansible-network/github_actions/.github/actions/checkout_repository@main
with:
# Repository name with owner. For example, ansible-collections/kubernetes.core
repository: ""

# The branch, tag, or SHA to checkout when the pull request body does not
# contain any override for this repository.
ref: ""

# Relative path under $GITHUB_WORKSPACE to place the repository
path: ""
```

<!-- end usage -->

# Depending on others PRs

The pull request body should contain the following sequence:

```
Depends-On: repository/pull/xx
```

# Scenarios

- [checkout pull request 12345 from repository my_org/my_collection](#Checkout-depending-pull-request)

## Checkout depending pull request

Github action step:

```yaml
- uses: ansible-network/github_actions/.github/actions/checkout_repository@main
with:
repository: my_org/my_collection
ref: main
path: /path/to/checkout/repository
```

Pull request body:

```text
Depends-On: https://github.com/my_org/my_collection/pull/12345
```
10 changes: 3 additions & 7 deletions .github/actions/checkout_repository/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,10 @@ inputs:
description: |
The default branch, tag or SHA to checkout.
required: true
destination_directory:
path:
description: |
Path where repositories will be checkout
required: true
pull_request_body:
description: "Pull request body used to override version to checkout"
required: false
default: ${{ github.event.pull_request.body }}
runs:
using: composite
steps:
Expand All @@ -37,7 +33,7 @@ runs:
run: |
python ${{ github.action_path }}/resolve_dependency.py
env:
RESOLVE_REF_PR_BODY: ${{ inputs.pull_request_body }}
RESOLVE_REF_PR_BODY: ${{ github.event.pull_request.body }}
RESOLVE_REF_REPOSITORY: ${{ inputs.repository }}

- name: display merge commit sha from dependency resolution
Expand All @@ -48,6 +44,6 @@ runs:
uses: actions/checkout@v3
with:
repository: ${{ inputs.repository }}
path: ${{ inputs.destination_directory }}
path: ${{ inputs.path }}
ref: ${{ steps.dependency-resolution.outputs.merge_commit_sha || inputs.ref }}
fetch-depth: "0"
14 changes: 7 additions & 7 deletions .github/actions/checkout_repository/resolve_dependency.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import os
import re
import sys
from typing import Any

from github import Github

Expand All @@ -14,7 +13,7 @@
logger.setLevel(logging.DEBUG)


def get_pr_merge_commit_sha(repository: str, pr_number: int) -> Any:
def get_pr_merge_commit_sha(repository: str, pr_number: int) -> str:
access_token = os.environ.get("GITHUB_TOKEN")
gh_obj = Github(access_token)
repo = gh_obj.get_repo(repository)
Expand All @@ -34,8 +33,8 @@ def resolve_ref(pr_body: str, repository: str) -> int:
re.MULTILINE | re.IGNORECASE,
)
# Search for expression starting with depends-on not case-sensitive
match = pr_regx.findall(pr_body)
return int(match[0]) if match else 0
match = pr_regx.search(pr_body)
return int(match.group(1)) if match else 0


def main() -> None:
Expand All @@ -55,9 +54,10 @@ def main() -> None:
logger.info(
"merge commit sha for pull request %d => '%s'", pr_number, merge_commit_sha
)
gh_output = str(os.environ.get("GITHUB_OUTPUT"))
with open(gh_output, "a", encoding="utf-8") as file_handler:
file_handler.write(f"merge_commit_sha={merge_commit_sha}\n")
github_output = os.environ.get("GITHUB_OUTPUT")
if github_output:
with open(str(github_output), "a", encoding="utf-8") as file_handler:
file_handler.write(f"merge_commit_sha={merge_commit_sha}\n")


if __name__ == "__main__":
Expand Down
123 changes: 123 additions & 0 deletions .github/actions/checkout_repository/test_resolve_dependency.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#!/usr/bin/env python3

import pytest
import os
import string
from random import choice
from unittest.mock import MagicMock, patch

from resolve_dependency import (
get_pr_merge_commit_sha,
resolve_ref,
main
)


@pytest.mark.parametrize(
"pr_body,match",
[
("Depends-On: https://github.com/my_org/my_collection/pull/12345", True),
(
"Depends-On: https://github.com/my_org/my_collection/pull/12345\n"\
"Depends-On: https://github.com/my_org/my_collection/pull/67890",
True,
),
(
"Depends-On: https://github.com/another_org/my_collection/pull/4000\n"\
"Depends-On: https://github.com/my_org/my_collection/pull/12345",
True,
),
(
"Depends-On: https://github.com/my_org/my_collection/pull/12345\n"\
"Depends-On: https://github.com/my_org/my_collection/pull/67890",
True,
),
("Depends-On: https://github.com/another_org/my_collection/pull/12345", False),
("Depends-On: https://github.com/my_org/my_collection2/pull/12345", False),
("Depends-On: https://github.com/my_org/my_collection/pull", False),
]
)
def test_resolve_ref(pr_body, match):

expected = 12345 if match else 0
assert resolve_ref(pr_body, "my_org/my_collection") == expected


class FakePullRequest(object):

def __init__(self, mergeable):
self.mergeable = mergeable
self.merge_commit_sha = self.generate_commit_sha()

@staticmethod
def generate_commit_sha(length=16):
data = string.ascii_letters + string.digits
return "".join([choice(data) for _ in range(length)])


@pytest.mark.parametrize("mergeable", [True, False])
@patch("resolve_dependency.Github")
def test_get_pr_merge_commit_sha(m_Github, mergeable):

m_github_obj = MagicMock()
m_Github.return_value = m_github_obj

os.environ["GITHUB_TOKEN"] = "unittest_github_token"

m_github_repo = MagicMock()
m_github_obj.get_repo = MagicMock()
m_github_obj.get_repo.return_value = m_github_repo

local_pr = FakePullRequest(mergeable=mergeable)
m_github_repo.get_pull = MagicMock()
m_github_repo.get_pull.return_value = local_pr

repository = "my_testing_repository"
pr_number = 12345

if mergeable:
assert get_pr_merge_commit_sha(repository, pr_number) == local_pr.merge_commit_sha
else:
with pytest.raises(ValueError):
get_pr_merge_commit_sha(repository, pr_number)

m_Github.assert_called_once_with("unittest_github_token")
m_github_obj.get_repo.assert_called_once_with(repository)
m_github_repo.get_pull.assert_called_once_with(pr_number)


@pytest.mark.parametrize("repository", [True, False])
@pytest.mark.parametrize("resolve_ref_pr", [0, 1])
@patch("resolve_dependency.get_pr_merge_commit_sha")
@patch("resolve_dependency.resolve_ref")
def test_main(m_resolve_ref, m_get_pr_merge_commit_sha, repository, resolve_ref_pr, tmp_path):

pr_body = "My pull request body - this is a sample for unit tests"
repository_name = "my_test_repository"
os.environ["RESOLVE_REF_PR_BODY"] = pr_body

gh_output_file = tmp_path / "github_output.txt"
env_update = {"GITHUB_OUTPUT": str(gh_output_file)}
if repository:
env_update.update({"RESOLVE_REF_REPOSITORY": repository_name})

m_resolve_ref.return_value = resolve_ref_pr
merge_commit_sha = FakePullRequest.generate_commit_sha()
m_get_pr_merge_commit_sha.return_value = merge_commit_sha

with patch.dict(os.environ, env_update):
main()

if not repository:
m_resolve_ref.assert_not_called()
m_get_pr_merge_commit_sha.assert_not_called()
assert not gh_output_file.exists()
elif not resolve_ref_pr:
m_resolve_ref.assert_called_once_with(pr_body, repository_name)
m_get_pr_merge_commit_sha.assert_not_called()
assert not gh_output_file.exists()
else:
m_resolve_ref.assert_called_once_with(pr_body, repository_name)
m_get_pr_merge_commit_sha.assert_called_once_with(repository_name, resolve_ref_pr)
assert gh_output_file.exists()
# gh_output_file.read_text() == f"merge_commit_sha={merge_commit_sha}\n"
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*__pycache__/
*.py[cod]
*$py.class

Expand Down
11 changes: 11 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ repos:
- id: mypy
additional_dependencies:
- types-PyYAML
- pygithub

- repo: https://github.com/pycqa/pylint
rev: v3.0.0a6
Expand All @@ -70,3 +71,13 @@ repos:
additional_dependencies:
- PyYAML
- pygithub

- repo: local
hooks:
- id: pytest-check
name: pytest-check
entry: pytest .github scripts -vvvv
types: [python]
language: system
pass_filenames: false
always_run: true