openSUSE:Build Service Future

Jump to: navigation, search


The Future is Open

This page collects the ideas, wishes and learned lessons of the Open Build Service developers as well as the community. This is not to be confused with the openSUSE:Build_Service_Roadmap, which covers shorter term (and more realistic) goals. Please understand that these are only ideas, neither promises nor planned features!

Ideas that are considered worth pursuing may be formulated into concepts and moved to the openSUSE:Build_Service_Concepts wiki page. They may then become part of the release goals of a future Open Build Service version. But for now, consider this page a braindump.


Architecture

Merge Api and Webui?

In other words, moving from a 3-tier architecture to 2 tiers.

  • Less development traction
  • Less caching issues and less sending XML around
  • You know when to purge what caches.
    • See bnc#559158
    • Smaller (easier!!) code-base
  • Enforce consistent API style (e.g. REST completely)
    • make test suite for it
    • use rails format handling
      • /project/home:darix/runit(.html) -> html
      • /project/home:darix/runit.json
      • /project/home:darix/runit.xml
  • Move to Rails-3 (or even Django :-)
    • Have optional features per project (e.g. merging redmine into the webui)
      • all additional features like bugtracking, wiki should be opt-in
      • it should be possible reference external wikis/bugtracker properly on per project/package base.
    • Small bugtracker/wiki/blog so projects can present themself

Mimetypes

Set proper mimetypes for files provided through the (future) REST API. Some current (bad) examples:

Workflows and Collaboration

  • submitrequest is to heavy / supports to many use cases
    • Rather have add and update requests
  • only one action per request to avoid current controller/view check-what-it-is madness
  • Workflow engine http://ruote.rubyforge.org/
  • Bugs/Tickets/Features closer to projects/packages?
    • Probably like Redmine, i.e. a per project/package ticket system with the option to delegate to a central / another bugzilla instance
    • Per project/package wiki (redmine, again)
  • User karma and statistics like packaging efforts, wiki edits, request editing, tickets / bugs handling
    • to motivate (feed the meritocracy), make user actions visible (facebook addictions)
    • +1 for submissions:
      • +1 for changelog entry
      • +2 for sucessful build
      • +1 for commit log entry, ...
    • -1 for non-building submission
    • needs metrics
       1:n           1:n
user ----> roles -----> permissions
             
workflow --> roles
             \-> permissions
    • properly defined use cases for all actions
      • cucumber/rspec maybe?
  • package blacklisting!
  • search-if-package-is-already-in-the-buildservice-and-hint-the-user-at-it-instead-of-letting-him-build-it-for-himself (tm)

Auditing

  • Backend and frontend should log into the same database who did what and when to be able to reproduce changes

Have everything backed by a model

