Browse Source

introduce run job now

Davide Alberani 6 years ago
parent
commit
24a6fe7d91
3 changed files with 97 additions and 28 deletions
  1. 59 13
      diffido.py
  2. 9 4
      dist/history.html
  3. 29 11
      dist/index.html

+ 59 - 13
diffido.py

@@ -69,7 +69,15 @@ def read_schedules():
         return {'schedules': {}}
     try:
         with open(SCHEDULES_FILE, 'r') as fd:
-            return json.loads(fd.read())
+            schedules = json.loads(fd.read())
+            for id_ in schedules.get('schedules', {}).keys():
+                schedule = schedules['schedules'][id_]
+                try:
+                    schedule['last_history'] = get_last_history(id_)
+                except:
+                    schedule['last_history'] = {}
+                    continue
+            return schedules
     except Exception as e:
         logger.error('unable to read %s: %s' % (SCHEDULES_FILE, e))
         return {'schedules': {}}
@@ -104,7 +112,7 @@ def next_id(schedules):
     return str(max([int(i) for i in ids]) + 1)
 
 
-def get_schedule(id_, add_id=True):
+def get_schedule(id_, add_id=True, add_history=False):
     """Return information about a single schedule
 
     :param id_: ID of the schedule
@@ -118,6 +126,8 @@ def get_schedule(id_, add_id=True):
     except Exception:
         return {}
     data = schedules.get('schedules', {}).get(id_, {})
+    if add_history and data:
+        data['last_history'] = get_last_history(id_)
     if add_id:
         data['id'] = str(id_)
     return data
@@ -161,6 +171,9 @@ def run_job(id_=None, *args, **kwargs):
     if not url:
         return False
     logger.debug('running job id:%s title:%s url: %s' % (id_, schedule.get('title', ''), url))
+    if not schedule.get('enabled'):
+        logger.info('not running job %s: disabled' % id_)
+        return True
     req = requests.get(url, allow_redirects=True, timeout=(30.10, 240))
     content = req.text
     xpath = schedule.get('xpath')
@@ -219,9 +232,10 @@ def run_job(id_=None, *args, **kwargs):
     # send notification
     diff = get_diff(id_).get('diff')
     if not diff:
-        return
+        return True
     send_email(to=email, subject='%s page changed' % schedule.get('title'),
                body='changes:\n\n%s' % diff)
+    return True
 
 
 def safe_run_job(id_=None, *args, **kwargs):
@@ -263,20 +277,27 @@ def send_email(to, subject='diffido', body='', from_=None):
     return True
 
 
-def get_history(id_):
+def get_history(id_, limit=None, add_info=False):
     """Read the history of a schedule
 
     :param id_: ID of the schedule
     :type id_: str
