├── .copier-answers.yml ├── .editorconfig ├── .github └── workflows │ ├── pre-commit.yml │ ├── stale.yml │ └── test.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .pylintrc ├── .pylintrc-mandatory ├── .ruff.toml ├── LICENSE ├── README.md ├── checklog-odoo.cfg ├── eslint.config.cjs ├── github_connector ├── README.rst ├── __init__.py ├── __manifest__.py ├── data │ ├── ir_config_parameter.xml │ └── ir_cron.xml ├── demo │ ├── github_analysis_rule_demo.xml │ ├── github_analysis_rule_group_demo.xml │ ├── github_organization.xml │ └── github_organization_serie.xml ├── i18n │ ├── es.po │ ├── github_connector.pot │ └── it.po ├── models │ ├── __init__.py │ ├── abstract_github_model.py │ ├── github_analysis_rule.py │ ├── github_analysis_rule_group.py │ ├── github_analysis_rule_info.py │ ├── github_organization.py │ ├── github_organization_serie.py │ ├── github_repository.py │ ├── github_repository_branch.py │ ├── github_team.py │ ├── github_team_partner.py │ ├── github_team_repository.py │ └── res_partner.py ├── pyproject.toml ├── readme │ ├── CONFIGURE.md │ ├── CONTRIBUTORS.md │ ├── DESCRIPTION.md │ ├── INSTALL.md │ ├── ROADMAP.md │ └── USAGE.md ├── report │ ├── __init__.py │ ├── github_repository_branch_rule_info_report.py │ └── github_repository_branch_rule_info_report_view.xml ├── security │ ├── ir.model.access.csv │ ├── ir_model_category.xml │ └── res_groups.xml ├── static │ ├── description │ │ ├── github_organization_external_services.png │ │ ├── github_organization_kanban.png │ │ ├── github_organization_series.png │ │ ├── github_organization_sync_buttons.png │ │ ├── github_repository_branch_kanban.png │ │ ├── github_repository_branch_list.png │ │ ├── github_repository_branch_rule_info_report.png │ │ ├── github_repository_kanban.png │ │ ├── github_settings.png │ │ ├── github_team_kanban.png │ │ ├── github_team_partner_kanban.png │ │ ├── github_team_repository_kanban.png │ │ ├── icon.png │ │ ├── icon.svg │ │ ├── index.html │ │ ├── reporting_branches_by_serie.png │ │ ├── reporting_sizes_by_serie.png │ │ ├── sync_organization.png │ │ ├── wizard_create_repository.png │ │ ├── wizard_create_team.png │ │ └── wizard_download_analyze.png │ └── src │ │ └── img │ │ └── default_github_organization.png ├── tests │ ├── __init__.py │ ├── common.py │ ├── res │ │ ├── github_repo_20558462_response.json │ │ ├── github_repo_70173147_response.json │ │ ├── github_search_issues_response.json │ │ └── github_user_OCA-git-bot_response.json │ ├── test_github_analysis_rule.py │ └── test_github_connector.py ├── views │ ├── action.xml │ ├── menu.xml │ ├── view_github_analysis_rule.xml │ ├── view_github_analysis_rule_group.xml │ ├── view_github_organization.xml │ ├── view_github_repository.xml │ ├── view_github_repository_branch.xml │ ├── view_github_team.xml │ ├── view_github_team_partner.xml │ ├── view_github_team_repository.xml │ ├── view_reporting.xml │ └── view_res_partner.xml └── wizards │ ├── __init__.py │ ├── view_wizard_create_repository.xml │ ├── view_wizard_create_team.xml │ ├── view_wizard_load_github_model.xml │ ├── wizard_create_repository.py │ ├── wizard_create_team.py │ └── wizard_load_github_model.py ├── github_connector_odoo ├── README.rst ├── __init__.py ├── __manifest__.py ├── data │ ├── function.xml │ ├── ir_cron.xml │ ├── oca.png │ ├── odoo_category_data.xml │ ├── odoo_licence.xml │ └── odoo_manifest_key_data.xml ├── demo │ ├── github_analysis_rule_demo.xml │ ├── github_analysis_rule_group_demo.xml │ └── github_organization.xml ├── i18n │ ├── es.po │ ├── github_connector_odoo.pot │ └── it.po ├── models │ ├── __init__.py │ ├── abstract_action_mixin.py │ ├── github_analysis_rule.py │ ├── github_organization.py │ ├── github_repository.py │ ├── github_repository_branch.py │ ├── odoo_author.py │ ├── odoo_category.py │ ├── odoo_lib_bin.py │ ├── odoo_lib_python.py │ ├── odoo_license.py │ ├── odoo_manifest_key.py │ ├── odoo_module.py │ └── odoo_module_version.py ├── monkeypatching.py ├── pyproject.toml ├── readme │ ├── CONFIGURE.md │ ├── CONTRIBUTORS.md │ ├── DESCRIPTION.md │ ├── ROADMAP.md │ └── USAGE.md ├── report │ ├── __init__.py │ ├── odoo_module_version_rule_info_report.py │ └── odoo_module_version_rule_info_report_view.xml ├── security │ └── ir.model.access.csv ├── static │ ├── description │ │ ├── github_organization_form.png │ │ ├── icon.png │ │ ├── index.html │ │ ├── menu.png │ │ ├── odoo_author.png │ │ ├── odoo_bin_libs.png │ │ ├── odoo_license.png │ │ ├── odoo_module_form.png │ │ ├── odoo_module_kanban.png │ │ ├── odoo_python_libs.png │ │ └── reporting_module_by_serie.png │ └── src │ │ └── img │ │ ├── default_image_module.png │ │ ├── default_image_module_version.png │ │ ├── github.png │ │ ├── odoo_licence_agpl_3-image.png │ │ ├── odoo_licence_gpl_3-image.png │ │ └── odoo_licence_lgpl_3-image.png ├── tests │ ├── __init__.py │ ├── res │ │ └── github_maintainer_tools_repos_with_ids.txt │ └── test_github_analysis_rule.py └── views │ ├── action.xml │ ├── menu.xml │ ├── view_github_analysis_rule.xml │ ├── view_github_organization.xml │ ├── view_github_repository.xml │ ├── view_github_repository_branch.xml │ ├── view_odoo_author.xml │ ├── view_odoo_lib_bin.xml │ ├── view_odoo_lib_python.xml │ ├── view_odoo_license.xml │ ├── view_odoo_module.xml │ ├── view_odoo_module_version.xml │ └── view_reporting.xml ├── prettier.config.cjs ├── requirements.txt ├── setup └── _metapackage │ └── pyproject.toml └── test-requirements.txt /.copier-answers.yml: -------------------------------------------------------------------------------- 1 | # Do NOT update manually; changes here will be overwritten by Copier 2 | _commit: v1.29 3 | _src_path: git+https://github.com/OCA/oca-addons-repo-template 4 | additional_ruff_rules: [] 5 | ci: GitHub 6 | convert_readme_fragments_to_markdown: true 7 | enable_checklog_odoo: true 8 | generate_requirements_txt: true 9 | github_check_license: true 10 | github_ci_extra_env: {} 11 | github_enable_codecov: true 12 | github_enable_makepot: true 13 | github_enable_stale_action: true 14 | github_enforce_dev_status_compatibility: true 15 | include_wkhtmltopdf: false 16 | odoo_test_flavor: Both 17 | odoo_version: 18.0 18 | org_name: Odoo Community Association (OCA) 19 | org_slug: OCA 20 | rebel_module_groups: [] 21 | repo_description: interface-github 22 | repo_name: interface-github 23 | repo_slug: interface-github 24 | repo_website: https://github.com/OCA/interface-github 25 | use_pyproject_toml: true 26 | use_ruff: true 27 | 28 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Configuration for known file extensions 2 | [*.{css,js,json,less,md,py,rst,sass,scss,xml,yaml,yml}] 3 | charset = utf-8 4 | end_of_line = lf 5 | indent_size = 4 6 | indent_style = space 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | 10 | [*.{json,yml,yaml,rst,md}] 11 | indent_size = 2 12 | 13 | # Do not configure editor for libs and autogenerated content 14 | [{*/static/{lib,src/lib}/**,*/static/description/index.html,*/readme/../README.rst}] 15 | charset = unset 16 | end_of_line = unset 17 | indent_size = unset 18 | indent_style = unset 19 | insert_final_newline = false 20 | trim_trailing_whitespace = false 21 | -------------------------------------------------------------------------------- /.github/workflows/pre-commit.yml: -------------------------------------------------------------------------------- 1 | name: pre-commit 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - "18.0*" 7 | push: 8 | branches: 9 | - "18.0" 10 | - "18.0-ocabot-*" 11 | 12 | jobs: 13 | pre-commit: 14 | runs-on: ubuntu-22.04 15 | steps: 16 | - uses: actions/checkout@v4 17 | - uses: actions/setup-python@v5 18 | with: 19 | python-version: "3.11" 20 | - name: Get python version 21 | run: echo "PY=$(python -VV | sha256sum | cut -d' ' -f1)" >> $GITHUB_ENV 22 | - uses: actions/cache@v4 23 | with: 24 | path: ~/.cache/pre-commit 25 | key: pre-commit|${{ env.PY }}|${{ hashFiles('.pre-commit-config.yaml') }} 26 | - name: Install pre-commit 27 | run: pip install pre-commit 28 | - name: Run pre-commit 29 | run: pre-commit run --all-files --show-diff-on-failure --color=always 30 | env: 31 | # Consider valid a PR that changes README fragments but doesn't 32 | # change the README.rst file itself. It's not really a problem 33 | # because the bot will update it anyway after merge. This way, we 34 | # lower the barrier for functional contributors that want to fix the 35 | # readme fragments, while still letting developers get README 36 | # auto-generated (which also helps functionals when using runboat). 37 | # DOCS https://pre-commit.com/#temporarily-disabling-hooks 38 | SKIP: oca-gen-addon-readme 39 | - name: Check that all files generated by pre-commit are in git 40 | run: | 41 | newfiles="$(git ls-files --others --exclude-from=.gitignore)" 42 | if [ "$newfiles" != "" ] ; then 43 | echo "Please check-in the following files:" 44 | echo "$newfiles" 45 | exit 1 46 | fi 47 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: Mark stale issues and pull requests 2 | 3 | on: 4 | schedule: 5 | - cron: "0 12 * * 0" 6 | 7 | jobs: 8 | stale: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Stale PRs and issues policy 12 | uses: actions/stale@v9 13 | with: 14 | repo-token: ${{ secrets.GITHUB_TOKEN }} 15 | # General settings. 16 | ascending: true 17 | remove-stale-when-updated: true 18 | # Pull Requests settings. 19 | # 120+30 day stale policy for PRs 20 | # * Except PRs marked as "no stale" 21 | days-before-pr-stale: 120 22 | days-before-pr-close: 30 23 | exempt-pr-labels: "no stale" 24 | stale-pr-label: "stale" 25 | stale-pr-message: > 26 | There hasn't been any activity on this pull request in the past 4 months, so 27 | it has been marked as stale and it will be closed automatically if no 28 | further activity occurs in the next 30 days. 29 | 30 | If you want this PR to never become stale, please ask a PSC member to apply 31 | the "no stale" label. 32 | # Issues settings. 33 | # 180+30 day stale policy for open issues 34 | # * Except Issues marked as "no stale" 35 | days-before-issue-stale: 180 36 | days-before-issue-close: 30 37 | exempt-issue-labels: "no stale,needs more information" 38 | stale-issue-label: "stale" 39 | stale-issue-message: > 40 | There hasn't been any activity on this issue in the past 6 months, so it has 41 | been marked as stale and it will be closed automatically if no further 42 | activity occurs in the next 30 days. 43 | 44 | If you want this issue to never become stale, please ask a PSC member to 45 | apply the "no stale" label. 46 | 47 | # 15+30 day stale policy for issues pending more information 48 | # * Issues that are pending more information 49 | # * Except Issues marked as "no stale" 50 | - name: Needs more information stale issues policy 51 | uses: actions/stale@v9 52 | with: 53 | repo-token: ${{ secrets.GITHUB_TOKEN }} 54 | ascending: true 55 | only-labels: "needs more information" 56 | exempt-issue-labels: "no stale" 57 | days-before-stale: 15 58 | days-before-close: 30 59 | days-before-pr-stale: -1 60 | days-before-pr-close: -1 61 | remove-stale-when-updated: true 62 | stale-issue-label: "stale" 63 | stale-issue-message: > 64 | This issue needs more information and there hasn't been any activity 65 | recently, so it has been marked as stale and it will be closed automatically 66 | if no further activity occurs in the next 30 days. 67 | 68 | If you think this is a mistake, please ask a PSC member to remove the "needs 69 | more information" label. 70 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: tests 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - "18.0*" 7 | push: 8 | branches: 9 | - "18.0" 10 | - "18.0-ocabot-*" 11 | 12 | jobs: 13 | unreleased-deps: 14 | runs-on: ubuntu-latest 15 | name: Detect unreleased dependencies 16 | steps: 17 | - uses: actions/checkout@v4 18 | - run: | 19 | for reqfile in requirements.txt test-requirements.txt ; do 20 | if [ -f ${reqfile} ] ; then 21 | result=0 22 | # reject non-comment lines that contain a / (i.e. URLs, relative paths) 23 | grep "^[^#].*/" ${reqfile} || result=$? 24 | if [ $result -eq 0 ] ; then 25 | echo "Unreleased dependencies found in ${reqfile}." 26 | exit 1 27 | fi 28 | fi 29 | done 30 | test: 31 | runs-on: ubuntu-22.04 32 | container: ${{ matrix.container }} 33 | name: ${{ matrix.name }} 34 | strategy: 35 | fail-fast: false 36 | matrix: 37 | include: 38 | - container: ghcr.io/oca/oca-ci/py3.10-odoo18.0:latest 39 | name: test with Odoo 40 | - container: ghcr.io/oca/oca-ci/py3.10-ocb18.0:latest 41 | name: test with OCB 42 | makepot: "true" 43 | services: 44 | postgres: 45 | image: postgres:12.0 46 | env: 47 | POSTGRES_USER: odoo 48 | POSTGRES_PASSWORD: odoo 49 | POSTGRES_DB: odoo 50 | ports: 51 | - 5432:5432 52 | env: 53 | OCA_ENABLE_CHECKLOG_ODOO: "1" 54 | steps: 55 | - uses: actions/checkout@v4 56 | with: 57 | persist-credentials: false 58 | - name: Install addons and dependencies 59 | run: oca_install_addons 60 | - name: Check licenses 61 | run: manifestoo -d . check-licenses 62 | - name: Check development status 63 | run: manifestoo -d . check-dev-status --default-dev-status=Beta 64 | - name: Initialize test db 65 | run: oca_init_test_database 66 | - name: Run tests 67 | run: oca_run_tests 68 | - uses: codecov/codecov-action@v4 69 | with: 70 | token: ${{ secrets.CODECOV_TOKEN }} 71 | - name: Update .pot files 72 | run: oca_export_and_push_pot https://x-access-token:${{ secrets.GIT_PUSH_TOKEN }}@github.com/${{ github.repository }} 73 | if: ${{ matrix.makepot == 'true' && github.event_name == 'push' && github.repository_owner == 'OCA' }} 74 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | /.venv 5 | /.pytest_cache 6 | /.ruff_cache 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | env/ 14 | bin/ 15 | build/ 16 | develop-eggs/ 17 | dist/ 18 | eggs/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | *.eggs 27 | 28 | # Windows installers 29 | *.msi 30 | 31 | # Debian packages 32 | *.deb 33 | 34 | # Redhat packages 35 | *.rpm 36 | 37 | # MacOS packages 38 | *.dmg 39 | *.pkg 40 | 41 | # Installer logs 42 | pip-log.txt 43 | pip-delete-this-directory.txt 44 | 45 | # Unit test / coverage reports 46 | htmlcov/ 47 | .tox/ 48 | .coverage 49 | .cache 50 | nosetests.xml 51 | coverage.xml 52 | 53 | # Translations 54 | *.mo 55 | 56 | # Pycharm 57 | .idea 58 | 59 | # Eclipse 60 | .settings 61 | 62 | # Visual Studio cache/options directory 63 | .vs/ 64 | .vscode 65 | 66 | # OSX Files 67 | .DS_Store 68 | 69 | # Django stuff: 70 | *.log 71 | 72 | # Mr Developer 73 | .mr.developer.cfg 74 | .project 75 | .pydevproject 76 | 77 | # Rope 78 | .ropeproject 79 | 80 | # Sphinx documentation 81 | docs/_build/ 82 | 83 | # Backup files 84 | *~ 85 | *.swp 86 | 87 | # OCA rules 88 | !static/lib/ 89 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | exclude: | 2 | (?x) 3 | # NOT INSTALLABLE ADDONS 4 | # END NOT INSTALLABLE ADDONS 5 | # Files and folders generated by bots, to avoid loops 6 | ^setup/|/static/description/index\.html$| 7 | # We don't want to mess with tool-generated files 8 | .svg$|/tests/([^/]+/)?cassettes/|^.copier-answers.yml$|^.github/|^eslint.config.cjs|^prettier.config.cjs| 9 | # Maybe reactivate this when all README files include prettier ignore tags? 10 | ^README\.md$| 11 | # Library files can have extraneous formatting (even minimized) 12 | /static/(src/)?lib/| 13 | # Repos using Sphinx to generate docs don't need prettying 14 | ^docs/_templates/.*\.html$| 15 | # Don't bother non-technical authors with formatting issues in docs 16 | readme/.*\.(rst|md)$| 17 | # Ignore build and dist directories in addons 18 | /build/|/dist/| 19 | # Ignore test files in addons 20 | /tests/samples/.*| 21 | # You don't usually want a bot to modify your legal texts 22 | (LICENSE.*|COPYING.*) 23 | default_language_version: 24 | python: python3 25 | node: "22.9.0" 26 | repos: 27 | - repo: local 28 | hooks: 29 | # These files are most likely copier diff rejection junks; if found, 30 | # review them manually, fix the problem (if needed) and remove them 31 | - id: forbidden-files 32 | name: forbidden files 33 | entry: found forbidden files; remove them 34 | language: fail 35 | files: "\\.rej$" 36 | - id: en-po-files 37 | name: en.po files cannot exist 38 | entry: found a en.po file 39 | language: fail 40 | files: '[a-zA-Z0-9_]*/i18n/en\.po$' 41 | - repo: https://github.com/sbidoul/whool 42 | rev: v1.2 43 | hooks: 44 | - id: whool-init 45 | - repo: https://github.com/oca/maintainer-tools 46 | rev: bf9ecb9938b6a5deca0ff3d870fbd3f33341fded 47 | hooks: 48 | # update the NOT INSTALLABLE ADDONS section above 49 | - id: oca-update-pre-commit-excluded-addons 50 | - id: oca-fix-manifest-website 51 | args: ["https://github.com/OCA/interface-github"] 52 | - id: oca-gen-addon-readme 53 | args: 54 | - --addons-dir=. 55 | - --branch=18.0 56 | - --org-name=OCA 57 | - --repo-name=interface-github 58 | - --if-source-changed 59 | - --keep-source-digest 60 | - --convert-fragments-to-markdown 61 | - id: oca-gen-external-dependencies 62 | - repo: https://github.com/OCA/odoo-pre-commit-hooks 63 | rev: v0.0.33 64 | hooks: 65 | - id: oca-checks-odoo-module 66 | - id: oca-checks-po 67 | args: 68 | - --disable=po-pretty-format 69 | - repo: local 70 | hooks: 71 | - id: prettier 72 | name: prettier (with plugin-xml) 73 | entry: prettier 74 | args: 75 | - --write 76 | - --list-different 77 | - --ignore-unknown 78 | types: [text] 79 | files: \.(css|htm|html|js|json|jsx|less|md|scss|toml|ts|xml|yaml|yml)$ 80 | language: node 81 | additional_dependencies: 82 | - "prettier@3.3.3" 83 | - "@prettier/plugin-xml@3.4.1" 84 | - repo: local 85 | hooks: 86 | - id: eslint 87 | name: eslint 88 | entry: eslint 89 | args: 90 | - --color 91 | - --fix 92 | verbose: true 93 | types: [javascript] 94 | language: node 95 | additional_dependencies: 96 | - "eslint@9.12.0" 97 | - "eslint-plugin-jsdoc@50.3.1" 98 | - repo: https://github.com/pre-commit/pre-commit-hooks 99 | rev: v4.6.0 100 | hooks: 101 | - id: trailing-whitespace 102 | # exclude autogenerated files 103 | exclude: /README\.rst$|\.pot?$ 104 | - id: end-of-file-fixer 105 | # exclude autogenerated files 106 | exclude: /README\.rst$|\.pot?$ 107 | - id: debug-statements 108 | - id: fix-encoding-pragma 109 | args: ["--remove"] 110 | - id: check-case-conflict 111 | - id: check-docstring-first 112 | - id: check-executables-have-shebangs 113 | - id: check-merge-conflict 114 | # exclude files where underlines are not distinguishable from merge conflicts 115 | exclude: /README\.rst$|^docs/.*\.rst$ 116 | - id: check-symlinks 117 | - id: check-xml 118 | - id: mixed-line-ending 119 | args: ["--fix=lf"] 120 | - repo: https://github.com/astral-sh/ruff-pre-commit 121 | rev: v0.6.8 122 | hooks: 123 | - id: ruff 124 | args: [--fix, --exit-non-zero-on-fix] 125 | - id: ruff-format 126 | - repo: https://github.com/OCA/pylint-odoo 127 | rev: v9.1.3 128 | hooks: 129 | - id: pylint_odoo 130 | name: pylint with optional checks 131 | args: 132 | - --rcfile=.pylintrc 133 | - --exit-zero 134 | verbose: true 135 | - id: pylint_odoo 136 | args: 137 | - --rcfile=.pylintrc-mandatory 138 | -------------------------------------------------------------------------------- /.pylintrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | [MASTER] 4 | load-plugins=pylint_odoo 5 | score=n 6 | 7 | [ODOOLINT] 8 | readme-template-url="https://github.com/OCA/maintainer-tools/blob/master/template/module/README.rst" 9 | manifest-required-authors=Odoo Community Association (OCA) 10 | manifest-required-keys=license 11 | manifest-deprecated-keys=description,active 12 | license-allowed=AGPL-3,GPL-2,GPL-2 or any later version,GPL-3,GPL-3 or any later version,LGPL-3 13 | valid-odoo-versions=18.0 14 | 15 | [MESSAGES CONTROL] 16 | disable=all 17 | 18 | # This .pylintrc contains optional AND mandatory checks and is meant to be 19 | # loaded in an IDE to have it check everything, in the hope this will make 20 | # optional checks more visible to contributors who otherwise never look at a 21 | # green travis to see optional checks that failed. 22 | # .pylintrc-mandatory containing only mandatory checks is used the pre-commit 23 | # config as a blocking check. 24 | 25 | enable=anomalous-backslash-in-string, 26 | api-one-deprecated, 27 | api-one-multi-together, 28 | assignment-from-none, 29 | attribute-deprecated, 30 | class-camelcase, 31 | dangerous-default-value, 32 | dangerous-view-replace-wo-priority, 33 | development-status-allowed, 34 | duplicate-id-csv, 35 | duplicate-key, 36 | duplicate-xml-fields, 37 | duplicate-xml-record-id, 38 | eval-referenced, 39 | eval-used, 40 | incoherent-interpreter-exec-perm, 41 | license-allowed, 42 | manifest-author-string, 43 | manifest-deprecated-key, 44 | manifest-required-author, 45 | manifest-required-key, 46 | manifest-version-format, 47 | method-compute, 48 | method-inverse, 49 | method-required-super, 50 | method-search, 51 | openerp-exception-warning, 52 | pointless-statement, 53 | pointless-string-statement, 54 | print-used, 55 | redundant-keyword-arg, 56 | redundant-modulename-xml, 57 | reimported, 58 | relative-import, 59 | return-in-init, 60 | rst-syntax-error, 61 | sql-injection, 62 | too-few-format-args, 63 | translation-field, 64 | translation-required, 65 | unreachable, 66 | use-vim-comment, 67 | wrong-tabs-instead-of-spaces, 68 | xml-syntax-error, 69 | attribute-string-redundant, 70 | character-not-valid-in-resource-link, 71 | consider-merging-classes-inherited, 72 | context-overridden, 73 | create-user-wo-reset-password, 74 | dangerous-filter-wo-user, 75 | dangerous-qweb-replace-wo-priority, 76 | deprecated-data-xml-node, 77 | deprecated-openerp-xml-node, 78 | duplicate-po-message-definition, 79 | except-pass, 80 | file-not-used, 81 | invalid-commit, 82 | manifest-maintainers-list, 83 | missing-newline-extrafiles, 84 | missing-readme, 85 | missing-return, 86 | odoo-addons-relative-import, 87 | old-api7-method-defined, 88 | po-msgstr-variables, 89 | po-syntax-error, 90 | renamed-field-parameter, 91 | resource-not-exist, 92 | str-format-used, 93 | test-folder-imported, 94 | translation-contains-variable, 95 | translation-positional-used, 96 | unnecessary-utf8-coding-comment, 97 | website-manifest-key-not-valid-uri, 98 | xml-attribute-translatable, 99 | xml-deprecated-qweb-directive, 100 | xml-deprecated-tree-attribute, 101 | external-request-timeout, 102 | # messages that do not cause the lint step to fail 103 | consider-merging-classes-inherited, 104 | create-user-wo-reset-password, 105 | dangerous-filter-wo-user, 106 | deprecated-module, 107 | file-not-used, 108 | invalid-commit, 109 | missing-manifest-dependency, 110 | missing-newline-extrafiles, 111 | missing-readme, 112 | no-utf8-coding-comment, 113 | odoo-addons-relative-import, 114 | old-api7-method-defined, 115 | redefined-builtin, 116 | too-complex, 117 | unnecessary-utf8-coding-comment 118 | 119 | 120 | [REPORTS] 121 | msg-template={path}:{line}: [{msg_id}({symbol}), {obj}] {msg} 122 | output-format=colorized 123 | reports=no 124 | -------------------------------------------------------------------------------- /.pylintrc-mandatory: -------------------------------------------------------------------------------- 1 | 2 | [MASTER] 3 | load-plugins=pylint_odoo 4 | score=n 5 | 6 | [ODOOLINT] 7 | readme-template-url="https://github.com/OCA/maintainer-tools/blob/master/template/module/README.rst" 8 | manifest-required-authors=Odoo Community Association (OCA) 9 | manifest-required-keys=license 10 | manifest-deprecated-keys=description,active 11 | license-allowed=AGPL-3,GPL-2,GPL-2 or any later version,GPL-3,GPL-3 or any later version,LGPL-3 12 | valid-odoo-versions=18.0 13 | 14 | [MESSAGES CONTROL] 15 | disable=all 16 | 17 | enable=anomalous-backslash-in-string, 18 | api-one-deprecated, 19 | api-one-multi-together, 20 | assignment-from-none, 21 | attribute-deprecated, 22 | class-camelcase, 23 | dangerous-default-value, 24 | dangerous-view-replace-wo-priority, 25 | development-status-allowed, 26 | duplicate-id-csv, 27 | duplicate-key, 28 | duplicate-xml-fields, 29 | duplicate-xml-record-id, 30 | eval-referenced, 31 | eval-used, 32 | incoherent-interpreter-exec-perm, 33 | license-allowed, 34 | manifest-author-string, 35 | manifest-deprecated-key, 36 | manifest-required-author, 37 | manifest-required-key, 38 | manifest-version-format, 39 | method-compute, 40 | method-inverse, 41 | method-required-super, 42 | method-search, 43 | openerp-exception-warning, 44 | pointless-statement, 45 | pointless-string-statement, 46 | print-used, 47 | redundant-keyword-arg, 48 | redundant-modulename-xml, 49 | reimported, 50 | relative-import, 51 | return-in-init, 52 | rst-syntax-error, 53 | sql-injection, 54 | too-few-format-args, 55 | translation-field, 56 | translation-required, 57 | unreachable, 58 | use-vim-comment, 59 | wrong-tabs-instead-of-spaces, 60 | xml-syntax-error, 61 | attribute-string-redundant, 62 | character-not-valid-in-resource-link, 63 | consider-merging-classes-inherited, 64 | context-overridden, 65 | create-user-wo-reset-password, 66 | dangerous-filter-wo-user, 67 | dangerous-qweb-replace-wo-priority, 68 | deprecated-data-xml-node, 69 | deprecated-openerp-xml-node, 70 | duplicate-po-message-definition, 71 | except-pass, 72 | file-not-used, 73 | invalid-commit, 74 | manifest-maintainers-list, 75 | missing-newline-extrafiles, 76 | missing-readme, 77 | missing-return, 78 | odoo-addons-relative-import, 79 | old-api7-method-defined, 80 | po-msgstr-variables, 81 | po-syntax-error, 82 | renamed-field-parameter, 83 | resource-not-exist, 84 | str-format-used, 85 | test-folder-imported, 86 | translation-contains-variable, 87 | translation-positional-used, 88 | unnecessary-utf8-coding-comment, 89 | website-manifest-key-not-valid-uri, 90 | xml-attribute-translatable, 91 | xml-deprecated-qweb-directive, 92 | xml-deprecated-tree-attribute, 93 | external-request-timeout 94 | 95 | [REPORTS] 96 | msg-template={path}:{line}: [{msg_id}({symbol}), {obj}] {msg} 97 | output-format=colorized 98 | reports=no 99 | -------------------------------------------------------------------------------- /.ruff.toml: -------------------------------------------------------------------------------- 1 | 2 | target-version = "py310" 3 | fix = true 4 | 5 | [lint] 6 | extend-select = [ 7 | "B", 8 | "C90", 9 | "E501", # line too long (default 88) 10 | "I", # isort 11 | "UP", # pyupgrade 12 | ] 13 | extend-safe-fixes = ["UP008"] 14 | exclude = ["setup/*"] 15 | 16 | [format] 17 | exclude = ["setup/*"] 18 | 19 | [lint.per-file-ignores] 20 | "__init__.py" = ["F401", "I001"] # ignore unused and unsorted imports in __init__.py 21 | "__manifest__.py" = ["B018"] # useless expression 22 | 23 | [lint.isort] 24 | section-order = ["future", "standard-library", "third-party", "odoo", "odoo-addons", "first-party", "local-folder"] 25 | 26 | [lint.isort.sections] 27 | "odoo" = ["odoo"] 28 | "odoo-addons" = ["odoo.addons"] 29 | 30 | [lint.mccabe] 31 | max-complexity = 16 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | [![Runboat](https://img.shields.io/badge/runboat-Try%20me-875A7B.png)](https://runboat.odoo-community.org/builds?repo=OCA/interface-github&target_branch=18.0) 3 | [![Pre-commit Status](https://github.com/OCA/interface-github/actions/workflows/pre-commit.yml/badge.svg?branch=18.0)](https://github.com/OCA/interface-github/actions/workflows/pre-commit.yml?query=branch%3A18.0) 4 | [![Build Status](https://github.com/OCA/interface-github/actions/workflows/test.yml/badge.svg?branch=18.0)](https://github.com/OCA/interface-github/actions/workflows/test.yml?query=branch%3A18.0) 5 | [![codecov](https://codecov.io/gh/OCA/interface-github/branch/18.0/graph/badge.svg)](https://codecov.io/gh/OCA/interface-github) 6 | [![Translation Status](https://translation.odoo-community.org/widgets/interface-github-18-0/-/svg-badge.svg)](https://translation.odoo-community.org/engage/interface-github-18-0/?utm_source=widget) 7 | 8 | 9 | 10 | # interface-github 11 | 12 | interface-github 13 | 14 | 15 | 16 | 17 | 18 | [//]: # (addons) 19 | 20 | Available addons 21 | ---------------- 22 | addon | version | maintainers | summary 23 | --- | --- | --- | --- 24 | [github_connector](github_connector/) | 18.0.1.0.0 | | Synchronize information from Github repositories 25 | [github_connector_odoo](github_connector_odoo/) | 18.0.1.0.0 | | Analyze Odoo modules information from Github repositories 26 | 27 | [//]: # (end addons) 28 | 29 | 30 | 31 | ## Licenses 32 | 33 | This repository is licensed under [AGPL-3.0](LICENSE). 34 | 35 | However, each module can have a totally different license, as long as they adhere to Odoo Community Association (OCA) 36 | policy. Consult each module's `__manifest__.py` file, which contains a `license` key 37 | that explains its license. 38 | 39 | ---- 40 | OCA, or the [Odoo Community Association](http://odoo-community.org/), is a nonprofit 41 | organization whose mission is to support the collaborative development of Odoo features 42 | and promote its widespread use. 43 | -------------------------------------------------------------------------------- /checklog-odoo.cfg: -------------------------------------------------------------------------------- 1 | [checklog-odoo] 2 | ignore= 3 | WARNING.* 0 failed, 0 error\(s\).* 4 | -------------------------------------------------------------------------------- /eslint.config.cjs: -------------------------------------------------------------------------------- 1 | jsdoc = require("eslint-plugin-jsdoc"); 2 | 3 | const config = [{ 4 | plugins: { 5 | jsdoc, 6 | }, 7 | 8 | languageOptions: { 9 | globals: { 10 | _: "readonly", 11 | $: "readonly", 12 | fuzzy: "readonly", 13 | jQuery: "readonly", 14 | moment: "readonly", 15 | odoo: "readonly", 16 | openerp: "readonly", 17 | owl: "readonly", 18 | luxon: "readonly", 19 | }, 20 | 21 | ecmaVersion: 2024, 22 | sourceType: "script", 23 | }, 24 | 25 | rules: { 26 | "accessor-pairs": "warn", 27 | "array-callback-return": "warn", 28 | "callback-return": "warn", 29 | "capitalized-comments": ["warn", "always", { 30 | ignoreConsecutiveComments: true, 31 | ignoreInlineComments: true, 32 | }], 33 | complexity: ["warn", 15], 34 | "constructor-super": "warn", 35 | "dot-notation": "warn", 36 | eqeqeq: "warn", 37 | "global-require": "warn", 38 | "handle-callback-err": "warn", 39 | "id-blacklist": "warn", 40 | "id-match": "warn", 41 | "init-declarations": "error", 42 | "max-depth": "warn", 43 | "max-nested-callbacks": "warn", 44 | "max-statements-per-line": "warn", 45 | "no-alert": "warn", 46 | "no-array-constructor": "warn", 47 | "no-caller": "warn", 48 | "no-case-declarations": "warn", 49 | "no-class-assign": "warn", 50 | "no-cond-assign": "error", 51 | "no-const-assign": "error", 52 | "no-constant-condition": "warn", 53 | "no-control-regex": "warn", 54 | "no-debugger": "error", 55 | "no-delete-var": "warn", 56 | "no-div-regex": "warn", 57 | "no-dupe-args": "error", 58 | "no-dupe-class-members": "error", 59 | "no-dupe-keys": "error", 60 | "no-duplicate-case": "error", 61 | "no-duplicate-imports": "error", 62 | "no-else-return": "warn", 63 | "no-empty-character-class": "warn", 64 | "no-empty-function": "error", 65 | "no-empty-pattern": "error", 66 | "no-empty": "warn", 67 | "no-eq-null": "error", 68 | "no-eval": "error", 69 | "no-ex-assign": "error", 70 | "no-extend-native": "warn", 71 | "no-extra-bind": "warn", 72 | "no-extra-boolean-cast": "warn", 73 | "no-extra-label": "warn", 74 | "no-fallthrough": "warn", 75 | "no-func-assign": "error", 76 | "no-global-assign": "error", 77 | "no-implicit-coercion": ["warn", { 78 | allow: ["~"], 79 | }], 80 | "no-implicit-globals": "warn", 81 | "no-implied-eval": "warn", 82 | "no-inline-comments": "warn", 83 | "no-inner-declarations": "warn", 84 | "no-invalid-regexp": "warn", 85 | "no-irregular-whitespace": "warn", 86 | "no-iterator": "warn", 87 | "no-label-var": "warn", 88 | "no-labels": "warn", 89 | "no-lone-blocks": "warn", 90 | "no-lonely-if": "error", 91 | "no-mixed-requires": "error", 92 | "no-multi-str": "warn", 93 | "no-native-reassign": "error", 94 | "no-negated-condition": "warn", 95 | "no-negated-in-lhs": "error", 96 | "no-new-func": "warn", 97 | "no-new-object": "warn", 98 | "no-new-require": "warn", 99 | "no-new-symbol": "warn", 100 | "no-new-wrappers": "warn", 101 | "no-new": "warn", 102 | "no-obj-calls": "warn", 103 | "no-octal-escape": "warn", 104 | "no-octal": "warn", 105 | "no-param-reassign": "warn", 106 | "no-path-concat": "warn", 107 | "no-process-env": "warn", 108 | "no-process-exit": "warn", 109 | "no-proto": "warn", 110 | "no-prototype-builtins": "warn", 111 | "no-redeclare": "warn", 112 | "no-regex-spaces": "warn", 113 | "no-restricted-globals": "warn", 114 | "no-restricted-imports": "warn", 115 | "no-restricted-modules": "warn", 116 | "no-restricted-syntax": "warn", 117 | "no-return-assign": "error", 118 | "no-script-url": "warn", 119 | "no-self-assign": "warn", 120 | "no-self-compare": "warn", 121 | "no-sequences": "warn", 122 | "no-shadow-restricted-names": "warn", 123 | "no-shadow": "warn", 124 | "no-sparse-arrays": "warn", 125 | "no-sync": "warn", 126 | "no-this-before-super": "warn", 127 | "no-throw-literal": "warn", 128 | "no-undef-init": "warn", 129 | "no-undef": "error", 130 | "no-unmodified-loop-condition": "warn", 131 | "no-unneeded-ternary": "error", 132 | "no-unreachable": "error", 133 | "no-unsafe-finally": "error", 134 | "no-unused-expressions": "error", 135 | "no-unused-labels": "error", 136 | "no-unused-vars": "error", 137 | "no-use-before-define": "error", 138 | "no-useless-call": "warn", 139 | "no-useless-computed-key": "warn", 140 | "no-useless-concat": "warn", 141 | "no-useless-constructor": "warn", 142 | "no-useless-escape": "warn", 143 | "no-useless-rename": "warn", 144 | "no-void": "warn", 145 | "no-with": "warn", 146 | "operator-assignment": ["error", "always"], 147 | "prefer-const": "warn", 148 | radix: "warn", 149 | "require-yield": "warn", 150 | "sort-imports": "warn", 151 | "spaced-comment": ["error", "always"], 152 | strict: ["error", "function"], 153 | "use-isnan": "error", 154 | 155 | "jsdoc/check-tag-names": "warn", 156 | "jsdoc/check-types": "warn", 157 | "jsdoc/require-param-description": "off", 158 | "jsdoc/require-return": "off", 159 | "jsdoc/require-return-description": "off", 160 | "jsdoc/require-return-type": "off", 161 | 162 | "valid-typeof": "warn", 163 | yoda: "warn", 164 | }, 165 | 166 | settings: { 167 | jsdoc: { 168 | tagNamePreference: { 169 | arg: "param", 170 | argument: "param", 171 | augments: "extends", 172 | constructor: "class", 173 | exception: "throws", 174 | func: "function", 175 | method: "function", 176 | prop: "property", 177 | return: "returns", 178 | virtual: "abstract", 179 | yield: "yields", 180 | }, 181 | preferredTypes: { 182 | array: "Array", 183 | bool: "Boolean", 184 | boolean: "Boolean", 185 | number: "Number", 186 | object: "Object", 187 | str: "String", 188 | string: "String", 189 | }, 190 | }, 191 | }, 192 | 193 | }, { 194 | files: ["**/*.esm.js"], 195 | 196 | languageOptions: { 197 | ecmaVersion: 2024, 198 | sourceType: "module", 199 | }, 200 | }]; 201 | 202 | module.exports = config 203 | -------------------------------------------------------------------------------- /github_connector/__init__.py: -------------------------------------------------------------------------------- 1 | from . import models 2 | from . import report 3 | from . import wizards 4 | -------------------------------------------------------------------------------- /github_connector/__manifest__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016-Today: Odoo Community Association (OCA) 2 | # @author: Sylvain LE GAL (https://twitter.com/legalsylvain) 3 | # @author: Sébastien BEAU 4 | # Copyright 2019 Tecnativa - Cristina Martin R. 5 | # Copyright 2024 Tecnativa - Carolina Fernandez 6 | # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). 7 | { 8 | "name": "Github Connector", 9 | "summary": "Synchronize information from Github repositories", 10 | "version": "18.0.1.0.0", 11 | "category": "Connector", 12 | "license": "AGPL-3", 13 | "author": "Odoo Community Association (OCA), GRAP, Akretion, Tecnativa", 14 | "website": "https://github.com/OCA/interface-github", 15 | "depends": ["base", "web"], 16 | "data": [ 17 | "security/ir_model_category.xml", 18 | "security/res_groups.xml", 19 | "security/ir.model.access.csv", 20 | "data/ir_config_parameter.xml", 21 | "data/ir_cron.xml", 22 | "wizards/view_wizard_load_github_model.xml", 23 | "views/view_reporting.xml", 24 | "views/view_github_team_partner.xml", 25 | "views/view_github_team_repository.xml", 26 | "views/action.xml", 27 | "views/view_res_partner.xml", 28 | "views/view_github_analysis_rule.xml", 29 | "views/view_github_analysis_rule_group.xml", 30 | "views/view_github_organization.xml", 31 | "views/view_github_repository.xml", 32 | "views/view_github_repository_branch.xml", 33 | "views/view_github_team.xml", 34 | "views/menu.xml", 35 | "report/github_repository_branch_rule_info_report_view.xml", 36 | "wizards/view_wizard_create_team.xml", 37 | "wizards/view_wizard_create_repository.xml", 38 | ], 39 | "demo": [ 40 | "demo/github_analysis_rule_group_demo.xml", 41 | "demo/github_analysis_rule_demo.xml", 42 | "demo/github_organization.xml", 43 | "demo/github_organization_serie.xml", 44 | ], 45 | "installable": True, 46 | "external_dependencies": { 47 | "python": ["GitPython", "pathspec", "PyGithub"], 48 | "bin": ["cloc"], 49 | # special definition used by OCA to install packages 50 | "deb": ["cloc"], 51 | }, 52 | } 53 | -------------------------------------------------------------------------------- /github_connector/data/ir_config_parameter.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | github.max_try 10 | 5 11 | 12 | 13 | git.partial_commit_during_analysis 14 | True 15 | 16 | 17 | -------------------------------------------------------------------------------- /github_connector/data/ir_cron.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | Synchronize All Organizations and Teams 10 | 1 11 | 12 | 13 | days 14 | code 15 | 16 | model.cron_update_organization_team() 17 | 18 | 19 | Synchronize Branches List for All Repositories 20 | 1 21 | 22 | 23 | days 24 | code 25 | 26 | model.cron_update_branch_list() 27 | 28 | 29 | Download Source Code for All Github Branches 30 | 1 31 | 32 | 33 | days 34 | code 35 | 36 | model.cron_download_all() 37 | 38 | 39 | Analyze Source Code for All Github Branches 40 | 1 41 | 42 | 43 | days 44 | code 45 | 46 | model.cron_analyze_all() 47 | 48 | 49 | -------------------------------------------------------------------------------- /github_connector/demo/github_analysis_rule_demo.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | Python files 9 | 10 | 11 | *.py 12 | !/setup 13 | !.* 14 | 15 | 16 | 17 | XML files 18 | 19 | 20 | *.xml 21 | !/setup 22 | !.* 23 | 24 | 25 | 26 | JS files 27 | 28 | 29 | *.js 30 | !/setup 31 | !.* 32 | 33 | 34 | 35 | Test files 36 | 37 | /tests/*.py 38 | 39 | 40 | -------------------------------------------------------------------------------- /github_connector/demo/github_analysis_rule_group_demo.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | Odoo modules 9 | 10 | 11 | -------------------------------------------------------------------------------- /github_connector/demo/github_organization.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | Odoo Community Association 10 | OCA 11 | 7600578 12 | https://codecov.io/gh/{organization_name}/{repository_name}/branch/{branch_name} 15 | https://travis-ci.org/{organization_name}/{repository_name} 18 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /github_connector/demo/github_organization_serie.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 2 10 | 6.0 11 | 12 | 13 | 14 | 3 15 | 6.1 16 | 17 | 18 | 19 | 4 20 | 7.0 21 | 22 | 23 | 24 | 5 25 | 8.0 26 | 27 | 28 | 29 | 6 30 | 9.0 31 | 32 | 33 | 34 | 7 35 | 10.0 36 | 37 | 38 | 39 | 8 40 | 11.0 41 | 42 | 43 | 44 | 9 45 | 12.0 46 | 47 | 48 | 49 | 10 50 | 13.0 51 | 52 | 53 | 54 | 11 55 | 14.0 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /github_connector/models/__init__.py: -------------------------------------------------------------------------------- 1 | from . import abstract_github_model 2 | 3 | from . import res_partner 4 | 5 | from . import github_analysis_rule 6 | from . import github_analysis_rule_group 7 | from . import github_analysis_rule_info 8 | from . import github_organization 9 | from . import github_organization_serie 10 | from . import github_repository 11 | from . import github_repository_branch 12 | from . import github_team 13 | from . import github_team_partner 14 | from . import github_team_repository 15 | -------------------------------------------------------------------------------- /github_connector/models/github_analysis_rule.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Tecnativa - Víctor Martínez 2 | # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). 3 | 4 | import pathspec 5 | 6 | from odoo import fields, models 7 | 8 | 9 | class GithubAnalysisRule(models.Model): 10 | _name = "github.analysis.rule" 11 | _description = "Github Analysis Rule" 12 | 13 | name = fields.Char(required=True) 14 | group_id = fields.Many2one( 15 | string="Group", comodel_name="github.analysis.rule.group", required=True 16 | ) 17 | """ 18 | Example paths: https://git-scm.com/docs/gitignore#_pattern_format 19 | """ 20 | paths = fields.Text( 21 | help="Define with pathspec especification", 22 | default="*", 23 | required=True, 24 | ) 25 | 26 | def _set_spec(self, lines): 27 | return pathspec.PathSpec.from_lines("gitwildmatch", lines) 28 | 29 | def _get_matches(self, path): 30 | """ 31 | Get all matches from rule paths (multiple per line allow in rule) 32 | in a local path 33 | """ 34 | return self._set_spec(self.paths.splitlines()).match_tree(path) 35 | -------------------------------------------------------------------------------- /github_connector/models/github_analysis_rule_group.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Tecnativa - Víctor Martínez 2 | # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). 3 | 4 | from odoo import fields, models 5 | 6 | 7 | class GithubAnalysisRuleGroup(models.Model): 8 | _name = "github.analysis.rule.group" 9 | _description = "Github Analysis Rule Group" 10 | 11 | name = fields.Char(required=True) 12 | -------------------------------------------------------------------------------- /github_connector/models/github_analysis_rule_info.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Tecnativa - Víctor Martínez 2 | # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). 3 | 4 | from odoo import api, fields, models 5 | 6 | 7 | class GithubAnalysisRuleInfoMixin(models.AbstractModel): 8 | _name = "github.analysis.rule.info.mixin" 9 | _description = "Github Analysis Rule Mixin" 10 | 11 | analysis_rule_id = fields.Many2one( 12 | string="Analysis Rule", 13 | comodel_name="github.analysis.rule", 14 | ondelete="cascade", 15 | ) 16 | group_id = fields.Many2one( 17 | string="Group", related="analysis_rule_id.group_id", readonly=True 18 | ) 19 | code_count = fields.Integer(string="# Code") 20 | documentation_count = fields.Integer(string="# Doc.") 21 | empty_count = fields.Integer(string="# Empty") 22 | total_count = fields.Integer( 23 | string="# Total", store=True, compute="_compute_total_count" 24 | ) 25 | scanned_files = fields.Integer() 26 | 27 | @api.depends("code_count", "documentation_count", "empty_count") 28 | def _compute_total_count(self): 29 | for item in self: 30 | item.total_count = ( 31 | item.code_count + item.documentation_count + item.empty_count 32 | ) 33 | -------------------------------------------------------------------------------- /github_connector/models/github_organization_serie.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016-Today: Odoo Community Association (OCA) 2 | # @author: Sylvain LE GAL (https://twitter.com/legalsylvain) 3 | # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). 4 | 5 | from odoo import fields, models 6 | 7 | 8 | class GithubOrganizationSerie(models.Model): 9 | _name = "github.organization.serie" 10 | _description = "Github Organization Serie" 11 | _order = "sequence, name" 12 | 13 | # Columns Section 14 | name = fields.Char(required=True) 15 | sequence = fields.Integer(required=True) 16 | organization_id = fields.Many2one( 17 | comodel_name="github.organization", 18 | string="Organization", 19 | ondelete="cascade", 20 | required=True, 21 | ) 22 | 23 | _sql_constraints = [ 24 | ( 25 | "sequence_organization_uniq", 26 | "unique(organization_id, sequence)", 27 | "Sequence serie must be unique by organization.", 28 | ) 29 | ] 30 | -------------------------------------------------------------------------------- /github_connector/models/github_team_partner.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016-Today: Odoo Community Association (OCA) 2 | # @author: Sylvain LE GAL (https://twitter.com/legalsylvain) 3 | # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). 4 | 5 | from odoo import api, fields, models 6 | 7 | 8 | class GithubTeamPartner(models.Model): 9 | _name = "github.team.partner" 10 | _description = "Github Team Partner" 11 | _order = "team_id, partner_id" 12 | _rec_name = "partner_id" 13 | 14 | _ROLE_SELECTION = [("member", "Member"), ("maintainer", "Maintainer")] 15 | 16 | # Column Section 17 | team_id = fields.Many2one( 18 | comodel_name="github.team", 19 | string="Team", 20 | required=True, 21 | index=True, 22 | readonly=True, 23 | ondelete="cascade", 24 | ) 25 | partner_id = fields.Many2one( 26 | comodel_name="res.partner", 27 | string="Member", 28 | required=True, 29 | index=True, 30 | readonly=True, 31 | ondelete="cascade", 32 | ) 33 | role = fields.Selection(selection=_ROLE_SELECTION, required=True, readonly=True) 34 | context_search_default_team_id = fields.Integer( 35 | compute="_compute_context_search_default" 36 | ) 37 | context_search_default_partner_id = fields.Integer( 38 | compute="_compute_context_search_default" 39 | ) 40 | 41 | @api.depends_context("search_default_team_id", "search_default_partner_id") 42 | def _compute_context_search_default(self): 43 | """Compute the context value for the search terms 44 | into helper fields for the view 45 | """ 46 | for record in self: 47 | record.context_search_default_team_id = self.env.context.get( 48 | "search_default_team_id", False 49 | ) 50 | record.context_search_default_partner_id = self.env.context.get( 51 | "search_default_partner_id", False 52 | ) 53 | -------------------------------------------------------------------------------- /github_connector/models/github_team_repository.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016-Today: Odoo Community Association (OCA) 2 | # @author: Sylvain LE GAL (https://twitter.com/legalsylvain) 3 | # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). 4 | 5 | from odoo import api, fields, models 6 | 7 | 8 | class GithubTeamRepository(models.Model): 9 | _name = "github.team.repository" 10 | _description = "Github Team Repository" 11 | _order = "team_id, repository_id" 12 | _rec_name = "repository_id" 13 | 14 | _PERMISSION_SELECTION = [ 15 | ("undefined", "Undefined"), 16 | ("read", "Read"), 17 | ("write", "Write"), 18 | ("admin", "Admin"), 19 | ] 20 | 21 | # Column Section 22 | team_id = fields.Many2one( 23 | comodel_name="github.team", 24 | string="Team", 25 | required=True, 26 | index=True, 27 | readonly=True, 28 | ondelete="cascade", 29 | ) 30 | repository_id = fields.Many2one( 31 | comodel_name="github.repository", 32 | string="Repository", 33 | required=True, 34 | index=True, 35 | readonly=True, 36 | ondelete="cascade", 37 | ) 38 | permission = fields.Selection( 39 | selection=_PERMISSION_SELECTION, 40 | required=True, 41 | readonly=True, 42 | ) 43 | context_search_default_team_id = fields.Integer( 44 | compute="_compute_context_search_default" 45 | ) 46 | context_search_default_repository_id = fields.Integer( 47 | compute="_compute_context_search_default" 48 | ) 49 | 50 | @api.depends_context("search_default_team_id", "search_default_repository_id") 51 | def _compute_context_search_default(self): 52 | """Compute the context value for the search terms 53 | into helper fields for the view 54 | """ 55 | for record in self: 56 | record.context_search_default_team_id = self.env.context.get( 57 | "search_default_team_id", False 58 | ) 59 | record.context_search_default_repository_id = self.env.context.get( 60 | "search_default_repository_id", False 61 | ) 62 | -------------------------------------------------------------------------------- /github_connector/models/res_partner.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016-Today: Odoo Community Association (OCA) 2 | # Copyright 2021 Tecnativa - João Marques 3 | # @author: Sylvain LE GAL (https://twitter.com/legalsylvain) 4 | # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). 5 | 6 | # pylint: disable=missing-manifest-dependency 7 | from github.GithubException import UnknownObjectException 8 | 9 | from odoo import api, fields, models 10 | from odoo.exceptions import UserError 11 | 12 | 13 | class ResPartner(models.Model): 14 | _name = "res.partner" 15 | _inherit = ["res.partner", "abstract.github.model"] 16 | 17 | _github_login_field = "login" 18 | _need_individual_call = True 19 | _field_list_prevent_overwrite = ["name", "website", "email", "image_1920"] 20 | 21 | # Column Section 22 | is_bot_account = fields.Boolean( 23 | string="Is Bot Github Account", 24 | help="Check this box if this " "account is a bot or similar.", 25 | ) 26 | github_team_partner_ids = fields.One2many( 27 | string="Teams", 28 | comodel_name="github.team.partner", 29 | inverse_name="partner_id", 30 | readonly=True, 31 | ) 32 | github_team_qty = fields.Integer( 33 | string="Number of Teams", compute="_compute_github_team_qty", store=True 34 | ) 35 | organization_ids = fields.Many2many( 36 | string="Organizations", 37 | comodel_name="github.organization", 38 | relation="github_organization_partner_rel", 39 | column1="partner_id", 40 | column2="organization_id", 41 | readonly=True, 42 | ) 43 | organization_qty = fields.Integer( 44 | string="Number of Organizations", 45 | compute="_compute_organization_qty", 46 | store=True, 47 | ) 48 | 49 | # Constraints Section 50 | _sql_constraints = [ 51 | ( 52 | "github_login_uniq", 53 | "unique(github_name)", 54 | "Two different partners cannot have the same Github Login", 55 | ) 56 | ] 57 | 58 | @api.constrains("github_name", "is_company") 59 | def _check_login_company(self): 60 | for partner in self: 61 | if partner.is_company and partner.github_name: 62 | raise UserError( 63 | self.env._( 64 | "A company ('%s') can not have a Github login" " associated.", 65 | partner.name, 66 | ) 67 | ) 68 | 69 | # Compute Section 70 | @api.depends("organization_ids", "organization_ids.member_ids") 71 | def _compute_organization_qty(self): 72 | for partner in self: 73 | partner.organization_qty = len(partner.organization_ids) 74 | 75 | @api.depends("github_team_partner_ids") 76 | def _compute_github_team_qty(self): 77 | data = self.env["github.team.partner"].read_group( 78 | [("partner_id", "in", self.ids)], ["partner_id"], ["partner_id"] 79 | ) 80 | mapping = {data["partner_id"][0]: data["partner_id_count"] for data in data} 81 | for item in self: 82 | item.github_team_qty = mapping.get(item.id, 0) 83 | 84 | # Custom Section 85 | @api.model 86 | def get_conversion_dict(self): 87 | res = super().get_conversion_dict() 88 | res.update({"website": "blog", "email": "email"}) 89 | return res 90 | 91 | @api.model 92 | def get_odoo_data_from_github(self, gh_data): 93 | res = super().get_odoo_data_from_github(gh_data) 94 | res.update({"name": gh_data.name or f"{gh_data.login} (Github)"}) 95 | if hasattr(gh_data, "avatar_url"): 96 | res.update( 97 | {"image_1920": self.get_base64_image_from_github(gh_data.avatar_url)} 98 | ) 99 | return res 100 | 101 | def find_related_github_object(self, obj_id=None): 102 | """Query Github API to find the related object""" 103 | gh_api = self.get_github_connector() 104 | try: 105 | return gh_api.get_user_by_id(int(obj_id or self.github_id_external)) 106 | except UnknownObjectException: 107 | return gh_api.get_user(self.github_name) 108 | 109 | def action_github_organization(self): 110 | self.ensure_one() 111 | action = self.env["ir.actions.act_window"]._for_xml_id( 112 | "github_connector.action_github_organization" 113 | ) 114 | action["context"] = dict(self.env.context) 115 | action["context"].pop("group_by", None) 116 | action["context"]["search_default_member_ids"] = self.id 117 | return action 118 | 119 | def action_github_team_partner_from_partner(self): 120 | self.ensure_one() 121 | action = self.env["ir.actions.act_window"]._for_xml_id( 122 | "github_connector.action_github_team_partner_from_partner" 123 | ) 124 | action["context"] = dict(self.env.context) 125 | action["context"].pop("group_by", None) 126 | action["context"]["search_default_partner_id"] = self.id 127 | return action 128 | -------------------------------------------------------------------------------- /github_connector/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["whool"] 3 | build-backend = "whool.buildapi" 4 | -------------------------------------------------------------------------------- /github_connector/readme/CONFIGURE.md: -------------------------------------------------------------------------------- 1 | Once installed, you have to: 2 | 3 | 1. Open your odoo.conf file and add extra settings to mention Github 4 | credentials, and the local path where the source code will be 5 | downloaded: 6 | - `source_code_local_path = /workspace/source_code/` 7 | 8 | Note: you can define the route as environment variable using the key 9 | SOURCE_CODE_LOCAL_PATH 10 | 11 | Note: make sure that Odoo process has read / write access on that folder 12 | 13 | > - `github_token = your_github_access_token` 14 | 15 | Note: The login/password auth has been deprecated by GitHub. 16 | 17 | 18 | 1. Go to 'Settings' / 'Technical' / 'Parameters' / 'System Parameters' 19 | and define the following values: 20 | 21 | 1. `github.max_try`: number of call to the API before an error is 22 | raised. The more unstable/slow your connection, the higher 23 | should be this value 24 | 2. `git.partial_commit_during_analysis`: Set to `True` if you want 25 | to commit the result of the analysis in the database after each 26 | repository analysis. We recommend to set to `True` when you 27 | perform the initial download (potentially with a lot of 28 | repositories) in order to reduce the size of the transaction 29 | 30 | ![image](../static/description/github_settings.png) 31 | 32 | 2. Go to your(s) user(s) form to add them in the new 'Connector Github 33 | Manager' groups. The members of this group will have the possibility 34 | to run Github synchronization. 35 | 36 | ## Technical Information 37 | 38 | This module provides 4 crons that you can enable: 39 | 40 | - Synchronize All Organizations and Teams (`cron_update_organization`) 41 | - Synchronize Branches List for All repositories 42 | (`cron_update_branch_list`) 43 | - Download Source Code for All Github Branches (`cron_download_code`) 44 | - Analyze Source Code for All Github Branches (`cron_analyze_code`) 45 | -------------------------------------------------------------------------------- /github_connector/readme/CONTRIBUTORS.md: -------------------------------------------------------------------------------- 1 | - Sylvain LE GAL () 2 | - Sébastien BEAU () 3 | - Benoît GUILLOT () 4 | - Enrique Martín () 5 | - [Tecnativa](https://www.tecnativa.com):", 6 | - Pedro M. Baeza 7 | - Vicent Cubells 8 | - Alexandre Díaz 9 | - Ernesto Tejeda 10 | - Carlos Roca 11 | - Víctor Martínez 12 | - João Marques 13 | - Carolina Fernandez 14 | -------------------------------------------------------------------------------- /github_connector/readme/DESCRIPTION.md: -------------------------------------------------------------------------------- 1 | This module allows you to: 2 | 3 | - Fetch into Odoo social information from Github (Organizations, Teams, 4 | Users) 5 | - Fetch into Odoo Code structure information from Github (Repositories, 6 | Branches) 7 | - Download source code from Github 8 | - Analyze repository code from rules previously created 9 | -------------------------------------------------------------------------------- /github_connector/readme/INSTALL.md: -------------------------------------------------------------------------------- 1 | To install this addon, you need to install some python dependencies 2 | 3 | ``` bash 4 | sudo pip install PyGitHub 5 | sudo apt install cloc 6 | sudo pip install pathspec 7 | sudo pip install GitPython 8 | ``` 9 | 10 | Analysis source code is generated by 11 | 12 | -------------------------------------------------------------------------------- /github_connector/readme/ROADMAP.md: -------------------------------------------------------------------------------- 1 | - For the time being, Github API doesn't provide some informations that 2 | are available by the classic UI, that includes: 3 | 4 | 1. team hierarchy: the field is present in the model 5 | github_team.parent_id, but unused. 6 | 7 | - Possible improvements: 8 | 9 | 1. Create a new module github_connector_website, that could display 10 | teams / repositories / branches informations for non logged users. 11 | 2. Analyze commits (author, quantity by series, etc...): this feature 12 | has been partially implemented in a V8.0 PR. 13 | 3. Synchronize Pull Request, Issues, Comments: this feature has been 14 | partially implemented in a V8.0 PR. 15 | 16 | - Refactor the github connector: 17 | 18 | A python library called PyGitHub is available. It could be interesting 19 | to use it, instead of using custom code. However, this lib doesn't 20 | provide good access to child object, generating for the time being, 21 | unnecessary API calls. For example, updating a repository should call 22 | before a call to the parent organization (The current module is so 23 | faster). 24 | -------------------------------------------------------------------------------- /github_connector/readme/USAGE.md: -------------------------------------------------------------------------------- 1 | ## Initial upload from Github 2 | 3 | To fetch information from Github, you have to: 4 | 5 | 1. go to 'Github' / 'Settings' / 'Sync Object' 6 | 7 | 2. Select the object type you want to synchronize and its Gthub name 8 | 9 | ![sync_organization](static/description/sync_organization.png) 10 | 11 | 3. Once done for your organization(s), go to 'Github' / 'Github 12 | Commnunity' / 'Organizations' 13 | 14 | ![github_organization_kanban](static/description/github_organization_kanban.png) 15 | 16 | 4. Optionally, once organization is created, you can create series for 17 | your projects. Go to 'Github' / 'Organizations' / click on your 18 | organization / 'Organization Series' Tabs 19 | 20 | ![github_organization_series](static/description/github_organization_series.png) 21 | 22 | ## Select branches to download 23 | 24 | This setting will prevent to download undesired branches, downloading 25 | only main branches (releases): 26 | 27 | 1. In the 'Settings' tab, set repositories you don't want to download 28 | (or repositories you want to download). If 'Specific repositories' 29 | is set, 'Ignored Repositories' value is ignored. 30 | 31 | 2. In the 'Settings' tab, set the URL of the 'External Services' you 32 | use for Continuous Integration and Coverage. 33 | 34 | ![github_organization_external_services](static/description/github_organization_external_services.png) 35 | 36 | 3. Once done, click on buttons 'Syncs', to synchronize repositories, 37 | teams and members. (This process can take a while depending of your 38 | size) 39 | 40 | ![github_organization_sync_buttons](static/description/github_organization_sync_buttons.png) 41 | 42 | ## Team / members synchronization 43 | 44 | You can synchronize members teams: 45 | 46 | 1. Go to 'Teams' / tree view / 'Actions' / 'Update from Github'. 47 | 48 | ![github_team_kanban](static/description/github_team_kanban.png) 49 | 50 | 2. In each team, you can see the members list and the role of the 51 | members 52 | 53 | ![github_team_partner_kanban](static/description/github_team_partner_kanban.png) 54 | 55 | 3. In each team, you can see the repositories list but not the 56 | permissions of the team. (See 'Known Issues' Section) 57 | 58 | ![github_team_repository_kanban](static/description/github_team_repository_kanban.png) 59 | 60 | ## Repositories synchronization 61 | 62 | You can synchronize the branches of your repositories: 63 | 64 | 1. Go to 'Repositories' / tree view / 'Actions' / 'Update from Github' 65 | 66 | ![github_repository_kanban](static/description/github_repository_kanban.png) 67 | 68 | 2. In each repository, you can see the main branches list and the size 69 | of code source. 70 | 71 | ![github_repository_branch_kanban](static/description/github_repository_branch_kanban.png) 72 | 73 | ## Fetching the source code 74 | 75 | Finally, you can download locally the source code of all your branches: 76 | 77 | 1. Go to 'Repository Branches' / tree view / 'Actions' / 'Download and 78 | Analyse Source Code'. 79 | 80 | ![wizard_download_analyze](static/description/wizard_download_analyze.png) 81 | 82 | 2. In the tree view you can update manually source code or refresh 83 | analysis. 84 | 85 | ![github_repository_branch_list](static/description/github_repository_branch_list.png) 86 | 87 | ## Analysis source code 88 | 89 | It's possible to create custom analysis rules that relate to a GitHub 90 | organization, GitHub repository and/or GitHub repository branch to 91 | analyze code. 92 | 93 | 1. Go to 'Settings' / 'Analysis rule groups' and create records that 94 | allow to organize the rules 95 | 2. Go to 'Settings' / 'Analysis rules' and create rules, for example: 96 | 97 | > 1. Name: All code, Group: General, Paths: `*` 98 | > 2. Name: Python code, Group: General, Paths: `*.py` 99 | > 3. Name: Xml code, Group: General, Paths: `*.xml` 100 | > 4. Name: Repository 1, Group: Custom, Paths: /path/ 101 | 102 | Note: Paths field in 'Analysis rule' allow to put multiple paths for 103 | line, path format is according to 104 | 105 | 106 | 1. Go to *GitHub \> GitHub Community \> Organizations* and define 107 | Analysis rules (optional) 108 | 2. Go to *GitHub \> GitHub Repository \> Repositories* and define 109 | Analysis rules (optional) 110 | 3. Go to *GitHub \> GitHub Repository \> Repository Branches* and 111 | define Analysis rules (optional) 112 | 113 | Analysis source code is executed when 'Update Source Code Analysis' 114 | button in some 'Repository Branch', get all the Analysis rules 115 | (Repository + Organization) and analyze code and generate info about it 116 | Other option to Analysis source code is in cron called 'Analyze Source 117 | Code for All Github Branches' 118 | 119 | You can see in 'Repository Branch' / 'Code Analysis' the info obtained 120 | from analysis rules. 121 | 122 | ## Data creation in Github 123 | 124 | You have the possibility to creates two items in Github directly from 125 | Odoo 126 | 127 | 1. Teams: 128 | 129 | 1. Go to 'Settings' / 'Create Team in Github'. 130 | 2. Set the information and click on Create in Github. 131 | 3. Odoo will try to create the team. If access right and datas are 132 | correct, the creation will be done directly in Github 133 | 4. Later on, a synchronization will be performed, to create the 134 | according team in the Odoo instance. 135 | 136 | ![wizard_create_team](static/description/wizard_create_team.png) 137 | 138 | 2. Repositories: 139 | 140 | 1. Go to 'Settings' / 'Create Team in Github'. 141 | 2. Set the information and click on Create in Github. 142 | 143 | ![wizard_create_repository](static/description/wizard_create_repository.png) 144 | 145 | ## Note 146 | 147 | Analysis in this module is basic: for the time being, it just gives 148 | branches size. 149 | 150 | Nevertheless, you can develop an extra Odoo Custom module to extend 151 | analysis function and get extra statistics, depending on your needs. 152 | 153 | In that way, you can see the module github_connector_odoo, if your 154 | repositories contain Odoo modules. 155 | 156 | ## Reporting 157 | 158 | This module provides several reports 159 | 160 | **Branches by Serie** 161 | 162 | ![reporting_branches_by_serie](static/description/reporting_branches_by_serie.png) 163 | 164 | **Sizes by Serie** 165 | 166 | ![reporting_sizes_by_serie](static/description/reporting_sizes_by_serie.png) 167 | 168 | **Repository branch analysis rule** 169 | 170 | ![github_repository_branch_rule_info_report](static/description/github_repository_branch_rule_info_report.png) 171 | -------------------------------------------------------------------------------- /github_connector/report/__init__.py: -------------------------------------------------------------------------------- 1 | from . import github_repository_branch_rule_info_report 2 | -------------------------------------------------------------------------------- /github_connector/report/github_repository_branch_rule_info_report.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Tecnativa - Víctor Martínez 2 | # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). 3 | from psycopg2 import sql 4 | 5 | from odoo import api, fields, models, tools 6 | 7 | 8 | class GithubRepositoryBranchRuleInfoReport(models.Model): 9 | _inherit = "github.analysis.rule" 10 | _name = "github.repository.branch.rule.info.report" 11 | _description = "Github Repository Branch Rule Info Report" 12 | _auto = False 13 | 14 | analysis_rule_id = fields.Many2one( 15 | string="Analysis Rule", 16 | comodel_name="github.analysis.rule", 17 | ) 18 | group_id = fields.Many2one( 19 | string="Group", related="analysis_rule_id.group_id", readonly=True 20 | ) 21 | repository_branch_id = fields.Many2one( 22 | string="Repository Branch", 23 | comodel_name="github.repository.branch", 24 | ) 25 | repository_id = fields.Many2one( 26 | string="Repository", 27 | comodel_name="github.repository", 28 | ) 29 | organization_serie_id = fields.Many2one( 30 | string="Organization serie", 31 | comodel_name="github.organization.serie", 32 | ) 33 | code_count = fields.Integer(string="# Code") 34 | documentation_count = fields.Integer(string="# Documentation") 35 | empty_count = fields.Integer(string="# Empty") 36 | total_count = fields.Integer(string="# Total") 37 | scanned_files = fields.Integer() 38 | 39 | @property 40 | def _table_query(self): 41 | return f"{self._select()} {self._from()} {self._group_by()}" 42 | 43 | @api.model 44 | def _select(self): 45 | return """ 46 | SELECT 47 | min(grbri.id) as id, 48 | gar.id as analysis_rule_id, 49 | garg.id as group_id, 50 | grb.id as repository_branch_id, 51 | gr.id as repository_id, 52 | gos.id as organization_serie_id, 53 | sum(grbri.code_count) as code_count, 54 | sum(grbri.documentation_count) as documentation_count, 55 | sum(grbri.empty_count) as empty_count, 56 | sum(grbri.total_count) as total_count, 57 | sum(grbri.scanned_files) as scanned_files 58 | """ 59 | 60 | @api.model 61 | def _from(self): 62 | return """ 63 | FROM github_repository_branch_rule_info as grbri 64 | LEFT JOIN github_analysis_rule as gar ON grbri.analysis_rule_id = gar.id 65 | LEFT JOIN github_analysis_rule_group as garg ON gar.group_id = garg.id 66 | LEFT JOIN github_repository_branch as grb 67 | ON grbri.repository_branch_id = grb.id 68 | LEFT JOIN github_organization_serie as gos 69 | ON grb.organization_serie_id = gos.id 70 | LEFT JOIN github_repository as gr ON grb.repository_id = gr.id 71 | """ 72 | 73 | def _group_by(self): 74 | return """ 75 | GROUP BY 76 | gar.id, 77 | garg.id, 78 | grb.id, 79 | gr.id, 80 | gos.id 81 | """ 82 | 83 | def init(self): 84 | tools.drop_view_if_exists(self.env.cr, self._table) 85 | self.env.cr.execute( 86 | sql.SQL("CREATE or REPLACE VIEW {} as ({})").format( 87 | sql.Identifier(self._table), sql.SQL(self._table_query) 88 | ) 89 | ) 90 | -------------------------------------------------------------------------------- /github_connector/report/github_repository_branch_rule_info_report_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | github.repository.branch.rule.info.report 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 23 | github.repository.branch.rule.info.report 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 35 | Repository branch analysis rule 36 | github.repository.branch.rule.info.report 37 | pivot,graph 38 | 39 | 46 | 47 | -------------------------------------------------------------------------------- /github_connector/security/ir.model.access.csv: -------------------------------------------------------------------------------- 1 | id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink 2 | access_github_analysis_rule_reader,github_analysis_rule reader,model_github_analysis_rule,base.group_user,1,0,0,0 3 | access_github_analysis_rule_manager,github_analysis_rule manager,model_github_analysis_rule,github_connector.group_github_connector_manager,1,1,1,1 4 | access_github_analysis_rule_group_reader,github_analysis_rule_group reader,model_github_analysis_rule_group,base.group_user,1,0,0,0 5 | access_github_analysis_rule_group_manager,github_analysis_rule_group manager,model_github_analysis_rule_group,github_connector.group_github_connector_manager,1,1,1,1 6 | access_github_organization_reader,github_organization reader,model_github_organization,base.group_user,1,0,0,0 7 | access_github_organization_manager,github_organization manager,model_github_organization,github_connector.group_github_connector_manager,1,1,1,1 8 | access_github_organization_serie_reader,github_organization_serie reader,model_github_organization_serie,base.group_user,1,0,0,0 9 | access_github_organization_serie_manager,github_organization_serie manager,model_github_organization_serie,github_connector.group_github_connector_manager,1,1,1,1 10 | access_github_repository_branch_rule_info_report_reader,github_repository_branch_rule_info_report reader,model_github_repository_branch_rule_info_report,base.group_user,1,0,0,0 11 | access_github_repository_reader,github_repository reader,model_github_repository,base.group_user,1,0,0,0 12 | access_github_repository_manager,github_repository manager,model_github_repository,github_connector.group_github_connector_manager,1,1,1,1 13 | access_github_repository_branch_reader,github_repository_branch reader,model_github_repository_branch,base.group_user,1,0,0,0 14 | access_github_repository_branch_manager,github_repository_branch manager,model_github_repository_branch,github_connector.group_github_connector_manager,1,1,1,1 15 | access_github_team_reader,github_team reader,model_github_team,base.group_user,1,0,0,0 16 | access_github_team_manager,github_team manager,model_github_team,github_connector.group_github_connector_manager,1,1,1,1 17 | access_github_team_partner_reader,github_team partner reader,model_github_team_partner,base.group_user,1,0,0,0 18 | access_github_team_partner_manager,github_team partner manager,model_github_team_partner,github_connector.group_github_connector_manager,1,1,1,1 19 | access_github_team_repository_reader,github_team repository reader,model_github_team_repository,base.group_user,1,0,0,0 20 | access_github_team_repository_manager,github_team repository manager,model_github_team_repository,github_connector.group_github_connector_manager,1,1,1,1 21 | access_github_repository_branch_rule_info_reader,access_github_repository_branch_rule_info_reader,model_github_repository_branch_rule_info,base.group_user,1,0,0,0 22 | access_github_repository_branch_rule_info_manager,access_github_repository_branch_rule_info_manager,model_github_repository_branch_rule_info,github_connector.group_github_connector_manager,1,1,1,1 23 | access_wizard_load_github_model_reader,access_wizard_load_github_model,model_wizard_load_github_model,base.group_user,1,0,0,0 24 | access_wizard_load_github_model_manager,access_wizard_load_github_model_manager,model_wizard_load_github_model,github_connector.group_github_connector_manager,1,1,1,1 25 | access_wizard_create_repository_reader,access_wizard_create_repository,model_wizard_create_repository,base.group_user,1,0,0,0 26 | access_wizard_create_repository_manager,access_wizard_create_repository_manager,model_wizard_create_repository,github_connector.group_github_connector_manager,1,1,1,1 27 | access_wizard_create_team_reader,access_wizard_create_team_reader,model_wizard_create_team,base.group_user,1,0,0,0 28 | access_wizard_create_team_manager,access_wizard_create_team_manager,model_wizard_create_team,github_connector.group_github_connector_manager,1,1,1,1 29 | -------------------------------------------------------------------------------- /github_connector/security/ir_model_category.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | Github Connector 10 | 20 11 | 12 | 13 | -------------------------------------------------------------------------------- /github_connector/security/res_groups.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | Connector Github User 13 | 14 | 15 | 16 | Connector Github Manager 17 | 18 | 22 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /github_connector/static/description/github_organization_external_services.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OCA/interface-github/4a57125597bf5f3e231a3191ffaec311bdd878cb/github_connector/static/description/github_organization_external_services.png -------------------------------------------------------------------------------- /github_connector/static/description/github_organization_kanban.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OCA/interface-github/4a57125597bf5f3e231a3191ffaec311bdd878cb/github_connector/static/description/github_organization_kanban.png -------------------------------------------------------------------------------- /github_connector/static/description/github_organization_series.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OCA/interface-github/4a57125597bf5f3e231a3191ffaec311bdd878cb/github_connector/static/description/github_organization_series.png -------------------------------------------------------------------------------- /github_connector/static/description/github_organization_sync_buttons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OCA/interface-github/4a57125597bf5f3e231a3191ffaec311bdd878cb/github_connector/static/description/github_organization_sync_buttons.png -------------------------------------------------------------------------------- /github_connector/static/description/github_repository_branch_kanban.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OCA/interface-github/4a57125597bf5f3e231a3191ffaec311bdd878cb/github_connector/static/description/github_repository_branch_kanban.png -------------------------------------------------------------------------------- /github_connector/static/description/github_repository_branch_list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OCA/interface-github/4a57125597bf5f3e231a3191ffaec311bdd878cb/github_connector/static/description/github_repository_branch_list.png -------------------------------------------------------------------------------- /github_connector/static/description/github_repository_branch_rule_info_report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OCA/interface-github/4a57125597bf5f3e231a3191ffaec311bdd878cb/github_connector/static/description/github_repository_branch_rule_info_report.png -------------------------------------------------------------------------------- /github_connector/static/description/github_repository_kanban.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OCA/interface-github/4a57125597bf5f3e231a3191ffaec311bdd878cb/github_connector/static/description/github_repository_kanban.png -------------------------------------------------------------------------------- /github_connector/static/description/github_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OCA/interface-github/4a57125597bf5f3e231a3191ffaec311bdd878cb/github_connector/static/description/github_settings.png -------------------------------------------------------------------------------- /github_connector/static/description/github_team_kanban.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OCA/interface-github/4a57125597bf5f3e231a3191ffaec311bdd878cb/github_connector/static/description/github_team_kanban.png -------------------------------------------------------------------------------- /github_connector/static/description/github_team_partner_kanban.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OCA/interface-github/4a57125597bf5f3e231a3191ffaec311bdd878cb/github_connector/static/description/github_team_partner_kanban.png -------------------------------------------------------------------------------- /github_connector/static/description/github_team_repository_kanban.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OCA/interface-github/4a57125597bf5f3e231a3191ffaec311bdd878cb/github_connector/static/description/github_team_repository_kanban.png -------------------------------------------------------------------------------- /github_connector/static/description/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OCA/interface-github/4a57125597bf5f3e231a3191ffaec311bdd878cb/github_connector/static/description/icon.png -------------------------------------------------------------------------------- /github_connector/static/description/reporting_branches_by_serie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OCA/interface-github/4a57125597bf5f3e231a3191ffaec311bdd878cb/github_connector/static/description/reporting_branches_by_serie.png -------------------------------------------------------------------------------- /github_connector/static/description/reporting_sizes_by_serie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OCA/interface-github/4a57125597bf5f3e231a3191ffaec311bdd878cb/github_connector/static/description/reporting_sizes_by_serie.png -------------------------------------------------------------------------------- /github_connector/static/description/sync_organization.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OCA/interface-github/4a57125597bf5f3e231a3191ffaec311bdd878cb/github_connector/static/description/sync_organization.png -------------------------------------------------------------------------------- /github_connector/static/description/wizard_create_repository.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OCA/interface-github/4a57125597bf5f3e231a3191ffaec311bdd878cb/github_connector/static/description/wizard_create_repository.png -------------------------------------------------------------------------------- /github_connector/static/description/wizard_create_team.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OCA/interface-github/4a57125597bf5f3e231a3191ffaec311bdd878cb/github_connector/static/description/wizard_create_team.png -------------------------------------------------------------------------------- /github_connector/static/description/wizard_download_analyze.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OCA/interface-github/4a57125597bf5f3e231a3191ffaec311bdd878cb/github_connector/static/description/wizard_download_analyze.png -------------------------------------------------------------------------------- /github_connector/static/src/img/default_github_organization.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OCA/interface-github/4a57125597bf5f3e231a3191ffaec311bdd878cb/github_connector/static/src/img/default_github_organization.png -------------------------------------------------------------------------------- /github_connector/tests/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2022 Tecnativa - Víctor Martínez 2 | # License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html 3 | from . import test_github_connector 4 | from . import test_github_analysis_rule 5 | -------------------------------------------------------------------------------- /github_connector/tests/common.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2022 Tecnativa - Víctor Martínez 2 | # License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html 3 | import requests 4 | import responses 5 | 6 | from odoo.addons.base.tests.common import BaseCommon 7 | 8 | 9 | class TestGithubConnectorCommon(BaseCommon): 10 | @classmethod 11 | def _request_handler(cls, s, r, /, **kw): 12 | """Don't block external requests.""" 13 | return cls._super_send(s, r, **kw) 14 | 15 | @classmethod 16 | def setUpClass(cls): 17 | cls._super_send = requests.Session.send 18 | super().setUpClass() 19 | cls.info_keys = [ 20 | "code_count", 21 | "documentation_count", 22 | "empty_count", 23 | "scanned_files", 24 | ] 25 | cls.model_gos = cls.env["github.organization.serie"] 26 | cls.model_gr = cls.env["github.repository"] 27 | cls.model_grb = cls.env["github.repository.branch"] 28 | cls.oca = cls.env.ref("github_connector.oca_organization") 29 | cls.serie_13 = cls.env.ref("github_connector.oca_organization_serie_13") 30 | cls.repository_ocb = cls.model_gr.create( 31 | { 32 | "name": "OCB", 33 | "organization_id": cls.oca.id, 34 | "github_id_external": 20558462, 35 | } 36 | ) 37 | cls.repository_interface_github = cls.model_gr.create( 38 | { 39 | "name": "interface-github", 40 | "organization_id": cls.oca.id, 41 | "github_id_external": 70173147, 42 | } 43 | ) 44 | # repository branch 45 | cls.repository_ocb_13 = cls.model_grb.create( 46 | { 47 | "name": cls.serie_13.name, 48 | "organization_id": cls.oca.id, 49 | "repository_id": cls.repository_ocb.id, 50 | "organization_serie_id": cls.serie_13.id, 51 | } 52 | ) 53 | cls.repository_interface_github_13 = cls.model_grb.create( 54 | { 55 | "name": cls.serie_13.name, 56 | "organization_id": cls.oca.id, 57 | "repository_id": cls.repository_interface_github.id, 58 | "organization_serie_id": cls.serie_13.id, 59 | } 60 | ) 61 | cls.env["ir.config_parameter"].set_param("github.access_token", "test") 62 | 63 | @responses.activate 64 | def _download_and_analyze(self, repo_branch): 65 | if repo_branch.state == "to_download": 66 | repo_branch._download_code() 67 | repo_branch.analyze_code_one() 68 | -------------------------------------------------------------------------------- /github_connector/tests/res/github_repo_70173147_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 70173147, 3 | "node_id": "MDEwOlJlcG9zaXRvcnk3MDE3MzE0Nw==", 4 | "name": "interface-github", 5 | "full_name": "OCA/interface-github", 6 | "private": false, 7 | "owner": { 8 | "login": "OCA", 9 | "id": 7600578, 10 | "node_id": "MDEyOk9yZ2FuaXphdGlvbjc2MDA1Nzg=", 11 | "avatar_url": "https://avatars.githubusercontent.com/u/7600578?v=4", 12 | "gravatar_id": "", 13 | "url": "https://api.github.com/users/OCA", 14 | "html_url": "https://github.com/OCA", 15 | "followers_url": "https://api.github.com/users/OCA/followers", 16 | "following_url": "https://api.github.com/users/OCA/following{/other_user}", 17 | "gists_url": "https://api.github.com/users/OCA/gists{/gist_id}", 18 | "starred_url": "https://api.github.com/users/OCA/starred{/owner}{/repo}", 19 | "subscriptions_url": "https://api.github.com/users/OCA/subscriptions", 20 | "organizations_url": "https://api.github.com/users/OCA/orgs", 21 | "repos_url": "https://api.github.com/users/OCA/repos", 22 | "events_url": "https://api.github.com/users/OCA/events{/privacy}", 23 | "received_events_url": "https://api.github.com/users/OCA/received_events", 24 | "type": "Organization", 25 | "site_admin": false 26 | }, 27 | "html_url": "https://github.com/OCA/interface-github", 28 | "description": "Tools to interact with github from Odoo", 29 | "fork": false, 30 | "url": "https://api.github.com/repos/OCA/interface-github", 31 | "forks_url": "https://api.github.com/repos/OCA/interface-github/forks", 32 | "keys_url": "https://api.github.com/repos/OCA/interface-github/keys{/key_id}", 33 | "collaborators_url": "https://api.github.com/repos/OCA/interface-github/collaborators{/collaborator}", 34 | "teams_url": "https://api.github.com/repos/OCA/interface-github/teams", 35 | "hooks_url": "https://api.github.com/repos/OCA/interface-github/hooks", 36 | "issue_events_url": "https://api.github.com/repos/OCA/interface-github/issues/events{/number}", 37 | "events_url": "https://api.github.com/repos/OCA/interface-github/events", 38 | "assignees_url": "https://api.github.com/repos/OCA/interface-github/assignees{/user}", 39 | "branches_url": "https://api.github.com/repos/OCA/interface-github/branches{/branch}", 40 | "tags_url": "https://api.github.com/repos/OCA/interface-github/tags", 41 | "blobs_url": "https://api.github.com/repos/OCA/interface-github/git/blobs{/sha}", 42 | "git_tags_url": "https://api.github.com/repos/OCA/interface-github/git/tags{/sha}", 43 | "git_refs_url": "https://api.github.com/repos/OCA/interface-github/git/refs{/sha}", 44 | "trees_url": "https://api.github.com/repos/OCA/interface-github/git/trees{/sha}", 45 | "statuses_url": "https://api.github.com/repos/OCA/interface-github/statuses/{sha}", 46 | "languages_url": "https://api.github.com/repos/OCA/interface-github/languages", 47 | "stargazers_url": "https://api.github.com/repos/OCA/interface-github/stargazers", 48 | "contributors_url": "https://api.github.com/repos/OCA/interface-github/contributors", 49 | "subscribers_url": "https://api.github.com/repos/OCA/interface-github/subscribers", 50 | "subscription_url": "https://api.github.com/repos/OCA/interface-github/subscription", 51 | "commits_url": "https://api.github.com/repos/OCA/interface-github/commits{/sha}", 52 | "git_commits_url": "https://api.github.com/repos/OCA/interface-github/git/commits{/sha}", 53 | "comments_url": "https://api.github.com/repos/OCA/interface-github/comments{/number}", 54 | "issue_comment_url": "https://api.github.com/repos/OCA/interface-github/issues/comments{/number}", 55 | "contents_url": "https://api.github.com/repos/OCA/interface-github/contents/{+path}", 56 | "compare_url": "https://api.github.com/repos/OCA/interface-github/compare/{base}...{head}", 57 | "merges_url": "https://api.github.com/repos/OCA/interface-github/merges", 58 | "archive_url": "https://api.github.com/repos/OCA/interface-github/{archive_format}{/ref}", 59 | "downloads_url": "https://api.github.com/repos/OCA/interface-github/downloads", 60 | "issues_url": "https://api.github.com/repos/OCA/interface-github/issues{/number}", 61 | "pulls_url": "https://api.github.com/repos/OCA/interface-github/pulls{/number}", 62 | "milestones_url": "https://api.github.com/repos/OCA/interface-github/milestones{/number}", 63 | "notifications_url": "https://api.github.com/repos/OCA/interface-github/notifications{?since,all,participating}", 64 | "labels_url": "https://api.github.com/repos/OCA/interface-github/labels{/name}", 65 | "releases_url": "https://api.github.com/repos/OCA/interface-github/releases{/id}", 66 | "deployments_url": "https://api.github.com/repos/OCA/interface-github/deployments", 67 | "created_at": "2016-10-06T16:42:24Z", 68 | "updated_at": "2022-06-22T12:50:39Z", 69 | "pushed_at": "2022-07-20T10:34:42Z", 70 | "git_url": "git://github.com/OCA/interface-github.git", 71 | "ssh_url": "git@github.com:OCA/interface-github.git", 72 | "clone_url": "https://github.com/OCA/interface-github.git", 73 | "svn_url": "https://github.com/OCA/interface-github", 74 | "homepage": null, 75 | "size": 1573, 76 | "stargazers_count": 39, 77 | "watchers_count": 39, 78 | "language": "Python", 79 | "has_issues": true, 80 | "has_projects": true, 81 | "has_downloads": true, 82 | "has_wiki": true, 83 | "has_pages": false, 84 | "forks_count": 64, 85 | "mirror_url": null, 86 | "archived": false, 87 | "disabled": false, 88 | "open_issues_count": 11, 89 | "license": { 90 | "key": "agpl-3.0", 91 | "name": "GNU Affero General Public License v3.0", 92 | "spdx_id": "AGPL-3.0", 93 | "url": "https://api.github.com/licenses/agpl-3.0", 94 | "node_id": "MDc6TGljZW5zZTE=" 95 | }, 96 | "allow_forking": true, 97 | "is_template": false, 98 | "web_commit_signoff_required": false, 99 | "topics": [], 100 | "visibility": "public", 101 | "forks": 64, 102 | "open_issues": 11, 103 | "watchers": 39, 104 | "default_branch": "13.0", 105 | "temp_clone_token": null, 106 | "organization": { 107 | "login": "OCA", 108 | "id": 7600578, 109 | "node_id": "MDEyOk9yZ2FuaXphdGlvbjc2MDA1Nzg=", 110 | "avatar_url": "https://avatars.githubusercontent.com/u/7600578?v=4", 111 | "gravatar_id": "", 112 | "url": "https://api.github.com/users/OCA", 113 | "html_url": "https://github.com/OCA", 114 | "followers_url": "https://api.github.com/users/OCA/followers", 115 | "following_url": "https://api.github.com/users/OCA/following{/other_user}", 116 | "gists_url": "https://api.github.com/users/OCA/gists{/gist_id}", 117 | "starred_url": "https://api.github.com/users/OCA/starred{/owner}{/repo}", 118 | "subscriptions_url": "https://api.github.com/users/OCA/subscriptions", 119 | "organizations_url": "https://api.github.com/users/OCA/orgs", 120 | "repos_url": "https://api.github.com/users/OCA/repos", 121 | "events_url": "https://api.github.com/users/OCA/events{/privacy}", 122 | "received_events_url": "https://api.github.com/users/OCA/received_events", 123 | "type": "Organization", 124 | "site_admin": false 125 | }, 126 | "network_count": 64, 127 | "subscribers_count": 31 128 | } 129 | -------------------------------------------------------------------------------- /github_connector/tests/res/github_search_issues_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "total_count": 280, 3 | "incomplete_results": false, 4 | "items": [ 5 | { 6 | "url": "https://api.github.com/repos/batterseapower/pinyin-toolkit/issues/132", 7 | "repository_url": "https://api.github.com/repos/batterseapower/pinyin-toolkit", 8 | "labels_url": "https://api.github.com/repos/batterseapower/pinyin-toolkit/issues/132/labels{/name}", 9 | "comments_url": "https://api.github.com/repos/batterseapower/pinyin-toolkit/issues/132/comments", 10 | "events_url": "https://api.github.com/repos/batterseapower/pinyin-toolkit/issues/132/events", 11 | "html_url": "https://github.com/batterseapower/pinyin-toolkit/issues/132", 12 | "id": 35802, 13 | "node_id": "MDU6SXNzdWUzNTgwMg==", 14 | "number": 132, 15 | "title": "Line Number Indexes Beyond 20 Not Displayed", 16 | "user": { 17 | "login": "Nick3C", 18 | "id": 90254, 19 | "node_id": "MDQ6VXNlcjkwMjU0", 20 | "avatar_url": "https://secure.gravatar.com/avatar/934442aadfe3b2f4630510de416c5718?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png", 21 | "gravatar_id": "", 22 | "url": "https://api.github.com/users/Nick3C", 23 | "html_url": "https://github.com/Nick3C", 24 | "followers_url": "https://api.github.com/users/Nick3C/followers", 25 | "following_url": "https://api.github.com/users/Nick3C/following{/other_user}", 26 | "gists_url": "https://api.github.com/users/Nick3C/gists{/gist_id}", 27 | "starred_url": "https://api.github.com/users/Nick3C/starred{/owner}{/repo}", 28 | "subscriptions_url": "https://api.github.com/users/Nick3C/subscriptions", 29 | "organizations_url": "https://api.github.com/users/Nick3C/orgs", 30 | "repos_url": "https://api.github.com/users/Nick3C/repos", 31 | "events_url": "https://api.github.com/users/Nick3C/events{/privacy}", 32 | "received_events_url": "https://api.github.com/users/Nick3C/received_events", 33 | "type": "User", 34 | "site_admin": true 35 | }, 36 | "labels": [ 37 | { 38 | "id": 4, 39 | "node_id": "MDU6TGFiZWw0", 40 | "url": "https://api.github.com/repos/batterseapower/pinyin-toolkit/labels/bug", 41 | "name": "bug", 42 | "color": "ff0000" 43 | } 44 | ], 45 | "state": "open", 46 | "assignee": null, 47 | "milestone": { 48 | "url": "https://api.github.com/repos/octocat/Hello-World/milestones/1", 49 | "html_url": "https://github.com/octocat/Hello-World/milestones/v1.0", 50 | "labels_url": "https://api.github.com/repos/octocat/Hello-World/milestones/1/labels", 51 | "id": 1002604, 52 | "node_id": "MDk6TWlsZXN0b25lMTAwMjYwNA==", 53 | "number": 1, 54 | "state": "open", 55 | "title": "v1.0", 56 | "description": "Tracking milestone for version 1.0", 57 | "creator": { 58 | "login": "octocat", 59 | "id": 1, 60 | "node_id": "MDQ6VXNlcjE=", 61 | "avatar_url": "https://github.com/images/error/octocat_happy.gif", 62 | "gravatar_id": "", 63 | "url": "https://api.github.com/users/octocat", 64 | "html_url": "https://github.com/octocat", 65 | "followers_url": "https://api.github.com/users/octocat/followers", 66 | "following_url": "https://api.github.com/users/octocat/following{/other_user}", 67 | "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", 68 | "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", 69 | "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", 70 | "organizations_url": "https://api.github.com/users/octocat/orgs", 71 | "repos_url": "https://api.github.com/users/octocat/repos", 72 | "events_url": "https://api.github.com/users/octocat/events{/privacy}", 73 | "received_events_url": "https://api.github.com/users/octocat/received_events", 74 | "type": "User", 75 | "site_admin": false 76 | }, 77 | "open_issues": 4, 78 | "closed_issues": 8, 79 | "created_at": "2011-04-10T20:09:31Z", 80 | "updated_at": "2014-03-03T18:58:10Z", 81 | "closed_at": "2013-02-12T13:22:01Z", 82 | "due_on": "2012-10-09T23:39:01Z" 83 | }, 84 | "comments": 15, 85 | "created_at": "2009-07-12T20:10:41Z", 86 | "updated_at": "2009-07-19T09:23:43Z", 87 | "closed_at": null, 88 | "pull_request": { 89 | "url": "https://api/github.com/repos/octocat/Hello-World/pull/1347", 90 | "html_url": "https://github.com/octocat/Hello-World/pull/1347", 91 | "diff_url": "https://github.com/octocat/Hello-World/pull/1347.diff", 92 | "patch_url": "https://api.github.com/repos/octocat/Hello-World/pulls/1347" 93 | }, 94 | "body": "...", 95 | "score": 1, 96 | "locked": true, 97 | "author_association": "COLLABORATOR" 98 | } 99 | ] 100 | } 101 | -------------------------------------------------------------------------------- /github_connector/tests/res/github_user_OCA-git-bot_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "login": "OCA-git-bot", 3 | "id": 8723280, 4 | "node_id": "MDQ6VXNlcjg3MjMyODA=", 5 | "avatar_url": "https://avatars.githubusercontent.com/u/8723280?v=4", 6 | "gravatar_id": "", 7 | "url": "https://api.github.com/users/OCA-git-bot", 8 | "html_url": "https://github.com/OCA-git-bot", 9 | "followers_url": "https://api.github.com/users/OCA-git-bot/followers", 10 | "following_url": "https://api.github.com/users/OCA-git-bot/following{/other_user}", 11 | "gists_url": "https://api.github.com/users/OCA-git-bot/gists{/gist_id}", 12 | "starred_url": "https://api.github.com/users/OCA-git-bot/starred{/owner}{/repo}", 13 | "subscriptions_url": "https://api.github.com/users/OCA-git-bot/subscriptions", 14 | "organizations_url": "https://api.github.com/users/OCA-git-bot/orgs", 15 | "repos_url": "https://api.github.com/users/OCA-git-bot/repos", 16 | "events_url": "https://api.github.com/users/OCA-git-bot/events{/privacy}", 17 | "received_events_url": "https://api.github.com/users/OCA-git-bot/received_events", 18 | "type": "User", 19 | "site_admin": false, 20 | "name": "OCA Bot", 21 | "company": "OCA", 22 | "blog": "", 23 | "location": null, 24 | "email": null, 25 | "hireable": null, 26 | "bio": null, 27 | "twitter_username": null, 28 | "public_repos": 1, 29 | "public_gists": 0, 30 | "followers": 24, 31 | "following": 0, 32 | "created_at": "2014-09-10T13:03:33Z", 33 | "updated_at": "2021-05-15T09:42:06Z" 34 | } 35 | -------------------------------------------------------------------------------- /github_connector/tests/test_github_connector.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2022 Tecnativa - Víctor Martínez 2 | # Copyright 2021 Tecnativa - João Marques 3 | # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). 4 | 5 | import json 6 | 7 | import responses 8 | 9 | from odoo.tools.misc import file_path 10 | 11 | from .common import TestGithubConnectorCommon 12 | 13 | 14 | class TestGithubConnector(TestGithubConnectorCommon): 15 | @classmethod 16 | def setUpClass(cls): 17 | super().setUpClass() 18 | # Create appropriate responses for the API calls 19 | jsonfile = file_path( 20 | "github_connector/tests/res/github_user_OCA-git-bot_response.json" 21 | ) 22 | cls.user_data = json.loads(open(jsonfile, "rb").read()) 23 | responses.add( 24 | responses.GET, 25 | "https://api.github.com:443/users/OCA-git-bot", 26 | json=cls.user_data, 27 | status=200, 28 | ) 29 | responses.add( 30 | responses.GET, 31 | "https://api.github.com:443/user/8723280", 32 | json=cls.user_data, 33 | status=200, 34 | ) 35 | responses.add( 36 | responses.GET, 37 | "https://api.github.com:443/orgs/OCA-git-bot", 38 | json={ 39 | "message": "Not Found", 40 | }, 41 | status=404, 42 | ) 43 | 44 | @responses.activate 45 | def test_partner_get_from_id_or_create(self): 46 | partner_model = self.env["res.partner"] 47 | partner = partner_model.create_from_name("OCA-git-bot") 48 | self.assertEqual(partner.github_name, "OCA-git-bot") 49 | # Check create process not really create new record 50 | res = partner_model.get_from_id_or_create(data={"login": "OCA-git-bot"}) 51 | self.assertEqual(partner.id, res.id) 52 | # Try to archive record and try to create again 53 | partner.active = False 54 | res = partner_model.get_from_id_or_create(data={"login": "OCA-git-bot"}) 55 | self.assertEqual(partner.id, res.id) 56 | -------------------------------------------------------------------------------- /github_connector/views/action.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | Organizations 11 | ir.actions.act_window 12 | github.organization 13 | kanban,list,form 14 | 15 | 16 | Users 17 | ir.actions.act_window 18 | res.partner 19 | kanban,list,form 20 | {'search_default_has_github_account':1} 21 | 22 | 23 | Teams 24 | ir.actions.act_window 25 | github.team 26 | kanban,list,form 27 | 28 | 29 | Teams 30 | ir.actions.act_window 31 | github.team.partner 32 | 33 | kanban,list,form 34 | 35 | 36 | Members 37 | ir.actions.act_window 38 | github.team.partner 39 | 40 | kanban,list,form 41 | 42 | 46 | Team 47 | ir.actions.act_window 48 | github.team.repository 49 | 53 | kanban,list,form 54 | 55 | 56 | Repositories 57 | ir.actions.act_window 58 | github.team.repository 59 | 60 | kanban,list,form 61 | 62 | 63 | 64 | Repositories 65 | ir.actions.act_window 66 | github.repository 67 | kanban,list,form 68 | 69 | 70 | Repository Branches 71 | ir.actions.act_window 72 | github.repository.branch 73 | kanban,list,form 74 | 75 | 76 | 77 | Load from Github Wizard 78 | ir.actions.act_window 79 | wizard.load.github.model 80 | form 81 | new 82 | 83 | 84 | Create Team in Github Wizard 85 | ir.actions.act_window 86 | wizard.create.team 87 | form 88 | new 89 | 90 | 91 | Create Repo in Github Wizard 92 | ir.actions.act_window 93 | wizard.create.repository 94 | form 95 | new 96 | 97 | 98 | Analysis rule 99 | github.analysis.rule 100 | list,form 101 | 102 | 103 | Analysis rule group 104 | github.analysis.rule.group 105 | list,form 106 | 107 | 108 | 109 | Branches by Serie 110 | ir.actions.act_window 111 | github.repository.branch 112 | graph,pivot 113 | {'search_default_group_by_organization_serie_id': True} 116 | 117 | 118 | 119 | Sizes by Serie 120 | ir.actions.act_window 121 | github.repository.branch 122 | graph,pivot 123 | {'search_default_group_by_organization_serie_id': True} 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /github_connector/views/menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | 21 | 27 | 33 | 40 | 41 | 47 | 53 | 59 | 60 | 67 | 74 | 81 | 88 | 95 | 102 | 103 | 104 | 110 | 116 | 117 | -------------------------------------------------------------------------------- /github_connector/views/view_github_analysis_rule.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | github.analysis.rule 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | github.analysis.rule 18 | 19 |
20 | 21 |
22 |

