diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000000..6bcce42f549 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,17 @@ +--- +name: Feature request +about: Suggest an idea for this project + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/issue.md b/.github/ISSUE_TEMPLATE/issue.md new file mode 100644 index 00000000000..81b1400103d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/issue.md @@ -0,0 +1,36 @@ +--- +name: Issue +about: Create a new issue + +--- + + + +## Version of HACS + + + +## Describe the bug +A clear and concise description of what the bug is. + + +## Debug log + + + +```text + +Add your logs here. + +``` \ No newline at end of file diff --git a/.github/settings.yml b/.github/settings.yml new file mode 100644 index 00000000000..6b75ccc1f6b --- /dev/null +++ b/.github/settings.yml @@ -0,0 +1,23 @@ +repository: + private: false + has_issues: true + has_projects: false + has_wiki: false + has_downloads: false + default_branch: master + allow_squash_merge: true + allow_merge_commit: false + allow_rebase_merge: false +labels: + - name: "Feature Request" + color: "fbca04" + - name: "Bug" + color: "b60205" + - name: "Wont Fix" + color: "ffffff" + - name: "Enhancement" + color: a2eeef + - name: "Documentation" + color: "008672" + - name: "Stale" + color: "930191" \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000000..eadefd3e17f --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Joakim Sørensen @ludeeus + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/custom_components/hacs/__init__.py b/custom_components/hacs/__init__.py index eaa8efa700c..07754ce9d7e 100644 --- a/custom_components/hacs/__init__.py +++ b/custom_components/hacs/__init__.py @@ -2,16 +2,7 @@ Custom element manager for community created elements. For more details about this component, please refer to the documentation at -https://github.com/custom-components/hacs (eventually) - -For now: -in configuration.yaml: -hacs: - token: xxxxxxxxxxxxxxxxxx -------------------------------------- -The token is a GitHub Access token, you can create one here: -https://github.com/settings/tokens -You don't have to check any of the boxes. +https://custom-components.github.io/hacs/ """ import logging import os.path @@ -59,6 +50,9 @@ INTERVAL = timedelta(minutes=500) +# TODO: Requirements are not loaded from manifest, needs investigation. +REQUIREMENTS = ["PyGithub", "markdown"] + _LOGGER = logging.getLogger(__name__) CONFIG_SCHEMA = vol.Schema( @@ -144,6 +138,9 @@ async def startup_tasks(self): self.hass.data[DOMAIN_DATA]["repos"] = returndata["repos"] self.hass.data[DOMAIN_DATA]["hacs"] = returndata["hacs"] + # Make sure we have the correct version + self.hass.data[DOMAIN_DATA]["hacs"]["local"] = VERSION + # Reset restart_pending flag self.hass.data[DOMAIN_DATA]["hacs"]["restart_pending"] = False for element in self.hass.data[DOMAIN_DATA]["elements"]: diff --git a/custom_components/hacs/const.py b/custom_components/hacs/const.py index 2f3e8e0b6a5..aded3a2f560 100644 --- a/custom_components/hacs/const.py +++ b/custom_components/hacs/const.py @@ -1,5 +1,5 @@ """Constants for HACS""" -VERSION = None +VERSION = "0.1.0" NAME_LONG = "HACS (Home Assistant Community Store)" NAME_SHORT = "HACS" STORENAME = "hacs" diff --git a/custom_components/hacs/element.py b/custom_components/hacs/element.py index d08ccd8279c..1b1e738c002 100644 --- a/custom_components/hacs/element.py +++ b/custom_components/hacs/element.py @@ -15,8 +15,7 @@ def __init__(self, element_type, name): self.isinstalled = False self.installed_version = None self.avaiable_version = None - self.example_config = None - self.example_image = None + self.info = None self.manifest = None self.remote_dir_location = None self.authors = [] diff --git a/custom_components/hacs/frontend/elements/generate.py b/custom_components/hacs/frontend/elements/generate.py index 76ef54e3816..eb231709a06 100644 --- a/custom_components/hacs/frontend/elements/generate.py +++ b/custom_components/hacs/frontend/elements/generate.py @@ -48,6 +48,7 @@ async def avaiable_version(self):

Available version: {}

