[
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "content": "* git-notion version:\n* Python version:\n* Operating System:\n\n### Description\n\nDescribe what you were trying to get done.\nTell us what happened, what went wrong, and what you expected to happen.\n\n### What I Did\n\n```\nPaste the command(s) you ran and the output.\nIf there was a crash, please include the traceback here.\n```\n"
  },
  {
    "path": ".github/workflows/sync-md2notion-pr-merge.yml",
    "content": "name: Sync md files to notion when PR merged\n\non:\n  pull_request:\n    types: [closed]\n\njobs:\n  sync:\n    timeout-minutes: 10\n    runs-on: ubuntu-latest\n    steps:\n        - uses: actions/checkout@v2\n        - name: Setup Python\n          uses: actions/setup-python@v2\n          with:\n            python-version: '3.x'\n        - name: Cache pip\n          uses: actions/cache@v2\n          with:\n            # This path is specific to Ubuntu\n            path: ~/.cache/pip\n            # Look to see if there is a cache hit for the corresponding requirements file\n            key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}\n            restore-keys: |\n              ${{ runner.os }}-pip-\n              ${{ runner.os }}-\n        - name: Install dependencies\n          run: |\n            python -m pip install --upgrade pip git-notion\n        - name: Sync md doc\n          run: |\n            git-notion\n          env:\n            NOTION_IGNORE_REGEX: ${{ secrets.NOTION_IGNORE_REGEX }}\n            NOTION_ROOT_PAGE: ${{ secrets.NOTION_ROOT_PAGE }}\n            NOTION_TOKEN_V2: ${{ secrets.NOTION_TOKEN_V2 }}"
  },
  {
    "path": ".gitignore",
    "content": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\nenv/\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\nwheels/\n*.egg-info/\n.installed.cfg\n*.egg\n\n# PyInstaller\n#  Usually these files are written by a python script from a template\n#  before PyInstaller builds the exe, so as to inject date/other infos into it.\n*.manifest\n*.spec\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.coverage\n.coverage.*\n.cache\nnosetests.xml\ncoverage.xml\n*.cover\n.hypothesis/\n.pytest_cache/\n\n# Translations\n*.mo\n*.pot\n\n# Django stuff:\n*.log\nlocal_settings.py\n\n# Flask stuff:\ninstance/\n.webassets-cache\n\n# Scrapy stuff:\n.scrapy\n\n# Sphinx documentation\ndocs/_build/\n\n# PyBuilder\ntarget/\n\n# Jupyter Notebook\n.ipynb_checkpoints\n\n# pyenv\n.python-version\n\n# celery beat schedule file\ncelerybeat-schedule\n\n# SageMath parsed files\n*.sage.py\n\n# dotenv\n.env\n\n# virtualenv\n.venv\nvenv/\nENV/\n\n# Spyder project settings\n.spyderproject\n.spyproject\n\n# Rope project settings\n.ropeproject\n\n# mkdocs documentation\n/site\n\n# mypy\n.mypy_cache/\n\n# IDE settings\n.vscode/"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2020, NarekA\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "README.md",
    "content": "Git Notion\n==========\n\nSyncs Github markdown files in your repository to Notion.\n\nThis utility is described in the following [blog post](https://www.swiftlane.com/blog/syncing-docs-from-code-repositories-to-notion/).\n\nSee example [Notion page](https://www.notion.so/git_notion-195c08d3d14140eb9a35ac00f9a0f078).\n\n## Installation\n```\npip install git-notion\n```\n\nor for local installation:\n\n```bash\ngit clone https://github.com/NarekA/git-notion.git\ncd git-notion\npip install -e .\n```\n\n## Configuring\n\n`NOTION_TOKEN_V2` - Can be found in your [browser cookies](https://www.redgregory.com/notion/2020/6/15/9zuzav95gwzwewdu1dspweqbv481s5) for Notion's website.\n`NOTION_ROOT_PAGE` - URL for notion page. Repo docs will be a new page under this page.\n`NOTION_IGNORE_REGEX` - Regex for paths to ignore.\n\nThese environment variables can be set.\n```bash\nexport NOTION_TOKEN_V2=<YOUR_TOKEN>\nexport NOTION_ROOT_PAGE=\"https://www.notion.so/...\"  # Can be in setup.cfg as well\nexport NOTION_IGNORE_REGEX=\"models/.*\"               # Can be in setup.cfg as well\n```\n\nThese parameters can be set in the `setup.cfg` for the repo.\n```\n[git-notion]\nignore_regex = models/.*\nnotion_root_page = https://www.notion.so/...\n```\n\nIf you want to map specific Github folders to Notion subpages besides the `notion_root_page`, you can add the folder names and subpage URLs as parameters in the `setup.cfg` for the repo:\n```\n[folders]\n# docs = <any_notion_url> # This can be any subpage of the Notion root page\n# docs/NestedTest = <any_other_notion_url> # This can be the same subpage as above, or any other subpage of the Notion root page\n```\n\n## Usage\n\n```bash\n# To upload your current directory\ngit-notion\n\n# To upload another directory\ngit-notion --path path/to/your/repo\n```\n\n\n## Pushing to PYPI\n\n```bash\nbumpversion patch   # Look-up bumpversion\nrm -rf dist/\npython3 setup.py sdist bdist_wheel\npython3 -m twine upload dist/*\n```\n"
  },
  {
    "path": "docs/NestedTest/nested_example.md",
    "content": "### Heading for Test\nHere's an example of a markdown file that's in a nested folder within the folder `docs`. We can also add the folder path `docs/NestedDocs` in  `setup.cfg` to pick up this file to the specified Notion URL.\n"
  },
  {
    "path": "docs/example.md",
    "content": "Example\n==\n\nThis is an example markdown file to sync.\n\nIf you add the `docs` folder name to the `[folders]` config settings in `setup.cfg`, this file will sync to the specified Notion subpage URL.\n"
  },
  {
    "path": "git_notion/__init__.py",
    "content": "\"\"\"Top-level package for git-notion.\"\"\"\n\n__author__ = \"\"\"NarekA\"\"\"\n__version__ = '0.2.4'\n\nfrom git_notion.git_notion import *\n"
  },
  {
    "path": "git_notion/cli.py",
    "content": "\"\"\"Console script for git_notion.\"\"\"\nimport sys\nimport click\nimport git_notion\n\n\n@click.command()\n@click.option('--path', default=\".\", help='The path to the repo you want to sync')\ndef main(path):\n    \"\"\"Console script for git_notion.\"\"\"\n    click.echo(\"running sync\")\n    git_notion.sync_to_notion(path)\n    return 0\n\n\nif __name__ == \"__main__\":\n    sys.exit(main())  # pragma: no cover\n"
  },
  {
    "path": "git_notion/git_notion.py",
    "content": "\"\"\"Main module.\"\"\"\nimport hashlib\nimport os\nimport glob\nfrom configparser import ConfigParser\nimport re\n\nfrom notion.block import PageBlock\nfrom notion.block import TextBlock\nfrom notion.client import NotionClient\nfrom md2notion.upload import upload\n\n\nTOKEN = os.getenv(\"NOTION_TOKEN_V2\", \"\")\n_client = None\n\n\ndef get_client():\n    global _client\n    if not _client:\n        _client = NotionClient(token_v2=TOKEN)\n    return _client\n\n\ndef get_or_create_page(base_page, title):\n    page = None\n    for child in base_page.children.filter(PageBlock):\n        if child.title == title:\n            page = child\n\n    if not page:\n        page = base_page.children.add_new(PageBlock, title=title)\n    return page\n\n\ndef upload_file(base_page, filename: str, page_title=None):\n    page_title = page_title or filename\n    page = get_or_create_page(base_page, page_title)\n    hasher = hashlib.md5()\n    with open(filename, \"rb\") as mdFile:\n        buf = mdFile.read()\n        hasher.update(buf)\n    if page.children and hasher.hexdigest() in str(page.children[0]):\n        return page\n\n    for child in page.children:\n        child.remove()\n    page.children.add_new(TextBlock, title=f\"MD5: {hasher.hexdigest()}\")\n\n    with open(filename, \"r\", encoding=\"utf-8\") as mdFile:\n        upload(mdFile, page)\n    return page\n\n\ndef sync_to_notion(repo_root: str = \".\"):\n    os.chdir(repo_root)\n    config = ConfigParser()\n    config.read(os.path.join(repo_root, \"setup.cfg\"))\n    repo_name = os.path.basename(os.getcwd())\n\n    root_page_url = os.getenv(\"NOTION_ROOT_PAGE\") or config.get('git-notion', 'notion_root_page')\n    ignore_regex = os.getenv(\"NOTION_IGNORE_REGEX\") or config.get('git-notion', 'ignore_regex', fallback=None)\n    root_page = get_client().get_block(root_page_url)\n    repo_page = get_or_create_page(root_page, repo_name)\n\n    for file in glob.glob(\"**/*.md\", recursive=True):\n        if ignore_regex is None or not re.match(ignore_regex, file):\n\n            # Extract folder from the file path\n            folder = os.path.dirname(file)\n\n            # Use folder-specific URL if available, otherwise use the default repo_page URL\n            folder_url = config.get('folders', folder, fallback=None)\n            upload_file(repo_page if folder_url is None else get_client().get_block(folder_url), file)\n            if folder_url:\n                print(file, \"uploaded to: \", folder_url)\n            else:\n                print(file, \"uploaded to: default repo page\")\n\n\n\n# Example call:\n# sync_to_notion(repo_root=\"/path/to/repo\", config_file_path=\"notion_config.ini\")\n"
  },
  {
    "path": "requirements.in",
    "content": "click\nmd2notion"
  },
  {
    "path": "setup.cfg",
    "content": "[bumpversion]\ncurrent_version = 0.2.4\ncommit = True\ntag = True\n\n[bumpversion:file:setup.py]\nsearch = version='{current_version}'\nreplace = version='{new_version}'\n\n[bumpversion:file:git_notion/__init__.py]\nsearch = __version__ = '{current_version}'\nreplace = __version__ = '{new_version}'\n\n[bdist_wheel]\nuniversal = 1\n\n[flake8]\nexclude = docs\n\n[aliases]\ntest = pytest\n\n[tool:pytest]\ncollect_ignore = ['setup.py']\n\n[git-notion]\nnotion_root_page = https://www.notion.so/Git-Documents-6cf97b2d7ab64a7d964c7a7bcc42f9aa\n\n[folders]\n# docs = <any_notion_url> # This can be any subpage of the Notion root page\n# docs/NestedTest = <any_other_notion_url> # This can be the same subpage as above, or any other subpage of the Notion root page\n"
  },
  {
    "path": "setup.py",
    "content": "#!/usr/bin/env python\n\nfrom setuptools import setup, find_packages\nimport os\n\nbase_dir = os.path.abspath(os.path.dirname(__file__))\n\nwith open(os.path.join('requirements.in')) as f:\n    requirements = [l.strip() for l in f.readlines() if l.strip()]\n\nwith open(os.path.join(base_dir, 'README.md'), encoding='utf-8') as f:\n    long_description = f.read()\n\nsetup_requirements = ['pytest-runner', ]\n\ntest_requirements = ['pytest>=3', ]\n\nsetup(\n    author=\"NarekA\",\n    python_requires='>=3.5',\n    classifiers=[\n        'Development Status :: 2 - Pre-Alpha',\n        'Intended Audience :: Developers',\n        'License :: OSI Approved :: MIT License',\n        'Natural Language :: English',\n        'Programming Language :: Python :: 3',\n        'Programming Language :: Python :: 3.5',\n        'Programming Language :: Python :: 3.6',\n        'Programming Language :: Python :: 3.7',\n        'Programming Language :: Python :: 3.8',\n    ],\n    description=\"Syncs Github Mmarkdown files to Notion\",\n    entry_points={\n        'console_scripts': [\n            'git-notion=git_notion.cli:main',\n        ],\n    },\n    install_requires=requirements,\n    license=\"MIT license\",\n    include_package_data=True,\n    keywords='git_notion',\n    long_description=long_description,\n    long_description_content_type='text/markdown',\n    name='git_notion',\n    packages=find_packages(include=['git_notion', 'git_notion.*']),\n    setup_requires=setup_requirements,\n    test_suite='tests',\n    tests_require=test_requirements,\n    url='https://github.com/NarekA/git-notion',\n    version='0.2.5',\n    zip_safe=False,\n)\n"
  },
  {
    "path": "tests/__init__.py",
    "content": "\"\"\"Unit test package for git_notion.\"\"\"\n"
  },
  {
    "path": "tests/test_git_notion.py",
    "content": "#!/usr/bin/env python\n\n\"\"\"Tests for `git_notion` package.\"\"\"\n\nimport pytest\n\nfrom click.testing import CliRunner\n\nfrom git_notion import git_notion\nfrom git_notion import cli\n\n\n@pytest.fixture\ndef response():\n    \"\"\"Sample pytest fixture.\n\n    See more at: http://doc.pytest.org/en/latest/fixture.html\n    \"\"\"\n    # import requests\n    # return requests.get('https://github.com/audreyr/cookiecutter-pypackage')\n\n\ndef test_content(response):\n    \"\"\"Sample pytest test function with the pytest fixture as an argument.\"\"\"\n    # from bs4 import BeautifulSoup\n    # assert 'GitHub' in BeautifulSoup(response.content).title.string\n\n\ndef test_command_line_interface():\n    \"\"\"Test the CLI.\"\"\"\n    runner = CliRunner()\n    result = runner.invoke(cli.main)\n    assert result.exit_code == 0\n    assert 'git_notion.cli.main' in result.output\n    help_result = runner.invoke(cli.main, ['--help'])\n    assert help_result.exit_code == 0\n    assert '--help  Show this message and exit.' in help_result.output\n"
  }
]