{"id":22153476,"url":"https://github.com/phil65/githarbor","last_synced_at":"2025-07-26T05:32:47.532Z","repository":{"id":262537669,"uuid":"887600518","full_name":"phil65/githarbor","owner":"phil65","description":"Wrapper for repository APIs of different Hosters (GitHub, GitLab, ...)","archived":false,"fork":false,"pushed_at":"2025-04-28T04:31:41.000Z","size":325,"stargazers_count":1,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-28T12:56:59.578Z","etag":null,"topics":["api","bitbucket","git","github","gitlab","repository","wrapper","wrapper-api","wrapper-library"],"latest_commit_sha":null,"homepage":"https://github.io/phil/githarbor","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/phil65.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"phil65","custom":["https://www.paypal.me/phil65"]}},"created_at":"2024-11-13T00:36:06.000Z","updated_at":"2025-04-22T05:08:03.000Z","dependencies_parsed_at":null,"dependency_job_id":"a32142cb-4de5-40b1-9941-c50c0d0646c6","html_url":"https://github.com/phil65/githarbor","commit_stats":null,"previous_names":["phil65/githarbor"],"tags_count":24,"template":false,"template_full_name":null,"purl":"pkg:github/phil65/githarbor","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phil65%2Fgitharbor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phil65%2Fgitharbor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phil65%2Fgitharbor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phil65%2Fgitharbor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/phil65","download_url":"https://codeload.github.com/phil65/githarbor/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phil65%2Fgitharbor/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267123516,"owners_count":24039457,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-26T02:00:08.937Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","bitbucket","git","github","gitlab","repository","wrapper","wrapper-api","wrapper-library"],"created_at":"2024-12-02T01:19:59.563Z","updated_at":"2025-07-26T05:32:47.525Z","avatar_url":"https://github.com/phil65.png","language":"Python","funding_links":["https://github.com/sponsors/phil65","https://www.paypal.me/phil65"],"categories":[],"sub_categories":[],"readme":"# GitHarbor\n\n[![PyPI License](https://img.shields.io/pypi/l/githarbor.svg)](https://pypi.org/project/githarbor/)\n[![Package status](https://img.shields.io/pypi/status/githarbor.svg)](https://pypi.org/project/githarbor/)\n[![Daily downloads](https://img.shields.io/pypi/dd/githarbor.svg)](https://pypi.org/project/githarbor/)\n[![Weekly downloads](https://img.shields.io/pypi/dw/githarbor.svg)](https://pypi.org/project/githarbor/)\n[![Monthly downloads](https://img.shields.io/pypi/dm/githarbor.svg)](https://pypi.org/project/githarbor/)\n[![Distribution format](https://img.shields.io/pypi/format/githarbor.svg)](https://pypi.org/project/githarbor/)\n[![Wheel availability](https://img.shields.io/pypi/wheel/githarbor.svg)](https://pypi.org/project/githarbor/)\n[![Python version](https://img.shields.io/pypi/pyversions/githarbor.svg)](https://pypi.org/project/githarbor/)\n[![Implementation](https://img.shields.io/pypi/implementation/githarbor.svg)](https://pypi.org/project/githarbor/)\n[![Releases](https://img.shields.io/github/downloads/phil65/githarbor/total.svg)](https://github.com/phil65/githarbor/releases)\n[![Github Contributors](https://img.shields.io/github/contributors/phil65/githarbor)](https://github.com/phil65/githarbor/graphs/contributors)\n[![Github Discussions](https://img.shields.io/github/discussions/phil65/githarbor)](https://github.com/phil65/githarbor/discussions)\n[![Github Forks](https://img.shields.io/github/forks/phil65/githarbor)](https://github.com/phil65/githarbor/forks)\n[![Github Issues](https://img.shields.io/github/issues/phil65/githarbor)](https://github.com/phil65/githarbor/issues)\n[![Github Issues](https://img.shields.io/github/issues-pr/phil65/githarbor)](https://github.com/phil65/githarbor/pulls)\n[![Github Watchers](https://img.shields.io/github/watchers/phil65/githarbor)](https://github.com/phil65/githarbor/watchers)\n[![Github Stars](https://img.shields.io/github/stars/phil65/githarbor)](https://github.com/phil65/githarbor/stars)\n[![Github Repository size](https://img.shields.io/github/repo-size/phil65/githarbor)](https://github.com/phil65/githarbor)\n[![Github last commit](https://img.shields.io/github/last-commit/phil65/githarbor)](https://github.com/phil65/githarbor/commits)\n[![Github release date](https://img.shields.io/github/release-date/phil65/githarbor)](https://github.com/phil65/githarbor/releases)\n[![Github language count](https://img.shields.io/github/languages/count/phil65/githarbor)](https://github.com/phil65/githarbor)\n[![Github commits this week](https://img.shields.io/github/commit-activity/w/phil65/githarbor)](https://github.com/phil65/githarbor)\n[![Github commits this month](https://img.shields.io/github/commit-activity/m/phil65/githarbor)](https://github.com/phil65/githarbor)\n[![Github commits this year](https://img.shields.io/github/commit-activity/y/phil65/githarbor)](https://github.com/phil65/githarbor)\n[![Package status](https://codecov.io/gh/phil65/githarbor/branch/main/graph/badge.svg)](https://codecov.io/gh/phil65/githarbor/)\n[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)\n[![PyUp](https://pyup.io/repos/github/phil65/githarbor/shield.svg)](https://pyup.io/repos/github/phil65/githarbor/)\n\n[Read the documentation!](https://phil65.github.io/githarbor/)\n\n# GitHarbor User Guide\n\nGitHarbor is a unified interface for interacting with Git hosting platforms. It provides a consistent API to work with repositories hosted on [GitHub](https://github.com), [GitLab](https://gitlab.com), [Azure DevOps](https://azure.microsoft.com/products/devops), [Gitea](https://gitea.io), [CodeBerg](https://codeberg.org) and [Bitbucket](https://bitbucket.org).\n\n## Getting Started\n\nThe main entry point is the `create_repository()` function which accepts a repository URL and platform-specific credentials:\n\n```python\nfrom githarbor import create_repository\n\n# GitHub repository\nrepo = create_repository(\"https://github.com/owner/repo\", token=\"github_pat_...\")\n\n# GitLab repository\nrepo = create_repository(\"https://gitlab.com/owner/repo\", token=\"glpat-...\")\n\n# Azure DevOps repository\nrepo = create_repository(\n    \"https://dev.azure.com/org/project/_git/repo\",\n    token=\"azure_pat\"\n)\n```\n\n\u003e [!TIP]\n\u003e Always use personal access tokens (PATs) for authentication. Never hardcode tokens in your source code.\n\n## Working with Repositories\n\n### Basic Repository Information\n\n```python\n# Get repository name and default branch\nprint(repo.name)\nprint(repo.default_branch)\n\n# Get language statistics\nlanguages = repo.get_languages()\n# Returns: {\"Python\": 10000, \"JavaScript\": 5000}\n\n# Get recent activity statistics\nactivity = repo.get_recent_activity(\n    days=30,\n    include_commits=True,\n    include_prs=True,\n    include_issues=True\n)\n```\n\n### Branches and Tags\n\n```python\n# List all branches\nbranches = repo.list_branches()\n\n# Get specific branch\nmain_branch = repo.get_branch(\"main\")\n\n# List all tags\ntags = repo.list_tags()\n\n# Get specific tag\ntag = repo.get_tag(\"v1.0.0\")\n\n# Compare branches\ndiff = repo.compare_branches(\n    base=\"main\",\n    head=\"feature\",\n    include_commits=True,\n    include_files=True,\n    include_stats=True\n)\n```\n\n### Commits\n\n```python\n# Get specific commit\ncommit = repo.get_commit(\"abcd1234\")\n\n# List commits with filters\ncommits = repo.list_commits(\n    branch=\"main\",\n    since=datetime(2024, 1, 1),\n    until=datetime(2024, 2, 1),\n    author=\"username\",\n    path=\"src/\",\n    max_results=100\n)\n\n# Search commits\nresults = repo.search_commits(\n    query=\"fix bug\",\n    branch=\"main\",\n    path=\"src/\",\n    max_results=10\n)\n```\n\n### Issues and Pull Requests\n\n```python\n# List open issues\nopen_issues = repo.list_issues(state=\"open\")\n\n# Get specific issue\nissue = repo.get_issue(123)\n\n# List pull requests\nprs = repo.list_pull_requests(state=\"open\")  # or \"closed\" or \"all\"\n\n# Get specific pull request\npr = repo.get_pull_request(456)\n```\n\n### Releases\n\n```python\n# Get latest release\nlatest = repo.get_latest_release(\n    include_drafts=False,\n    include_prereleases=False\n)\n\n# List all releases\nreleases = repo.list_releases(\n    include_drafts=False,\n    include_prereleases=True,\n    limit=10\n)\n\n# Get specific release\nrelease = repo.get_release(\"v1.0.0\")\n```\n\n### Repository Content\n\n```python\n# Download single file\nrepo.download(\n    path=\"README.md\",\n    destination=\"local/README.md\"\n)\n\n# Download directory recursively\nrepo.download(\n    path=\"src/\",\n    destination=\"local/src\",\n    recursive=True\n)\n\n# Iterate through files\nfor file_path in repo.iter_files(\n    path=\"src/\",\n    ref=\"main\",\n    pattern=\"*.py\"\n):\n    print(file_path)\n```\n\n### CI/CD Workflows\n\n```python\n# List all workflows\nworkflows = repo.list_workflows()\n\n# Get specific workflow\nworkflow = repo.get_workflow(\"workflow_id\")\n\n# Get specific workflow run\nrun = repo.get_workflow_run(\"run_id\")\n```\n\n### Contributors\n\n```python\n# Get repository contributors\ncontributors = repo.get_contributors(\n    sort_by=\"commits\",  # or \"name\" or \"date\"\n    limit=10\n)\n```\n\n## Error Handling\n\nGitHarbor provides specific exceptions for different error cases:\n\n```python\nfrom githarbor.exceptions import (\n    RepositoryNotFoundError,\n    ResourceNotFoundError,\n    FeatureNotSupportedError\n)\n\ntry:\n    repo = create_repository(\"https://github.com/nonexistent/repo\")\nexcept RepositoryNotFoundError:\n    print(\"Repository does not exist\")\n\ntry:\n    issue = repo.get_issue(999999)\nexcept ResourceNotFoundError:\n    print(\"Issue does not exist\")\n\ntry:\n    repo.some_unsupported_method()\nexcept FeatureNotSupportedError:\n    print(\"This feature is not supported by this repository provider\")\n```\n\n\u003e [!NOTE]\n\u003e Not all features are supported by all platforms. Operations that aren't supported will raise `FeatureNotSupportedError`.\n\n\u003e [!IMPORTANT]\n\u003e Be mindful of API rate limits when making many requests. Consider implementing retries and delays in your code.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphil65%2Fgitharbor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphil65%2Fgitharbor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphil65%2Fgitharbor/lists"}