This is actually a no-brainer, here's what happen if you don't do it:

  def involved_requests(opts = {})
    opts = {:cache => true}.merge opts

    cachekey = "#{login}_involved_requests"
    Rails.cache.delete cachekey unless opts[:cache]

    requests = Rails.cache.fetch(cachekey, :expires_in => 10.minutes) do
      # FIXME: we assume that the user is involved in all his subprojects (home:#{login}:...)
      #        that should not be needed ... verify ...
      iprojects = involved_projects.each.map {|x| x.name}.reject {|x| /^home:#{login}:/.match(x) }.sort
      requests = Array.new
      request_ids = Array.new

      myrequests = Hash.new
      unless iprojects.empty?
        # find active requests where person is maintained in target project
        predicate = iprojects.map {|item| "action/target/@project='#{item}'"}.join(" or ")
        predicate = "#{predicate} or starts-with(action/target/@project, 'home:#{login}:')"
        predicate = "(state/@name='new' or state/@name='review') and (#{predicate})"
        collection = Collection.find :what => :request, :predicate => predicate
        collection.each do |req| myrequests[Integer(req.value :id)] = req end
        # find requests created by person and still active
        collection = Collection.find :what => :request, :predicate => "(state/@name='new' or state/@name='review') and state/@who='#{login}'"
        collection.each do |req| myrequests[Integer(req.value :id)] = req end
        # find requests where person is reviewer
        collection = Collection.find :what => :request, :predicate => "state/@name='review' and review[@by_user='#{login}' and @state='new']"
        collection.each do |req| myrequests[Integer(req.value :id)] = req end
        keys = myrequests.keys().sort {|x,y| y <=> x}
        keys.each do |id| 
          unless request_ids.include? id
            requests << myrequests[id]
            request_ids << id
          end
        end
      end

      # check for all open review tasks
      collection = BsRequest.find_open_review_requests(login)
      collection.each do |req| myrequests[Integer(req.value :id)] = req end
      keys = myrequests.keys().sort {|x,y| y <=> x}
      keys.each do |id| 
        unless request_ids.include? id
          requests << myrequests[id]
          request_ids << id
        end
      end

      requests
    end
    return requests
  end

This piece of madness actually tries to catch all requests that a specific user is involved (and coolo said it's not even complete / buggy). Actually, this should be only asking the model for all requests of a specific id....

Users and Groups

Recently, we gained support for by_project and by_package reviews, which is actually a crude hack because we don't have a real groups concept. A new OBS iteration should create a group for each new project and package or take an existing group as owner. On top of that, every user should have a group which contains only himself. This way, the code only has to do group checks and management becomes a breeze. BTW, this is done by several major Web Development Frameworks and is proven to work.

  • Every user gets a group with only him
  • Every project/package/whatever is owned by a group
  • By default, a new group is created for projects/packages/whatever OR an already existing group is used upon creation

Simple design, no hacks needed, no freaking corner-cases.


The Web Frontend

  • log to /var/log/obs-frontend instead of $RAILS_ROOT/log
  • server-side syntax highlighting / ditch JavaScript-based syntax highlighting
    • results should be generated only upon source change / first access
    • results should be cached accordingly

Modell / Data Storage

  • ActiveXML is a bit awkward
    • Use ActiveModel
    • Do we need a wrapper around the XML stuff?
    • Would something like JSON be better maybe?
      • If we go for JSON, CouchDB might be a good idea for the store?
  • Git-based storage?
    • One Git repository per package?
      • pre-commit-hooks for authentication
      • post-commit-hooks to generate global statistics (karma, contribution history)
resources :projects do
  resources :packages do
    resources :history
    resources :roles
    resources :flags
    resources :attributes
  end
  resources :roles
  resources :flags
end

Controllers

  • Considered too fat, real logic should be only in the models, whereas controllers only aggregate data for presentation

Views

  • Considered to fat, views should contain no code at all (i.e. enforce MVC pattern)
    • Move to a different template engine than ERB / eRuby / erubis
      • Interesting candidates may be Django templates (Python) or Mustache, Liquid, Haml
  • Pagination for projects, packages, monitor and status pages?

Helpers

  • They are currently much to fat, i.e. they should only transform data and shall be small
    • Actually, they should be used only as a last resort.
  • We have helper methods that span multiple pages and generate lots of HTML.
    • Helpers shall never generate HTML !!! (XSS madness here)

Routing

Discussed at openSUSE:Build_Service_Future_Routing

Searches

Discussed at openSUSE:Build_Service_Future_Searches

Authorization

Backend Communication

Internationalization / Localization

  • Incorporate right from the start (gettext preferred, http://www.yotabanana.com/hiki/ruby-gettext.html)
  • We have to find out, which template engine supports this (apart from ERB)
  • JavaScript poses issues on i18n/l10n
    • Avoid generating text thru JavaScript, i.e. only DOM-manipulation
    • AJAX-queries should then fetch translated content generated on the server side
  • Language can be determined from what the User Agent sends (never Geolocation) and it should be a configurable option in the user settings

Communication with other tools


The Backend

  • Move to Perl6 :-D

Code Conventions

  • Proper indenting rules (i.e. no tabs checked in)
  • Be explicit rather than implicit or automagical (as much as possible)

ChangeLogs

A nice idea would be to have a git pre-commit hook which checks the commit message. If the message contains a special tag, like "#change", it may add an entry to a (yet to create) ChangeLog file and add this to the current commit.

Ruby-specific

  • Always use foo() function call syntax
  • Use lower_case_function_names
  • Add an explicit return statement at the end of each function (even return nil?)
    • Improves security: functions don't leak the last statement!
    • Allows to set breackpoint on last statement (debugging)

Rails Forms

  • Only use form_for and style forms with CSS
  • Every form into its own partial ! (future prof, reusable)

Perl-specific

  • Use comments to explain awesome code constructs!

See also

The Open Build Service roadmap and concepts pages are closely related to this topic.

Related articles