+    :param limit: number of entries to fetch
+    :type limit: int
+    :param add_info: add information about the schedule itself
+    :type add_info: int
     :returns: information about the schedule and its history
     :rtype: dict"""
-    def _history(id_, queue):
+    def _history(id_, limit, queue):
         os.chdir('storage/%s' % id_)
-        p = subprocess.Popen([GIT_CMD, 'log', '--pretty=oneline', '--shortstat'], stdout=subprocess.PIPE)
+        cmd = [GIT_CMD, 'log', '--pretty=oneline', '--shortstat']
+        if limit is not None:
+            cmd.append('-%s' % limit)
+        p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
         stdout, _ = p.communicate()
         queue.put(stdout)
     queue = multiprocessing.Queue()
-    p = multiprocessing.Process(target=_history, args=(id_, queue))
+    p = multiprocessing.Process(target=_history, args=(id_, limit, queue))
     p.start()
     res = queue.get().decode('utf-8')
     p.join()
@@ -287,13 +308,26 @@ def get_history(id_):
         info['deletions'] = int(info['deletions'] or 0)
         info['changes'] = max(info['insertions'], info['deletions'])
         history.append(info)
-    lastid = None
+    last_id = None
     if history and 'id' in history[0]:
-        lastid = history[0]['id']
+        last_id = history[0]['id']
     for idx, item in enumerate(history):
         item['seq'] = idx + 1
-    schedule = get_schedule(id_)
-    return {'history': history, 'lastid': lastid, 'schedule': schedule}
+    data = {'history': history, 'last_id': last_id}
+    if add_info:
+        data['schedule'] = get_schedule(id_)
+    return data
+
+
+def get_last_history(id_):
+    """Read the last history entry of a schedule
+
+    :param id_: ID of the schedule
+    :type id_: str
+    :returns: information about the schedule and its history
+    :rtype: dict"""
+    history = get_history(id_, limit=1)
+    return history.get('history', [{}])[0]
 
 
 def get_diff(id_, commit_id='HEAD', old_commit_id=None):
@@ -505,7 +539,7 @@ class SchedulesHandler(BaseHandler):
     def get(self, id_=None, *args, **kwargs):
         """Get a schedule."""
         if id_ is not None:
-            return self.write({'schedule': get_schedule(id_)})
+            return self.write({'schedule': get_schedule(id_, add_history=True)})
         schedules = read_schedules()
         self.write(schedules)
 
@@ -547,6 +581,15 @@ class SchedulesHandler(BaseHandler):
         self.build_success(message='removed schedule %s' % id_)
 
 
+class RunScheduleHandler(BaseHandler):
+    """Reset schedules handler."""
+    @gen.coroutine
+    def post(self, id_, *args, **kwargs):
+        if run_job(id_):
+            return self.build_success('job run')
+        self.build_error('job not run')
+
+
 class ResetSchedulesHandler(BaseHandler):
     """Reset schedules handler."""
     @gen.coroutine
@@ -558,7 +601,7 @@ class HistoryHandler(BaseHandler):
     """History handler."""
     @gen.coroutine
     def get(self, id_, *args, **kwargs):
-        self.write(get_history(id_))
+        self.write(get_history(id_, add_info=True))
 
 
 class DiffHandler(BaseHandler):
@@ -614,12 +657,15 @@ def serve():
                        scheduler=scheduler)
 
     _reset_schedules_path = r'schedules/reset'
+    _schedule_run_path = r'schedules/(?P<id_>\d+)/run'
     _schedules_path = r'schedules/?(?P<id_>\d+)?'
     _history_path = r'history/?(?P<id_>\d+)'
     _diff_path = r'diff/(?P<id_>\d+)/(?P<commit_id>[0-9a-f]+)/?(?P<old_commit_id>[0-9a-f]+)?/?'
     application = tornado.web.Application([
             (r'/api/%s' % _reset_schedules_path, ResetSchedulesHandler, init_params),
             (r'/api/v%s/%s' % (API_VERSION, _reset_schedules_path), ResetSchedulesHandler, init_params),
+            (r'/api/%s' % _schedule_run_path, RunScheduleHandler, init_params),
+            (r'/api/v%s/%s' % (API_VERSION, _schedule_run_path), RunScheduleHandler, init_params),
             (r'/api/%s' % _schedules_path, SchedulesHandler, init_params),
             (r'/api/v%s/%s' % (API_VERSION, _schedules_path), SchedulesHandler, init_params),
             (r'/api/%s' % _history_path, HistoryHandler, init_params),

+ 9 - 4
dist/history.html

@@ -21,8 +21,8 @@
                         </md-table-toolbar>
                         <md-table-row slot="md-table-row" slot-scope="{item}">
                             <md-table-cell>
-                                (<a v-if="item.seq > 1" :href="'/diff.html?id=' + id + '&oldid=' + item.id + '&diff=' + lastid">cur</a><span v-if="item.seq == 1">cur</span> | <a :href="'/diff.html?id=' + id + '&diff=' + item.id">prev</a>)
-                                <md-radio name="oldid" v-model="oldid" :value="item.id" v-if="item.seq > 1" :seq="item.seq"></md-radio><span id="placeholder" v-if="item.seq == 1"> ---- </span>
+                                (<a v-if="item.seq > 1" :href="'/diff.html?id=' + id + '&oldid=' + item.id + '&diff=' + last_id">cur</a><span v-if="item.seq == 1">cur</span> | <a :href="'/diff.html?id=' + id + '&diff=' + item.id">prev</a>)
+                                <md-radio name="oldid" v-model="oldid" :value="item.id" v-if="item.seq > 1" :seq="item.seq"></md-radio><span class="placeholder" v-if="item.seq == 1"></span>
                                 <md-radio name="diff" v-model="diff" :value="item.id" :seq="item.seq"></md-radio>
                             </md-table-cell>
                             <md-table-cell md-label="commit ID" md-sort-by="id">${ item.id }</md-table-cell>
@@ -50,7 +50,7 @@ var app = new Vue({
         filtered_history: [],
         oldid: null,
         diff: null,
-        lasstid: null,
+        last_id: null,
         {% if isinstance(id, str) %}
         id: "{{id}}",
         {% else %}
@@ -67,7 +67,7 @@ var app = new Vue({
                 self.history = response.data.history;
                 self.updateFilter();
                 self.schedule = response.data.schedule;
-                self.lastid = response.data.lastid;
+                self.last_id = response.data.last_id;
             });
         },
         updateFilter: function() {
@@ -96,5 +96,10 @@ body {
     height: 80%;
 }
 
+.placeholder {
+    width: 36px;
+    display: inline-block;
+}
+
 </style>
 {% end %}

+ 29 - 11
dist/index.html

@@ -21,14 +21,24 @@
                     <md-table id="schedules-table" v-model="schedules">
                         <md-table-row slot="md-table-row" slot-scope="{item}">
                             <md-table-cell md-label="#" md-sort-by="id" md-numeric><a :href="'/schedule.html?id=' + item.id">${ item.id }</a></md-table-cell>
+                            <md-table-cell md-label="enabled" md-sort-by="enabled">
+                                <md-icon v-if="item.enabled">check_box</md-icon>
+                                <md-icon v-if="!item.enabled">check_box_outline_blank</md-icon>
+                            </md-table-cell>
                             <md-table-cell md-label="title" md-sort-by="title"><a :href="'/schedule.html?id=' + item.id">${ item.title }</a></md-table-cell>
-                            <md-table-cell md-label="url" md-sort-by="email"><a :href="item.url" target="_new">${ item.url }</a></md-table-cell>
+                            <md-table-cell md-label="url" md-sort-by="url"><a :href="item.url" target="_new">${ item.url }</a></md-table-cell>
                             <md-table-cell md-label="trigger" md-sort-by="trigger">${ triggerString(item) }</md-table-cell>
-                            <md-table-cell md-label="history" md-sort-by="email">
+                            <md-table-cell md-label="last check" md-sort-by="last_history">${ item.last_history && item.last_history.message }</md-table-cell>
+                            <md-table-cell md-label="history">
                                 <md-button :href="'/history.html?id=' + item.id" class="md-icon-button md-primary">
                                     <md-icon>history</md-icon>
                                 </md-button>
                             </md-table-cell>
+                            <md-table-cell md-label="run now">
+                                <md-button class="md-icon-button md-primary" @click="runSchedule(item.id)">
+                                    <md-icon>play_circle_outline</md-icon>
+                                </md-button>
+                            </md-table-cell>
                         </md-table-row>
                     </md-table>
                 </md-card-content>
@@ -50,11 +60,9 @@ var app = new Vue({
     mounted: function() {
         this.getSchedules();
     },
-    computed: {
-    },
     methods: {
         getSchedules: function() {
-            self = this;
+            var self = this;
             var data = axios.get('/api/schedules').then(function(response) {
                 var schedules = [];
                 _.forEach(response.data.schedules || {}, function(value, key) {
@@ -69,18 +77,28 @@ var app = new Vue({
                 return 'cron: ' + item.cron_crontab;
             }
             if (item.trigger == 'interval') {
-                trigger = 'interval: ';
+                var text = 'interval: ';
+                var pieces = [];
                 _.each(['weeks', 'days', 'hours', 'minutes', 'seconds'], function(value, key) {
-                    if ('interval_' + value) {
-                        if (trigger) {
-                            trigger = trigger + ' ';
+                    var int_val = item['interval_' + value];
+                    if (int_val && parseInt(int_val)) {
+                        var unit = value;
+                        if (int_val == 1) {
+                            unit = unit.slice(0, -1);
                         }
-                        trigger = trigger + ''
+                        pieces.push('' + int_val + ' ' + unit);
                     }
                 });
-                return trigger;
+                text = text + _.join(pieces, ', ');
+                return text;
             }
             return '';
+        },
+        runSchedule: function(id) {
+            var self = this;
+            var data = axios.post('/api/schedules/' + id + '/run').then(function(response) {
+                setTimeout(self.getSchedules, 2500);
+            });
         }
     }
 });