Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GitLab-CI sensor integration addition. #16561

Merged
merged 22 commits into from
Sep 25, 2018
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
ccd049c
Updates to GitLab Sensor
DanielWinks Sep 5, 2018
c48713a
Updates to GitLab_CI sensor.
DanielWinks Sep 5, 2018
9cb8d9e
Added GitLab_CI sensor.
DanielWinks Sep 10, 2018
28e00ab
Updated interval to a more appropriate 300 seconds.
DanielWinks Sep 10, 2018
d12e642
Added GitLab_CI.py to ommitted files.
DanielWinks Sep 11, 2018
04b1252
Merge remote-tracking branch 'origin/dev' into dev
DanielWinks Sep 13, 2018
68f0684
Initial refactor to use python-gitlab PyPI module.
DanielWinks Sep 13, 2018
4944692
Fixes to dict parsing.
DanielWinks Sep 13, 2018
ef7a326
Updated required packages for GitLab_CI requirements.
DanielWinks Sep 13, 2018
1266c99
Updates and refactoring to more closely align with Home-Assistant sta…
DanielWinks Sep 14, 2018
55a3464
Merge remote-tracking branch 'origin/dev' into dev
DanielWinks Sep 14, 2018
2a22416
Moved import to init, removed unreachable requests exception.
DanielWinks Sep 14, 2018
bde9fdc
Removed references to STATE_UNKNOWN and replaced with None
DanielWinks Sep 17, 2018
10cf054
Merge branch 'dev' of github.com:DanielWinks/home-assistant into dev
DanielWinks Sep 17, 2018
fd98338
Removed extra whitespace
DanielWinks Sep 17, 2018
58dcf3e
Changed PLATFORM_SCHEMA and renamed add_devices.
DanielWinks Sep 21, 2018
f364e76
Merge remote-tracking branch 'upstream/dev' into dev
DanielWinks Sep 21, 2018
b473850
Added configurable name, changed logger and removed cruft.
DanielWinks Sep 21, 2018
2282c43
Removed _status to use _state instead, as both held same value.
DanielWinks Sep 21, 2018
3dcc7cc
Fixed ATTR_BUILD_BRANCH, removed more extraneous cruft.
DanielWinks Sep 21, 2018
8f58654
Changed required config keys to dict[key] format.
DanielWinks Sep 21, 2018
cb626f2
Removed extraneous CONF_SCAN_INTERVAL as it's already defined.
DanielWinks Sep 21, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -679,6 +679,7 @@ omit =
homeassistant/components/sensor/fritzbox_netmonitor.py
homeassistant/components/sensor/gearbest.py
homeassistant/components/sensor/geizhals.py
homeassistant/components/sensor/gitlab_ci.py
homeassistant/components/sensor/gitter.py
homeassistant/components/sensor/glances.py
homeassistant/components/sensor/google_travel_time.py
Expand Down
183 changes: 183 additions & 0 deletions homeassistant/components/sensor/gitlab_ci.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
"""Module for retrieving latest GitLab CI job information."""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update the docstring to match other platforms.

from datetime import timedelta
import logging

import voluptuous as vol

from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.const import (
ATTR_ATTRIBUTION, CONF_NAME, CONF_SCAN_INTERVAL, CONF_TOKEN, CONF_URL)
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import Entity
from homeassistant.util import Throttle

CONF_GITLAB_ID = 'gitlab_id'
CONF_ATTRIBUTION = "Information provided by https://gitlab.com/"

ICON_HAPPY = 'mdi:emoticon-happy'
ICON_SAD = 'mdi:emoticon-happy'
ICON_OTHER = 'mdi:git'

ATTR_BUILD_ID = 'build id'
ATTR_BUILD_STATUS = 'build_status'
ATTR_BUILD_STARTED = 'build_started'
ATTR_BUILD_FINISHED = 'build_finished'
ATTR_BUILD_DURATION = 'build_duration'
ATTR_BUILD_COMMIT_ID = 'commit id'
ATTR_BUILD_COMMIT_DATE = 'commit date'
ATTR_BUILD_BRANCH = 'master'

SCAN_INTERVAL = timedelta(seconds=300)

_LOGGER = logging.getLogger(__name__)

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_TOKEN): cv.string,
vol.Required(CONF_GITLAB_ID): cv.string,
vol.Optional(CONF_NAME, default='GitLab CI Status'): cv.string,
vol.Optional(CONF_URL, default='https://gitlab.com'): cv.string,
vol.Optional(CONF_SCAN_INTERVAL,
DanielWinks marked this conversation as resolved.
Show resolved Hide resolved
DanielWinks marked this conversation as resolved.
Show resolved Hide resolved
default=SCAN_INTERVAL): cv.time_period,
})

REQUIREMENTS = ['python-gitlab==1.6.0']


def setup_platform(hass, config, add_entities, discovery_info=None):
"""Sensor platform setup."""
_priv_token = config.get(CONF_TOKEN)
DanielWinks marked this conversation as resolved.
Show resolved Hide resolved
_gitlab_id = config.get(CONF_GITLAB_ID)
_name = config.get(CONF_NAME)
_interval = config.get(CONF_SCAN_INTERVAL, SCAN_INTERVAL)
_url = config.get(CONF_URL)