+
""".format( self.element.avaiable_version ) @@ -136,14 +137,12 @@ async def element_note(self): When installed, this will be located in '{config}/www/community/{element}', you still need to add it to your lovelace configuration ('ui-lovelace.yaml' or the raw UI config editor). -
+

When you add this to your configuration use this as the URL:
- - '/community_plugin/{element}/{file_name}.js' - +
url: /community_plugin/{element}/{file_name}.js


To learn more about how to configure this, @@ -157,40 +156,35 @@ async def element_note(self): else: return "" - async def example_config(self): - """Generate example config.""" - _LOGGER.debug("Generating example config for %s", self.element.element_id) + async def info(self): + """Generate info.""" + import markdown - if self.element.example_config is None: - return "" + _LOGGER.debug("Generating info for %s", self.element.element_id) - return """ -
-

- Example configuration: -

-
-          
- """.format( - self.element.example_config - ) - - async def example_image(self): - """Generate example image.""" - _LOGGER.debug("Generating example image for %s", self.element.element_id) - - if self.element.example_image is None: + if self.element.info is None: return "" - return """ -

- -
- """.format( - self.element.example_image + markdown_render = markdown.markdown( + self.element.info, + extensions=["markdown.extensions.tables", "markdown.extensions.codehilite"], ) + markdown_render = markdown_render.replace("

", "

").replace( + "
", "" + ) + markdown_render = markdown_render.replace("

", "

").replace( + "
", "" + ) + markdown_render = markdown_render.replace("

", "

").replace( + "

", "" + ) + markdown_render = markdown_render.replace("", "
").replace(
+            "", "
" + ) + markdown_render = markdown_render.replace( + "", "
" + ) + return "{}".format(markdown_render) async def installed_version(self): """Generate installed version.""" @@ -200,7 +194,6 @@ async def installed_version(self): return "" return """ -

Installed version: {}

