1 new commit in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/commits/c2c22e38826b/ Changeset: c2c22e38826b User: greg Date: 2013-05-01 19:42:47 Summary: Move the My invalid tools menu item in the tool shed to a grid that filters to the latest metadata revision. Affected #: 8 files diff -r 4fce5cfe8be5724f27a1a909dac135c3f010fe30 -r c2c22e38826b65c67202b39e2f7e789c1761c892 lib/galaxy/webapps/tool_shed/api/repositories.py --- a/lib/galaxy/webapps/tool_shed/api/repositories.py +++ b/lib/galaxy/webapps/tool_shed/api/repositories.py @@ -48,7 +48,7 @@ encoded_repository_id = trans.security.encode_id( repository.id ) repo_dir = repository.repo_path( trans.app ) repo = hg.repository( suc.get_configured_ui(), repo_dir ) - ordered_installable_revisions = suc.get_ordered_downloadable_changeset_revisions( repository, repo ) + ordered_installable_revisions = suc.get_ordered_metadata_changeset_revisions( repository, repo, downloadable=True ) return ordered_installable_revisions except Exception, e: message = "Error in the Tool Shed repositories API in get_ordered_installable_revisions: %s" % str( e ) diff -r 4fce5cfe8be5724f27a1a909dac135c3f010fe30 -r c2c22e38826b65c67202b39e2f7e789c1761c892 lib/galaxy/webapps/tool_shed/controllers/repository.py --- a/lib/galaxy/webapps/tool_shed/controllers/repository.py +++ b/lib/galaxy/webapps/tool_shed/controllers/repository.py @@ -61,12 +61,14 @@ my_writable_repositories_grid = repository_grids.MyWritableRepositoriesGrid() my_writable_repositories_missing_tool_test_components_grid = repository_grids.MyWritableRepositoriesMissingToolTestComponentsGrid() my_writable_repositories_with_failing_tool_tests_grid = repository_grids.MyWritableRepositoriesWithFailingToolTestsGrid() + my_writable_repositories_with_invalid_tools_grid = repository_grids.MyWritableRepositoriesWithInvalidToolsGrid() my_writable_repositories_with_no_failing_tool_tests_grid = repository_grids.MyWritableRepositoriesWithNoFailingToolTestsGrid() repositories_by_user_grid = repository_grids.RepositoriesByUserGrid() repositories_i_own_grid = repository_grids.RepositoriesIOwnGrid() repositories_in_category_grid = repository_grids.RepositoriesInCategoryGrid() repositories_missing_tool_test_components_grid = repository_grids.RepositoriesMissingToolTestComponentsGrid() repositories_with_failing_tool_tests_grid = repository_grids.RepositoriesWithFailingToolTestsGrid() + repositories_with_invalid_tools_grid = repository_grids.RepositoriesWithInvalidToolsGrid() repositories_with_no_failing_tool_tests_grid = repository_grids.RepositoriesWithNoFailingToolTestsGrid() repository_dependencies_grid = repository_grids.RepositoryDependenciesGrid() repository_grid = repository_grids.RepositoryGrid() @@ -141,47 +143,6 @@ return self.deprecated_repositories_i_own_grid( trans, **kwd ) @web.expose - def browse_invalid_tools( self, trans, **kwd ): - params = util.Params( kwd ) - message = util.restore_text( params.get( 'message', '' ) ) - status = params.get( 'status', 'done' ) - cntrller = params.get( 'cntrller', 'repository' ) - is_admin = trans.user_is_admin() - invalid_tools_dict = odict() - if is_admin and cntrller == 'admin': - for repository in trans.sa_session.query( trans.model.Repository ) \ - .filter( trans.model.Repository.table.c.deleted == False ) \ - .order_by( trans.model.Repository.table.c.name ): - # A repository's metadata_revisions are those that ignore the value of the repository_metadata.downloadable column. - for downloadable_revision in repository.metadata_revisions: - metadata = downloadable_revision.metadata - invalid_tools = metadata.get( 'invalid_tools', [] ) - for invalid_tool_config in invalid_tools: - invalid_tools_dict[ invalid_tool_config ] = ( repository.id, - repository.name, - repository.user.username, - downloadable_revision.changeset_revision ) - else: - for repository in trans.sa_session.query( trans.model.Repository ) \ - .filter( and_( trans.model.Repository.table.c.deleted == False, - trans.model.Repository.table.c.user_id == trans.user.id ) ) \ - .order_by( trans.model.Repository.table.c.name ): - for downloadable_revision in repository.metadata_revisions: - metadata = downloadable_revision.metadata - if metadata: - invalid_tools = metadata.get( 'invalid_tools', [] ) - for invalid_tool_config in invalid_tools: - invalid_tools_dict[ invalid_tool_config ] = ( repository.id, - repository.name, - repository.user.username, - downloadable_revision.changeset_revision ) - return trans.fill_template( '/webapps/tool_shed/repository/browse_invalid_tools.mako', - cntrller=cntrller, - invalid_tools_dict=invalid_tools_dict, - message=message, - status=status ) - - @web.expose def browse_my_writable_repositories( self, trans, **kwd ): if 'operation' in kwd: operation = kwd[ 'operation' ].lower() @@ -265,6 +226,34 @@ return self.my_writable_repositories_with_failing_tool_tests_grid( trans, **kwd ) @web.expose + def browse_my_writable_repositories_with_invalid_tools( self, trans, **kwd ): + if 'operation' in kwd: + operation = kwd[ 'operation' ].lower() + if operation == "view_or_manage_repository": + return trans.response.send_redirect( web.url_for( controller='repository', + action='view_or_manage_repository', + **kwd ) ) + elif operation == "repositories_by_user": + return trans.response.send_redirect( web.url_for( controller='repository', + action='browse_repositories_by_user', + **kwd ) ) + elif operation in [ 'mark as deprecated', 'mark as not deprecated' ]: + kwd[ 'mark_deprecated' ] = operation == 'mark as deprecated' + return trans.response.send_redirect( web.url_for( controller='repository', + action='deprecate', + **kwd ) ) + if 'message' not in kwd: + message = 'This list contains repositories that match the following criteria:<br>' + message += '<ul>' + message += '<li>you are authorized to update them</li>' + message += '<li>the latest metadata revision contains at least 1 invalid tool</li>' + message += '</ul>' + message += 'Click the tool config file name to see why the tool is invalid.' + kwd[ 'message' ] = message + kwd[ 'status' ] = 'warning' + return self.my_writable_repositories_with_invalid_tools_grid( trans, **kwd ) + + @web.expose def browse_my_writable_repositories_with_no_failing_tool_tests( self, trans, **kwd ): if 'operation' in kwd: operation = kwd[ 'operation' ].lower() @@ -492,6 +481,33 @@ return self.repositories_with_failing_tool_tests_grid( trans, **kwd ) @web.expose + def browse_repositories_with_invalid_tools( self, trans, **kwd ): + if 'operation' in kwd: + operation = kwd[ 'operation' ].lower() + if operation == "view_or_manage_repository": + return trans.response.send_redirect( web.url_for( controller='repository', + action='view_or_manage_repository', + **kwd ) ) + elif operation == "repositories_by_user": + return trans.response.send_redirect( web.url_for( controller='repository', + action='browse_repositories_by_user', + **kwd ) ) + elif operation in [ 'mark as deprecated', 'mark as not deprecated' ]: + kwd[ 'mark_deprecated' ] = operation == 'mark as deprecated' + return trans.response.send_redirect( web.url_for( controller='repository', + action='deprecate', + **kwd ) ) + if 'message' not in kwd: + message = 'This list contains repositories that match the following criteria:<br>' + message += '<ul>' + message += '<li>the latest metadata revision contains at least 1 invalid tool</li>' + message += '</ul>' + message += 'Click the tool config file name to see why the tool is invalid.' + kwd[ 'message' ] = message + kwd[ 'status' ] = 'warning' + return self.repositories_with_invalid_tools_grid( trans, **kwd ) + + @web.expose def browse_repositories_with_no_failing_tool_tests( self, trans, **kwd ): if 'operation' in kwd: operation = kwd[ 'operation' ].lower() @@ -1976,7 +1992,7 @@ is_malicious = repository_metadata.malicious else: # There is no repository_metadata defined for the changeset_revision, so see if it was defined in a previous changeset in the changelog. - previous_changeset_revision = suc.get_previous_downloadable_changeset_revision( repository, repo, changeset_revision ) + previous_changeset_revision = suc.get_previous_metadata_changeset_revision( repository, repo, changeset_revision, downloadable=False ) if previous_changeset_revision != suc.INITIAL_CHANGELOG_HASH: repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans, id, previous_changeset_revision ) if repository_metadata: @@ -2161,7 +2177,7 @@ repo_dir = repository.repo_path( trans.app ) repo = hg.repository( suc.get_configured_ui(), repo_dir ) # Get the lower bound changeset revision. - lower_bound_changeset_revision = suc.get_previous_downloadable_changeset_revision( repository, repo, changeset_revision ) + lower_bound_changeset_revision = suc.get_previous_metadata_changeset_revision( repository, repo, changeset_revision, downloadable=True ) # Build the list of changeset revision hashes. changeset_hashes = [] for changeset in suc.reversed_lower_upper_bounded_changelog( repo, lower_bound_changeset_revision, changeset_revision ): diff -r 4fce5cfe8be5724f27a1a909dac135c3f010fe30 -r c2c22e38826b65c67202b39e2f7e789c1761c892 lib/tool_shed/grids/repository_grids.py --- a/lib/tool_shed/grids/repository_grids.py +++ b/lib/tool_shed/grids/repository_grids.py @@ -73,48 +73,6 @@ use_paging = False -class ValidCategoryGrid( CategoryGrid ): - - - class RepositoriesColumn( grids.TextColumn ): - - def get_value( self, trans, grid, category ): - if category.repositories: - viewable_repositories = 0 - for rca in category.repositories: - repository = rca.repository - if not repository.deleted and not repository.deprecated and repository.downloadable_revisions: - viewable_repositories += 1 - return viewable_repositories - return 0 - - title = "Categories of valid repositories" - model_class = model.Category - template='/webapps/tool_shed/category/valid_grid.mako' - default_sort_key = "name" - columns = [ - CategoryGrid.NameColumn( "Name", - key="Category.name", - link=( lambda item: dict( operation="valid_repositories_by_category", id=item.id ) ), - attach_popup=False ), - CategoryGrid.DescriptionColumn( "Description", - key="Category.description", - attach_popup=False ), - # Columns that are valid for filtering but are not visible. - RepositoriesColumn( "Valid repositories", - model_class=model.Repository, - attach_popup=False ) - ] - # Override these - default_filter = {} - global_actions = [] - operations = [] - standard_filters = [] - num_rows_per_page = 50 - preserve_state = False - use_paging = False - - class RepositoryGrid( grids.Grid ): @@ -248,7 +206,7 @@ NameColumn( "Name", key="name", link=( lambda item: dict( operation="view_or_manage_repository", id=item.id ) ), - attach_popup=True ), + attach_popup=False ), DescriptionColumn( "Synopsis", key="description", attach_popup=False ), @@ -294,6 +252,195 @@ .outerjoin( model.Category.table ) +class EmailAlertsRepositoryGrid( RepositoryGrid ): + columns = [ + RepositoryGrid.NameColumn( "Name", + key="name", + link=( lambda item: dict( operation="view_or_manage_repository", id=item.id ) ), + attach_popup=False ), + RepositoryGrid.DescriptionColumn( "Synopsis", + key="description", + attach_popup=False ), + RepositoryGrid.UserColumn( "Owner", + model_class=model.User, + link=( lambda item: dict( operation="repositories_by_user", id=item.id ) ), + attach_popup=False, + key="User.username" ), + RepositoryGrid.EmailAlertsColumn( "Alert", attach_popup=False ), + # Columns that are valid for filtering but are not visible. + grids.DeletedColumn( "Deleted", + key="deleted", + visible=False, + filterable="advanced" ) + ] + operations = [] + global_actions = [ + grids.GridAction( "User preferences", dict( controller='user', action='index', cntrller='repository' ) ) + ] + + +class MatchedRepositoryGrid( grids.Grid ): + # This grid filters out repositories that have been marked as deleted or deprecated. + + + class NameColumn( grids.TextColumn ): + + def get_value( self, trans, grid, repository_metadata ): + return repository_metadata.repository.name + + + class DescriptionColumn( grids.TextColumn ): + + def get_value( self, trans, grid, repository_metadata ): + return repository_metadata.repository.description + + + class RevisionColumn( grids.TextColumn ): + + def get_value( self, trans, grid, repository_metadata ): + return repository_metadata.changeset_revision + + + class UserColumn( grids.TextColumn ): + + def get_value( self, trans, grid, repository_metadata ): + if repository_metadata.repository.user: + return repository_metadata.repository.user.username + return 'no user' + + # Grid definition + title = "Matching repositories" + model_class = model.RepositoryMetadata + template='/webapps/tool_shed/repository/grid.mako' + default_sort_key = "Repository.name" + columns = [ + NameColumn( "Repository name", + link=( lambda item: dict( operation="view_or_manage_repository", id=item.id ) ), + attach_popup=True ), + DescriptionColumn( "Synopsis", + attach_popup=False ), + RevisionColumn( "Revision" ), + UserColumn( "Owner", + model_class=model.User, + attach_popup=False ) + ] + operations = [ grids.GridOperation( "Install to Galaxy", allow_multiple=True ) ] + standard_filters = [] + default_filter = {} + num_rows_per_page = 50 + preserve_state = False + use_paging = False + + def build_initial_query( self, trans, **kwd ): + match_tuples = kwd.get( 'match_tuples', [] ) + clause_list = [] + if match_tuples: + for match_tuple in match_tuples: + repository_id, changeset_revision = match_tuple + clause_list.append( "%s=%d and %s='%s'" % ( model.RepositoryMetadata.table.c.repository_id, + int( repository_id ), + model.RepositoryMetadata.table.c.changeset_revision, + changeset_revision ) ) + return trans.sa_session.query( model.RepositoryMetadata ) \ + .join( model.Repository ) \ + .filter( and_( model.Repository.table.c.deleted == False, + model.Repository.table.c.deprecated == False ) ) \ + .join( model.User.table ) \ + .filter( or_( *clause_list ) ) \ + .order_by( model.Repository.name ) + # Return an empty query + return trans.sa_session.query( model.RepositoryMetadata ) \ + .filter( model.RepositoryMetadata.id < 0 ) + + +class InstallMatchedRepositoryGrid( MatchedRepositoryGrid ): + columns = [ col for col in MatchedRepositoryGrid.columns ] + # Override the NameColumn + columns[ 0 ] = MatchedRepositoryGrid.NameColumn( "Name", + link=( lambda item: dict( operation="view_or_manage_repository", id=item.id ) ), + attach_popup=False ) + + +class MyWritableRepositoriesGrid( RepositoryGrid ): + # This grid filters out repositories that have been marked as either deprecated or deleted. + title = 'Repositories I can change' + columns = [ + RepositoryGrid.NameColumn( "Name", + key="name", + link=( lambda item: dict( operation="view_or_manage_repository", id=item.id ) ), + attach_popup=False ), + RepositoryGrid.MetadataRevisionColumn( "Metadata Revisions" ), + RepositoryGrid.ToolsFunctionallyCorrectColumn( "Tools Verified" ), + RepositoryGrid.UserColumn( "Owner", + model_class=model.User, + link=( lambda item: dict( operation="repositories_by_user", id=item.id ) ), + attach_popup=False, + key="User.username" ) + ] + columns.append( grids.MulticolFilterColumn( "Search repository name", + cols_to_filter=[ columns[ 0 ] ], + key="free-text-search", + visible=False, + filterable="standard" ) ) + operations = [] + use_paging = False + + def build_initial_query( self, trans, **kwd ): + # TODO: improve performance by adding a db table associating users with repositories for which they have write access. + username = trans.user.username + clause_list = [] + for repository in trans.sa_session.query( model.Repository ) \ + .filter( and_( model.Repository.table.c.deprecated == False, + model.Repository.table.c.deleted == False ) ): + allow_push = repository.allow_push( trans.app ) + if allow_push: + allow_push_usernames = allow_push.split( ',' ) + if username in allow_push_usernames: + clause_list.append( model.Repository.table.c.id == repository.id ) + if clause_list: + return trans.sa_session.query( model.Repository ) \ + .filter( or_( *clause_list ) ) \ + .join( model.User.table ) + # Return an empty query. + return trans.sa_session.query( model.Repository ) \ + .filter( model.Repository.table.c.id < 0 ) + + +class RepositoriesByUserGrid( RepositoryGrid ): + title = "Repositories by user" + columns = [ + RepositoryGrid.NameColumn( "Name", + key="name", + link=( lambda item: dict( operation="view_or_manage_repository", id=item.id ) ), + attach_popup=False ), + RepositoryGrid.DescriptionColumn( "Synopsis", + key="description", + attach_popup=False ), + RepositoryGrid.MetadataRevisionColumn( "Metadata Revisions" ), + RepositoryGrid.ToolsFunctionallyCorrectColumn( "Tools Verified" ), + RepositoryGrid.CategoryColumn( "Category", + model_class=model.Category, + key="Category.name", + attach_popup=False ) + ] + operations = [] + standard_filters = [] + default_filter = dict( deleted="False" ) + num_rows_per_page = 50 + preserve_state = False + use_paging = False + + def build_initial_query( self, trans, **kwd ): + decoded_user_id = trans.security.decode_id( kwd[ 'user_id' ] ) + return trans.sa_session.query( model.Repository ) \ + .filter( and_( model.Repository.table.c.deleted == False, + model.Repository.table.c.deprecated == False, + model.Repository.table.c.user_id == decoded_user_id ) ) \ + .join( model.User.table ) \ + .outerjoin( model.RepositoryCategoryAssociation.table ) \ + .outerjoin( model.Category.table ) + + class RepositoriesInCategoryGrid( RepositoryGrid ): title = "Category" @@ -346,48 +493,13 @@ .outerjoin( model.Category.table ) -class RepositoriesByUserGrid( RepositoryGrid ): - title = "Repositories by user" - columns = [ - RepositoryGrid.NameColumn( "Name", - key="name", - link=( lambda item: dict( operation="view_or_manage_repository", id=item.id ) ), - attach_popup=False ), - RepositoryGrid.DescriptionColumn( "Synopsis", - key="description", - attach_popup=False ), - RepositoryGrid.MetadataRevisionColumn( "Metadata Revisions" ), - RepositoryGrid.ToolsFunctionallyCorrectColumn( "Tools Verified" ), - RepositoryGrid.CategoryColumn( "Category", - model_class=model.Category, - key="Category.name", - attach_popup=False ) - ] - operations = [] - standard_filters = [] - default_filter = dict( deleted="False" ) - num_rows_per_page = 50 - preserve_state = False - use_paging = False - - def build_initial_query( self, trans, **kwd ): - decoded_user_id = trans.security.decode_id( kwd[ 'user_id' ] ) - return trans.sa_session.query( model.Repository ) \ - .filter( and_( model.Repository.table.c.deleted == False, - model.Repository.table.c.deprecated == False, - model.Repository.table.c.user_id == decoded_user_id ) ) \ - .join( model.User.table ) \ - .outerjoin( model.RepositoryCategoryAssociation.table ) \ - .outerjoin( model.Category.table ) - - class RepositoriesIOwnGrid( RepositoryGrid ): title = "Repositories I own" columns = [ RepositoryGrid.NameColumn( "Name", key="name", link=( lambda item: dict( operation="view_or_manage_repository", id=item.id ) ), - attach_popup=True ), + attach_popup=False ), RepositoryGrid.MetadataRevisionColumn( "Metadata Revisions" ), RepositoryGrid.ToolsFunctionallyCorrectColumn( "Tools Verified" ), RepositoryGrid.DeprecatedColumn( "Deprecated" ) @@ -409,110 +521,8 @@ .outerjoin( model.Category.table ) -class DeprecatedRepositoriesIOwnGrid( RepositoriesIOwnGrid ): - title = "Deprecated repositories I own" - columns = [ - RepositoriesIOwnGrid.NameColumn( "Name", - key="name", - link=( lambda item: dict( operation="view_or_manage_repository", id=item.id ) ), - attach_popup=True ), - RepositoriesIOwnGrid.MetadataRevisionColumn( "Metadata Revisions" ), - RepositoryGrid.ToolsFunctionallyCorrectColumn( "Tools Verified" ), - RepositoriesIOwnGrid.CategoryColumn( "Category", - model_class=model.Category, - key="Category.name", - attach_popup=False ), - ] - columns.append( grids.MulticolFilterColumn( "Search repository name", - cols_to_filter=[ columns[0] ], - key="free-text-search", - visible=False, - filterable="standard" ) ) - use_paging = False - - def build_initial_query( self, trans, **kwd ): - return trans.sa_session.query( model.Repository ) \ - .filter( and_( model.Repository.table.c.deleted == False, - model.Repository.table.c.user_id == trans.user.id, - model.Repository.table.c.deprecated == True ) ) \ - .join( model.User.table ) \ - .outerjoin( model.RepositoryCategoryAssociation.table ) \ - .outerjoin( model.Category.table ) - - -class EmailAlertsRepositoryGrid( RepositoryGrid ): - columns = [ - RepositoryGrid.NameColumn( "Name", - key="name", - link=( lambda item: dict( operation="view_or_manage_repository", id=item.id ) ), - attach_popup=False ), - RepositoryGrid.DescriptionColumn( "Synopsis", - key="description", - attach_popup=False ), - RepositoryGrid.UserColumn( "Owner", - model_class=model.User, - link=( lambda item: dict( operation="repositories_by_user", id=item.id ) ), - attach_popup=False, - key="User.username" ), - RepositoryGrid.EmailAlertsColumn( "Alert", attach_popup=False ), - # Columns that are valid for filtering but are not visible. - grids.DeletedColumn( "Deleted", - key="deleted", - visible=False, - filterable="advanced" ) - ] - operations = [] - global_actions = [ - grids.GridAction( "User preferences", dict( controller='user', action='index', cntrller='repository' ) ) - ] - - -class MyWritableRepositoriesGrid( RepositoryGrid ): - # This grid filters out repositories that have been marked as either deprecated or deleted. - title = 'Repositories I can change' - columns = [ - RepositoryGrid.NameColumn( "Name", - key="name", - link=( lambda item: dict( operation="view_or_manage_repository", id=item.id ) ), - attach_popup=True ), - RepositoryGrid.MetadataRevisionColumn( "Metadata Revisions" ), - RepositoryGrid.ToolsFunctionallyCorrectColumn( "Tools Verified" ), - RepositoryGrid.UserColumn( "Owner", - model_class=model.User, - link=( lambda item: dict( operation="repositories_by_user", id=item.id ) ), - attach_popup=False, - key="User.username" ) - ] - columns.append( grids.MulticolFilterColumn( "Search repository name", - cols_to_filter=[ columns[ 0 ] ], - key="free-text-search", - visible=False, - filterable="standard" ) ) - operations = [] - use_paging = False - - def build_initial_query( self, trans, **kwd ): - # TODO: improve performance by adding a db table associating users with repositories for which they have write access. - username = trans.user.username - clause_list = [] - for repository in trans.sa_session.query( model.Repository ) \ - .filter( and_( model.Repository.table.c.deprecated == False, - model.Repository.table.c.deleted == False ) ): - allow_push = repository.allow_push( trans.app ) - if allow_push: - allow_push_usernames = allow_push.split( ',' ) - if username in allow_push_usernames: - clause_list.append( model.Repository.table.c.id == repository.id ) - if clause_list: - return trans.sa_session.query( model.Repository ) \ - .filter( or_( *clause_list ) ) \ - .join( model.User.table ) - # Return an empty query. - return trans.sa_session.query( model.Repository ) \ - .filter( model.Repository.table.c.id < 0 ) - - class RepositoriesMissingToolTestComponentsGrid( RepositoryGrid ): + # This grid displays only the latest installable revision of each repository. title = "Repositories with missing tool test components" columns = [ RepositoryGrid.NameColumn( "Name", @@ -545,6 +555,8 @@ revision_clause_list.append( model.RepositoryMetadata.table.c.changeset_revision == changeset_revision ) if revision_clause_list: return trans.sa_session.query( model.Repository ) \ + .filter( and_( model.Repository.table.c.deprecated == False, + model.Repository.table.c.deleted == False ) ) \ .join( model.RepositoryMetadata ) \ .filter( or_( *revision_clause_list ) ) \ .join( model.User.table ) @@ -554,6 +566,7 @@ class MyWritableRepositoriesMissingToolTestComponentsGrid( RepositoriesMissingToolTestComponentsGrid ): + # This grid displays only the latest installable revision of each repository. title = "Repositories I can change with missing tool test components" columns = [ col for col in RepositoriesMissingToolTestComponentsGrid.columns ] operations = [] @@ -576,12 +589,16 @@ # tools with missing tool test components. revision_clause_list = [] for repository in trans.sa_session.query( model.Repository ) \ + .filter( and_( model.Repository.table.c.deprecated == False, + model.Repository.table.c.deleted == False ) ) \ .filter( or_( *user_clause_list ) ): changeset_revision = filter_by_latest_downloadable_changeset_revision_that_has_missing_tool_test_components( trans, repository ) if changeset_revision: revision_clause_list.append( model.RepositoryMetadata.table.c.changeset_revision == changeset_revision ) if revision_clause_list: return trans.sa_session.query( model.Repository ) \ + .filter( and_( model.Repository.table.c.deprecated == False, + model.Repository.table.c.deleted == False ) ) \ .join( model.User.table ) \ .filter( or_( *user_clause_list ) ) \ .join( model.RepositoryMetadata ) \ @@ -591,7 +608,39 @@ .filter( model.Repository.table.c.id < 0 ) +class DeprecatedRepositoriesIOwnGrid( RepositoriesIOwnGrid ): + title = "Deprecated repositories I own" + columns = [ + RepositoriesIOwnGrid.NameColumn( "Name", + key="name", + link=( lambda item: dict( operation="view_or_manage_repository", id=item.id ) ), + attach_popup=False ), + RepositoriesIOwnGrid.MetadataRevisionColumn( "Metadata Revisions" ), + RepositoryGrid.ToolsFunctionallyCorrectColumn( "Tools Verified" ), + RepositoriesIOwnGrid.CategoryColumn( "Category", + model_class=model.Category, + key="Category.name", + attach_popup=False ), + ] + columns.append( grids.MulticolFilterColumn( "Search repository name", + cols_to_filter=[ columns[0] ], + key="free-text-search", + visible=False, + filterable="standard" ) ) + use_paging = False + + def build_initial_query( self, trans, **kwd ): + return trans.sa_session.query( model.Repository ) \ + .filter( and_( model.Repository.table.c.deleted == False, + model.Repository.table.c.user_id == trans.user.id, + model.Repository.table.c.deprecated == True ) ) \ + .join( model.User.table ) \ + .outerjoin( model.RepositoryCategoryAssociation.table ) \ + .outerjoin( model.Category.table ) + + class RepositoriesWithFailingToolTestsGrid( RepositoryGrid ): + # This grid displays only the latest installable revision of each repository. title = "Repositories with failing tool tests" columns = [ RepositoryGrid.NameColumn( "Name", @@ -624,6 +673,8 @@ revision_clause_list.append( model.RepositoryMetadata.table.c.changeset_revision == changeset_revision ) if revision_clause_list: return trans.sa_session.query( model.Repository ) \ + .filter( and_( model.Repository.table.c.deprecated == False, + model.Repository.table.c.deleted == False ) ) \ .join( model.RepositoryMetadata ) \ .filter( or_( *revision_clause_list ) ) \ .join( model.User.table ) @@ -633,6 +684,7 @@ class MyWritableRepositoriesWithFailingToolTestsGrid( RepositoriesWithFailingToolTestsGrid ): + # This grid displays only the latest installable revision of each repository. title = "Repositories I can change with failing tool tests" columns = [ col for col in RepositoriesWithFailingToolTestsGrid.columns ] operations = [] @@ -655,12 +707,16 @@ # tools with at least 1 failing tool test. revision_clause_list = [] for repository in trans.sa_session.query( model.Repository ) \ + .filter( and_( model.Repository.table.c.deprecated == False, + model.Repository.table.c.deleted == False ) ) \ .filter( or_( *user_clause_list ) ): changeset_revision = filter_by_latest_downloadable_changeset_revision_that_has_failing_tool_tests( trans, repository ) if changeset_revision: revision_clause_list.append( model.RepositoryMetadata.table.c.changeset_revision == changeset_revision ) if revision_clause_list: return trans.sa_session.query( model.Repository ) \ + .filter( and_( model.Repository.table.c.deprecated == False, + model.Repository.table.c.deleted == False ) ) \ .join( model.User.table ) \ .filter( or_( *user_clause_list ) ) \ .join( model.RepositoryMetadata ) \ @@ -671,6 +727,7 @@ class RepositoriesWithNoFailingToolTestsGrid( RepositoryGrid ): + # This grid displays only the latest installable revision of each repository. title = "Repositories with no failing tool tests" columns = [ RepositoryGrid.NameColumn( "Name", @@ -704,6 +761,8 @@ revision_clause_list.append( model.RepositoryMetadata.table.c.changeset_revision == changeset_revision ) if revision_clause_list: return trans.sa_session.query( model.Repository ) \ + .filter( and_( model.Repository.table.c.deprecated == False, + model.Repository.table.c.deleted == False ) ) \ .join( model.RepositoryMetadata ) \ .filter( or_( *revision_clause_list ) ) \ .join( model.User.table ) @@ -713,6 +772,7 @@ class MyWritableRepositoriesWithNoFailingToolTestsGrid( RepositoriesWithNoFailingToolTestsGrid ): + # This grid displays only the latest installable revision of each repository. title = "Repositories I can change with no failing tool tests" columns = [ col for col in RepositoriesWithNoFailingToolTestsGrid.columns ] operations = [] @@ -735,12 +795,16 @@ # at least 1 tool, no missing tool test components, and no failing tool tests. revision_clause_list = [] for repository in trans.sa_session.query( model.Repository ) \ + .filter( and_( model.Repository.table.c.deprecated == False, + model.Repository.table.c.deleted == False ) ) \ .filter( or_( *user_clause_list ) ): changeset_revision = filter_by_latest_downloadable_changeset_revision_that_has_no_failing_tool_tests( trans, repository ) if changeset_revision: revision_clause_list.append( model.RepositoryMetadata.table.c.changeset_revision == changeset_revision ) if revision_clause_list: return trans.sa_session.query( model.Repository ) \ + .filter( and_( model.Repository.table.c.deprecated == False, + model.Repository.table.c.deleted == False ) ) \ .join( model.User.table ) \ .filter( or_( *user_clause_list ) ) \ .join( model.RepositoryMetadata ) \ @@ -750,179 +814,110 @@ .filter( model.Repository.table.c.id < 0 ) -class ValidRepositoryGrid( RepositoryGrid ): - # This grid filters out repositories that have been marked as either deleted or deprecated. +class RepositoriesWithInvalidToolsGrid( RepositoryGrid ): + # This grid displays only the latest installable revision of each repository. - class CategoryColumn( grids.TextColumn ): - - def get_value( self, trans, grid, repository ): - rval = '<ul>' - if repository.categories: - for rca in repository.categories: - rval += '<li><a href="browse_repositories?operation=valid_repositories_by_category&id=%s">%s</a></li>' \ - % ( trans.security.encode_id( rca.category.id ), rca.category.name ) - else: - rval += '<li>not set</li>' - rval += '</ul>' - return rval - - - class RepositoryCategoryColumn( grids.GridColumn ): - - def filter( self, trans, user, query, column_filter ): - """Modify query to filter by category.""" - if column_filter == "All": - return query - return query.filter( model.Category.name == column_filter ) - - - class InstallableRevisionColumn( grids.GridColumn ): + class InvalidToolConfigColumn( grids.GridColumn ): def __init__( self, col_name ): grids.GridColumn.__init__( self, col_name ) def get_value( self, trans, grid, repository ): - """Display a SelectField whose options are the changeset_revision strings of all download-able revisions of this repository.""" - select_field = grids_util.build_changeset_revision_select_field( trans, repository, downloadable=True ) - if len( select_field.options ) > 1: - return select_field.get_html() - elif len( select_field.options ) == 1: - return select_field.options[ 0 ][ 0 ] - return '' + # At the time this grid is displayed we know that the received repository will have invalid tools in it's latest changeset revision + # that has associated metadata. + val = '' + repository_metadata = get_latest_repository_metadata_if_it_includes_invalid_tools( trans, repository ) + metadata = repository_metadata.metadata + invalid_tools = metadata.get( 'invalid_tools', [] ) + if invalid_tools: + for invalid_tool_config in invalid_tools: + href_str = '<a href="load_invalid_tool?repository_id=%s&tool_config=%s&changeset_revision=%s">%s</a>' % \ + ( trans.security.encode_id( repository.id ), invalid_tool_config, repository_metadata.changeset_revision, invalid_tool_config ) + val += href_str + val += '<br/>' + val = val.rstrip( '<br/>' ) + return val - title = "Valid repositories" - columns = [ + title = "Repositories with invalid tools" + columns = [ + InvalidToolConfigColumn( "Tool config" ), RepositoryGrid.NameColumn( "Name", key="name", - attach_popup=True ), - RepositoryGrid.DescriptionColumn( "Synopsis", - key="description", - attach_popup=False ), - InstallableRevisionColumn( "Installable Revisions" ), - RepositoryGrid.ToolsFunctionallyCorrectColumn( "Tools Verified" ), + link=( lambda item: dict( operation="view_or_manage_repository", id=item.id ) ), + attach_popup=False ), + RepositoryGrid.LatestInstallableRevisionColumn( "Latest Metadata Revision" ), RepositoryGrid.UserColumn( "Owner", + key="User.username", model_class=model.User, - attach_popup=False ), - # Columns that are valid for filtering but are not visible. - RepositoryCategoryColumn( "Category", - model_class=model.Category, - key="Category.name", - visible=False ) + link=( lambda item: dict( operation="repositories_by_user", id=item.id ) ), + attach_popup=False ) ] - columns.append( grids.MulticolFilterColumn( "Search repository name, description", - cols_to_filter=[ columns[0], columns[1] ], - key="free-text-search", - visible=False, - filterable="standard" ) ) operations = [] use_paging = False def build_initial_query( self, trans, **kwd ): - if 'id' in kwd: - # The user is browsing categories of valid repositories, so filter the request by the received id, which is a category id. + # Filter by latest metadata revisions that contain invalid tools. + revision_clause_list = [] + for repository in trans.sa_session.query( model.Repository ) \ + .filter( and_( model.Repository.table.c.deprecated == False, + model.Repository.table.c.deleted == False ) ): + changeset_revision = filter_by_latest_metadata_changeset_revision_that_has_invalid_tools( trans, repository ) + if changeset_revision: + revision_clause_list.append( model.RepositoryMetadata.table.c.changeset_revision == changeset_revision ) + if revision_clause_list: return trans.sa_session.query( model.Repository ) \ - .filter( and_( model.Repository.table.c.deleted == False, - model.Repository.table.c.deprecated == False ) ) \ - .join( model.RepositoryMetadata.table ) \ - .join( model.User.table ) \ - .join( model.RepositoryCategoryAssociation.table ) \ - .join( model.Category.table ) \ - .filter( and_( model.Category.table.c.id == trans.security.decode_id( kwd[ 'id' ] ), - model.RepositoryMetadata.table.c.downloadable == True ) ) - # The user performed a free text search on the ValidCategoryGrid. + .filter( and_( model.Repository.table.c.deprecated == False, + model.Repository.table.c.deleted == False ) ) \ + .join( model.RepositoryMetadata ) \ + .filter( or_( *revision_clause_list ) ) \ + .join( model.User.table ) + # Return an empty query. return trans.sa_session.query( model.Repository ) \ - .filter( and_( model.Repository.table.c.deleted == False, - model.Repository.table.c.deprecated == False ) ) \ - .join( model.RepositoryMetadata.table ) \ - .join( model.User.table ) \ - .outerjoin( model.RepositoryCategoryAssociation.table ) \ - .outerjoin( model.Category.table ) \ - .filter( model.RepositoryMetadata.table.c.downloadable == True ) + .filter( model.Repository.table.c.id < 0 ) -class MatchedRepositoryGrid( grids.Grid ): - # This grid filters out repositories that have been marked as deprecated. - - - class NameColumn( grids.TextColumn ): - - def get_value( self, trans, grid, repository_metadata ): - return repository_metadata.repository.name - - - class DescriptionColumn( grids.TextColumn ): - - def get_value( self, trans, grid, repository_metadata ): - return repository_metadata.repository.description - - - class RevisionColumn( grids.TextColumn ): - - def get_value( self, trans, grid, repository_metadata ): - return repository_metadata.changeset_revision - - - class UserColumn( grids.TextColumn ): - - def get_value( self, trans, grid, repository_metadata ): - if repository_metadata.repository.user: - return repository_metadata.repository.user.username - return 'no user' - - # Grid definition - title = "Matching repositories" - model_class = model.RepositoryMetadata - template='/webapps/tool_shed/repository/grid.mako' - default_sort_key = "Repository.name" - columns = [ - NameColumn( "Repository name", - link=( lambda item: dict( operation="view_or_manage_repository", id=item.id ) ), - attach_popup=True ), - DescriptionColumn( "Synopsis", - attach_popup=False ), - RevisionColumn( "Revision" ), - UserColumn( "Owner", - model_class=model.User, - attach_popup=False ) - ] - operations = [ - grids.GridOperation( "Install to Galaxy", allow_multiple=True ) - ] - standard_filters = [] - default_filter = {} - num_rows_per_page = 50 - preserve_state = False +class MyWritableRepositoriesWithInvalidToolsGrid( RepositoriesWithInvalidToolsGrid ): + # This grid displays only the latest installable revision of each repository. + title = "Repositories I can change with invalid tools" + columns = [ col for col in RepositoriesWithInvalidToolsGrid.columns ] + operations = [] use_paging = False def build_initial_query( self, trans, **kwd ): - match_tuples = kwd.get( 'match_tuples', [] ) - clause_list = [] - if match_tuples: - for match_tuple in match_tuples: - repository_id, changeset_revision = match_tuple - clause_list.append( "%s=%d and %s='%s'" % ( model.RepositoryMetadata.table.c.repository_id, - int( repository_id ), - model.RepositoryMetadata.table.c.changeset_revision, - changeset_revision ) ) - return trans.sa_session.query( model.RepositoryMetadata ) \ - .join( model.Repository ) \ - .filter( and_( model.Repository.table.c.deleted == False, - model.Repository.table.c.deprecated == False ) ) \ - .join( model.User.table ) \ - .filter( or_( *clause_list ) ) \ - .order_by( model.Repository.name ) - # Return an empty query - return trans.sa_session.query( model.RepositoryMetadata ) \ - .filter( model.RepositoryMetadata.id < 0 ) - - -class InstallMatchedRepositoryGrid( MatchedRepositoryGrid ): - columns = [ col for col in MatchedRepositoryGrid.columns ] - # Override the NameColumn - columns[ 0 ] = MatchedRepositoryGrid.NameColumn( "Name", - link=( lambda item: dict( operation="view_or_manage_repository", id=item.id ) ), - attach_popup=False ) + # First get all repositories that the current user is authorized to update. + username = trans.user.username + user_clause_list = [] + for repository in trans.sa_session.query( model.Repository ) \ + .filter( and_( model.Repository.table.c.deprecated == False, + model.Repository.table.c.deleted == False ) ): + allow_push = repository.allow_push( trans.app ) + if allow_push: + allow_push_usernames = allow_push.split( ',' ) + if username in allow_push_usernames: + user_clause_list.append( model.Repository.table.c.id == repository.id ) + if user_clause_list: + # We have the list of repositories that the current user is authorized to update, so filter further by latest metadata revisions that contain + # invalid tools. + revision_clause_list = [] + for repository in trans.sa_session.query( model.Repository ) \ + .filter( and_( model.Repository.table.c.deprecated == False, + model.Repository.table.c.deleted == False ) ) \ + .filter( or_( *user_clause_list ) ): + changeset_revision = filter_by_latest_metadata_changeset_revision_that_has_invalid_tools( trans, repository ) + if changeset_revision: + revision_clause_list.append( model.RepositoryMetadata.table.c.changeset_revision == changeset_revision ) + if revision_clause_list: + return trans.sa_session.query( model.Repository ) \ + .filter( and_( model.Repository.table.c.deprecated == False, + model.Repository.table.c.deleted == False ) ) \ + .join( model.User.table ) \ + .filter( or_( *user_clause_list ) ) \ + .join( model.RepositoryMetadata ) \ + .filter( or_( *revision_clause_list ) ) + # Return an empty query. + return trans.sa_session.query( model.Repository ) \ + .filter( model.Repository.table.c.id < 0 ) class RepositoryMetadataGrid( grids.Grid ): @@ -1136,6 +1131,73 @@ .join( model.User.table ) +class DatatypesGrid( RepositoryMetadataGrid ): + + + class DatatypesColumn( grids.TextColumn ): + + def get_value( self, trans, grid, repository_metadata ): + datatype_str = '' + if repository_metadata: + metadata = repository_metadata.metadata + if metadata: + datatype_dicts = metadata.get( 'datatypes', [] ) + if datatype_dicts: + # Create tuples of the attributes we want so we can sort them by extension. + datatype_tups = [] + for datatype_dict in datatype_dicts: + # Example: {"display_in_upload": "true", "dtype": "galaxy.datatypes.blast:BlastXml", "extension": "blastxml", "mimetype": "application/xml"} + extension = datatype_dict.get( 'extension', '' ) + dtype = datatype_dict.get( 'dtype', '' ) + mimetype = datatype_dict.get( 'mimetype', '' ) + display_in_upload = datatype_dict.get( 'display_in_upload', False ) + # For now we'll just display extension and dtype. + if extension and dtype: + datatype_tups.append( ( extension, dtype ) ) + sorted_datatype_tups = sorted( datatype_tups, key=lambda datatype_tup: datatype_tup[ 0 ] ) + num_datatype_tups = len( sorted_datatype_tups ) + for index, datatype_tup in enumerate( sorted_datatype_tups ): + extension = datatype_tup[ 0 ] + dtype = datatype_tup[ 1 ] + datatype_str += '<a href="browse_datatypes?operation=view_or_manage_repository&id=%s">' % trans.security.encode_id( repository_metadata.id ) + datatype_str += '<b>%s:</b> %s' % ( escape_html( extension ), escape_html( dtype ) ) + datatype_str += '</a>' + if index < num_datatype_tups - 1: + datatype_str += '<br/>' + return datatype_str + + title = "Custom datatypes in this tool shed" + default_sort_key = "Repository.name" + columns = [ + DatatypesColumn( "Datatype extension and class", + attach_popup=False ), + RepositoryMetadataGrid.RepositoryNameColumn( "Repository name", + model_class=model.Repository, + link=( lambda item: dict( operation="view_or_manage_repository", id=item.id ) ), + attach_popup=False, + key="Repository.name" ), + RepositoryMetadataGrid.RepositoryOwnerColumn( "Owner", + model_class=model.User, + attach_popup=False, + key="User.username" ), + RepositoryMetadataGrid.ChangesetRevisionColumn( "Revision", + attach_popup=False ) + ] + columns.append( grids.MulticolFilterColumn( "Search repository name, owner", + cols_to_filter=[ columns[1], columns[2] ], + key="free-text-search", + visible=False, + filterable="standard" ) ) + + def build_initial_query( self, trans, **kwd ): + return trans.sa_session.query( model.RepositoryMetadata ) \ + .join( model.Repository ) \ + .filter( and_( model.RepositoryMetadata.table.c.includes_datatypes == True, + model.Repository.table.c.deleted == False, + model.Repository.table.c.deprecated == False ) ) \ + .join( model.User.table ) + + class ToolDependenciesGrid( RepositoryMetadataGrid ): @@ -1275,71 +1337,137 @@ .join( model.User.table ) -class DatatypesGrid( RepositoryMetadataGrid ): +class ValidCategoryGrid( CategoryGrid ): - class DatatypesColumn( grids.TextColumn ): + class RepositoriesColumn( grids.TextColumn ): - def get_value( self, trans, grid, repository_metadata ): - datatype_str = '' - if repository_metadata: - metadata = repository_metadata.metadata - if metadata: - datatype_dicts = metadata.get( 'datatypes', [] ) - if datatype_dicts: - # Create tuples of the attributes we want so we can sort them by extension. - datatype_tups = [] - for datatype_dict in datatype_dicts: - # Example: {"display_in_upload": "true", "dtype": "galaxy.datatypes.blast:BlastXml", "extension": "blastxml", "mimetype": "application/xml"} - extension = datatype_dict.get( 'extension', '' ) - dtype = datatype_dict.get( 'dtype', '' ) - mimetype = datatype_dict.get( 'mimetype', '' ) - display_in_upload = datatype_dict.get( 'display_in_upload', False ) - # For now we'll just display extension and dtype. - if extension and dtype: - datatype_tups.append( ( extension, dtype ) ) - sorted_datatype_tups = sorted( datatype_tups, key=lambda datatype_tup: datatype_tup[ 0 ] ) - num_datatype_tups = len( sorted_datatype_tups ) - for index, datatype_tup in enumerate( sorted_datatype_tups ): - extension = datatype_tup[ 0 ] - dtype = datatype_tup[ 1 ] - datatype_str += '<a href="browse_datatypes?operation=view_or_manage_repository&id=%s">' % trans.security.encode_id( repository_metadata.id ) - datatype_str += '<b>%s:</b> %s' % ( escape_html( extension ), escape_html( dtype ) ) - datatype_str += '</a>' - if index < num_datatype_tups - 1: - datatype_str += '<br/>' - return datatype_str + def get_value( self, trans, grid, category ): + if category.repositories: + viewable_repositories = 0 + for rca in category.repositories: + repository = rca.repository + if not repository.deleted and not repository.deprecated and repository.downloadable_revisions: + viewable_repositories += 1 + return viewable_repositories + return 0 - title = "Custom datatypes in this tool shed" - default_sort_key = "Repository.name" + title = "Categories of valid repositories" + model_class = model.Category + template='/webapps/tool_shed/category/valid_grid.mako' + default_sort_key = "name" columns = [ - DatatypesColumn( "Datatype extension and class", - attach_popup=False ), - RepositoryMetadataGrid.RepositoryNameColumn( "Repository name", - model_class=model.Repository, - link=( lambda item: dict( operation="view_or_manage_repository", id=item.id ) ), - attach_popup=False, - key="Repository.name" ), - RepositoryMetadataGrid.RepositoryOwnerColumn( "Owner", - model_class=model.User, - attach_popup=False, - key="User.username" ), - RepositoryMetadataGrid.ChangesetRevisionColumn( "Revision", - attach_popup=False ) + CategoryGrid.NameColumn( "Name", + key="Category.name", + link=( lambda item: dict( operation="valid_repositories_by_category", id=item.id ) ), + attach_popup=False ), + CategoryGrid.DescriptionColumn( "Description", + key="Category.description", + attach_popup=False ), + # Columns that are valid for filtering but are not visible. + RepositoriesColumn( "Valid repositories", + model_class=model.Repository, + attach_popup=False ) ] - columns.append( grids.MulticolFilterColumn( "Search repository name, owner", - cols_to_filter=[ columns[1], columns[2] ], + # Override these + default_filter = {} + global_actions = [] + operations = [] + standard_filters = [] + num_rows_per_page = 50 + preserve_state = False + use_paging = False + + +class ValidRepositoryGrid( RepositoryGrid ): + # This grid filters out repositories that have been marked as either deleted or deprecated. + + + class CategoryColumn( grids.TextColumn ): + + def get_value( self, trans, grid, repository ): + rval = '<ul>' + if repository.categories: + for rca in repository.categories: + rval += '<li><a href="browse_repositories?operation=valid_repositories_by_category&id=%s">%s</a></li>' \ + % ( trans.security.encode_id( rca.category.id ), rca.category.name ) + else: + rval += '<li>not set</li>' + rval += '</ul>' + return rval + + + class RepositoryCategoryColumn( grids.GridColumn ): + + def filter( self, trans, user, query, column_filter ): + """Modify query to filter by category.""" + if column_filter == "All": + return query + return query.filter( model.Category.name == column_filter ) + + + class InstallableRevisionColumn( grids.GridColumn ): + + def __init__( self, col_name ): + grids.GridColumn.__init__( self, col_name ) + + def get_value( self, trans, grid, repository ): + """Display a SelectField whose options are the changeset_revision strings of all download-able revisions of this repository.""" + select_field = grids_util.build_changeset_revision_select_field( trans, repository, downloadable=True ) + if len( select_field.options ) > 1: + return select_field.get_html() + elif len( select_field.options ) == 1: + return select_field.options[ 0 ][ 0 ] + return '' + + title = "Valid repositories" + columns = [ + RepositoryGrid.NameColumn( "Name", + key="name", + attach_popup=False ), + RepositoryGrid.DescriptionColumn( "Synopsis", + key="description", + attach_popup=False ), + InstallableRevisionColumn( "Installable Revisions" ), + RepositoryGrid.ToolsFunctionallyCorrectColumn( "Tools Verified" ), + RepositoryGrid.UserColumn( "Owner", + model_class=model.User, + attach_popup=False ), + # Columns that are valid for filtering but are not visible. + RepositoryCategoryColumn( "Category", + model_class=model.Category, + key="Category.name", + visible=False ) + ] + columns.append( grids.MulticolFilterColumn( "Search repository name, description", + cols_to_filter=[ columns[0], columns[1] ], key="free-text-search", visible=False, filterable="standard" ) ) + operations = [] + use_paging = False def build_initial_query( self, trans, **kwd ): - return trans.sa_session.query( model.RepositoryMetadata ) \ - .join( model.Repository ) \ - .filter( and_( model.RepositoryMetadata.table.c.includes_datatypes == True, - model.Repository.table.c.deleted == False, + if 'id' in kwd: + # The user is browsing categories of valid repositories, so filter the request by the received id, which is a category id. + return trans.sa_session.query( model.Repository ) \ + .filter( and_( model.Repository.table.c.deleted == False, + model.Repository.table.c.deprecated == False ) ) \ + .join( model.RepositoryMetadata.table ) \ + .join( model.User.table ) \ + .join( model.RepositoryCategoryAssociation.table ) \ + .join( model.Category.table ) \ + .filter( and_( model.Category.table.c.id == trans.security.decode_id( kwd[ 'id' ] ), + model.RepositoryMetadata.table.c.downloadable == True ) ) + # The user performed a free text search on the ValidCategoryGrid. + return trans.sa_session.query( model.Repository ) \ + .filter( and_( model.Repository.table.c.deleted == False, model.Repository.table.c.deprecated == False ) ) \ - .join( model.User.table ) + .join( model.RepositoryMetadata.table ) \ + .join( model.User.table ) \ + .outerjoin( model.RepositoryCategoryAssociation.table ) \ + .outerjoin( model.Category.table ) \ + .filter( model.RepositoryMetadata.table.c.downloadable == True ) # ------ utility methods ------------------- @@ -1380,8 +1508,46 @@ return repository_metadata.changeset_revision return None +def filter_by_latest_metadata_changeset_revision_that_has_invalid_tools( trans, repository ): + """ + Inspect the latest changeset revision with associated metadata for the received repository to see if it has invalid tools. + """ + encoded_repository_id = trans.security.encode_id( repository.id ) + repo = hg.repository( suc.get_configured_ui(), repository.repo_path( trans.app ) ) + tip_ctx = str( repo.changectx( repo.changelog.tip() ) ) + repository_metadata = get_latest_repository_metadata_if_it_includes_invalid_tools( trans, repository ) + if repository_metadata: + return repository_metadata.changeset_revision + return None + +def get_latest_repository_metadata_if_it_includes_invalid_tools( trans, repository ): + """Return the latest repository_metadata record for the received repository that contains invalid tools if one exists.""" + encoded_repository_id = trans.security.encode_id( repository.id ) + repo = hg.repository( suc.get_configured_ui(), repository.repo_path( trans.app ) ) + tip_ctx = str( repo.changectx( repo.changelog.tip() ) ) + repository_metadata = None + try: + repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans, encoded_repository_id, tip_ctx ) + if repository_metadata: + metadata = repository_metadata.metadata + if metadata and 'invalid_tools' in metadata: + return repository_metadata + return None + return None + except: + latest_installable_revision = suc.get_previous_metadata_changeset_revision( repository, repo, tip_ctx, downloadable=False ) + if latest_installable_revision == suc.INITIAL_CHANGELOG_HASH: + return None + repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans, encoded_repository_id, latest_installable_revision ) + if repository_metadata: + metadata = repository_metadata.metadata + if metadata and 'invalid_tools' in metadata: + return repository_metadata + return None + return None + def get_latest_installable_repository_metadata_if_it_includes_tools( trans, repository ): - """Return the latest installable repository_metadata record for the received repository if one exists.""" + """Return the latest installable repository_metadata record for the received repository that contains valid tools if one exists.""" encoded_repository_id = trans.security.encode_id( repository.id ) repo = hg.repository( suc.get_configured_ui(), repository.repo_path( trans.app ) ) tip_ctx = str( repo.changectx( repo.changelog.tip() ) ) @@ -1392,7 +1558,7 @@ return repository_metadata return None except: - latest_installable_revision = suc.get_previous_downloadable_changeset_revision( repository, repo, tip_ctx ) + latest_installable_revision = suc.get_previous_metadata_changeset_revision( repository, repo, tip_ctx, downloadable=True ) if latest_installable_revision == suc.INITIAL_CHANGELOG_HASH: return None repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans, encoded_repository_id, latest_installable_revision ) diff -r 4fce5cfe8be5724f27a1a909dac135c3f010fe30 -r c2c22e38826b65c67202b39e2f7e789c1761c892 lib/tool_shed/util/shed_util_common.py --- a/lib/tool_shed/util/shed_util_common.py +++ b/lib/tool_shed/util/shed_util_common.py @@ -520,7 +520,7 @@ Return the installable changeset_revision in the repository changelog after the changeset to which after_changeset_revision refers. If there isn't one, return None. """ - changeset_revisions = get_ordered_downloadable_changeset_revisions( repository, repo ) + changeset_revisions = get_ordered_metadata_changeset_revisions( repository, repo, downloadable=True ) if len( changeset_revisions ) == 1: changeset_revision = changeset_revisions[ 0 ] if changeset_revision == after_changeset_revision: @@ -560,10 +560,14 @@ dist_to_shed=False ) return repository -def get_ordered_downloadable_changeset_revisions( repository, repo ): - """Return an ordered list of changeset_revisions defined by a repository changelog.""" +def get_ordered_metadata_changeset_revisions( repository, repo, downloadable=True ): + """Return an ordered list of changeset_revisions that are associated with metadata where order is defined by the repository changelog.""" + if downloadable: + metadata_revisions = repository.downloadable_revisions + else: + metadata_revisions = repository.metadata_revisions changeset_tups = [] - for repository_metadata in repository.downloadable_revisions: + for repository_metadata in metadata_revisions: changeset_revision = repository_metadata.changeset_revision ctx = get_changectx_for_changeset( repo, changeset_revision ) if ctx: @@ -575,12 +579,12 @@ sorted_changeset_revisions = [ changeset_tup[ 1 ] for changeset_tup in sorted_changeset_tups ] return sorted_changeset_revisions -def get_previous_downloadable_changeset_revision( repository, repo, before_changeset_revision ): +def get_previous_metadata_changeset_revision( repository, repo, before_changeset_revision, downloadable=True ): """ - Return the installable changeset_revision in the repository changelog prior to the changeset to which before_changeset_revision - refers. If there isn't one, return the hash value of an empty repository changelog, INITIAL_CHANGELOG_HASH. + Return the changeset_revision in the repository changelog that has associated metadata prior to the changeset to which + before_changeset_revision refers. If there isn't one, return the hash value of an empty repository changelog, INITIAL_CHANGELOG_HASH. """ - changeset_revisions = get_ordered_downloadable_changeset_revisions( repository, repo ) + changeset_revisions = get_ordered_metadata_changeset_revisions( repository, repo, downloadable=downloadable ) if len( changeset_revisions ) == 1: changeset_revision = changeset_revisions[ 0 ] if changeset_revision == before_changeset_revision: @@ -1091,7 +1095,7 @@ """ # To set excluded_lower_bounds_changeset_revision, calling methods should do the following, where the value of changeset_revision # is a downloadable changeset_revision. - # excluded_lower_bounds_changeset_revision = get_previous_downloadable_changeset_revision( repository, repo, changeset_revision ) + # excluded_lower_bounds_changeset_revision = get_previous_metadata_changeset_revision( repository, repo, changeset_revision, downloadable=? ) if excluded_lower_bounds_changeset_revision == INITIAL_CHANGELOG_HASH: appending_started = True else: diff -r 4fce5cfe8be5724f27a1a909dac135c3f010fe30 -r c2c22e38826b65c67202b39e2f7e789c1761c892 templates/webapps/tool_shed/admin/index.mako --- a/templates/webapps/tool_shed/admin/index.mako +++ b/templates/webapps/tool_shed/admin/index.mako @@ -60,58 +60,8 @@ <div class="toolTitle"><a target="galaxy_main" href="${h.url_for( controller='admin', action='browse_repository_metadata' )}">Browse metadata</a></div> - <div class="toolTitle"> - <a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_invalid_tools', cntrller='admin' )}">Browse invalid tools</a> - </div></div></div> - %if can_review_repositories: - <div class="toolSectionPad"></div> - <div class="toolSectionTitle"> - Reviewing Repositories - </div> - <div class="toolSectionBody"> - <div class="toolSectionBg"> - <div class="toolTitle"> - <a target="galaxy_main" href="${h.url_for( controller='repository_review', action='manage_repositories_ready_for_review' )}">Repositories ready for review</a> - </div> - <div class="toolTitle"> - <a target="galaxy_main" href="${h.url_for( controller='repository_review', action='manage_repositories_without_reviews' )}">All repositories with no reviews</a> - </div> - %if trans.user.repository_reviews: - <div class="toolTitle"> - <a target="galaxy_main" href="${h.url_for( controller='repository_review', action='manage_repositories_reviewed_by_me' )}">Repositories reviewed by me</a> - </div> - %endif - <div class="toolTitle"> - <a target="galaxy_main" href="${h.url_for( controller='repository_review', action='manage_repositories_with_reviews' )}">All reviewed repositories</a> - </div> - <div class="toolTitle"> - <a target="galaxy_main" href="${h.url_for( controller='repository_review', action='manage_components' )}">Manage review components</a> - </div> - </div> - </div> - <div class="toolSectionPad"></div> - <div class="toolSectionTitle"> - Reviewing Repositories With Tools - </div> - <div class="toolSectionBody"> - <div class="toolSectionPad"></div> - <div class="toolSectionBody"> - <div class="toolSectionBg"> - <div class="toolTitle"> - <a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_repositories_missing_tool_test_components' )}">Latest revision missing tool tests</a> - </div> - <div class="toolTitle"> - <a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_repositories_with_failing_tool_tests' )}">Latest revision failing tool tests</a> - </div> - <div class="toolTitle"> - <a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_repositories_with_no_failing_tool_tests' )}">Latest revision all tool tests pass</a> - </div> - </div> - </div> - </div> - %endif <div class="toolSectionPad"></div><div class="toolSectionTitle"> Categories diff -r 4fce5cfe8be5724f27a1a909dac135c3f010fe30 -r c2c22e38826b65c67202b39e2f7e789c1761c892 templates/webapps/tool_shed/index.mako --- a/templates/webapps/tool_shed/index.mako +++ b/templates/webapps/tool_shed/index.mako @@ -113,16 +113,16 @@ <a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_my_writable_repositories' )}">My writable repositories</a></div><div class="toolTitle"> - <a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_my_writable_repositories_missing_tool_test_components' )}">Latest revision missing tool tests</a> + <a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_my_writable_repositories_missing_tool_test_components' )}">Latest revision: missing tool tests</a></div><div class="toolTitle"> - <a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_my_writable_repositories_with_failing_tool_tests' )}">Latest revision failing tool tests</a> + <a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_my_writable_repositories_with_failing_tool_tests' )}">Latest revision: failing tool tests</a></div><div class="toolTitle"> - <a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_my_writable_repositories_with_no_failing_tool_tests' )}">Latest revision all tool tests pass</a> + <a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_my_writable_repositories_with_no_failing_tool_tests' )}">Latest revision: all tool tests pass</a></div><div class="toolTitle"> - <a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_invalid_tools', cntrller='repository' )}">My invalid tools</a> + <a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_my_writable_repositories_with_invalid_tools' )}">Latest revision: invalid tools</a></div><div class="toolSectionPad"></div><div class="toolSectionTitle"> @@ -164,13 +164,16 @@ <div class="toolSectionBody"><div class="toolSectionBg"><div class="toolTitle"> - <a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_repositories_missing_tool_test_components' )}">Latest revision missing tool tests</a> + <a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_repositories_missing_tool_test_components' )}">Latest revision: missing tool tests</a></div><div class="toolTitle"> - <a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_repositories_with_failing_tool_tests' )}">Latest revision failing tool tests</a> + <a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_repositories_with_failing_tool_tests' )}">Latest revision: failing tool tests</a></div><div class="toolTitle"> - <a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_repositories_with_no_failing_tool_tests' )}">Latest revision all tool tests pass</a> + <a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_repositories_with_no_failing_tool_tests' )}">Latest revision: all tool tests pass</a> + </div> + <div class="toolTitle"> + <a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_repositories_with_invalid_tools' )}">Latest revision: invalid tools</a></div></div></div> diff -r 4fce5cfe8be5724f27a1a909dac135c3f010fe30 -r c2c22e38826b65c67202b39e2f7e789c1761c892 templates/webapps/tool_shed/repository/browse_invalid_tools.mako --- a/templates/webapps/tool_shed/repository/browse_invalid_tools.mako +++ /dev/null @@ -1,44 +0,0 @@ -<%inherit file="/base.mako"/> -<%namespace file="/message.mako" import="render_msg" /> - -%if message: - ${render_msg( message, status )} -%endif - -<div class="toolForm"> - %if invalid_tools_dict: - <div class="toolFormTitle">Invalid tools<i> - click the tool config file name to see why the tool is invalid</i></div> - <div class="form-row"> - <table class="grid"> - <tr> - <th>Tool config</th> - <th>Repository name</th> - <th>Repository owner</th> - <th>Changeset revision</th> - </tr> - %for invalid_tool_config, repository_tup in invalid_tools_dict.items(): - <% repository_id, repository_name, repository_owner, changeset_revision = repository_tup %> - <tr> - <td> - <a class="view-info" href="${h.url_for( controller='repository', action='load_invalid_tool', repository_id=trans.security.encode_id( repository_id ), tool_config=invalid_tool_config, changeset_revision=changeset_revision )}"> - ${invalid_tool_config} - </a> - </td> - <td>${repository_name | h}</td> - <td>${repository_owner | h}</td> - <td>${changeset_revision | h}</td> - </tr> - %endfor - </table> - </div> - </div> - %else: - <div class="form-row"> - %if cntrller == 'admin' and trans.user_is_admin(): - No repositories in this tool shed contain invalid tools. - %else: - None of your repositories contain invalid tools. - %endif - </div> - %endif -</div> diff -r 4fce5cfe8be5724f27a1a909dac135c3f010fe30 -r c2c22e38826b65c67202b39e2f7e789c1761c892 templates/webapps/tool_shed/repository/display_tool_functional_test_results.mako --- a/templates/webapps/tool_shed/repository/display_tool_functional_test_results.mako +++ /dev/null @@ -1,309 +0,0 @@ -<%inherit file="/base.mako"/> -<%namespace file="/message.mako" import="render_msg" /> -<%namespace file="/webapps/tool_shed/common/common.mako" import="*" /> -<%namespace file="/webapps/tool_shed/repository/common.mako" import="*" /> - -<%! - def inherit(context): - if context.get('use_panels'): - return '/webapps/tool_shed/base_panels.mako' - else: - return '/base.mako' -%> - -<%inherit file="${inherit(context)}"/> - -<%def name="render_functional_test_text( functional_test_text )"> - <% - from tool_shed.util.shed_util_common import to_safe_string - %> - <style type="text/css"> - #functional_test_table{ table-layout:fixed; - width:100%; - overflow-wrap:normal; - overflow:hidden; - border:0px; - word-break:keep-all; - word-wrap:break-word; - line-break:strict; } - </style> - <table id="functional_test_table"> - <tr><td>${ to_safe_string( functional_test_text, to_html=True ) }</td></tr> - </table> -</%def> - -<% - from galaxy.web.framework.helpers import time_ago - - changeset_revision = repository_metadata.changeset_revision - has_metadata = repository.metadata_revisions - has_readme = metadata and 'readme' in metadata - is_admin = trans.user_is_admin() - is_new = repository.is_new( trans.app ) - is_deprecated = repository.deprecated - - can_browse_contents = trans.webapp.name == 'tool_shed' and not is_new - can_contact_owner = trans.user and trans.user != repository.user - can_download = not is_new and ( not is_malicious or can_push ) - can_manage = is_admin or repository.user == trans.user - can_push = trans.app.security_agent.can_push( trans.app, trans.user, repository ) - can_rate = repository.user != trans.user - can_review_repository = has_metadata and not is_deprecated and trans.app.security_agent.user_can_review_repositories( trans.user ) - can_upload = can_push - can_view_change_log = trans.webapp.name == 'tool_shed' and not is_new - if repository_metadata.tool_test_results: - # The tool_test_results will contain a dictionary that includes information about the test environment even if all tests passed and the - # repository_metadata.tools_functionally_correct column is set to True. - tool_test_results = repository_metadata.tool_test_results - test_environment_dict = tool_test_results.get( 'test_environment', None ) - missing_test_components = tool_test_results.get( 'missing_test_components', [] ) - failed_tests = tool_test_results.get( 'failed_tests', [] ) - passed_tests = tool_test_results.get( 'passed_tests', [] ) - else: - tool_test_results = None - test_environment_dict = {} - missing_test_components = [] - failed_tests = [] - passed_tests = [] - - if can_push: - browse_label = 'Browse or delete repository tip files' - else: - browse_label = 'Browse repository tip files' -%> - -<br/><br/> -<ul class="manage-table-actions"> - %if is_new: - <a class="action-button" href="${h.url_for( controller='upload', action='upload', repository_id=trans.security.encode_id( repository.id ) )}">Upload files to repository</a> - %else: - <li><a class="action-button" id="repository-${repository.id}-popup" class="menubutton">Repository Actions</a></li> - <div popupmenu="repository-${repository.id}-popup"> - %if can_review_repository: - %if reviewed_by_user: - <a class="action-button" href="${h.url_for( controller='repository_review', action='edit_review', id=review_id )}">Manage my review of this revision</a> - %else: - <a class="action-button" href="${h.url_for( controller='repository_review', action='create_review', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Add a review to this revision</a> - %endif - %endif - %if can_manage: - <a class="action-button" href="${h.url_for( controller='repository', action='manage_repository', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Manage repository</a> - %else: - <a class="action-button" href="${h.url_for( controller='repository', action='view_repository', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">View repository</a> - %endif - %if can_upload: - <a class="action-button" href="${h.url_for( controller='upload', action='upload', repository_id=trans.security.encode_id( repository.id ) )}">Upload files to repository</a> - %endif - %if can_view_change_log: - <a class="action-button" href="${h.url_for( controller='repository', action='view_changelog', id=trans.app.security.encode_id( repository.id ) )}">View change log</a> - %endif - %if can_browse_contents: - <a class="action-button" href="${h.url_for( controller='repository', action='browse_repository', id=trans.app.security.encode_id( repository.id ) )}">${browse_label}</a> - %endif - %if can_contact_owner: - <a class="action-button" href="${h.url_for( controller='repository', action='contact_owner', id=trans.security.encode_id( repository.id ) )}">Contact repository owner</a> - %endif - %if can_download: - <a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision, file_type='gz' )}">Download as a .tar.gz file</a> - <a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision, file_type='bz2' )}">Download as a .tar.bz2 file</a> - <a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision, file_type='zip' )}">Download as a zip file</a> - %endif - </div> - %endif -</ul> - -%if message: - ${render_msg( message, status )} -%endif - -<div class="toolForm"> - <div class="toolFormTitle">Repository revision</div> - <div class="toolFormBody"> - <div class="form-row"> - <label>Revision:</label> - %if can_view_change_log: - <a href="${h.url_for( controller='repository', action='view_changelog', id=trans.app.security.encode_id( repository.id ) )}">${revision_label}</a> - %else: - ${revision_label} - %endif - </div> - </div> -</div> -<p/> -%if can_download: - <div class="toolForm"> - <div class="toolFormTitle">Repository '${repository.name}'</div> - <div class="toolFormBody"> - <div class="form-row"> - <label>Clone this repository:</label> - ${render_clone_str( repository )} - </div> - </div> - </div> -%else: - <b>Repository name:</b><br/> - ${repository.name} -%endif -%if missing_test_components or tool_test_results or passed_tests: - <p/> - <div class="toolForm"> - <div class="toolFormTitle">Tool functional test results</div> - <div class="toolFormBody"> - <div class="form-row"> - <label>Time tested:</label> - ${time_ago( repository_metadata.time_last_tested ) | h} - </div> - <div class="form-row"> - <table width="100%"> - <tr bgcolor="#D8D8D8" width="100%"><td><b>Tool Shed environment</td></tr> - </table> - </div> - <div class="form-row"> - <label>Tool shed version:</label> - ${test_environment_dict.get( 'tool_shed_revision', 'unknown' ) | h} - <div style="clear: both"></div> - </div> - <div class="form-row"> - <label>Tool shed database version:</label> - ${test_environment_dict.get( 'tool_shed_database_version', 'unknown' ) | h} - <div style="clear: both"></div> - </div> - <div class="form-row"> - <label>Mercurial version:</label> - ${test_environment_dict.get( 'tool_shed_mercurial_version', 'unknown' ) | h} - <div style="clear: both"></div> - </div> - <div class="form-row"> - <table width="100%"> - <tr bgcolor="#D8D8D8" width="100%"><td><b>Galaxy environment</td></tr> - </table> - </div> - <div class="form-row"> - <label>Galaxy version:</label> - ${test_environment_dict.get( 'galaxy_revision', 'unknown' ) | h} - <div style="clear: both"></div> - </div> - <div class="form-row"> - <label>Galaxy database version:</label> - ${test_environment_dict.get( 'galaxy_database_version', 'unknown' ) | h} - <div style="clear: both"></div> - </div> - <div class="form-row"> - <label>Architecture:</label> - ${test_environment_dict.get( 'architecture', 'unknown' ) | h} - <div style="clear: both"></div> - </div> - <div class="form-row"> - <label>Operating system:</label> - ${test_environment_dict.get( 'system', 'unknown' ) | h} - <div style="clear: both"></div> - </div> - <div class="form-row"> - <label>Python version:</label> - ${test_environment_dict.get( 'python_version', 'unknown' ) | h} - <div style="clear: both"></div> - </div> - %if failed_tests: - <div class="form-row"> - <table width="100%"> - <tr bgcolor="#D8D8D8" width="100%"><td><b>Tests that failed</td></tr> - </table> - </div> - <div class="form-row"> - <table class="grid"> - %for test_results_dict in failed_tests: - <% - test_id = test_results_dict.get( 'test_id', 'unknown' ) - tool_id = test_results_dict.get( 'tool_id', 'unknown' ) - tool_version = test_results_dict.get( 'tool_version', 'unknown' ) - test_status = '<font color="red">Test failed</font>' - stderr = test_results_dict.get( 'stderr', '' ) - traceback = test_results_dict.get( 'traceback', '' ) - %> - <tr> - <td colspan="2" bgcolor="#FFFFCC">Tool id: <b>${tool_id}</b> version: <b>${tool_version}</b></td> - </tr> - <tr> - <td><b>Test id</b></td> - <td>${test_id}</td> - </tr> - <tr> - <td><b>Status</b></td> - <td>${test_status}</td> - </tr> - <tr> - <td><b>Stderr</b></td> - <td>${render_functional_test_text( stderr )}</td> - </tr> - <tr> - <td><b>Traceback</b></td> - <td>${render_functional_test_text( traceback )}</td> - </tr> - %endfor - </table> - <div style="clear: both"></div> - </div> - %endif - %if passed_tests: - <div class="form-row"> - <table width="100%"> - <tr bgcolor="#D8D8D8" width="100%"><td><b>Tests that passed successfully</td></tr> - </table> - </div> - <div class="form-row"> - <table class="grid"> - %for test_results_dict in passed_tests: - <% - test_id = test_results_dict.get( 'test_id', 'unknown' ) - tool_id = test_results_dict.get( 'tool_id', 'unknown' ) - tool_version = test_results_dict.get( 'tool_version', 'unknown' ) - test_status = '<font color="green">Test passed</font>' - %> - <tr> - <td colspan="2" bgcolor="#FFFFCC">Tool id: <b>${tool_id}</b> version: <b>${tool_version}</b></td> - </tr> - <tr> - <td><b>Test id</b></td> - <td>${test_id}</td> - </tr> - <tr> - <td><b>Status</b></td> - <td>${test_status}</td> - </tr> - %endfor - </table> - </div> - %endif - %if missing_test_components: - <div class="form-row"> - <table width="100%"> - <tr bgcolor="#D8D8D8" width="100%"><td><b>Invalid tests</td></tr> - </table> - </div> - <div class="form-row"> - <table class="grid"> - %for test_results_dict in missing_test_components: - <% - guid = test_results_dict.get( 'tool_guid', None ) - tool_id = test_results_dict.get( 'tool_id', None ) - tool_version = test_results_dict.get( 'tool_version', None ) - missing_components = test_results_dict.get( 'missing_components', None ) - %> - %if tool_id or tool_version: - <tr> - <td colspan="2" bgcolor="#FFFFCC">Tool id: <b>${tool_id}</b> version: <b>${tool_version}</b></td> - </tr> - %endif - %if missing_components: - <tr> - <td><b>Reason test is invalid</b></td> - <td>${render_functional_test_text( missing_components )}</td> - </tr> - %endif - %endfor - </table> - </div> - %endif - </div> - </div> -%endif Repository URL: https://bitbucket.org/galaxy/galaxy-central/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email.