_gitlab_data = GitLabData(
priv_token=_priv_token,
gitlab_id=_gitlab_id,
interval=_interval,
url=_url
)

add_entities([GitLabSensor(_gitlab_data, _name)], True)


class GitLabSensor(Entity):
"""Representation of a Sensor."""

def __init__(self, gitlab_data, name):
"""Initialize the sensor."""
self._state = None
self._available = False
self._status = None
self._started_at = None
self._finished_at = None
self._duration = None
self._commit_id = None
self._commit_date = None
self._build_id = None
self._branch = None
self._gitlab_data = gitlab_data
self._name = name

@property
def name(self):
"""Return the name of the sensor."""
return self._name

@property
def state(self):
"""Return the state of the sensor."""
return self._state

@property
def available(self):
"""Return True if entity is available."""
return self._available

@property
def device_state_attributes(self):
"""Return the state attributes."""
return {
ATTR_ATTRIBUTION: CONF_ATTRIBUTION,
ATTR_BUILD_STATUS: self._status,
ATTR_BUILD_STARTED: self._started_at,
ATTR_BUILD_FINISHED: self._finished_at,
ATTR_BUILD_DURATION: self._duration,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not include duration. You're not allowed to store those in the state machine.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the duration that GitLab-CI took to build the CI job. It's just a string value, so the end user can see how long it took GitLab-CI to build. This should be fine, correct? This is not a duration of this sensor or generated by this sensor, it's the string 'duration' returned from the GitLab API.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it being updated while a build is running? If so, it should not be included.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it's the duration the build took, as reported by the GitLab API. Basically, the API returns data of "This is the build SHA, this is the branch, your CI/CD was successful or failed, and it took X seconds to run". It isn't updated while it's running, it's just a data point returned by the API when the build has completed. It's exactly the same "duration" as the "last_build_duration" reported in the current Travis CI sensor.

ATTR_BUILD_COMMIT_ID: self._commit_id,
ATTR_BUILD_COMMIT_DATE: self._commit_date,
ATTR_BUILD_ID: self._build_id,
ATTR_BUILD_BRANCH: self._branch
}

@property
def icon(self):
"""Return the icon to use in the frontend."""
if self._status == 'success':
return ICON_HAPPY
if self._status == 'failed':
return ICON_SAD
return ICON_OTHER

def update(self):
DanielWinks marked this conversation as resolved.
Show resolved Hide resolved
"""Collect updated data from GitLab API."""
self._gitlab_data.update()

self._status = self._gitlab_data.status
DanielWinks marked this conversation as resolved.
Show resolved Hide resolved
self._started_at = self._gitlab_data.started_at
self._finished_at = self._gitlab_data.finished_at
self._duration = self._gitlab_data.duration
self._commit_id = self._gitlab_data.commit_id
self._commit_date = self._gitlab_data.commit_date
self._build_id = self._gitlab_data.build_id
self._branch = self._gitlab_data.branch
self._state = self._gitlab_data.status
self._available = self._gitlab_data.available


class GitLabData():
"""GitLab Data object."""

def __init__(self, gitlab_id, priv_token, interval, url):
"""Fetch data from GitLab API for most recent CI job."""
import gitlab
self._gitlab_id = gitlab_id
self._priv_token = priv_token
DanielWinks marked this conversation as resolved.
Show resolved Hide resolved
self._interval = interval
DanielWinks marked this conversation as resolved.
Show resolved Hide resolved
self._url = url
DanielWinks marked this conversation as resolved.
Show resolved Hide resolved
self._gitlab = gitlab.Gitlab(
self._url, private_token=self._priv_token, per_page=1)
self._gitlab.auth()
self._gitlab_exceptions = gitlab.exceptions
self.update = Throttle(interval)(self._update)

self.available = False
self.status = None
self.started_at = None
self.finished_at = None
self.duration = None
self.commit_id = None
self.commit_date = None
self.build_id = None
self.branch = None

def _update(self):
try:
_projects = self._gitlab.projects.get(self._gitlab_id)
_last_pipeline = _projects.pipelines.list(page=1)[0]
_last_job = _last_pipeline.jobs.list(page=1)[0]
self.status = _last_pipeline.attributes.get('status')
self.started_at = _last_job.attributes.get('started_at')
self.finished_at = _last_job.attributes.get('finished_at')
self.duration = _last_job.attributes.get('duration')
_commit = _last_job.attributes.get('commit')
self.commit_id = _commit.get('id')
self.commit_date = _commit.get('committed_date')
self.build_id = _last_job.attributes.get('id')
self.branch = _last_job.attributes.get('ref')
self.available = True
except self._gitlab_exceptions.GitlabAuthenticationError as erra:
_LOGGER.error("Authentication Error: %s", erra)
self.available = False
except self._gitlab_exceptions.GitlabGetError as errg:
_LOGGER.error("Project Not Found: %s", errg)
self.available = False
3 changes: 3 additions & 0 deletions requirements_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1104,6 +1104,9 @@ python-forecastio==1.4.0
# homeassistant.components.gc100
python-gc100==1.0.3a

# homeassistant.components.sensor.gitlab_ci
python-gitlab==1.6.0

# homeassistant.components.sensor.hp_ilo
python-hpilo==3.9

Expand Down