#3065 sync the out files back into the jenkins workspace
Merged 6 years ago by pingou. Opened 6 years ago by bstinson.
bstinson/pagure add-sync  into  ci_testing

file modified
+23 -4
@@ -1,7 +1,7 @@ 

  def onmyduffynode(script){

      ansiColor('xterm'){

          timestamps{

-             sh 'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -l root ${DUFFY_NODE}.ci.centos.org -t "' + script + '"'

+             sh 'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -l root ${DUFFY_NODE}.ci.centos.org -t REPO=${REPO} BRANCH=${BRANCH} "' + script + '"'

          }

      }

  }
@@ -12,6 +12,13 @@ 

  

  node('pagure') {

  

+     properties([

+             parameters([

+                 string(defaultValue: "", description: "", name: "REPO"),

+                 string(defaultValue: "", description: "", name: "BRANCH"),

+                 ])

+             ])

+ 

      stage('Allocate Node'){

          env.CICO_API_KEY = readFile("${env.HOME}/duffy.key").trim()

          duffy_rtn=sh(
@@ -25,15 +32,19 @@ 

      try {

          stage('Pre Setup Node'){

              // Install EPEL

-             onmyduffynode 'yum -y install epel-release'

+             onmyduffynode 'yum -y install epel-release git'

          }

  

          stage('Clone Test Suite') {

-             onmyduffynode "git clone -b \"${env.BRANCH_NAME}\" --single-branch --depth 1 https://pagure.io/pagure.git"

+             if (env.BRANCH_NAME){

+                 onmyduffynode "git clone -b \"${env.BRANCH_NAME}\" --single-branch --depth 1 https://pagure.io/pagure.git"

+             } else {

+                 onmyduffynode "git clone --single-branch --depth 1 https://pagure.io/pagure.git"

+             }

          }

  

          stage('Run Test Suite') {

-             timeout(6, 'HOURS') {

+             timeout(time: 6, unit: 'HOURS') {

                  onmyduffynode 'cd pagure && sh ./run_ci_tests.sh'

              }

          }
@@ -42,8 +53,16 @@ 

          currentBuild.result = "FAILED"

          throw e

      } finally {

+         stage('Sync Artifacts'){

+             syncfromduffynode('pagure/*.out')

+         }

+ 

          stage('Deallocate Node'){

              sh 'cico node done ${SSID}'

          }

+ 

+         stage('Archive Artifacts'){

+             archiveArtifacts artifacts: '*.out'

+         }

      }

  }

@@ -0,0 +1,42 @@ 

+ """Add the pr_to_issue table

+ 

+ Revision ID: 369deb8c8b63

+ Revises: 22fb5256f555

+ Create Date: 2018-03-12 11:38:00.955252

+ 

+ """

+ 

+ # revision identifiers, used by Alembic.

+ revision = '369deb8c8b63'

+ down_revision = '22fb5256f555'

+ 

+ from alembic import op

+ import sqlalchemy as sa

+ 

+ 

+ def upgrade():

+     ''' Create the pr_to_issue table. '''

+ 

+     op.create_table(

+         'pr_to_issue',

+         sa.Column(

+             'pull_request_uid',

+             sa.String(32),

+             sa.ForeignKey(

+                 'pull_requests.uid', ondelete='CASCADE', onupdate='CASCADE',

+             ),

+             primary_key=True),

+         sa.Column(

+             'issue_uid',

+             sa.String(32),

+             sa.ForeignKey(

+                 'issues.uid', ondelete='CASCADE', onupdate='CASCADE',

+             ),

+             primary_key=True)

+     )

+ 

+ 

+ def downgrade():

+     ''' Drop the pr_to_issue table. '''

+ 

+     op.drop_table('pr_to_issue')

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

      jsonout = flask.jsonify(output)

      return jsonout

  

+ 

  @API.route('/<repo>/c/<commit_hash>/flag')

  @API.route('/<namespace>/<repo>/c/<commit_hash>/flag')

  @API.route('/fork/<username>/<repo>/c/<commit_hash>/flag')

@@ -138,6 +138,10 @@ 

          # Link to existing PRs if there are any

          seen = len(prs) != 0

          for pr in prs:

+             # Link tickets with pull-requests if the commit mentions it

+             pagure.lib.tasks.link_pr_to_ticket.delay(pr.uid)

+ 

+             # Inform the user about the PR

              print('View pull-request for %s' % refname)

              print('   %s/%s/pull-request/%s' % (

                  _config['APP_URL'].rstrip('/'),

file modified
+26
@@ -1739,6 +1739,8 @@ 

      pagure.lib.git.update_git(

          request, repo=request.project, repofolder=requestfolder)

  

+     pagure.lib.tasks.link_pr_to_ticket.delay(request.uid)

+ 

      log_action(session, 'created', request, user_obj)

  

      if notify:
@@ -5011,3 +5013,27 @@ 

      )

  

      return [parent] + query.all()

+ 

+ 

+ def link_pr_issue(session, issue, request):

+     ''' Associate the specified issue with the specified pull-requets.

+ 

+     :arg session: The SQLAlchemy session to use

+     :type session: sqlalchemy.orm.session.Session

+     :arg issue: The issue mentionned in the commits of the pull-requests to

+         be associated with

+     :type issue: pagure.lib.model.Issue

+     :arg request: A pull-request to associate the specified issue with

+     :type request: pagure.lib.model.PullRequest

+ 

+     '''

+ 

+     associated_issue = [iss.uid for iss in request.related_issues]

+     if issue.uid not in associated_issue:

+         obj = model.PrToIssue(

+             pull_request_uid=request.uid,

+             issue_uid=issue.uid

+         )

+         session.add(obj)

+         session.flush()

+     session.commit()

file modified
+30
@@ -1309,6 +1309,28 @@ 

          primary_key=True)

  

  

+ class PrToIssue(BASE):

+     """ Stores the associations between issues and pull-requests.

+ 

+     Table -- pr_to_issue

+     """

+ 

+     __tablename__ = 'pr_to_issue'

+ 

+     pull_request_uid = sa.Column(

+         sa.String(32),

+         sa.ForeignKey(

+             'pull_requests.uid', ondelete='CASCADE', onupdate='CASCADE',

+         ),

+         primary_key=True)

+     issue_uid = sa.Column(

+         sa.String(32),

+         sa.ForeignKey(

+             'issues.uid', ondelete='CASCADE', onupdate='CASCADE',

+         ),

+         primary_key=True)

+ 

+ 

  class IssueComment(BASE):

      """ Stores the comments made on a commit/file.

  
@@ -1762,6 +1784,14 @@ 

          viewonly=True

      )

  

+     related_issues = relation(

+         "Issue",

+         secondary="pr_to_issue",

+         primaryjoin="pull_requests.c.uid==pr_to_issue.c.pull_request_uid",

+         secondaryjoin="pr_to_issue.c.issue_uid==issues.c.uid",

+         backref=backref("related_prs", order_by="pull_requests.c.id.desc()")

+     )

+ 

      def __repr__(self):

          return 'PullRequest(%s, project:%s, user:%s, title:%s)' % (

              self.id, self.project.name, self.user.user, self.title

file modified
+68
@@ -32,9 +32,11 @@ 

  import pagure.lib

  import pagure.lib.git

  import pagure.lib.git_auth

+ import pagure.lib.link

  import pagure.lib.repo

  import pagure.utils

  from pagure.config import config as pagure_config

+ from pagure.utils import get_parent_repo_path

  

  # logging.config.dictConfig(pagure_config.get('LOGGING') or {'version': 1})

  _log = logging.getLogger(__name__)
@@ -890,3 +892,69 @@ 

          dates[arrow.get(commit.commit_time).date().isoformat()] += 1

  

      return [(key, dates[key]) for key in sorted(dates)]

+ 

+ 

+ @conn.task(bind=True)

+ @set_status

+ def link_pr_to_ticket(self, pr_uid):

+     """ Link the specified pull-request against the ticket(s) mentioned in

+     the commits of the pull-request

+ 

+     """

+     _log.info(

+         'LINK_PR_TO_TICKET: Linking ticket(s) to PR for: %s' % pr_uid)

+ 

+     session = pagure.lib.create_session(pagure_config['DB_URL'])

+ 

+     request = pagure.lib.get_request_by_uid(session, pr_uid)

+     if not request:

+         _log.info('LINK_PR_TO_TICKET: Not PR found for: %s' % pr_uid)

+         session.close()

+         return

+ 

+     if request.remote:

+         repopath = pagure.utils.get_remote_repo_path(

+             request.remote_git, request.branch_from)

+         parentpath = pagure.utils.get_repo_path(request.project)

+     else:

+         repo_from = request.project_from

+         repopath = pagure.utils.get_repo_path(repo_from)

+         parentpath = get_parent_repo_path(repo_from)

+ 

+     repo_obj = pygit2.Repository(repopath)

+     orig_repo = pygit2.Repository(parentpath)

+ 

+     diff_commits = pagure.lib.git.diff_pull_request(

+         session, request, repo_obj, orig_repo,

+         requestfolder=pagure_config['REQUESTS_FOLDER'], with_diff=False)

+ 

+     _log.info(

+         'LINK_PR_TO_TICKET: Found %s commits in that PR' % len(diff_commits))

+ 

+     name = request.project.name

+     namespace = request.project.namespace

+     user = request.project.user.user \

+         if request.project.is_fork else None

+ 

+     for line in pagure.lib.git.read_git_lines(

+             ['log', '--no-walk']

+             + [c.oid.hex for c in diff_commits]

+             + ['--'], repopath):

+ 

+         line = line.strip()

+         for issue in pagure.lib.link.get_relation(

+                 session, name, user, namespace, line, 'fixes',

+                 include_prs=False):

+             _log.info(

+                 'LINK_PR_TO_TICKET: Link ticket %s to PRs %s' % (

+                     issue, request))

+             pagure.lib.link_pr_issue(session, issue, request)

+ 

+         for issue in pagure.lib.link.get_relation(

+                 session, name, user, namespace, line, 'relates'):

+             _log.info(

+                 'LINK_PR_TO_TICKET: Link ticket %s to PRs %s' % (

+                     issue, request))

+             pagure.lib.link_pr_issue(session, issue, request)

+ 

+     session.close()

@@ -365,6 +365,32 @@ 

      </div>

    {% endif %}

  

+   {% if issue.related_prs %}

+   <div class="col-md-4 card-block">

+     <div class="card">

+       <div class="card-block">

+         <label><strong>Related PR(s)</strong></label>

+         <div id="pr_list">

+           <ul class="list-unstyled">

+             {% for pr in issue.related_prs %}

+             <li>

+               <a class="label label-default" href="{{ url_for(

+                   'ui_ns.request_pull',

+                   repo=pr.project.name,

+                   username=pr.project.user.user if pr.project.is_fork else none,

+                   namespace=pr.project.namespace,

+                   requestid=pr.id) }}">#{{pr.id}}</a>

+               {{ pr.status if pr.status != 'Open' else 'Last updated'

+                 }} {{ pr.last_updated | humanize }}

+             </li>

+             {% endfor %}

+           </ul>

+         </div>

+       </div>

+     </div>

+   </div>

+   {% endif %}

+ 

    {% if repo.issue_keys %}

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

      <div class="card">

file modified
+4 -16
@@ -33,25 +33,13 @@ 

  import pagure.forms

  from pagure.config import config as pagure_config

  from pagure.ui import UI_NS

- from pagure.utils import login_required, __get_file_in_tree

+ from pagure.utils import (

+     login_required, __get_file_in_tree, get_parent_repo_path)

  

  

  _log = logging.getLogger(__name__)

  

  

- def _get_parent_repo_path(repo):

-     """ Return the path of the parent git repository corresponding to the

-     provided Repository object from the DB.

-     """

-     if repo.parent:

-         parentpath = os.path.join(

-             pagure_config['GIT_FOLDER'], repo.parent.path)

-     else:

-         parentpath = os.path.join(pagure_config['GIT_FOLDER'], repo.path)

- 

-     return parentpath

- 

- 

  def _get_parent_request_repo_path(repo):

      """ Return the path of the parent git repository corresponding to the

      provided Repository object from the DB.
@@ -326,7 +314,7 @@ 

      else:

          repo_from = request.project_from

          repopath = pagure.utils.get_repo_path(repo_from)

-         parentpath = _get_parent_repo_path(repo_from)

+         parentpath = get_parent_repo_path(repo_from)

  

      repo_obj = pygit2.Repository(repopath)

      orig_repo = pygit2.Repository(parentpath)
@@ -1105,7 +1093,7 @@ 

      repo_obj = flask.g.repo_obj

  

      if not project_to:

-         parentpath = _get_parent_repo_path(repo)

+         parentpath = get_parent_repo_path(repo)

          orig_repo = pygit2.Repository(parentpath)

      else:

          p_namespace = None

file modified
+13
@@ -338,3 +338,16 @@ 

          form_data=form.data,

          csrf=form.csrf_token,

          initial=initial)

+ 

+ 

+ def get_parent_repo_path(repo):

+     """ Return the path of the parent git repository corresponding to the

+     provided Repository object from the DB.

+     """

+     if repo.parent:

+         parentpath = os.path.join(

+             pagure_config['GIT_FOLDER'], repo.parent.path)

+     else:

+         parentpath = os.path.join(pagure_config['GIT_FOLDER'], repo.path)

+ 

+     return parentpath

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

  # Use this file by running "$ pip install -r requirements.txt"

  alembic

  arrow

+ bcrypt

  binaryornot

  bleach

  blinker

file modified
+22 -24
@@ -1,3 +1,10 @@ 

+ yum install -y python-virtualenv \

+                gcc python-cryptography \

+                libgit2 python-pygit2 \

+                redis swig openssl-devel m2crypto fedmsg

+ 

+ sysctl -w fs.file-max=2048

+ 

  set -e

  

  if [ -n "$REPO" -a -n "$BRANCH" ]; then
@@ -16,30 +23,21 @@ 

  fi

  

  

- DATE=`date +%Y%m%d`

- HASH=`sha1sum requirements.txt | awk '{print $1}'`

- 

- if [ ! -d pagureenv-$DATE-$HASH ];

- then

-     rm -rf pagureenv*;

-     virtualenv pagureenv-$DATE-$HASH --system-site-packages

-     source pagureenv-$DATE-$HASH/bin/activate

- 

-     pip install pip --upgrade

-     # Needed within the venv

-     pip install nose --upgrade

-     pip install --upgrade --force-reinstall python-fedora 'setuptools>=17.1' pygments

-     pip install -r tests_requirements.txt

-     pip install -r requirements-ev.txt  # We have one test on the SSE server

-     sed -i -e 's|pygit2 >= 0.20.1||' requirements.txt

-     pip install -r requirements.txt

-     pip install psycopg2

-     pip install python-openid python-openid-teams python-openid-cla

- 

-     pip uninstall cffi -y

- else

-     source pagureenv-$DATE-$HASH/bin/activate

- fi

+ virtualenv pagureenv --system-site-packages

+ source pagureenv/bin/activate

+ 

+ pip install pip --upgrade

+ # Needed within the venv

+ pip install nose --upgrade

+ pip install --upgrade --force-reinstall python-fedora 'setuptools>=17.1' pygments

+ pip install -r tests_requirements.txt

+ pip install -r requirements-ev.txt  # We have one test on the SSE server

+ sed -i -e 's|pygit2 >= 0.20.1||' requirements.txt

+ pip install -r requirements.txt

+ pip install psycopg2

+ pip install python-openid python-openid-teams python-openid-cla

+ 

+ #    pip uninstall cffi -y

  trap deactivate SIGINT SIGTERM EXIT

  

  

file modified
+13 -7
@@ -482,31 +482,37 @@ 

          return self.dic[key]

  

  

- def create_projects(session):

+ def create_projects(session, is_fork=False, user_id=1, hook_token_suffix=''):

      """ Create some projects in the database. """

      item = pagure.lib.model.Project(

-         user_id=1,  # pingou

+         user_id=user_id,  # pingou

          name='test',

+         is_fork=is_fork,

+         parent_id=1 if is_fork else None,

          description='test project #1',

-         hook_token='aaabbbccc',

+         hook_token='aaabbbccc' + hook_token_suffix,

      )

      item.close_status = ['Invalid', 'Insufficient data', 'Fixed', 'Duplicate']

      session.add(item)

  

      item = pagure.lib.model.Project(

-         user_id=1,  # pingou

+         user_id=user_id,  # pingou

          name='test2',

+         is_fork=is_fork,

+         parent_id=2 if is_fork else None,

          description='test project #2',

-         hook_token='aaabbbddd',

+         hook_token='aaabbbddd' + hook_token_suffix,

      )

      item.close_status = ['Invalid', 'Insufficient data', 'Fixed', 'Duplicate']

      session.add(item)

  

      item = pagure.lib.model.Project(

-         user_id=1,  # pingou

+         user_id=user_id,  # pingou

          name='test3',

+         is_fork=is_fork,

+         parent_id=3 if is_fork else None,

          description='namespaced test project',

-         hook_token='aaabbbeee',

+         hook_token='aaabbbeee' + hook_token_suffix,

          namespace='somenamespace',

      )

      item.close_status = ['Invalid', 'Insufficient data', 'Fixed', 'Duplicate']

@@ -0,0 +1,160 @@ 

+ # -*- coding: utf-8 -*-

+ 

+ """

+  (c) 2018 - Copyright Red Hat Inc

+ 

+  Authors:

+    Pierre-Yves Chibon <pingou@pingoured.fr>

+ 

+ """

+ 

+ __requires__ = ['SQLAlchemy >= 0.8']

+ import pkg_resources

+ 

+ import datetime

+ import json

+ import unittest

+ import re

+ import shutil

+ import sys

+ import tempfile

+ import time

+ import os

+ 

+ import pygit2

+ from mock import ANY, patch, MagicMock

+ 

+ sys.path.insert(0, os.path.join(os.path.dirname(

+     os.path.abspath(__file__)), '..'))

+ 

+ import pagure

+ import pagure.lib

+ import tests

+ from pagure.lib.repo import PagureRepo

+ 

+ 

+ class PagureFlaskPrIssueLinkTest(tests.Modeltests):

+     """ Tests pagure when linking PRs to tickets """

+ 

+     maxDiff = None

+ 

+     def setUp(self):

+         """ Set up the environnment, ran before every tests. """

+         super(PagureFlaskPrIssueLinkTest, self).setUp()

+ 

+         tests.create_projects(self.session)

+         tests.create_projects(

+             self.session, is_fork=True, user_id=2, hook_token_suffix='bar')

+         tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)

+         tests.create_projects_git(os.path.join(

+             self.path, 'repos', 'forks', 'foo'), bare=True)

+ 

+         repo = pagure.lib.get_authorized_project(self.session, 'test')

+ 

+         # Create issues to play with

+         msg = pagure.lib.new_issue(

+             session=self.session,

+             repo=repo,

+             title=u'tést íssüé',

+             content='We should work on this',

+             user='pingou',

+             ticketfolder=None

+         )

+         self.session.commit()

+         self.assertEqual(msg.title, u'tést íssüé')

+ 

+         msg = pagure.lib.new_issue(

+             session=self.session,

+             repo=repo,

+             title=u'tést íssüé #2',

+             content='We should still work on this',

+             user='foo',

+             ticketfolder=None

+         )

+         self.session.commit()

+         self.assertEqual(msg.title, u'tést íssüé #2')

+ 

+         # Add a commit to the fork

+ 

+         newpath = tempfile.mkdtemp(prefix='pagure-fork-test')

+         repopath = os.path.join(newpath, 'test')

+         clone_repo = pygit2.clone_repository(os.path.join(

+             self.path, 'repos', 'forks', 'foo', 'test.git'), repopath)

+ 

+         # Create a file in that git repo

+         with open(os.path.join(repopath, 'sources'), 'w') as stream:

+             stream.write('foo\n bar')

+         clone_repo.index.add('sources')

+         clone_repo.index.write()

+ 

+         try:

+             com = repo.revparse_single('HEAD')

+             prev_commit = [com.oid.hex]

+         except:

+             prev_commit = []

+ 

+         # Commits the files added

+         tree = clone_repo.index.write_tree()

+         author = pygit2.Signature(

+             'Alice Author', 'alice@authors.tld')

+         committer = pygit2.Signature(

+             'Cecil Committer', 'cecil@committers.tld')

+         clone_repo.create_commit(

+             'refs/heads/master',  # the name of the reference to update

+             author,

+             committer,

+             'Add sources file for testing\n\n Relates to #2',

+             # binary string representing the tree object ID

+             tree,

+             # list of binary strings representing parents of the new commit

+             prev_commit

+         )

+         refname = 'refs/heads/master:refs/heads/master'

+         ori_remote = clone_repo.remotes[0]

+         PagureRepo.push(ori_remote, refname)

+ 

+         # Create the corresponding PR

+ 

+         repo = pagure.lib.get_authorized_project(self.session, 'test')

+         fork_repo = pagure.lib.get_authorized_project(

+             self.session, 'test', user='foo')

+ 

+         request = pagure.lib.new_pull_request(

+             self.session,

+             branch_from='master',

+             repo_to=repo,

+             branch_to='master',

+             title='test PR',

+             user='foo',

+             requestfolder=None,

+             initial_comment=None,

+             repo_from=fork_repo,

+         )

+         self.session.commit()

+ 

+         pagure.lib.tasks.link_pr_to_ticket(request.uid)

+         self.assertEqual(request.id, 3)

+ 

+     def test_ticket_no_link(self):

+         """ Test that no Related PR(s) block is showing in the issue page.

+         """

+         output = self.app.get('/test/issue/1')

+         self.assertEqual(output.status_code, 200)

+         self.assertNotIn(

+             u'<strong>Related PR(s)</strong>',

+             output.data.decode('utf-8'))

+ 

+     def test_ticket_link(self):

+         """ Test that no Related PR(s) block is showing in the issue page.

+         """

+         time.sleep(1)

+         output = self.app.get('/test/issue/2')

+         print output.data.decode('utf-8')

+         self.assertEqual(output.status_code, 200)

+         self.assertIn(

+             u'<strong>Related PR(s)</strong>',

+             output.data.decode('utf-8'))

+ 

+ 

+ if __name__ == '__main__':

+     unittest.main(verbosity=2)

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

  nose>=0.10.4

  nosexcover

  flake8

+ fedmsg[all]  # optional dependency in the code but tested in the tests

  

  # Seems that mock doesn't list this one

  funcsigs