23 | 24 |

25 |
26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 44 | 45 | 46 | 47 |
48 |
49 |
50 |
51 |
52 | -------------------------------------------------------------------------------- /github_connector/views/view_github_analysis_rule_group.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | github.analysis.rule.group 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | github.analysis.rule.group 17 | 18 |
19 | 20 |
21 |

22 | 23 |

24 |
25 |
26 |
27 |
28 |
29 |
30 | -------------------------------------------------------------------------------- /github_connector/views/view_github_team_partner.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | github.team.partner 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | github.team.partner 20 | 21 | 22 | 23 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | github.team.partner 35 | 36 |
37 | 38 |
39 |
40 |

41 | 42 |

43 |

44 | 45 |

46 |
47 | 48 | 49 | 50 | 51 | 52 | 53 | github.team.partner.kanban 54 | github.team.partner 55 | 56 | 57 | 58 | 59 | 60 | 71 |
72 |
73 |

74 | 75 |

76 | 77 | 82 | 83 | 84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 | 92 | github.team.partner 93 | 94 | 95 | 96 | 97 | 98 | 99 | 110 |
111 |
112 |

113 | 114 |

115 | 116 | 121 | 122 | 123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 | 131 | -------------------------------------------------------------------------------- /github_connector/views/view_reporting.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | github.repository.branch 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | github.repository.branch 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /github_connector/views/view_res_partner.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | res.partner 10 | 11 | 12 | 13 | 18 | 19 | 20 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | res.partner 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
  • 41 | 42 |
  • 43 |
    44 |
    45 |
    46 | 47 | res.partner 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | res.partner 58 | 59 | 60 |
    61 | 74 | 83 |
    84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 |
    70 | 71 | github.repository.branch 72 | 76 | 77 | 78 | 79 | 80 | 81 | Modules 84 | 85 | 86 | 87 |
    88 | -------------------------------------------------------------------------------- /github_connector_odoo/views/view_odoo_author.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | odoo.author 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | odoo.author 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | odoo.author 27 | 28 |
    29 | 30 |
    31 | 45 |
    46 |
    47 |

    48 | 49 |

    50 |
    51 | 52 |
    53 |
    54 |
    55 |
    56 |
    57 | -------------------------------------------------------------------------------- /github_connector_odoo/views/view_odoo_lib_bin.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | odoo.lib.bin 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | odoo.lib.bin 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | odoo.lib.bin 27 | 28 |
    29 | 30 |
    31 | 45 |
    46 |
    47 |

    48 | 49 |

    50 |
    51 | 52 |
    53 |
    54 |
    55 |
    56 |
    57 | -------------------------------------------------------------------------------- /github_connector_odoo/views/view_odoo_lib_python.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | odoo.lib.python 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | odoo.lib.python 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | odoo.lib.python 27 | 28 |
    29 | 30 |
    31 | 45 |
    46 |
    47 |

    48 | 49 |

    50 |
    51 | 52 |
    53 |
    54 |
    55 |
    56 |
    57 | -------------------------------------------------------------------------------- /github_connector_odoo/views/view_odoo_license.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | odoo.license 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | odoo.license 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | odoo.license 27 | 28 |
    29 | 30 |
    31 | 45 |
    46 | 47 | 53 | 54 |
    55 |

    56 | 57 |

    58 |
    59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 |
    70 |
    71 |
    72 |
    73 | 74 | odoo.license 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 96 |
    97 |
    98 |

    99 | 100 |

    101 |

    102 | 103 | 104 | 105 | 106 |
    107 |
    108 |

    109 | 110 | 111 | 112 |
    113 |
    114 |
    115 |
    116 |
    117 |
    118 |
    119 |
    120 | -------------------------------------------------------------------------------- /github_connector_odoo/views/view_reporting.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | odoo.module.version 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /prettier.config.cjs: -------------------------------------------------------------------------------- 1 | /** @type {import('prettier').Config} */ 2 | 3 | const config = { 4 | // https://github.com/prettier/prettier/issues/15388#issuecomment-1717746872 5 | plugins: [require.resolve("@prettier/plugin-xml")], 6 | bracketSpacing: false, 7 | printWidth: 88, 8 | proseWrap: "always", 9 | semi: true, 10 | trailingComma: "es5", 11 | xmlWhitespaceSensitivity: "preserve", 12 | }; 13 | 14 | module.exports = config; 15 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # generated from manifests external_dependencies 2 | GitPython 3 | PyGithub 4 | pathspec 5 | -------------------------------------------------------------------------------- /setup/_metapackage/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "odoo-addons-oca-interface-github" 3 | version = "18.0.20250522.0" 4 | dependencies = [ 5 | "odoo-addon-github_connector==18.0.*", 6 | "odoo-addon-github_connector_odoo==18.0.*", 7 | ] 8 | classifiers=[ 9 | "Programming Language :: Python", 10 | "Framework :: Odoo", 11 | "Framework :: Odoo :: 18.0", 12 | ] 13 | -------------------------------------------------------------------------------- /test-requirements.txt: -------------------------------------------------------------------------------- 1 | responses 2 | Pygments 3 | --------------------------------------------------------------------------------