{"action":"created","comment":{"url":"https://api.github.com/repos/gitlabhq/gitlabhq/pulls/comments/45981196","id":45981196,"diff_hunk":"@@ -0,0 +1,84 @@\n+require 'digest/crc32'\n+\n+module Gitlab\n+  module Composer\n+    module Repository\n+      class ProjectRepository < ::Composer::Repository::WritableHashRepository\n+\n+        # Initializes the project repository.\n+        # @param [Composer::Json::JsonFile] repository_file The repository json file\n+        def initialize(repository_file)\n+          unless repository_file\n+            raise ::Composer::ArgumentError,\n+                  'repository_file must be specified'\n+          end\n+          unless repository_file.is_a?(::Composer::Json::JsonFile)\n+            raise ::Composer::TypeError,\n+                  'repository_file type must be a \\\n+                  Composer::Json::JsonFile or superclass'\n+          end\n+          super([])\n+          @file = repository_file\n+          @dumper = ::Composer::Package::Dumper::HashDumper.new\n+        end\n+\n+        def reload\n+          @packages = nil\n+          initialize_repository\n+        end\n+\n+        # Writes the project repository to the filesystem.\n+        def write\n+          data = {}\n+          unless packages.nil? || packages.empty?\n+            uid = 0\n+            crc = Digest::CRC32.hexdigest(packages[0].name)\n+            packages.each do |package|\n+              next if package.instance_of?(::Composer::Package::AliasPackage)\n+              data[package.pretty_name] = {} unless data[package.pretty_name]\n+              data[package.pretty_name][package.pretty_version] = @dumper.dump(package)\n+              data[package.pretty_name][package.pretty_version]['uid'] = \"#{crc}\" + (uid += 1).to_s\n+            end\n+          end\n+          @file.write({ 'packages' => data })\n+        rescue Exception => e","path":"lib/gitlab/composer/repository/project_repository.rb","position":44,"original_position":44,"commit_id":"efb576ff403bc6f4b394d98ea482d02bd483a624","original_commit_id":"efb576ff403bc6f4b394d98ea482d02bd483a624","user":{"login":"DouweM","id":159434,"avatar_url":"https://avatars.githubusercontent.com/u/159434?v=3","gravatar_id":"","url":"https://api.github.com/users/DouweM","html_url":"https://github.com/DouweM","followers_url":"https://api.github.com/users/DouweM/followers","following_url":"https://api.github.com/users/DouweM/following{/other_user}","gists_url":"https://api.github.com/users/DouweM/gists{/gist_id}","starred_url":"https://api.github.com/users/DouweM/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/DouweM/subscriptions","organizations_url":"https://api.github.com/users/DouweM/orgs","repos_url":"https://api.github.com/users/DouweM/repos","events_url":"https://api.github.com/users/DouweM/events{/privacy}","received_events_url":"https://api.github.com/users/DouweM/received_events","type":"User","site_admin":false},"body":"This method can be simplified like this:\r\n\r\n```ruby\r\ndef write\r\n  return if packages.nil? || packages.empty?\r\n\r\n  data = {}\r\n  \r\n  uid = 0\r\n  crc = Digest::CRC32.hexdigest(packages[0].name)\r\n  packages.each do |package|\r\n    next if package.instance_of?(::Composer::Package::AliasPackage)\r\n    uid += 1\r\n\r\n    version_data = @dumper.dump(package)\r\n    version_data['uid'] = \"#{crc}-#{uid}\"\r\n    \r\n    package_data = data[package.pretty_name] ||= {}\r\n    package_data[package.pretty_version] = version_data\r\n  end\r\n  \r\n  @file.write({ 'packages' => data })\r\nrescue => e\r\n  Gitlab::AppLogger.error(\"ProjectRepository: #{e.message}\")\r\nend\r\n```","created_at":"2015-11-26T14:07:19Z","updated_at":"2015-11-26T14:07:19Z","html_url":"https://github.com/gitlabhq/gitlabhq/pull/9301#discussion_r45981196","pull_request_url":"https://api.github.com/repos/gitlabhq/gitlabhq/pulls/9301","_links":{"self":{"href":"https://api.github.com/repos/gitlabhq/gitlabhq/pulls/comments/45981196"},"html":{"href":"https://github.com/gitlabhq/gitlabhq/pull/9301#discussion_r45981196"},"pull_request":{"href":"https://api.github.com/repos/gitlabhq/gitlabhq/pulls/9301"}}},"pull_request":{"url":"https://api.github.com/repos/gitlabhq/gitlabhq/pulls/9301","id":35519580,"html_url":"https://github.com/gitlabhq/gitlabhq/pull/9301","diff_url":"https://github.com/gitlabhq/gitlabhq/pull/9301.diff","patch_url":"https://github.com/gitlabhq/gitlabhq/pull/9301.patch","issue_url":"https://api.github.com/repos/gitlabhq/gitlabhq/issues/9301","number":9301,"state":"open","locked":false,"title":"Add Composer Project Service (updated #8768)","user":{"login":"ikappas","id":7887523,"avatar_url":"https://avatars.githubusercontent.com/u/7887523?v=3","gravatar_id":"","url":"https://api.github.com/users/ikappas","html_url":"https://github.com/ikappas","followers_url":"https://api.github.com/users/ikappas/followers","following_url":"https://api.github.com/users/ikappas/following{/other_user}","gists_url":"https://api.github.com/users/ikappas/gists{/gist_id}","starred_url":"https://api.github.com/users/ikappas/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ikappas/subscriptions","organizations_url":"https://api.github.com/users/ikappas/orgs","repos_url":"https://api.github.com/users/ikappas/repos","events_url":"https://api.github.com/users/ikappas/events{/privacy}","received_events_url":"https://api.github.com/users/ikappas/received_events","type":"User","site_admin":false},"body":"![composer-service-1](https://cloud.githubusercontent.com/assets/7887523/7655200/99e6a046-fb2a-11e4-8af2-b0880e6b46fb.jpg)\r\n\r\nThis commit adds the per-project option to expose a project as a composer package. It generates and maintains a packages.json file along with a project specific /p/project-{id}.json file (conforming to https://getcomposer.org/doc/05-repositories.md#includes) in the public/ folder, allowing the GitLab install to be used as a Composer repository.\r\n\r\nIt extends on the original idea providing extended service configuration options that allow to work with packages that do not include a composer.json file.\r\n\r\nIt has three operational modes allowing for:\r\n\r\n1. Default: Searches for a composer.json file in the source code root folder and if found exports the package.\r\n2. Project: Parse project attributes to create a virtual composer.json to use for exporting the package.\r\n3. Advanced: Parse a custom json string supplied in the service configuration to export the package.\r\n\r\nIt also has branch / tag filters that allows fine-grained filtering of specific branches/tags to be exposed as composer packages. \r\n\r\nThis is and updated merge request for:\r\n1. https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/106\r\n2. https://github.com/gitlabhq/gitlabhq/pull/8768 \r\n\r\nPlease see feature thread http://feedback.gitlab.com/forums/176466-general/suggestions/5953067-provide-composer-package-repository-support\r\n\r\nWhen a project that has activated the composer service receives a branch/ tag push, the public /packages.json file and project specific json file will be refreshed to include version definitions for the branches and tags as specified in the service configuration in the project's repository.\r\n\r\n## Note\r\nThere is a known issue integrating with the GitLab-Omnibus, namely that the public folder\r\nis owned by 'root' and GitLab is run as 'git'. The GitLab-Omnibus chef script needs to be updated \r\nto allow access to both packages.json and the /p/ folder in the public/ folder","created_at":"2015-05-15T14:49:11Z","updated_at":"2015-11-26T14:07:19Z","closed_at":null,"merged_at":null,"merge_commit_sha":"8daacf8e6f9d20925d40c19821620d4cfa64424c","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/gitlabhq/gitlabhq/pulls/9301/commits","review_comments_url":"https://api.github.com/repos/gitlabhq/gitlabhq/pulls/9301/comments","review_comment_url":"https://api.github.com/repos/gitlabhq/gitlabhq/pulls/comments{/number}","comments_url":"https://api.github.com/repos/gitlabhq/gitlabhq/issues/9301/comments","statuses_url":"https://api.github.com/repos/gitlabhq/gitlabhq/statuses/efb576ff403bc6f4b394d98ea482d02bd483a624","head":{"label":"ikappas:composer-service","ref":"composer-service","sha":"efb576ff403bc6f4b394d98ea482d02bd483a624","user":{"login":"ikappas","id":7887523,"avatar_url":"https://avatars.githubusercontent.com/u/7887523?v=3","gravatar_id":"","url":"https://api.github.com/users/ikappas","html_url":"https://github.com/ikappas","followers_url":"https://api.github.com/users/ikappas/followers","following_url":"https://api.github.com/users/ikappas/following{/other_user}","gists_url":"https://api.github.com/users/ikappas/gists{/gist_id}","starred_url":"https://api.github.com/users/ikappas/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ikappas/subscriptions","organizations_url":"https://api.github.com/users/ikappas/orgs","repos_url":"https://api.github.com/users/ikappas/repos","events_url":"https://api.github.com/users/ikappas/events{/privacy}","received_events_url":"https://api.github.com/users/ikappas/received_events","type":"User","site_admin":false},"repo":{"id":33296126,"name":"gitlabhq","full_name":"ikappas/gitlabhq","owner":{"login":"ikappas","id":7887523,"avatar_url":"https://avatars.githubusercontent.com/u/7887523?v=3","gravatar_id":"","url":"https://api.github.com/users/ikappas","html_url":"https://github.com/ikappas","followers_url":"https://api.github.com/users/ikappas/followers","following_url":"https://api.github.com/users/ikappas/following{/other_user}","gists_url":"https://api.github.com/users/ikappas/gists{/gist_id}","starred_url":"https://api.github.com/users/ikappas/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ikappas/subscriptions","organizations_url":"https://api.github.com/users/ikappas/orgs","repos_url":"https://api.github.com/users/ikappas/repos","events_url":"https://api.github.com/users/ikappas/events{/privacy}","received_events_url":"https://api.github.com/users/ikappas/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/ikappas/gitlabhq","description":"GitLab is version control for your server","fork":true,"url":"https://api.github.com/repos/ikappas/gitlabhq","forks_url":"https://api.github.com/repos/ikappas/gitlabhq/forks","keys_url":"https://api.github.com/repos/ikappas/gitlabhq/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ikappas/gitlabhq/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ikappas/gitlabhq/teams","hooks_url":"https://api.github.com/repos/ikappas/gitlabhq/hooks","issue_events_url":"https://api.github.com/repos/ikappas/gitlabhq/issues/events{/number}","events_url":"https://api.github.com/repos/ikappas/gitlabhq/events","assignees_url":"https://api.github.com/repos/ikappas/gitlabhq/assignees{/user}","branches_url":"https://api.github.com/repos/ikappas/gitlabhq/branches{/branch}","tags_url":"https://api.github.com/repos/ikappas/gitlabhq/tags","blobs_url":"https://api.github.com/repos/ikappas/gitlabhq/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ikappas/gitlabhq/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ikappas/gitlabhq/git/refs{/sha}","trees_url":"https://api.github.com/repos/ikappas/gitlabhq/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ikappas/gitlabhq/statuses/{sha}","languages_url":"https://api.github.com/repos/ikappas/gitlabhq/languages","stargazers_url":"https://api.github.com/repos/ikappas/gitlabhq/stargazers","contributors_url":"https://api.github.com/repos/ikappas/gitlabhq/contributors","subscribers_url":"https://api.github.com/repos/ikappas/gitlabhq/subscribers","subscription_url":"https://api.github.com/repos/ikappas/gitlabhq/subscription","commits_url":"https://api.github.com/repos/ikappas/gitlabhq/commits{/sha}","git_commits_url":"https://api.github.com/repos/ikappas/gitlabhq/git/commits{/sha}","comments_url":"https://api.github.com/repos/ikappas/gitlabhq/comments{/number}","issue_comment_url":"https://api.github.com/repos/ikappas/gitlabhq/issues/comments{/number}","contents_url":"https://api.github.com/repos/ikappas/gitlabhq/contents/{+path}","compare_url":"https://api.github.com/repos/ikappas/gitlabhq/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ikappas/gitlabhq/merges","archive_url":"https://api.github.com/repos/ikappas/gitlabhq/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ikappas/gitlabhq/downloads","issues_url":"https://api.github.com/repos/ikappas/gitlabhq/issues{/number}","pulls_url":"https://api.github.com/repos/ikappas/gitlabhq/pulls{/number}","milestones_url":"https://api.github.com/repos/ikappas/gitlabhq/milestones{/number}","notifications_url":"https://api.github.com/repos/ikappas/gitlabhq/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ikappas/gitlabhq/labels{/name}","releases_url":"https://api.github.com/repos/ikappas/gitlabhq/releases{/id}","created_at":"2015-04-02T07:43:42Z","updated_at":"2015-05-03T11:20:09Z","pushed_at":"2015-11-26T07:43:51Z","git_url":"git://github.com/ikappas/gitlabhq.git","ssh_url":"git@github.com:ikappas/gitlabhq.git","clone_url":"https://github.com/ikappas/gitlabhq.git","svn_url":"https://github.com/ikappas/gitlabhq","homepage":"https://gitlab.com/gitlab-org/gitlab-ce/tree/master","size":106564,"stargazers_count":0,"watchers_count":0,"language":"Ruby","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":0,"forks":1,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"gitlabhq:master","ref":"master","sha":"1324cc2f6ec3b9106391c478b1af402ea2e3b5c5","user":{"login":"gitlabhq","id":1086321,"avatar_url":"https://avatars.githubusercontent.com/u/1086321?v=3","gravatar_id":"","url":"https://api.github.com/users/gitlabhq","html_url":"https://github.com/gitlabhq","followers_url":"https://api.github.com/users/gitlabhq/followers","following_url":"https://api.github.com/users/gitlabhq/following{/other_user}","gists_url":"https://api.github.com/users/gitlabhq/gists{/gist_id}","starred_url":"https://api.github.com/users/gitlabhq/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gitlabhq/subscriptions","organizations_url":"https://api.github.com/users/gitlabhq/orgs","repos_url":"https://api.github.com/users/gitlabhq/repos","events_url":"https://api.github.com/users/gitlabhq/events{/privacy}","received_events_url":"https://api.github.com/users/gitlabhq/received_events","type":"Organization","site_admin":false},"repo":{"id":2500088,"name":"gitlabhq","full_name":"gitlabhq/gitlabhq","owner":{"login":"gitlabhq","id":1086321,"avatar_url":"https://avatars.githubusercontent.com/u/1086321?v=3","gravatar_id":"","url":"https://api.github.com/users/gitlabhq","html_url":"https://github.com/gitlabhq","followers_url":"https://api.github.com/users/gitlabhq/followers","following_url":"https://api.github.com/users/gitlabhq/following{/other_user}","gists_url":"https://api.github.com/users/gitlabhq/gists{/gist_id}","starred_url":"https://api.github.com/users/gitlabhq/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gitlabhq/subscriptions","organizations_url":"https://api.github.com/users/gitlabhq/orgs","repos_url":"https://api.github.com/users/gitlabhq/repos","events_url":"https://api.github.com/users/gitlabhq/events{/privacy}","received_events_url":"https://api.github.com/users/gitlabhq/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/gitlabhq/gitlabhq","description":"GitLab is version control for your server","fork":false,"url":"https://api.github.com/repos/gitlabhq/gitlabhq","forks_url":"https://api.github.com/repos/gitlabhq/gitlabhq/forks","keys_url":"https://api.github.com/repos/gitlabhq/gitlabhq/keys{/key_id}","collaborators_url":"https://api.github.com/repos/gitlabhq/gitlabhq/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/gitlabhq/gitlabhq/teams","hooks_url":"https://api.github.com/repos/gitlabhq/gitlabhq/hooks","issue_events_url":"https://api.github.com/repos/gitlabhq/gitlabhq/issues/events{/number}","events_url":"https://api.github.com/repos/gitlabhq/gitlabhq/events","assignees_url":"https://api.github.com/repos/gitlabhq/gitlabhq/assignees{/user}","branches_url":"https://api.github.com/repos/gitlabhq/gitlabhq/branches{/branch}","tags_url":"https://api.github.com/repos/gitlabhq/gitlabhq/tags","blobs_url":"https://api.github.com/repos/gitlabhq/gitlabhq/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/gitlabhq/gitlabhq/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/gitlabhq/gitlabhq/git/refs{/sha}","trees_url":"https://api.github.com/repos/gitlabhq/gitlabhq/git/trees{/sha}","statuses_url":"https://api.github.com/repos/gitlabhq/gitlabhq/statuses/{sha}","languages_url":"https://api.github.com/repos/gitlabhq/gitlabhq/languages","stargazers_url":"https://api.github.com/repos/gitlabhq/gitlabhq/stargazers","contributors_url":"https://api.github.com/repos/gitlabhq/gitlabhq/contributors","subscribers_url":"https://api.github.com/repos/gitlabhq/gitlabhq/subscribers","subscription_url":"https://api.github.com/repos/gitlabhq/gitlabhq/subscription","commits_url":"https://api.github.com/repos/gitlabhq/gitlabhq/commits{/sha}","git_commits_url":"https://api.github.com/repos/gitlabhq/gitlabhq/git/commits{/sha}","comments_url":"https://api.github.com/repos/gitlabhq/gitlabhq/comments{/number}","issue_comment_url":"https://api.github.com/repos/gitlabhq/gitlabhq/issues/comments{/number}","contents_url":"https://api.github.com/repos/gitlabhq/gitlabhq/contents/{+path}","compare_url":"https://api.github.com/repos/gitlabhq/gitlabhq/compare/{base}...{head}","merges_url":"https://api.github.com/repos/gitlabhq/gitlabhq/merges","archive_url":"https://api.github.com/repos/gitlabhq/gitlabhq/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/gitlabhq/gitlabhq/downloads","issues_url":"https://api.github.com/repos/gitlabhq/gitlabhq/issues{/number}","pulls_url":"https://api.github.com/repos/gitlabhq/gitlabhq/pulls{/number}","milestones_url":"https://api.github.com/repos/gitlabhq/gitlabhq/milestones{/number}","notifications_url":"https://api.github.com/repos/gitlabhq/gitlabhq/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/gitlabhq/gitlabhq/labels{/name}","releases_url":"https://api.github.com/repos/gitlabhq/gitlabhq/releases{/id}","created_at":"2011-10-02T16:25:27Z","updated_at":"2015-11-26T13:09:38Z","pushed_at":"2015-11-26T11:26:28Z","git_url":"git://github.com/gitlabhq/gitlabhq.git","ssh_url":"git@github.com:gitlabhq/gitlabhq.git","clone_url":"https://github.com/gitlabhq/gitlabhq.git","svn_url":"https://github.com/gitlabhq/gitlabhq","homepage":"https://gitlab.com/gitlab-org/gitlab-ce/tree/master","size":115101,"stargazers_count":16799,"watchers_count":16799,"language":"Ruby","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":4550,"mirror_url":null,"open_issues_count":214,"forks":4550,"open_issues":214,"watchers":16799,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/gitlabhq/gitlabhq/pulls/9301"},"html":{"href":"https://github.com/gitlabhq/gitlabhq/pull/9301"},"issue":{"href":"https://api.github.com/repos/gitlabhq/gitlabhq/issues/9301"},"comments":{"href":"https://api.github.com/repos/gitlabhq/gitlabhq/issues/9301/comments"},"review_comments":{"href":"https://api.github.com/repos/gitlabhq/gitlabhq/pulls/9301/comments"},"review_comment":{"href":"https://api.github.com/repos/gitlabhq/gitlabhq/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/gitlabhq/gitlabhq/pulls/9301/commits"},"statuses":{"href":"https://api.github.com/repos/gitlabhq/gitlabhq/statuses/efb576ff403bc6f4b394d98ea482d02bd483a624"}}}}