diff --git a/custom_components/hacs/frontend/views/element.py b/custom_components/hacs/frontend/views/element.py index 84bc07b5be4..2df1b6d7a51 100644 --- a/custom_components/hacs/frontend/views/element.py +++ b/custom_components/hacs/frontend/views/element.py @@ -70,8 +70,7 @@ async def element_view_content(self): changelog = await self.generate.changelog() description = await self.generate.description() element_note = await self.generate.element_note() - example_config = await self.generate.example_config() - example_image = await self.generate.example_image() + info = await self.generate.info() installed_version = await self.generate.installed_version() main_action = await self.generate.main_action() name = self.element.name @@ -89,8 +88,7 @@ async def element_view_content(self): {description} {installed_version} {avaiable_version} - {example_image} - {example_config} + {info}
{authors} {element_note} @@ -110,8 +108,7 @@ async def element_view_content(self): changelog=changelog, description=description, element_note=element_note, - example_config=example_config, - example_image=example_image, + info=info, installed_version=installed_version, main_action=main_action, name=name, diff --git a/custom_components/hacs/handler/download.py b/custom_components/hacs/handler/download.py index d7a2618eb00..d34d36dafcb 100644 --- a/custom_components/hacs/handler/download.py +++ b/custom_components/hacs/handler/download.py @@ -17,8 +17,6 @@ async def async_download_file(hass, url): """ Download files, and return the content. """ - _LOGGER.debug("Donwloading from %s", url) - # There is a bug somewhere... TODO: Find that bug.... if "tags/" in url: _LOGGER.debug( @@ -26,18 +24,25 @@ async def async_download_file(hass, url): ) url = url.replace("tags/", "") + _LOGGER.debug("Donwloading from %s", url) + result = None - with async_timeout.timeout(5, loop=hass.loop): - request = await async_get_clientsession(hass).get(url) + try: + with async_timeout.timeout(5, loop=hass.loop): + request = await async_get_clientsession(hass).get(url) + + # Make sure that we got a valid result + if request.status == 200: + result = await request.text() + else: + _LOGGER.debug( + "Got status code %s when trying to download %s", request.status, url + ) + + except Exception as error: # pylint: disable=broad-except + _LOGGER.debug("Downloading %s failed with %s", url, error) - # Make sure that we got a valid result - if request.status == 200: - result = await request.text() - else: - _LOGGER.debug( - "Got status code %s when trying to download %s", request.status, url - ) return result diff --git a/custom_components/hacs/handler/update.py b/custom_components/hacs/handler/update.py index 581676439f8..173ebb44f84 100644 --- a/custom_components/hacs/handler/update.py +++ b/custom_components/hacs/handler/update.py @@ -138,17 +138,12 @@ async def load_integrations_from_git(hass, repo_name): ################### Load custom info from repo. ################### - # Get example config + # Get info.md try: - example = repo.get_file_contents("example.yaml", ref).decoded_content.decode() - element.example_config = example - except Exception as error: # pylint: disable=broad-except - _LOGGER.debug(error) - - # Get example image - try: - element.example_image = repo.get_file_contents("example.png").download_url + info = repo.get_file_contents("info.md", ref).decoded_content.decode() + element.info = info except Exception as error: # pylint: disable=broad-except + element.info = "" _LOGGER.debug(error) # PrettyDescription @@ -188,6 +183,8 @@ async def load_plugins_from_git(hass, repo_name): # Try to find files files = [] + repo_root = repo.get_dir_contents("", ref) + if element.remote_dir_location is None: # Try RepoRoot/dist/ try: @@ -203,8 +200,7 @@ async def load_plugins_from_git(hass, repo_name): if element.remote_dir_location is None: # Try RepoRoot/ try: - test_remote_dir_location = repo.get_dir_contents("", ref) - for file in list(test_remote_dir_location): + for file in list(repo_root): if file.name.endswith(".js"): files.append(file) if files: @@ -227,17 +223,13 @@ async def load_plugins_from_git(hass, repo_name): element.repo = repo_name ################### Load custom info from repo. ################### - # Get example config - try: - example = repo.get_file_contents("example.yaml", ref).decoded_content.decode() - element.example_config = example - except Exception as error: # pylint: disable=broad-except - _LOGGER.debug(error) - # Get example image + # Get info.md try: - element.example_image = repo.get_file_contents("example.png").download_url + info = repo.get_file_contents("info.md", ref).decoded_content.decode() + element.info = info except Exception as error: # pylint: disable=broad-except + element.info = "" _LOGGER.debug(error) # PrettyDescription diff --git a/custom_components/hacs/manifest.json b/custom_components/hacs/manifest.json index 4eeebe07212..85f8c630260 100644 --- a/custom_components/hacs/manifest.json +++ b/custom_components/hacs/manifest.json @@ -4,5 +4,5 @@ "documentation": "https://custom-components.github.io/hacs", "dependencies": ["logger"], "codeowners": ["@ludeeus"], - "requirements": ["PyGithub"] + "requirements": ["PyGithub", "Markdown"] } \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index 9381645ae45..01ea2a675e5 100644 --- a/docs/index.md +++ b/docs/index.md @@ -50,12 +50,7 @@ The description for each element are gathered from the description of the reposi The version it shows/uses are gathered from the tag name of the latest release. -If you want to add a richer experience for your users you can add some extra files to the root of your repository (this is optional). - -filename | description --- | -- -`example.yaml` | A configuration example for your element. -`example.png` | A Sample image of how this can look. +If you want to add a richer experience for your users you can add a `info.md` file to the root of your repository (this is optional), this file will be rendered under the repository description, it does not support the full styling options as Github so use with care. ### Note for integration developers @@ -139,6 +134,8 @@ For new features / Changes to existing features or other big changes, please ope # Last notes from the initial developer +First startup after installation will take some time, but it's worth it. + This was developed under the influence of 🍺, a lot of 🍺, [if you want to support my work feel free to buy me a ☕️ (most likely 🍺)](meacoffee.com/ludeeus) How it works and what it does are added based on a single persons mindset, you may not agree with what I have done, if you have a suggestion please open an [RFC](https://github.com/custom-components/hacs/issues) diff --git a/docs/install.md b/docs/install.md index 57c0ac8d045..cb1f4f435df 100644 --- a/docs/install.md +++ b/docs/install.md @@ -9,6 +9,8 @@ **NB!: If you move from [`custom_updater`](https://github.com/custom-components/custom_updater) to this see the special note at the bottom here.** +**NB!: You need to have added `logger:` to your `configuration.yaml` for this to work.** + This integration requires **a lot** of files. The easiest way to make sure that you have them all is to download the `.zip` file from the repo.