#228 epel 7 support for jenkins runtest
Closed 7 years ago by skrzepto. Opened 7 years ago by skrzepto.
skrzepto/fedora-hubs jenkins  into  jenkins

manually running test
skrzepto • 7 years ago  
update setuptools on epel7
skrzepto • 7 years ago  
adding jenkins runtest
skrzepto • 7 years ago  
minor indentation fix
Máirín Duffy • 7 years ago  
making body background white
Máirín Duffy • 7 years ago  
first cut at vertical nav bar
Máirín Duffy • 7 years ago  
file modified
+58 -29
@@ -1,7 +1,7 @@ 

  @import url(https://fonts.googleapis.com/css?family=Open+Sans:400,300,300italic,400italic,600,600italic,700,700italic,800,800italic);

  

     body {

-       background-color: #d1d3d4;

+       background-color: #fff;

      }

  

      /*.super-header {
@@ -57,16 +57,18 @@ 

        .header .dropdown.edit {

          top: 140px !important;

        }

-       .header h3.team {

+       .header h2.team {

          top: 170px !important;

        }

      }

  

-     .header {

-       color: #ffffff;

-       background-color: #3c6eb4;

+     header {

+       color: #373a3c;

+       background: #f3f3f3 none repeat scroll 0 0;

        width: 100%;

        font-family: 'Open Sans', sans-serif;

+       min-height: 100px;

+       border-bottom: 1px solid #ddd;

      }

  

      /*.header .dropdown.edit {
@@ -75,45 +77,34 @@ 

        right: 0;

        z-index: 2;

      }*/

+     

+     /* line up header with cards below */

+     header .container {

+ 	padding-left: 1.75rem !important;

+ 	}

  

-     .header .img-wrap {

-       max-height: 100px;

-       overflow: hidden;

-       position: relative;

-     }

- 

-     .header .img-wrap img {

-       width: 100%;

-       text-align: center;

-     }

- 

-     .header h3.team {

-       position: absolute;

-       top: 120px;

-       left: 45%;

-     }

- 

-     .header img.avatar {

+     header img.avatar {

          width: 70px;

          float: left;

-         margin: 0 15px;

+         margin-right: 15px;

          display: inline;

          border: 5px solid #fff;

      }

  

-     .header h3 {

-         font-weight: 700;

+     header h2 {

+         font-weight: 500;

+         padding-top: .5rem;

      }

  

-     .header a, .header a:hover, .header a:focus {

+     header a, header a:hover, .header a:focus {

        color: #ffffff;

      }

  

-     .header span.edit {

+     header span.edit {

        margin: 5px 5px 0 0;

      }

      .row {

-       padding: 5px;

+       padding-top: 5px;

        margin: auto 0px;

      }

      .padded {
@@ -148,6 +139,7 @@ 

        padding: 5px;

        /* TODO -- lots more nice styling here... */

      }

+ 

      .panel {

        visibility: hidden;

        max-height: 0px;
@@ -280,6 +272,28 @@ 

  .navbar-nav > li.idle-2years  > a { color: #BBB; }

  .navbar-nav > li.idle-5years  > a { color: #CCC; }

  

+ .nav {

+   background-color: #fcfcfc;

+   padding: 1.5rem;

+   position: absolute;

+   z-index: 3;

+   min-height: 200px; 

+   float: left;

+ }

+ 

+ /* navbar fedora-bootstrap overrides to make it vertical */

+ 

+ .navbar-nav .nav-item {

+     float: none;

+ }

+ 

+ .navbar-nav .nav-item + .nav-item, .navbar-nav .nav-link + .nav-link {

+     box-shadow: none;

+     margin-left: 0px !important;

+ }

+ 

+ /* end fedora-bootstrap nav overrides */

+ 

  .media-object {

      max-width: 92px;

      max-height: 92px;
@@ -374,3 +388,18 @@ 

    height: 2em;

    width: 2em;

  }

+ 

+ 

+ /** fedora bootstrap overrides **/

+ 

+ /** tightening up card headers - they are too fat imho **/

+ .card-header {

+   padding: 0.3rem 0.5rem;

+ }

+ 

+ 

+ /** too much padding over the user's subheader, was attached to .m-b-1 with 

+  * !important so difficult to override **/

+ header h5.m-b-1 {

+   margin-top: 0.5rem!important;

+ }

file modified
+10 -6
@@ -3,12 +3,16 @@ 

  {% block title %}Groups{% endblock %}

  {% block content %}

  

- <div class="header">

-   <div class="img-wrap">

-     <img src="#" />

-   </div>

-   <h3 class="team">Groups</h3>

- </div>

+ <header class="p-t-2">

+ 	<div class="container">

+     <div class="col-md-8">

+       <h2 class="team m-b-0">Groups</h2>

+       <h5 class="m-t-1 m-b-1">Summary of available team hubs</h5>

+     </div>

+     <div class="col-md-4 header-right">

+     </div>

+ </header>

+ 

  <div class="container">

    <div class="row">

    </div>

file modified
+50 -43
@@ -2,51 +2,26 @@ 

  

  {% block title %}{{ hub.name }}{% endblock %}

  {% block content %}

- <div class="header">

-   {% if hub.user_hub %}

-     <div class="padded center-block medium-wide">

-       <img src="{{ hub.avatar }}" class="avatar" />

-       <h3>{{ hub.name }}</h3>

-       <h5>{{ hub.summary }}</h5>

-       <div class="clearfix"></div>

-     </div>

-     {% else %}

-     <div class="img-wrap">

-       <img src="{{ hub.header_img }}" />

-     </div>

-     <h3 class="team">{{ hub.name }}</h3>

-   {% endif %}

- </div>

  

- {%- with messages = get_flashed_messages(with_categories=true) -%}

-   {%- if category, messages -%}

-   <div class="container">

-     <div class="row">

-       <div class="col-md-6 col-md-offset-3">

-         <ul id="flashes" class="list-group">

-           {%- for category, message in messages -%}

-             <div class="alert {%

-               if category == 'error' %}alert-warning{%

-               else %}alert-info{%

-               endif %} alert-dismissible" role="alert">

-               <button type="button" class="close" data-dismiss="alert"

-                   aria-label="Close">

-                 <span aria-hidden="true">&times;</span>

-                 <span class="sr-only">Close</span>

-               </button>

-               {{ message }}

-             </div>

-           {%- endfor -%}

-         </ul>

-       </div>

+   <header class="p-t-2">

+     <div class="container">

+ 

+     <!-- Left side of header -->

+     <div class="col-md-8">

+         {% if hub.user_hub %}

+         <img src="{{ hub.avatar }}" class="avatar" />

+       <h2 class="user m-b-0">{{ hub.name }}</h2>

+       <h5 class="m-t-1 m-b-1">{{ hub.summary }}</h5>

+         <div class="clearfix"></div>

+         {% else %}

+         <h2 class="team">{{ hub.name }}</h2>

+         <h5 class="m-t-1 m-b-1">{{ hub.summary }}</h5>

+       {% endif %}

      </div>

-   </div>

-   {%- endif -%}

- {%- endwith -%}

  

- <div class="container">

-   {% if g.auth.logged_in and hub.is_admin(g.auth.user) %}

-       <div class="row">

+       <!-- right side of header -->

+       <div class="col-md-4 header-right">

+       {% if g.auth.logged_in and hub.is_admin(g.auth.user) %}

          {% if not edit %}

            <div class="dropdown edit pull-xs-right showpointer">

              <span class="dropdown-toggle edit-this-page" type="button"
@@ -75,11 +50,43 @@ 

              Save changes

            </div>

          {% endif %}

+       {% endif %}

        </div>

-   {% endif %}

+     </div>

+ 

+   </header>

+ 

  

+ {%- with messages = get_flashed_messages(with_categories=true) -%}

+   {%- if category, messages -%}

+   <div class="container">

+     <div class="row">

+       <div class="col-md-6 col-md-offset-3">

+         <ul id="flashes" class="list-group">

+           {%- for category, message in messages -%}

+             <div class="alert {%

+               if category == 'error' %}alert-warning{%

+               else %}alert-info{%

+               endif %} alert-dismissible" role="alert">

+               <button type="button" class="close" data-dismiss="alert"

+                   aria-label="Close">

+                 <span aria-hidden="true">&times;</span>

+                 <span class="sr-only">Close</span>

+               </button>

+               {{ message }}

+             </div>

+           {%- endfor -%}

+         </ul>

+       </div>

+     </div>

+   </div>

+   {%- endif -%}

+ {%- endwith -%}

  

+ <div class="container">

+   

    <div class="row">

+  

      <div class="col-md-{{ hub.left_width }}">

        <!--

          First, before the proper widgets.. a cobweb built-in widget.

file modified
+16 -13
@@ -53,30 +53,33 @@ 

    </div>

  </div>

  <div class="bodycontent">

- 

-   <nav class="navbar navbar-light navbar-underline p-t-0 p-b-0">

-         <button type="button" class="navbar-toggler hidden-sm-up"

-             data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">

-           <span class="sr-only">Toggle navigation</span>

-           <span class="oi" data-glyph="menu"></span>

-         </button>

+   <div class="col-md-2">

+     <nav class="navbar navbar-light p-t-2 p-b-0">

+       <button type="button" class="navbar-toggler hidden-sm-up"

+         data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">

+         <span class="sr-only">Toggle navigation</span>

+         <span class="oi" data-glyph="menu"></span>

+       </button>

  

        <!-- Collect the nav links, forms, and other content for toggling -->

+       {% if g.auth.logged_in %}

        <div class="collapse navbar-toggleable-xs" id="bs-example-navbar-collapse-1">

-         <ul class="nav navbar-nav nav-underline">

-           {% if g.auth.logged_in %}

+         <ul class="nav navbar-nav">

            <li class="p-x-1 nav-item {% if request.path.endswith('/' + g.auth.user.username + '/') %}active{% endif %}">

              <a class="nav-link" href="/{{g.auth.user.username}}">me</a></li>

            {% for hub in g.auth.user.bookmarks %}

            <li class='p-x-1 nav-item idle-{{hub.activity_class}}{% if request.path.endswith('/' + hub.name + '/') %} active{% endif %}'>

-           <a class="nav-link" href="/{{hub.name}}">{{hub.name}}</a></li>

+             <a class="nav-link" href="/{{hub.name}}">{{hub.name}}</a></li>

            {% endfor %}

            <!-- At the end of the list, tack on a link to all groups -->

-           <li class="p-x-1 nav-item"><a class="nav-link" href="/groups">all</a></li>

-           {% endif %}

+ 

+             <li class="p-x-1 nav-item"><a class="nav-link" href="/groups">all</a></li>

          </ul>

        </div><!-- /.navbar-collapse -->

-   </nav>

+       {% endif %}

+     </nav>

+   </div>

+ 

  {% block content %}{% endblock %}

  

  </div> <!--end bodycontent-->

file modified
+24 -6
@@ -1,6 +1,7 @@ 

  import kitchen.text.converters

  

  import hubs.models

+ import httplib

  

  

  def required(session, value):
@@ -22,20 +23,37 @@ 

  

  

  def username(session, value):

-     return hubs.models.User.by_username(session, value) is not None

+     if hubs.models.User.by_username(session, value) is not None:

+         return value

+     raise ValueError('Invalid username')

  

  

  def github_organization(session, value):

      # TODO -- implement this.

-     return True

+     return value

  

  

  def fmn_context(session, value):

      # TODO get this from the fedmsg config.

-     return value in [

-         'irc', 'email', 'android', 'desktop', 'hubs',

-     ]

+     if value in [

+         'irc', 'email', 'android', 'desktop', 'hubs',]:

+         return value

+     raise ValueError('Invalid FMN context')

  

  

  def pagure_repo(session, value):

-     return value

+     conn = httplib.HTTPSConnection("pagure.io")

+     conn.request("GET", "/%s" % value)

+     response = conn.getresponse()

+     if response.status == 200:

+         return value

+     raise ValueError('Invalid pagure repo')

+ 

+ 

+ def fedorahosted_project(session, value):

+     conn = httplib.HTTPSConnection("fedorahosted.org")

+     conn.request("GET", "/%s" % value)

+     response = conn.getresponse()

+     if response.status == 200:

+         return value

+     raise ValueError('Invalid fedorahosted project')

@@ -15,6 +15,8 @@ 

  from hubs.widgets import pagureissues

  from hubs.widgets import githubissues

  from hubs.widgets import bugzilla

+ from hubs.widgets import fhosted

+ from hubs.widgets import memberships

  

  from hubs.widgets.workflow import pendingacls

  from hubs.widgets.workflow import updates2stable
@@ -39,6 +41,8 @@ 

      'pagureissues': pagureissues,

      'githubissues': githubissues,

      'bugzilla': bugzilla,

+     'fedorahosted': fhosted,

+     'memberships': memberships,

  

      'workflow.pendingacls': pendingacls,

      'workflow.updates2stable': updates2stable,

@@ -0,0 +1,62 @@ 

+ from hubs.widgets.chrome import panel

+ from hubs.hinting import hint, prefixed as _

+ from hubs.widgets.base import argument

+ from hubs.widgets import templating

+ import hubs.validators as validators

+ import requests

+ 

+ chrome = panel("Fedorahosted: Open Tickets")

+ template = templating.environment.get_template('templates/fedorahosted.html')

+ position = 'right'

+ 

+ from xmlrpclib import ServerProxy

+ 

+ 

+ @argument(name="project",

+           default=None,

+           validator=validators.fedorahosted_project,

+           help="Name of the trac instance on fedorahosted.org")

+ @argument(name="n_tickets",

+           default=4,

+           validator=validators.integer,

+           help="The number of tickets to display.")

+ def data(session, widget, project, n_tickets=4):

+     n_tickets = int(n_tickets)

+     url = 'https://fedorahosted.org/%s/rpc' % project

+     filters = 'status=accepted&status=assigned&status=new&status=reopened'\

+         '&col=id&col=summary&col=status&col=owner&col=type&col=priority'\

+         '&col=milestone&col=changetime&order=changetime'

+     try:

+         server = ServerProxy(url)

+         tickets = server.ticket.query(filters)

+     except:

+         return dict(

+             error='Invalid or wrongly configured project'

+         )

+ 

+     output = []

+     total_tickets = len(tickets)

+     for idx, ticket in enumerate(tickets):

+         ticket = server.ticket.get(ticket)

+         data = ticket[3]

+         data['id'] = ticket[0]

+         data['short_summary'] = data['summary'][:45]

+         output.append(data)

+         if idx + 1 >= n_tickets:

+             break

+ 

+     return dict(

+         project=project,

+         tickets=output,

+         total_tickets=total_tickets,

+     )

+ 

+ 

+ @hint(topics=[_('trac.ticket.update'), _('trac.ticket.new')])

+ def should_invalidate(message, session, widget):

+     project = widget.config.get('project', '')

+     url = 'https://fedorahosted.org/%s/' % project

+     if '.trac.ticket' in message['topic']:

+         if message['msg']['instance']['base_url'] == url:

+             return True

+     return False

@@ -69,6 +69,7 @@ 

            validator=validators.integer,

            help="The number of meetings to display.")

  def data(session, widget, calendar, n_meetings=4):

+     n_meetings = int(n_meetings)

      base = 'https://apps.fedoraproject.org/calendar/api/meetings/?calendar=%s'

      url = base % calendar

      response = requests.get(url).json()

@@ -0,0 +1,39 @@ 

+ import hubs.models

+ from hubs.hinting import hint, prefixed as _

+ import hubs.validators as validators

+ from hubs.widgets.base import argument

+ from hubs.widgets.chrome import panel

+ from hubs.widgets import templating

+ 

+ ELLIPSIS_LIMIT = 3

+ chrome = panel('Hubs')

+ template = templating.environment.get_template('templates/memberships.html')

+ position = 'both'

+ 

+ 

+ def data(session, widget, **kwargs):

+     hub = widget.hub

+     members = []

+     if hub.user_hub:

+         user = hubs.models.User.by_username(session, hub.name)

+         members = [m.__json__(session) for m in user.memberships

+                    if m.name != user.username]

+     else:

+         members_name = []

+         for member in widget.hub.members:

+             if member.username in members_name:

+                 continue

+             members_name.append(member.username)

+             members.append(member.__json__(session))

+ 

+     oldest_members = sorted(members,

+                             key=lambda m: m.get('created_on'))[:ELLIPSIS_LIMIT]

+     return dict(memberships=list(members), oldest_members=list(oldest_members))

+ 

+ 

+ @hint(topics=[_('hubs.hub.update')])

+ def should_invalidate(message, session, widget):

+     if message['topic'].endswith('hubs.hub.update'):

+         if message['msg']['hub']['name'] == widget.hub.name:

+             return True

+     return False

@@ -0,0 +1,44 @@ 

+ {% if error %}

+ <p>{{ error }}</p>

+ {% else %}

+ <a class="btn btn-success" target="_blank"

+     href="https://fedorahosted.org/{{ project }}/report/1">

+   All Issues

+ </a>

+ <hr/>

+ 

+ <ul class="media-list">

+   {% for issue in tickets %}

+     <li class="media">

+       <div class="media-left">

+         <a  href="https://fedorahosted.org/{{ project }}/ticket/{{ issue['id'] }}"

+             target="_blank">

+         <span class="label label-default">#{{ issue['id'] }}</span>

+         </a>

+       </div>

+       <div class="media-body">

+         <h4 class="media-heading">

+           <span title="{{ issue['summary'] }}">

+             {{ issue['short_summary'] }} {% if

+               issue['summary'] | length > 45 %} ... {% endif %}

+           </span>

+         </h4>

+         Opened by:

+             {{ issue['reporter'] }}

+         --

+         {% if issue['owner'] %}

+           Assigned to:

+             {{issue['owner'] }}

+         {% else %}

+           <span class="text-muted">Unassigned</span>

+         {% endif %}

+       </div>

+     </li>

+   {% endfor %}

+   {% if total_tickets > tickets | length %}

+   <li>

+     And {{ total_tickets - tickets | length }} more ...

+   </li>

+   {% endif %}

+ </ul>

+ {% endif %}

@@ -0,0 +1,76 @@ 

+ <div class="card-block">

+   {% if memberships|length > oldest_members|length %}

+   {% for member in oldest_members %}

+   <div class="card-block">

+     <img class="img-responsive membership-avatar col-md-3" src="{{ member.avatar }}" alt="Hub avatar for {{ member.name }}">

+     <a href="/{{member.name}}">{{ member.name }}</a>

+     {% if g.auth.username in member.owners %}

+       <p class="text-muted">Owner</p>

+     {% else %}

+       <p>Member</p>

+     {% endif %}

+   </div>

+   {% endfor %}

+   <a href="#" class="btn btn-default" data-toggle="modal" data-target="#membersModal">View All</a>

+   {% else %}

+   {% for member in memberships %}

+   <div class="card-block">

+     <img class="img-responsive membership-avatar col-md-3" src="{{ member.avatar }}" alt="Hub avatar for {{ member.name }}">

+     <a href="/{{member.name}}">{{ member.name }}</a>

+     {% if g.auth.username in member.owners %}

+       <p class="text-muted">Owner</p>

+     {% else %}

+       <p>Member</p>

+     {% endif %}

+   </div>

+   {% endfor %}

+   {%endif%}

+ </div>

+ 

+ <!-- View all modal -->

+ <div class="modal fade" id="membersModal" tabindex="-1" role="dialog" aria-labelledby="membersModal" aria-hidden="true">

+   <div class="modal-dialog">

+     <div class="modal-content">

+       <div class="modal-header">

+         <h4 class="modal-title" id="myModalLabel">All Memberships</h4>

+       </div>

+       <div id="owners" class="modal-body">

+         <div class="card-block">

+           <div class="row">

+             {% for member in memberships %}

+             <div class="col-sm-6">

+               <img class="img-responsive membership-avatar col-sm-3"

+                 src="{{ member.avatar }}" alt="Hub avatar for {{ member.name }}">

+               <a href="/{{member.name}}">{{ member.name }}</a>

+               {% if g.auth.username in member.owners %}

+               <p class="text-muted">Owner</p>

+               {% else %}

+               <p>Member</p>

+               {% endif %}

+             </div>

+             {% if (loop.index % 2) == 0 %}

+               </div>

+               <div class="row">

+             {% endif %}

+           {% endfor %}

+         </div>

+         <div class="modal-footer clearfix">

+           <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>

+         </div>

+       </div>

+     </div>

+   </div>

+ 

+ <style>

+  .membership-avatar {

+    height: 4em;

+    width: 6em;

+  }

+  .modal-header {

+    border-bottom: 0;

+  }

+ 

+  #owners {

+    padding: 10px;

+  }

+ </style>

@@ -25,7 +25,7 @@ 

            Assigned to:

            <a href="https://pagure.io/user/{{ pr['pr_assignee'] }}"

                target="_blank">

-             {{ pr['pr_assignee'] }}

+             {{ pr['pr_assignee']['name'] }}

            </a>

          {% else %}

            <span class="text-muted">Unassigned</span>

file modified
+3
@@ -1,3 +1,6 @@ 

  #!/bin/bash

+ 

+ . ~/.virtualenvs/hubs/bin/activate || /bin/bash ./setup_python_test_env.sh

+ 

  HUBS_CONFIG=`pwd`/hubs/tests/hubs_test.cfg PYTHONPATH=. ./nosetests \

      --with-coverage --cover-erase --cover-package=hubs $*

file added
+24
@@ -0,0 +1,24 @@ 

+ #!/bin/bash

+ 

+ PATH=$WORKSPACE/venv/bin:/usr/local/bin:$PATH

+ 

+ if [ ! -d "venv" ]; then

+     virtualenv venv

+ fi

+ . venv/bin/activate

+ 

+ # epel 7 specific python setup

+ if ! grep -q "Fedora" /etc/os-release ; then

+     pip install --upgrade setuptools==18.5

+     cp -r /usr/lib/python2.7/site-packages/pygments_markdown_lexer $WORKSPACE/venv/lib/python2.7/site-packages/

+     cp -r /usr/lib/python2.7/site-packages/pygments_markdown_lexer-*-py2.7.egg-info $WORKSPACE/venv/lib/python2.7/site-packages/

+ fi

+ 

+ pip install -r requirements.txt

+ pip install -r test-requirements.txt

+ 

+ # Temporary: html5lib is breaking stability in some libraries

+ pip install html5lib==0.9999999

+ 

+ HUBS_CONFIG=$WORKSPACE/hubs/tests/hubs_test.cfg PYTHONPATH=. ./nosetests \

+     --cover-package=hubs $* 

\ No newline at end of file

@@ -0,0 +1,20 @@ 

+ #!/usr/bin/env bash

+ 

+ # have bash find mkvirutalenv

+ source ~/.bashrc

+ 

+ # remove the hubs env

+ rmvirtualenv hubs

+ 

+ # Create hubs env

+ mkvirtualenv hubs

+ 

+ # activate hubs

+ workon hubs

+ 

+ # install python deps

+ pip install --upgrade -r requirements.txt

+ pip install --upgrade -r test-requirements.txt

+ 

+ # TEMPORARY: html5lib update is causing other apps to crash

+ pip install html5lib==0.9999999

file added
+18
@@ -0,0 +1,18 @@ 

+ #!/usr/bin/env bash

+ 

+ ######

+ # Warning this file uses sudo to install dependencies use at your own risk

+ #####

+ 

+ # Install dependencies

+ sudo yum install -y gcc gcc-c++ sqlite-devel libffi-devel openssl-devel redhat-rpm-config

+ 

+ if ! grep -q "Fedora" /etc/os-release ; then

+     # Epel 7 specific

+     sudo yum install -y epel-release

+     sudo yum update -y

+     sudo yum install -y python-pip python-pygments-markdown-lexer

+ fi

+ 

+ # setup python virtualenv

+ sudo yum install -y python-virtualenvwrapper postgresql postgresql-devel 

\ No newline at end of file

file modified
+1
@@ -2,3 +2,4 @@ 

  vcrpy

  mock

  yanc

+ coverage 

\ No newline at end of file

had to add a monkey patch to get jenkins build succesful in epel 7

actually this file might not be needed at all

monkey patch start on the line below

There is one missing cp line here in order for this file to work

I'm a little curious as to what the goal of this PR is

The goal of the branch is to create scripts that you can use to setup jenkins easier.

The goal of this PR is to add epel 7 support to those scripts.

For some reason not all of my final changes saved on friday (guess I was just tired and forgot to save and commit :/)

1 new commit added

  • removing unused file, forgot to cp the pygments lib
7 years ago

This is still passing in epel 7 jenkins

2 new commits added

  • removing the python setup in the fedora dep setup
  • cleaning up and removing hardlink to use relative links
7 years ago

rebased

7 years ago

Pull-Request has been closed by skrzepto

7 years ago