From 9ff02c9959a3f5c8bca837ecfbcd3c6fdebbd934 Mon Sep 17 00:00:00 2001 From: HiroyasuTawara Date: Fri, 6 Oct 2023 08:42:34 +0000 Subject: [PATCH 01/17] =?UTF-8?q?branches,=20entries=20=E3=81=AE=E3=83=86?= =?UTF-8?q?=E3=82=B9=E3=83=88=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/unit/github_adapter_test.rb | 127 ++++++++++++++++++++++++++++++- 1 file changed, 125 insertions(+), 2 deletions(-) diff --git a/test/unit/github_adapter_test.rb b/test/unit/github_adapter_test.rb index cdb1991..5e88f04 100644 --- a/test/unit/github_adapter_test.rb +++ b/test/unit/github_adapter_test.rb @@ -4,6 +4,7 @@ class GithubAdapterTest < ActiveSupport::TestCase def setup @scm = Redmine::Scm::Adapters::GithubAdapter.new('https://github.com/farend/redmine_github_repo.git') @repo = "farend/redmine_github_repo" + @repos = [@repo] end def test_branches_Githubの戻り値が空の場合 @@ -20,7 +21,7 @@ def test_branches_Githubの戻り値が空の場合 end def test_branches_Githubの戻り値が1つある場合 - branch = OctokitBranch.new(name: 'main', commit: OctkoitCommit.new(sha: 'shashasha')) + branch = OctokitBranch.new(name: 'main', commit: OctokitCommit.new(sha: 'shashasha')) Octokit.stub(:branches, build_mock([branch], []) { |repos, options| assert options[:page] @@ -34,10 +35,132 @@ def test_branches_Githubの戻り値が1つある場合 end end + def test_branches_Githubの戻り値が複数ある場合 + multi_branche = ['main', 'dev', 'feat'].sort.map.with_index{ |name, i| + OctokitBranch.new(name: name, commit: OctokitCommit.new(sha: "shashasha#{i}")) + } + + Octokit.stub(:branches, build_mock(multi_branche, []) { |repos, options| + assert options[:page] + }) do + branches = @scm.branches + + assert_equal multi_branche.length, branches.length + branches.each.with_index do |branch,i| + assert_equal multi_branche[i].name, branch.to_s + assert_equal "shashasha#{i}", branch.revision + assert_equal "shashasha#{i}", branch.scmid + end + end + end + + def test_branches_Githubに未ソートのブランチが与えられた場合 + multi_branche = ['bbb', 'ccc', 'aaa'].map{ |name| + OctokitBranch.new(name: name, commit: OctokitCommit.new(sha: "sha#{name}")) + } + + sorted_multi_branche = ['aaa', 'bbb', 'ccc'] + + Octokit.stub(:branches, build_mock(multi_branche, []) { |repos, options| + assert options[:page] + }) do + branches = @scm.branches + + assert_equal multi_branche.length, branches.length + branches.each.with_index do |branch, i| + assert_equal sorted_multi_branche[i], branch.to_s + assert_equal "sha#{sorted_multi_branche[i]}", branch.revision + assert_equal "sha#{sorted_multi_branche[i]}", branch.scmid + end + end + end + + def test_entries_Githubの戻り値が空の場合 + Octokit.stub(:contents, build_mock([]) { |repos, path, ref| + }) do + entries = @scm.entries + assert_equal 0, entries.length + end + end + + def test_entries_Githubの戻り値が1つある場合 + content = OctokitContent.new('test.md', 'dir/test.md', 'file', 256) + + Octokit.stub(:contents, build_mock([content], []) { |repos, path, ref| + assert_equal @repo, repos + }) do + entries = @scm.entries + assert_equal 1, entries.length + assert_equal 'test.md', entries[0].name + assert_equal 'dir/test.md', entries[0].path + assert_equal 'file', entries[0].kind + assert_equal 256, entries[0].size + end + end + + def test_entries_Githubの戻り値が複数ある場合 + contents = ['test.md', 'test.txt'].sort.map{ |name| + OctokitContent.new(name, "dir/#{name}", 'file', 256) + } + + Octokit.stub(:contents, build_mock(contents, []) { |repos, path, ref| + assert_equal @repo, repos + }) do + entries = @scm.entries + assert_equal 2, entries.length + assert_equal 'test.md', entries[0].name + assert_equal 'dir/test.md', entries[0].path + assert_equal 'test.txt', entries[1].name + assert_equal 'dir/test.txt', entries[1].path + end + end + + def test_entries_Githubに未ソートのコンテンツが与えられた場合 + contents = ['bbb.md', 'ccc.md', 'aaa.md'].map{ |name| + OctokitContent.new(name, "dir/#{name}", 'file', 256) + } + + Octokit.stub(:contents, build_mock(contents, []) { |repos, path, ref| + assert_equal @repo, repos + }) do + entries = @scm.entries + assert_equal 'aaa.md', entries[0].name + assert_equal 'bbb.md', entries[1].name + assert_equal 'ccc.md', entries[2].name + end + end + + def test_entries_Githubで与えられたファイルパスがエントリ名として既に存在する場合 + contents = 3.times.map{ |i| OctokitContent.new('README.md', 'README.md', 'file', 256*i)} + + Octokit.stub(:contents, build_mock(contents, []) { |repos, path, ref| + assert_equal @repo, repos + }) do + entries = @scm.entries + assert_equal 1, entries.length + assert_equal 0, entries.last.size + end + end + + def test_entries_Githubでオプションreport_last_commitがtrueの場合 + # TODO: commitのモックをテスト内で使用可能にする + # content = OctokitContent.new('test.md', 'dir/test.md', 'file', 256) + # commits = [OctokitCommit.new(sha: 'shashasha')] + # + # Octokit.stub(:contents, build_mock([content], []) { |repos, path, ref| + # assert_equal @repo, repos + # }) do + # entries = @scm.entries(nil, 'shashasha', {report_last_commit: true}) + # end + end + + ## 以下、Octokitのモックに使う部品たち ## OctokitBranch = Struct.new(:name, :commit, keyword_init: true) - OctkoitCommit = Struct.new(:sha, keyword_init: true) + OctokitCommit = Struct.new(:sha, keyword_init: true) + OctokitContent = Struct.new(:name, :path, :type, :size, :lastrev) + def build_mock(*returns, &proc) mock = Minitest::Mock.new From efec5484f514df6f329af4cd63a0a2bef12a8c4e Mon Sep 17 00:00:00 2001 From: HiroyasuTawara Date: Tue, 10 Oct 2023 02:12:55 +0000 Subject: [PATCH 02/17] =?UTF-8?q?entries=E3=83=A1=E3=82=BD=E3=83=83?= =?UTF-8?q?=E3=83=89=E3=81=AE=E3=83=86=E3=82=B9=E3=83=88=E3=82=92=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/unit/github_adapter_test.rb | 38 ++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/test/unit/github_adapter_test.rb b/test/unit/github_adapter_test.rb index 5e88f04..dbd3e95 100644 --- a/test/unit/github_adapter_test.rb +++ b/test/unit/github_adapter_test.rb @@ -77,6 +77,7 @@ def test_branches_Githubに未ソートのブランチが与えられた場合 def test_entries_Githubの戻り値が空の場合 Octokit.stub(:contents, build_mock([]) { |repos, path, ref| + assert_equal @repo, repos }) do entries = @scm.entries assert_equal 0, entries.length @@ -84,7 +85,7 @@ def test_entries_Githubの戻り値が空の場合 end def test_entries_Githubの戻り値が1つある場合 - content = OctokitContent.new('test.md', 'dir/test.md', 'file', 256) + content = OctokitContent.new('test.md', 'farend/redmine_github_repo', 'file', 256) Octokit.stub(:contents, build_mock([content], []) { |repos, path, ref| assert_equal @repo, repos @@ -92,7 +93,7 @@ def test_entries_Githubの戻り値が1つある場合 entries = @scm.entries assert_equal 1, entries.length assert_equal 'test.md', entries[0].name - assert_equal 'dir/test.md', entries[0].path + assert_equal 'farend/redmine_github_repo', entries[0].path assert_equal 'file', entries[0].kind assert_equal 256, entries[0].size end @@ -100,7 +101,7 @@ def test_entries_Githubの戻り値が1つある場合 def test_entries_Githubの戻り値が複数ある場合 contents = ['test.md', 'test.txt'].sort.map{ |name| - OctokitContent.new(name, "dir/#{name}", 'file', 256) + OctokitContent.new(name, 'farend/redmine_github_repo', 'file', 256) } Octokit.stub(:contents, build_mock(contents, []) { |repos, path, ref| @@ -109,15 +110,15 @@ def test_entries_Githubの戻り値が複数ある場合 entries = @scm.entries assert_equal 2, entries.length assert_equal 'test.md', entries[0].name - assert_equal 'dir/test.md', entries[0].path + assert_equal 'farend/redmine_github_repo', entries[0].path assert_equal 'test.txt', entries[1].name - assert_equal 'dir/test.txt', entries[1].path + assert_equal 'farend/redmine_github_repo', entries[1].path end end def test_entries_Githubに未ソートのコンテンツが与えられた場合 contents = ['bbb.md', 'ccc.md', 'aaa.md'].map{ |name| - OctokitContent.new(name, "dir/#{name}", 'file', 256) + OctokitContent.new(name, 'farend/redmine_github_repo', 'file', 256) } Octokit.stub(:contents, build_mock(contents, []) { |repos, path, ref| @@ -144,14 +145,19 @@ def test_entries_Githubで与えられたファイルパスがエントリ名と def test_entries_Githubでオプションreport_last_commitがtrueの場合 # TODO: commitのモックをテスト内で使用可能にする - # content = OctokitContent.new('test.md', 'dir/test.md', 'file', 256) - # commits = [OctokitCommit.new(sha: 'shashasha')] - # - # Octokit.stub(:contents, build_mock([content], []) { |repos, path, ref| - # assert_equal @repo, repos - # }) do - # entries = @scm.entries(nil, 'shashasha', {report_last_commit: true}) - # end + content = OctokitContent.new('test.md', 'farend/redmine_github_repo', 'file', 256) + lastrev = OctokitRevision.new(identifier: 'shashasha') + # = [OctokitCommit.new(sha: 'shashasha')] + + Octokit.stub(:contents, build_mock(content, []) { |repos, path, ref| + assert_equal @repo, repos + }) do + @scm.stub(:lastrev, build_mock(lastrev, []) { |repos, rev| + assert_equal @repo, repos + }) do + entries = @scm.entries(nil, 'shashasha', {report_last_commit: true}) + end + end end @@ -159,8 +165,8 @@ def test_entries_Githubでオプションreport_last_commitがtrueの場合 OctokitBranch = Struct.new(:name, :commit, keyword_init: true) OctokitCommit = Struct.new(:sha, keyword_init: true) - OctokitContent = Struct.new(:name, :path, :type, :size, :lastrev) - + OctokitContent = Struct.new(:name, :path, :type, :size) + OctokitRevision = Struct.new(:identifier, :paths) def build_mock(*returns, &proc) mock = Minitest::Mock.new From 033497030a2c0ec06b82a884d6e630a1462a735d Mon Sep 17 00:00:00 2001 From: HiroyasuTawara Date: Tue, 10 Oct 2023 05:43:34 +0000 Subject: [PATCH 03/17] =?UTF-8?q?gitjib=5Fadapter=E3=81=AE=E5=90=84?= =?UTF-8?q?=E3=83=A1=E3=82=BD=E3=83=83=E3=83=89=E3=81=AE=E6=A6=82=E8=A6=81?= =?UTF-8?q?=E8=AA=AC=E6=98=8E=E3=82=B3=E3=83=A1=E3=83=B3=E3=83=88=E3=82=92?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/redmine/scm/adapters/github_adapter.rb | 25 ++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/lib/redmine/scm/adapters/github_adapter.rb b/lib/redmine/scm/adapters/github_adapter.rb index 5841c03..7b181d2 100644 --- a/lib/redmine/scm/adapters/github_adapter.rb +++ b/lib/redmine/scm/adapters/github_adapter.rb @@ -23,6 +23,8 @@ def initialize(url, root_url=nil, login=nil, password=nil, path_encoding=nil) end def branches + # レシーバに紐づくGithubBranchオブジェクトを配列にして返す + # 対象となるGithubBranchオブジェクトが存在しない場合、空の配列を返す return @branches if @branches @branches = [] 1.step do |i| @@ -42,6 +44,9 @@ def branches end def entries(path=nil, identifier=nil, options={}) + # identifier該当するコミットの、path以下に含まれる各ファイルのエントリを配列にして返す + # 対象となるファイルが存在しない場合、空の配列を返す + # report_last_commitオプションにtrueが与えられた場合、エントリにファイルの最新更新リビジョンを含める identifier = 'HEAD' if identifier.nil? entries = Entries.new @@ -68,12 +73,16 @@ def entries(path=nil, identifier=nil, options={}) end def revision_to_sha(rev) + # 引数に与えられたリビジョン番号に対応するshaを返す + # 存在しないリビジョン番号を指定した場合例外を返す Octokit.commits(@repos, rev, { per_page: 1 }).map(&:sha).first rescue Octokit::Error => e raise CommandFailed, handle_octokit_error(e) end def lastrev(path, rev) + # 引数に与えられたファイルパス・リビジョン番号に該当する最新のコミットをRevisionオブジェクトとして返す + # 該当するコミットが存在しない場合例外を返す return if path.nil? github_commits = Octokit.commits(@repos, rev, { path: path, per_page: 1 }) @@ -93,7 +102,8 @@ def lastrev(path, rev) end def get_path_name(path) - + # 引数で与えられたファイルパスに対応するコミットのSHAを返す + # 該当するものが存在しない場合例外を返す Octokit.commits(@repos).map {|c| Octokit.tree(@repos, c.commit.tree.sha).tree.map{|b| [b.sha, b.path] } }.flatten.each_slice(2).to_h[path] @@ -103,6 +113,8 @@ def get_path_name(path) end def revisions(path, identifier_from, identifier_to, options={}) + # 引数で与えられた条件に合致するコミットをrevisionオブジェクトの配列として返す + # 配列はコミット日時の降順でソートされる path ||= '' revs = Revisions.new per_page = options[:limit] ? options[:limit].to_i : PER_PAGE @@ -166,6 +178,8 @@ def revisions(path, identifier_from, identifier_to, options={}) end def get_filechanges_and_append_to(revisions) + # リビジョン番号の配列を引数に受け取る + # 該当するコミットの変更・追加箇所の情報を各revisionオブジェクトに追記する revisions.each do |revision| commit_diff = Octokit.commit(@repos, revision.identifier) files = commit_diff.files.map do |f| @@ -192,6 +206,8 @@ def get_filechanges_and_append_to(revisions) end def diff(path, identifier_from, identifier_to=nil) + # pathで指定されたファイルに関して、コミット間のファイル内容の差分箇所を特定する + # また差分範囲を整形し標準出力に引き渡す path ||= '' diff = [] @@ -246,6 +262,7 @@ def annotate(path, identifier=nil) end def default_branch + # デフォルトブランチを返す return if branches.blank? ( @@ -256,6 +273,8 @@ def default_branch end def entry(path=nil, identifier=nil) + # identifier該当するコミットの、pathに該当するエントリを返す + # pathが空の場合、トップレベルのエントリを返す identifier ||= 'HEAD' if path.blank? # Root entry @@ -274,11 +293,14 @@ def entry(path=nil, identifier=nil) end def cat(path, identifier=nil) + # pathで受け取ったファイルをutf-8にエンコードし標準出力する + # 取得したコンテンツタイプがバイナリ形式もしくはnilだった場合、空文字を返す identifier = 'HEAD' if identifier.nil? begin blob = Octokit.contents(@repos, path: path, ref: identifier) url = blob.download_url + rescue Octokit::NotFound commit = Octokit.commit(@repos, identifier).files.select{|c| c.filename == path }.first blob = Octokit.blob(@repos, commit.sha) @@ -287,7 +309,6 @@ def cat(path, identifier=nil) Octokit.get(url) content_type = Octokit.last_response.headers['content-type'].slice(/charset=.+$/)&.gsub("charset=", "") return '' if content_type == "binary" || content_type.nil? - content = blob.encoding == "base64" ? Base64.decode64(blob.content) : blob.content content.force_encoding 'utf-8' From c440d8df10f520163fa12170416b3b80598c2fe0 Mon Sep 17 00:00:00 2001 From: HiroyasuTawara Date: Tue, 10 Oct 2023 09:03:40 +0000 Subject: [PATCH 04/17] =?UTF-8?q?=E3=83=86=E3=82=B9=E3=83=88=E3=82=92?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0=E3=83=BB=E4=BF=AE=E6=AD=A3,=20=E3=83=A1?= =?UTF-8?q?=E3=82=BD=E3=83=83=E3=83=89=E6=A6=82=E8=A6=81=E3=82=B3=E3=83=A1?= =?UTF-8?q?=E3=83=B3=E3=83=88=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/redmine/scm/adapters/github_adapter.rb | 8 +-- test/unit/github_adapter_test.rb | 82 +++++++++++++++++++--- 2 files changed, 75 insertions(+), 15 deletions(-) diff --git a/lib/redmine/scm/adapters/github_adapter.rb b/lib/redmine/scm/adapters/github_adapter.rb index 7b181d2..6a4f6ba 100644 --- a/lib/redmine/scm/adapters/github_adapter.rb +++ b/lib/redmine/scm/adapters/github_adapter.rb @@ -74,7 +74,6 @@ def entries(path=nil, identifier=nil, options={}) def revision_to_sha(rev) # 引数に与えられたリビジョン番号に対応するshaを返す - # 存在しないリビジョン番号を指定した場合例外を返す Octokit.commits(@repos, rev, { per_page: 1 }).map(&:sha).first rescue Octokit::Error => e raise CommandFailed, handle_octokit_error(e) @@ -82,7 +81,7 @@ def revision_to_sha(rev) def lastrev(path, rev) # 引数に与えられたファイルパス・リビジョン番号に該当する最新のコミットをRevisionオブジェクトとして返す - # 該当するコミットが存在しない場合例外を返す + # 引数pathが与えられなかった場合、もしくは該当するコミットが存在しない場合nilを返す return if path.nil? github_commits = Octokit.commits(@repos, rev, { path: path, per_page: 1 }) @@ -102,12 +101,11 @@ def lastrev(path, rev) end def get_path_name(path) - # 引数で与えられたファイルパスに対応するコミットのSHAを返す - # 該当するものが存在しない場合例外を返す + # 引数で与えられたSHA対応するコミットのパス名を返す + Octokit.commits(@repos).map {|c| Octokit.tree(@repos, c.commit.tree.sha).tree.map{|b| [b.sha, b.path] } }.flatten.each_slice(2).to_h[path] - rescue Octokit::Error => e raise CommandFailed, handle_octokit_error(e) end diff --git a/test/unit/github_adapter_test.rb b/test/unit/github_adapter_test.rb index dbd3e95..21b6194 100644 --- a/test/unit/github_adapter_test.rb +++ b/test/unit/github_adapter_test.rb @@ -85,7 +85,7 @@ def test_entries_Githubの戻り値が空の場合 end def test_entries_Githubの戻り値が1つある場合 - content = OctokitContent.new('test.md', 'farend/redmine_github_repo', 'file', 256) + content = OctokitContent.new(name: 'test.md', path: 'farend/redmine_github_repo', type: 'file', size: 256) Octokit.stub(:contents, build_mock([content], []) { |repos, path, ref| assert_equal @repo, repos @@ -101,7 +101,7 @@ def test_entries_Githubの戻り値が1つある場合 def test_entries_Githubの戻り値が複数ある場合 contents = ['test.md', 'test.txt'].sort.map{ |name| - OctokitContent.new(name, 'farend/redmine_github_repo', 'file', 256) + OctokitContent.new(name: name, path: 'farend/redmine_github_repo', type: 'file', size: 256) } Octokit.stub(:contents, build_mock(contents, []) { |repos, path, ref| @@ -118,7 +118,7 @@ def test_entries_Githubの戻り値が複数ある場合 def test_entries_Githubに未ソートのコンテンツが与えられた場合 contents = ['bbb.md', 'ccc.md', 'aaa.md'].map{ |name| - OctokitContent.new(name, 'farend/redmine_github_repo', 'file', 256) + OctokitContent.new(name: name, path: 'farend/redmine_github_repo', type: 'file', size: 256) } Octokit.stub(:contents, build_mock(contents, []) { |repos, path, ref| @@ -132,7 +132,7 @@ def test_entries_Githubに未ソートのコンテンツが与えられた場合 end def test_entries_Githubで与えられたファイルパスがエントリ名として既に存在する場合 - contents = 3.times.map{ |i| OctokitContent.new('README.md', 'README.md', 'file', 256*i)} + contents = 3.times.map{ |i| OctokitContent.new(name: 'README.md', path: 'README.md', type: 'file', size: 256*i)} Octokit.stub(:contents, build_mock(contents, []) { |repos, path, ref| assert_equal @repo, repos @@ -144,10 +144,8 @@ def test_entries_Githubで与えられたファイルパスがエントリ名と end def test_entries_Githubでオプションreport_last_commitがtrueの場合 - # TODO: commitのモックをテスト内で使用可能にする - content = OctokitContent.new('test.md', 'farend/redmine_github_repo', 'file', 256) + content = OctokitContent.new(name: 'test.md', path: 'farend/redmine_github_repo', type: 'file', size: 256) lastrev = OctokitRevision.new(identifier: 'shashasha') - # = [OctokitCommit.new(sha: 'shashasha')] Octokit.stub(:contents, build_mock(content, []) { |repos, path, ref| assert_equal @repo, repos @@ -160,13 +158,77 @@ def test_entries_Githubでオプションreport_last_commitがtrueの場合 end end + def test_revision_to_sha_Githubの戻り値が存在する場合 + commit = OctokitCommit.new(sha: 'shashasha') + opt = { per_page: 1 } + + Octokit.stub(:commits, build_mock([commit], []) { |repos, rev, opt| + assert_equal @repo, repos + }) do + assert_equal 'shashasha', @scm.revision_to_sha('shashasha') + end + end + + def test_lastrev_Githubの戻り値が返ってくる場合 + author = OctokitAuthor.new(name: 'AuthorName') + committer = OctokitCommiter.new(date: '2023-01-01 00:00:00') + rev = OctokitRevision.new(identifier: 'shashasha', author: author, committer: committer) + commit = OctokitCommit.new(sha: 'shashasha', commit: rev ) + opt = { per_page: 1 } + + Octokit.stub(:commits, build_mock([commit], []) { |repos, rev| + assert_equal @repo, repos + }) do + revision = @scm.lastrev('farend/redmine_github_repo', 'shashasha') + + assert_equal 'shashasha', revision.identifier + assert_equal 'AuthorName', revision.author + assert_equal '2023-01-01 00:00:00', revision.time + end + end + + def test_lastrev_Githubの引数pathが与えられない場合 + Octokit.stub(:commits, build_mock([], []) { |repos, rev| + assert_equal @repo, repos + }) do + assert_equal nil, @scm.lastrev(nil, 'shashasha') + end + end + + def test_lastrev_Githubの引数に該当するコミットが存在しない場合 + Octokit.stub(:commits, build_mock([], []) { |repos, rev| + assert_equal @repo, repos + }) do + assert_equal nil, @scm.lastrev('farend/redmine_github_repo', 'shashasha') + end + end + + def test_get_path_name_Githubの戻り値が存在する場合 + blob = OctokitContent.new(sha: 'shashasha', path: 'farend/redmine_github_repo') + tree = OctokitTree.new(tree:[blob], sha: 'shashasha') + commit = OctokitCommit.new(sha: 'shashasha', commit: OctokitRevision.new(tree: tree)) + + Octokit.stub(:commits, build_mock([commit], []) { |repos, rev, opt| + assert_equal @repo, repos + }) do + Octokit.stub(:tree, build_mock(tree, []) { |repos, sha| + assert_equal @repo, repos + assert_equal 'shashasha', sha + }) do + assert_equal 'farend/redmine_github_repo', @scm.get_path_name('shashasha') + end + end + end ## 以下、Octokitのモックに使う部品たち ## OctokitBranch = Struct.new(:name, :commit, keyword_init: true) - OctokitCommit = Struct.new(:sha, keyword_init: true) - OctokitContent = Struct.new(:name, :path, :type, :size) - OctokitRevision = Struct.new(:identifier, :paths) + OctokitCommit = Struct.new(:sha, :commit, keyword_init: true) + OctokitContent = Struct.new(:sha, :name, :path, :type, :size, :download_url, keyword_init: true) + OctokitRevision = Struct.new(:identifier, :author, :committer, :tree, keyword_init: true) + OctokitAuthor = Struct.new(:name, keyword_init: true) + OctokitCommiter = Struct.new(:date, keyword_init: true) + OctokitTree = Struct.new(:tree, :sha, keyword_init: true) def build_mock(*returns, &proc) mock = Minitest::Mock.new From c4ff60b6bfb16159d5e2d1d318d992046f2e833b Mon Sep 17 00:00:00 2001 From: HiroyasuTawara Date: Wed, 11 Oct 2023 07:31:20 +0000 Subject: [PATCH 05/17] =?UTF-8?q?=E3=83=86=E3=82=B9=E3=83=88=E3=82=92?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0=E3=83=BB=E4=BF=AE=E6=AD=A3,=E3=83=A1?= =?UTF-8?q?=E3=82=BD=E3=83=83=E3=83=89=E6=A6=82=E8=A6=81=E3=82=B3=E3=83=A1?= =?UTF-8?q?=E3=83=B3=E3=83=88=E3=81=AE=E5=86=85=E5=AE=B9=E3=82=92=E6=8B=A1?= =?UTF-8?q?=E5=85=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/redmine/scm/adapters/github_adapter.rb | 53 +++++---- test/unit/github_adapter_test.rb | 118 ++++++++++++++++++--- 2 files changed, 132 insertions(+), 39 deletions(-) diff --git a/lib/redmine/scm/adapters/github_adapter.rb b/lib/redmine/scm/adapters/github_adapter.rb index 6a4f6ba..eb88ecf 100644 --- a/lib/redmine/scm/adapters/github_adapter.rb +++ b/lib/redmine/scm/adapters/github_adapter.rb @@ -22,9 +22,9 @@ def initialize(url, root_url=nil, login=nil, password=nil, path_encoding=nil) end end + # レシーバに紐づくGithubBranchオブジェクトを配列にし、ブランチ名でソートして返す + # 対象となるGithubBranchオブジェクトが存在しない場合、空の配列を返す def branches - # レシーバに紐づくGithubBranchオブジェクトを配列にして返す - # 対象となるGithubBranchオブジェクトが存在しない場合、空の配列を返す return @branches if @branches @branches = [] 1.step do |i| @@ -43,10 +43,12 @@ def branches raise CommandFailed, handle_octokit_error(e) end + # pathにファイル・ディレクトリのパス, identifierにコミットのSHAを受け取る + # identifierに該当するコミットの、path以下に含まれる各ファイルのエントリを配列にして返す + # pathが空の場合rootディレクトリを、identifierが空の場合HEADコミットを対象とする + # 対象となるファイルが存在しない場合、空の配列を返す + # report_last_commitオプションにtrueが与えられた場合、各エントリにファイルの最新コミット情報を含める def entries(path=nil, identifier=nil, options={}) - # identifier該当するコミットの、path以下に含まれる各ファイルのエントリを配列にして返す - # 対象となるファイルが存在しない場合、空の配列を返す - # report_last_commitオプションにtrueが与えられた場合、エントリにファイルの最新更新リビジョンを含める identifier = 'HEAD' if identifier.nil? entries = Entries.new @@ -72,16 +74,18 @@ def entries(path=nil, identifier=nil, options={}) raise CommandFailed, handle_octokit_error(e) end + # revにコミットのSHAもしくはブランチ名を受け取る + # 引数に該当するコミットをすべて取得し、その中で最新コミットのSHAを返す def revision_to_sha(rev) - # 引数に与えられたリビジョン番号に対応するshaを返す Octokit.commits(@repos, rev, { per_page: 1 }).map(&:sha).first rescue Octokit::Error => e raise CommandFailed, handle_octokit_error(e) end + # pathにファイル・ディレクトリのパス、revにコミットのSHAもしくはブランチ名を受け取る + # revに該当するコミット以前でpath以下に変更があった最新のコミットを取得し、Revisionオブジェクトとして返す + # 引数pathが与えられなかった場合、もしくは該当するコミットが存在しない場合nilを返す def lastrev(path, rev) - # 引数に与えられたファイルパス・リビジョン番号に該当する最新のコミットをRevisionオブジェクトとして返す - # 引数pathが与えられなかった場合、もしくは該当するコミットが存在しない場合nilを返す return if path.nil? github_commits = Octokit.commits(@repos, rev, { path: path, per_page: 1 }) @@ -100,19 +104,21 @@ def lastrev(path, rev) raise CommandFailed, handle_octokit_error(e) end + # pathにtreeオブジェクトのshaを受け取る + # treeの最上位に位置するファイル・ディレクトリ名を返す def get_path_name(path) - # 引数で与えられたSHA対応するコミットのパス名を返す - Octokit.commits(@repos).map {|c| Octokit.tree(@repos, c.commit.tree.sha).tree.map{|b| [b.sha, b.path] } }.flatten.each_slice(2).to_h[path] rescue Octokit::Error => e raise CommandFailed, handle_octokit_error(e) end - + + # pathにファイル・ディレクトリのパス, identifier_from/identifier_toにコミットのSHAを受け取る + # allオプションがtrueの場合、 + # 引数で与えられた条件に合致するコミットをRevisionオブジェクトの配列として返す + # 配列はコミット日時の降順でソートされる def revisions(path, identifier_from, identifier_to, options={}) - # 引数で与えられた条件に合致するコミットをrevisionオブジェクトの配列として返す - # 配列はコミット日時の降順でソートされる path ||= '' revs = Revisions.new per_page = options[:limit] ? options[:limit].to_i : PER_PAGE @@ -175,9 +181,9 @@ def revisions(path, identifier_from, identifier_to, options={}) raise CommandFailed, handle_octokit_error(e) end + # 複数のrevisionオブジェクトをを配列として受け取り、該当コミットの変更状況をhashにする + # 作成したhashを各revisionオブジェクトのpathsパラメータに追記する def get_filechanges_and_append_to(revisions) - # リビジョン番号の配列を引数に受け取る - # 該当するコミットの変更・追加箇所の情報を各revisionオブジェクトに追記する revisions.each do |revision| commit_diff = Octokit.commit(@repos, revision.identifier) files = commit_diff.files.map do |f| @@ -203,9 +209,10 @@ def get_filechanges_and_append_to(revisions) raise CommandFailed, handle_octokit_error(e) end + # pathにファイルのパス, identifier_from/identifier_toにコミットのSHAを受け取る + # pathで指定されたファイル内容について、identifier~で指定されたコミット間の差分箇所を特定する + # 特定した差分箇所に追記を行い、文字列の配列として返す def diff(path, identifier_from, identifier_to=nil) - # pathで指定されたファイルに関して、コミット間のファイル内容の差分箇所を特定する - # また差分範囲を整形し標準出力に引き渡す path ||= '' diff = [] @@ -259,8 +266,8 @@ def annotate(path, identifier=nil) nil end + # デフォルトブランチ名を文字列にして返す def default_branch - # デフォルトブランチを返す return if branches.blank? ( @@ -270,9 +277,11 @@ def default_branch ).to_s end + # pathにファイル・ディレクトリのパス, identifierにコミットのSHAを受け取る + # identifierに該当するコミットの、pathに指定されたファイル・ディレクトリのエントリを返す + # identifierが空の場合、HEADコミットを対象にする + # pathが空の場合、トップレベルのエントリを返す def entry(path=nil, identifier=nil) - # identifier該当するコミットの、pathに該当するエントリを返す - # pathが空の場合、トップレベルのエントリを返す identifier ||= 'HEAD' if path.blank? # Root entry @@ -290,9 +299,9 @@ def entry(path=nil, identifier=nil) end end + # identifierにSHAが該当するコミットの、pathに指定されたファイルの内容を文字列で返す + # identifierが空の場合、HEADコミットを対象にする def cat(path, identifier=nil) - # pathで受け取ったファイルをutf-8にエンコードし標準出力する - # 取得したコンテンツタイプがバイナリ形式もしくはnilだった場合、空文字を返す identifier = 'HEAD' if identifier.nil? begin diff --git a/test/unit/github_adapter_test.rb b/test/unit/github_adapter_test.rb index 21b6194..a9d686e 100644 --- a/test/unit/github_adapter_test.rb +++ b/test/unit/github_adapter_test.rb @@ -131,18 +131,6 @@ def test_entries_Githubに未ソートのコンテンツが与えられた場合 end end - def test_entries_Githubで与えられたファイルパスがエントリ名として既に存在する場合 - contents = 3.times.map{ |i| OctokitContent.new(name: 'README.md', path: 'README.md', type: 'file', size: 256*i)} - - Octokit.stub(:contents, build_mock(contents, []) { |repos, path, ref| - assert_equal @repo, repos - }) do - entries = @scm.entries - assert_equal 1, entries.length - assert_equal 0, entries.last.size - end - end - def test_entries_Githubでオプションreport_last_commitがtrueの場合 content = OctokitContent.new(name: 'test.md', path: 'farend/redmine_github_repo', type: 'file', size: 256) lastrev = OctokitRevision.new(identifier: 'shashasha') @@ -154,11 +142,12 @@ def test_entries_Githubでオプションreport_last_commitがtrueの場合 assert_equal @repo, repos }) do entries = @scm.entries(nil, 'shashasha', {report_last_commit: true}) + assert_equal 'shashasha', entries[0].lastrev.identifier end end end - def test_revision_to_sha_Githubの戻り値が存在する場合 + def test_revision_to_sha_GithubにコミットのSHAを渡した場合 commit = OctokitCommit.new(sha: 'shashasha') opt = { per_page: 1 } @@ -169,12 +158,23 @@ def test_revision_to_sha_Githubの戻り値が存在する場合 end end + def test_revision_to_sha_Githubにブランチ名を渡した場合 + branch = OctokitBranch.new(name: 'main', sha: 'shashasha') + opt = { per_page: 1 } + + Octokit.stub(:commits, build_mock([branch], []) { |repos, rev, opt| + assert_equal @repo, repos + assert_equal 'main', rev + }) do + assert_equal 'shashasha', @scm.revision_to_sha('main') + end + end + def test_lastrev_Githubの戻り値が返ってくる場合 author = OctokitAuthor.new(name: 'AuthorName') committer = OctokitCommiter.new(date: '2023-01-01 00:00:00') rev = OctokitRevision.new(identifier: 'shashasha', author: author, committer: committer) commit = OctokitCommit.new(sha: 'shashasha', commit: rev ) - opt = { per_page: 1 } Octokit.stub(:commits, build_mock([commit], []) { |repos, rev| assert_equal @repo, repos @@ -220,15 +220,99 @@ def test_get_path_name_Githubの戻り値が存在する場合 end end + def test_revisions_Githubの戻り値が1つある場合 + author = OctokitAuthor.new(name: 'AuthorName') + committer = OctokitCommiter.new(date: '2023-01-01 00:00:00') + parent = OctokitCommit.new(sha: 'shashafrom') + rev = OctokitRevision.new(identifier: 'shashato', author: author, committer: committer, message: 'commit message') + commit = OctokitCommit.new(sha: 'shashato', commit: rev, parents: [parent]) + opt = { path: @repo, per_page: 1 } + Octokit.stub(:commits, build_mock([commit], []) { |repos, rev| + assert_equal @repo, repos + }) do + revisions = @scm.revisions(@repo, 'shashato', 'shashafrom', opt ) + + assert_equal 1, revisions.size + assert_equal 'shashato', revisions[0].identifier + assert_equal 'commit message', revisions[0].message + assert_equal '2023-01-01 00:00:00', revisions[0].time + assert_equal 'shashafrom', revisions[0].parents[0] + end + end + + def test_revisions_Githubの戻り値が複数ある場合 + parents = [] + commits = 3.times.map { |i| + author = OctokitAuthor.new(name: "Author#{i}") + committer = OctokitCommiter.new(date: "2023-01-00 0#{i}:00:00") + parents << OctokitCommit.new(sha: "shashasha#{i}") + rev = OctokitRevision.new(identifier: "shashasha#{i+1}", author: author, committer: committer, message: 'commit message') + OctokitCommit.new(sha: "shashasha#{i+1}", commit: rev, parents: parents.dup) + } + + opt = { path: @repo, per_page: 1 } + Octokit.stub(:commits, build_mock(commits, []) { |repos, rev| + assert_equal @repo, repos + }) do + revisions = @scm.revisions(@repo, 'shashato', 'shashafrom', opt ) + + assert_equal 3, revisions.size + + revisions.each_with_index {|rev, i| + assert_equal "shashasha#{i+1}", rev.identifier + assert_equal "2023-01-00 0#{i}:00:00", rev.time + assert_equal i + 1, rev.parents.size + } + end + end + + def test_revisions_Githubのallオプションにtrueが与えられる場合 + parents = [] + commits = 3.times.map { |i| + author = OctokitAuthor.new(name: "Author#{i}") + committer = OctokitCommiter.new(date: "2023-01-00 0#{i}:00:00") + parents << OctokitCommit.new(sha: "shashasha#{i}") + rev = OctokitRevision.new(identifier: "shashasha#{i+1}", author: author, + committer: committer, message: 'commit message') + OctokitCommit.new(sha: "shashasha#{i+1}", commit: rev, parents: parents.dup) + } + opt = { path: @repo, per_page: 1, all: true, last_committed_id: 'shashasha3'} + Octokit.stub(:commits, build_mock(commits, []) { |repos, rev| + assert_equal @repo, repos + }) do + revisions = @scm.revisions(@repo, 'shashasha2', 'shashasha3', opt ) + + assert_equal 0, revisions.size + end + end + + def test_get_filechanges_and_append_to_Githubにrevisionが渡される場合 + add_file = TestFile.new(status: "added", filename: "add.md") + mod_file = TestFile.new(status: "modified", filename: "mod.md") + rev = OctokitRevision.new(identifier: "shashasha", paths: nil) + commit = OctokitCommit.new(sha: "shashasha", files: [add_file, mod_file]) + + Octokit.stub(:commit, build_mock(commit, []) { |repos, sha| + assert_equal @repo, repos + }) do + @scm.get_filechanges_and_append_to([rev]) + assert_equal 'A', rev.paths[0][:action] + assert_equal 'add.md', rev.paths[0][:path] + assert_equal 'M', rev.paths[1][:action] + assert_equal 'mod.md', rev.paths[1][:path] + end + end + ## 以下、Octokitのモックに使う部品たち ## - OctokitBranch = Struct.new(:name, :commit, keyword_init: true) - OctokitCommit = Struct.new(:sha, :commit, keyword_init: true) + OctokitBranch = Struct.new(:name, :commit, :sha, keyword_init: true) + OctokitCommit = Struct.new(:sha, :commit, :parents, :files, keyword_init: true) OctokitContent = Struct.new(:sha, :name, :path, :type, :size, :download_url, keyword_init: true) - OctokitRevision = Struct.new(:identifier, :author, :committer, :tree, keyword_init: true) + OctokitRevision = Struct.new(:identifier, :author, :committer, :tree, :message, :paths, keyword_init: true) OctokitAuthor = Struct.new(:name, keyword_init: true) OctokitCommiter = Struct.new(:date, keyword_init: true) OctokitTree = Struct.new(:tree, :sha, keyword_init: true) + TestFile = Struct.new(:status, :filename, :from_revision, keyword_init: true) def build_mock(*returns, &proc) mock = Minitest::Mock.new From 6104ed96929d13353938502ff94226daaa0a4f27 Mon Sep 17 00:00:00 2001 From: HiroyasuTawara Date: Thu, 12 Oct 2023 08:29:32 +0000 Subject: [PATCH 06/17] =?UTF-8?q?=E3=83=86=E3=82=B9=E3=83=88=E3=82=92?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/redmine/scm/adapters/github_adapter.rb | 4 +- test/unit/github_adapter_test.rb | 229 ++++++++++++++++++++- 2 files changed, 226 insertions(+), 7 deletions(-) diff --git a/lib/redmine/scm/adapters/github_adapter.rb b/lib/redmine/scm/adapters/github_adapter.rb index eb88ecf..ccb82dc 100644 --- a/lib/redmine/scm/adapters/github_adapter.rb +++ b/lib/redmine/scm/adapters/github_adapter.rb @@ -226,7 +226,7 @@ def diff(path, identifier_from, identifier_to=nil) if path.length > 0 next if github_diff.filename != path && !github_diff.filename.include?("#{path}/") end - + case github_diff.status when "renamed" diff << "diff" @@ -267,6 +267,7 @@ def annotate(path, identifier=nil) end # デフォルトブランチ名を文字列にして返す + # ブランチが1つも無い場合nilを返す def default_branch return if branches.blank? @@ -307,7 +308,6 @@ def cat(path, identifier=nil) begin blob = Octokit.contents(@repos, path: path, ref: identifier) url = blob.download_url - rescue Octokit::NotFound commit = Octokit.commit(@repos, identifier).files.select{|c| c.filename == path }.first blob = Octokit.blob(@repos, commit.sha) diff --git a/test/unit/github_adapter_test.rb b/test/unit/github_adapter_test.rb index a9d686e..c87e3a8 100644 --- a/test/unit/github_adapter_test.rb +++ b/test/unit/github_adapter_test.rb @@ -131,7 +131,7 @@ def test_entries_Githubに未ソートのコンテンツが与えられた場合 end end - def test_entries_Githubでオプションreport_last_commitがtrueの場合 + def test_entries_Githubのreport_last_commitオプションにtrueが与えられる場合 content = OctokitContent.new(name: 'test.md', path: 'farend/redmine_github_repo', type: 'file', size: 256) lastrev = OctokitRevision.new(identifier: 'shashasha') @@ -147,7 +147,7 @@ def test_entries_Githubでオプションreport_last_commitがtrueの場合 end end - def test_revision_to_sha_GithubにコミットのSHAを渡した場合 + def test_revision_to_sha_GithubにコミットのSHAを渡される場合 commit = OctokitCommit.new(sha: 'shashasha') opt = { per_page: 1 } @@ -158,7 +158,7 @@ def test_revision_to_sha_GithubにコミットのSHAを渡した場合 end end - def test_revision_to_sha_Githubにブランチ名を渡した場合 + def test_revision_to_sha_Githubにブランチ名を渡される場合 branch = OctokitBranch.new(name: 'main', sha: 'shashasha') opt = { per_page: 1 } @@ -303,16 +303,235 @@ def test_get_filechanges_and_append_to_Githubにrevisionが渡される場合 end end + def test_diff_Githubに追加差分のあるファイルパスとコミットSHAが渡される場合 + file = TestFile.new(status: 'added', filename: "farend/redmine_github_repo/README.md") + cat = "add_line" + commit = OctokitCommit.new(sha: 'shashasha', files: [file]) + + added_diffs = [ + "diff", + "--- /dev/null", + "+++ b/#{file.filename}", + "@@ -0,0 +1,2 @@", + "+#{cat}" + ] + + Octokit.stub(:commit, build_mock(commit, []) { |repos, sha| + assert_equal @repo, repos + }) do + @scm.stub(:cat, build_mock(cat, []) { |path, identifier| + assert_equal 'farend/redmine_github_repo/README.md', path + }) do + diffs = @scm.diff(@repo, "shashasha") + assert_equal added_diffs, diffs + end + end + end + + def test_diff_Githubにファイル名変更差分のあるファイルパスとコミットSHAが渡される場合 + file_from = TestFile.new(status: 'added', filename: "farend/redmine_github_repo/README.md") + file_to = TestFile.new(status: 'renamed', filename: "farend/redmine_github_repo/RENAME.md", previous_filename: "farend/redmine_github_repo/README.md") + cat = "add_line" + commit_from = OctokitCommit.new(sha: 'shashafrom') + commit_to = OctokitCommit.new(sha: 'shashato') + compare = OctokitCompare.new(base_commit: commit_from, commits: [commit_to], files: [file_to, file_from]) + + renamed_diffs = [ + "diff", + "--- a/#{file_from.filename}", + "+++ b/#{file_to.filename}", + "diff", + "--- /dev/null", + "+++ b/#{file_from.filename}", + "@@ -0,0 +1,2 @@", + "+#{cat}" + ] + + Octokit.stub(:compare, build_mock(compare, []) { |repos, sha| + assert_equal @repo, repos + }) do + @scm.stub(:cat, build_mock(cat, []) { |path, identifier| + assert_equal 'farend/redmine_github_repo/README.md', path + }) do + diffs = @scm.diff(@repo, 'shashafrom', 'shashato') + assert_equal renamed_diffs, diffs + end + end + end + + def test_diff_Githubに変更差分のあるファイルパスとコミットSHAが渡される場合 + file_from = TestFile.new(status: 'added', filename: "farend/redmine_github_repo/README.md") + file_to = TestFile.new(status: 'modifies', filename: "farend/redmine_github_repo/README.md", patch:'+mod_line') + cat = "add_line" + commit_from = OctokitCommit.new(sha: 'shashafrom') + commit_to = OctokitCommit.new(sha: 'shashato') + compare = OctokitCompare.new(base_commit: commit_from, commits: [commit_to], files: [file_to, file_from]) + + modified_diffs = [ + "diff", + "--- a/#{file_from.filename}", + "+++ b/#{file_to.filename}", + "#{file_to.patch}", + "diff", + "--- /dev/null", + "+++ b/#{file_from.filename}", + "@@ -0,0 +1,2 @@", + "+#{cat}" + ] + + Octokit.stub(:compare, build_mock(compare, []) { |repos, sha| + assert_equal @repo, repos + }) do + @scm.stub(:cat, build_mock(cat, []) { |path, identifier| + assert_equal 'farend/redmine_github_repo/README.md', path + }) do + diffs = @scm.diff(@repo, "shashafrom", "shashato") + assert_equal modified_diffs, diffs + end + end + end + + def test_diff_Githubに削除差分のあるファイルパスとコミットSHAが渡される場合 + file_from = TestFile.new(status: 'added', filename: "farend/redmine_github_repo/README.md") + file_to = TestFile.new(status: 'removed', filename: "farend/redmine_github_repo/README.md", patch:'-add_line') + cat = "add_line" + commit_from = OctokitCommit.new(sha: 'shashafrom') + commit_to = OctokitCommit.new(sha: 'shashato') + compare = OctokitCompare.new(base_commit: commit_from, commits: [commit_to], files: [file_from, file_to]) + + removed_diffs = [ + "diff", + "--- /dev/null", + "+++ b/#{file_from.filename}", + "@@ -0,0 +1,2 @@", + "+#{cat}", + "diff", + "--- a/#{file_from.filename}", + "+++ /dev/null", + "@@ -1,2 +0,0 @@", + "-[]" + ] + + Octokit.stub(:compare, build_mock(compare, []) { |repos, sha| + assert_equal @repo, repos + }) do + @scm.stub(:cat, build_mock(cat, []) { |path, identifier| + assert_equal 'farend/redmine_github_repo/README.md', path + }) do + diffs = @scm.diff(@repo, "shashafrom", "shashato") + assert_equal removed_diffs, diffs + end + end + end + + def test_default_branch_Githubの戻り値が存在する場合 + branch = OctokitBranch.new(name: 'main', commit: OctokitCommit.new(sha: 'shashasha')) + Octokit.stub(:branches, build_mock([branch], []) { |repos, rev| + assert_equal @repo, repos + }) do + assert_equal 'main', @scm.default_branch + end + end + + def test_default_branch_Githubの戻り値が存在しない場合 + Octokit.stub(:branches, build_mock([], []) { |repos, rev| + assert_equal @repo, repos + }) do + assert_equal nil, @scm.default_branch + end + end + + def test_entry_Githubに引数を渡す場合 + content = OctokitContent.new(name: 'README.md', path: @repo, type: 'file', size: 256) + lastrev = OctokitRevision.new(identifier:'shashasha') + + Octokit.stub(:contents, build_mock([content], []) { |repos, path, ref| + assert_equal @repo, repos + }) do + @scm.stub(:lastrev, build_mock(lastrev, []) { |repos, rev| + assert_equal @repo, repos + }) do + entry = @scm.entry('README.md') + assert_equal 'README.md', entry.name + assert_equal 'file', entry.kind + assert_equal @repo, entry.path + assert_equal 256, entry.size + end + end + end + + def test_entry_Githubに引数を渡さない場合 + Octokit.stub(:contents, build_mock([], []) { |repos, path, ref| + assert_equal @repo, repos + }) do + entry = @scm.entry + assert_equal 'dir', entry.kind + assert_equal '', entry.path + end + end + + def test_cat_Githubで取得ファイルのエンコードが不要な場合 + blob = OctokitContent.new(path: @repos, sha: 'shashasha', download_url: 'http://download/url', + encoding: 'utf-8', content: 'test_content') + get = OctokitGet.new(headers:{ "content-type" => 'text/html; charset=utf-8'}) + Octokit.stub(:contents, build_mock(blob, []) { |repos, path, ref| + assert_equal @repo, repos + }) do + Octokit.stub(:get, build_mock(get, []) { |url| + assert_equal 'http://download/url', url + }) do + Octokit.stub(:last_response, build_mock(get, [])) do + assert_equal 'test_content', @scm.cat(@repos) + end + end + end + end + + def test_cat_Githubで取得ファイルがエンコードが必要な場合 + blob = OctokitContent.new(path: @repos, sha: 'shashasha', download_url: 'http://download/url', + encoding: 'base64', content: 'dGVzdF9jb250ZW50') + get = OctokitGet.new(headers:{ "content-type" => 'text/html; charset=base64'}) + Octokit.stub(:contents, build_mock(blob, []) { |repos, path, ref| + assert_equal @repo, repos + }) do + Octokit.stub(:get, build_mock(get, []) { |url| + assert_equal 'http://download/url', url + }) do + Octokit.stub(:last_response, build_mock(get, [])) do + assert_equal 'test_content', @scm.cat(@repos) + end + end + end + end + + def test_cat_Githubで取得ファイルがバイナリ形式の場合 + blob = OctokitContent.new(path: @repos, sha: 'shashasha', download_url: 'http://download/url') + get = OctokitGet.new(headers:{ "content-type" => 'binary'}) + Octokit.stub(:contents, build_mock(blob, []) { |repos, path, ref| + assert_equal @repo, repos + }) do + Octokit.stub(:get, build_mock(get, []) { |url| + assert_equal 'http://download/url', url + }) do + Octokit.stub(:last_response, build_mock(get, [])) do + assert_equal '', @scm.cat(@repos) + end + end + end + end + ## 以下、Octokitのモックに使う部品たち ## OctokitBranch = Struct.new(:name, :commit, :sha, keyword_init: true) OctokitCommit = Struct.new(:sha, :commit, :parents, :files, keyword_init: true) - OctokitContent = Struct.new(:sha, :name, :path, :type, :size, :download_url, keyword_init: true) + OctokitContent = Struct.new(:sha, :name, :path, :type, :size, :download_url, :content, :encoding, keyword_init: true) OctokitRevision = Struct.new(:identifier, :author, :committer, :tree, :message, :paths, keyword_init: true) OctokitAuthor = Struct.new(:name, keyword_init: true) OctokitCommiter = Struct.new(:date, keyword_init: true) OctokitTree = Struct.new(:tree, :sha, keyword_init: true) - TestFile = Struct.new(:status, :filename, :from_revision, keyword_init: true) + OctokitCompare = Struct.new(:base_commit, :commits, :files, keyword_init: true) + OctokitGet = Struct.new(:headers, keyword_init: true) + TestFile = Struct.new(:status, :filename, :previous_filename, :from_revision, :patch, keyword_init: true) def build_mock(*returns, &proc) mock = Minitest::Mock.new From faa0eca9b1b42fbe64bd54e60e0d1bae306b12e3 Mon Sep 17 00:00:00 2001 From: HiroyasuTawara Date: Fri, 13 Oct 2023 01:30:41 +0000 Subject: [PATCH 07/17] =?UTF-8?q?stub=E3=81=AB=E5=BC=95=E6=95=B0=E3=81=AEa?= =?UTF-8?q?ssertion=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/redmine/scm/adapters/github_adapter.rb | 3 +- test/unit/github_adapter_test.rb | 239 +++++++++++++-------- 2 files changed, 154 insertions(+), 88 deletions(-) diff --git a/lib/redmine/scm/adapters/github_adapter.rb b/lib/redmine/scm/adapters/github_adapter.rb index ccb82dc..c2e36f8 100644 --- a/lib/redmine/scm/adapters/github_adapter.rb +++ b/lib/redmine/scm/adapters/github_adapter.rb @@ -226,7 +226,7 @@ def diff(path, identifier_from, identifier_to=nil) if path.length > 0 next if github_diff.filename != path && !github_diff.filename.include?("#{path}/") end - + case github_diff.status when "renamed" diff << "diff" @@ -308,6 +308,7 @@ def cat(path, identifier=nil) begin blob = Octokit.contents(@repos, path: path, ref: identifier) url = blob.download_url + rescue Octokit::NotFound commit = Octokit.commit(@repos, identifier).files.select{|c| c.filename == path }.first blob = Octokit.blob(@repos, commit.sha) diff --git a/test/unit/github_adapter_test.rb b/test/unit/github_adapter_test.rb index c87e3a8..5a8f13e 100644 --- a/test/unit/github_adapter_test.rb +++ b/test/unit/github_adapter_test.rb @@ -4,12 +4,10 @@ class GithubAdapterTest < ActiveSupport::TestCase def setup @scm = Redmine::Scm::Adapters::GithubAdapter.new('https://github.com/farend/redmine_github_repo.git') @repo = "farend/redmine_github_repo" - @repos = [@repo] end def test_branches_Githubの戻り値が空の場合 Octokit.stub(:branches, build_mock([]) {|repo, options| - # 引数のアサーションをしておく assert_equal @repo, repo assert_equal 1, options[:page] assert_equal 100, options[:per_page] @@ -23,8 +21,12 @@ def test_branches_Githubの戻り値が空の場合 def test_branches_Githubの戻り値が1つある場合 branch = OctokitBranch.new(name: 'main', commit: OctokitCommit.new(sha: 'shashasha')) - Octokit.stub(:branches, build_mock([branch], []) { |repos, options| - assert options[:page] + pages = [1, 2] + + Octokit.stub(:branches, build_mock([branch], []) { |repo, options| + assert_equal @repo, repo + assert_equal pages.shift, options[:page] + assert_equal 100, options[:per_page] }) do branches = @scm.branches @@ -40,8 +42,12 @@ def test_branches_Githubの戻り値が複数ある場合 OctokitBranch.new(name: name, commit: OctokitCommit.new(sha: "shashasha#{i}")) } - Octokit.stub(:branches, build_mock(multi_branche, []) { |repos, options| - assert options[:page] + pages = [1, 2] + + Octokit.stub(:branches, build_mock(multi_branche, []) { |repo, options| + assert_equal @repo, repo + assert_equal pages.shift, options[:page] + assert_equal 100, options[:per_page] }) do branches = @scm.branches @@ -60,9 +66,12 @@ def test_branches_Githubに未ソートのブランチが与えられた場合 } sorted_multi_branche = ['aaa', 'bbb', 'ccc'] + pages = [1, 2] - Octokit.stub(:branches, build_mock(multi_branche, []) { |repos, options| - assert options[:page] + Octokit.stub(:branches, build_mock(multi_branche, []) { |repo, options| + assert_equal @repo, repo + assert_equal pages.shift, options[:page] + assert_equal 100, options[:per_page] }) do branches = @scm.branches @@ -76,8 +85,10 @@ def test_branches_Githubに未ソートのブランチが与えられた場合 end def test_entries_Githubの戻り値が空の場合 - Octokit.stub(:contents, build_mock([]) { |repos, path, ref| - assert_equal @repo, repos + Octokit.stub(:contents, build_mock([]) { |repo, options| + assert_equal @repo, repo + assert_equal nil, options[:path] + assert_equal 'HEAD', options[:ref] }) do entries = @scm.entries assert_equal 0, entries.length @@ -87,8 +98,10 @@ def test_entries_Githubの戻り値が空の場合 def test_entries_Githubの戻り値が1つある場合 content = OctokitContent.new(name: 'test.md', path: 'farend/redmine_github_repo', type: 'file', size: 256) - Octokit.stub(:contents, build_mock([content], []) { |repos, path, ref| - assert_equal @repo, repos + Octokit.stub(:contents, build_mock([content], []) { |repo, options| + assert_equal @repo, repo + assert_equal nil, options[:path] + assert_equal 'HEAD', options[:ref] }) do entries = @scm.entries assert_equal 1, entries.length @@ -104,8 +117,10 @@ def test_entries_Githubの戻り値が複数ある場合 OctokitContent.new(name: name, path: 'farend/redmine_github_repo', type: 'file', size: 256) } - Octokit.stub(:contents, build_mock(contents, []) { |repos, path, ref| - assert_equal @repo, repos + Octokit.stub(:contents, build_mock(contents, []) { |repo, options| + assert_equal @repo, repo + assert_equal nil, options[:path] + assert_equal 'HEAD', options[:ref] }) do entries = @scm.entries assert_equal 2, entries.length @@ -121,8 +136,10 @@ def test_entries_Githubに未ソートのコンテンツが与えられた場合 OctokitContent.new(name: name, path: 'farend/redmine_github_repo', type: 'file', size: 256) } - Octokit.stub(:contents, build_mock(contents, []) { |repos, path, ref| - assert_equal @repo, repos + Octokit.stub(:contents, build_mock(contents, []) { |repo, options| + assert_equal @repo, repo + assert_equal nil, options[:path] + assert_equal 'HEAD', options[:ref] }) do entries = @scm.entries assert_equal 'aaa.md', entries[0].name @@ -135,11 +152,14 @@ def test_entries_Githubのreport_last_commitオプションにtrueが与えら content = OctokitContent.new(name: 'test.md', path: 'farend/redmine_github_repo', type: 'file', size: 256) lastrev = OctokitRevision.new(identifier: 'shashasha') - Octokit.stub(:contents, build_mock(content, []) { |repos, path, ref| - assert_equal @repo, repos + Octokit.stub(:contents, build_mock(content, []) { |repo, options| + assert_equal @repo, repo + assert_equal nil, options[:path] + assert_equal 'shashasha', options[:ref] }) do - @scm.stub(:lastrev, build_mock(lastrev, []) { |repos, rev| - assert_equal @repo, repos + @scm.stub(:lastrev, build_mock(lastrev, []) { |repo, rev| + assert_equal @repo, repo + assert_equal 'shashasha', rev }) do entries = @scm.entries(nil, 'shashasha', {report_last_commit: true}) assert_equal 'shashasha', entries[0].lastrev.identifier @@ -149,10 +169,11 @@ def test_entries_Githubのreport_last_commitオプションにtrueが与えら def test_revision_to_sha_GithubにコミットのSHAを渡される場合 commit = OctokitCommit.new(sha: 'shashasha') - opt = { per_page: 1 } - Octokit.stub(:commits, build_mock([commit], []) { |repos, rev, opt| - assert_equal @repo, repos + Octokit.stub(:commits, build_mock([commit], []) { |repo, rev, options| + assert_equal @repo, repo + assert_equal 'shashasha', rev + assert_equal 1, options[:per_page] }) do assert_equal 'shashasha', @scm.revision_to_sha('shashasha') end @@ -160,11 +181,11 @@ def test_revision_to_sha_GithubにコミットのSHAを渡される場合 def test_revision_to_sha_Githubにブランチ名を渡される場合 branch = OctokitBranch.new(name: 'main', sha: 'shashasha') - opt = { per_page: 1 } - Octokit.stub(:commits, build_mock([branch], []) { |repos, rev, opt| - assert_equal @repo, repos + Octokit.stub(:commits, build_mock([branch], []) { |repo, rev, options| + assert_equal @repo, repo assert_equal 'main', rev + assert_equal 1, options[:per_page] }) do assert_equal 'shashasha', @scm.revision_to_sha('main') end @@ -176,8 +197,11 @@ def test_lastrev_Githubの戻り値が返ってくる場合 rev = OctokitRevision.new(identifier: 'shashasha', author: author, committer: committer) commit = OctokitCommit.new(sha: 'shashasha', commit: rev ) - Octokit.stub(:commits, build_mock([commit], []) { |repos, rev| - assert_equal @repo, repos + Octokit.stub(:commits, build_mock([commit], []) { |repo, rev, options| + assert_equal @repo, repo + assert_equal 'shashasha', rev + assert_equal @repo, options[:path] + assert_equal 1, options[:per_page] }) do revision = @scm.lastrev('farend/redmine_github_repo', 'shashasha') @@ -188,18 +212,24 @@ def test_lastrev_Githubの戻り値が返ってくる場合 end def test_lastrev_Githubの引数pathが与えられない場合 - Octokit.stub(:commits, build_mock([], []) { |repos, rev| - assert_equal @repo, repos + Octokit.stub(:commits, build_mock([], []) { |repo, rev, options| + assert_equal nil, repo + assert_equal 'shashasha', rev + assert_equal @repo, options[:path] + assert_equal 1, options[:per_page] }) do assert_equal nil, @scm.lastrev(nil, 'shashasha') end end def test_lastrev_Githubの引数に該当するコミットが存在しない場合 - Octokit.stub(:commits, build_mock([], []) { |repos, rev| - assert_equal @repo, repos + Octokit.stub(:commits, build_mock([], []) { |repo, rev, options| + assert_equal @repo, repo + assert_equal 'shashasha', rev + assert_equal @repo, options[:path] + assert_equal 1, options[:per_page] }) do - assert_equal nil, @scm.lastrev('farend/redmine_github_repo', 'shashasha') + assert_equal nil, @scm.lastrev(@repo, 'shashasha') end end @@ -208,14 +238,14 @@ def test_get_path_name_Githubの戻り値が存在する場合 tree = OctokitTree.new(tree:[blob], sha: 'shashasha') commit = OctokitCommit.new(sha: 'shashasha', commit: OctokitRevision.new(tree: tree)) - Octokit.stub(:commits, build_mock([commit], []) { |repos, rev, opt| - assert_equal @repo, repos + Octokit.stub(:commits, build_mock([commit], []) { |repo| + assert_equal @repo, repo }) do - Octokit.stub(:tree, build_mock(tree, []) { |repos, sha| - assert_equal @repo, repos + Octokit.stub(:tree, build_mock(tree, []) { |repo, sha| + assert_equal @repo, repo assert_equal 'shashasha', sha }) do - assert_equal 'farend/redmine_github_repo', @scm.get_path_name('shashasha') + assert_equal @repo, @scm.get_path_name('shashasha') end end end @@ -226,11 +256,11 @@ def test_revisions_Githubの戻り値が1つある場合 parent = OctokitCommit.new(sha: 'shashafrom') rev = OctokitRevision.new(identifier: 'shashato', author: author, committer: committer, message: 'commit message') commit = OctokitCommit.new(sha: 'shashato', commit: rev, parents: [parent]) - opt = { path: @repo, per_page: 1 } - Octokit.stub(:commits, build_mock([commit], []) { |repos, rev| - assert_equal @repo, repos + options = { path: @repo, per_page: 1 } + Octokit.stub(:commits, build_mock([commit], []) { |repo| + assert_equal @repo, repo }) do - revisions = @scm.revisions(@repo, 'shashato', 'shashafrom', opt ) + revisions = @scm.revisions(@repo, 'shashato', 'shashafrom', options ) assert_equal 1, revisions.size assert_equal 'shashato', revisions[0].identifier @@ -250,11 +280,11 @@ def test_revisions_Githubの戻り値が複数ある場合 OctokitCommit.new(sha: "shashasha#{i+1}", commit: rev, parents: parents.dup) } - opt = { path: @repo, per_page: 1 } - Octokit.stub(:commits, build_mock(commits, []) { |repos, rev| - assert_equal @repo, repos + options = { path: @repo, per_page: 1 } + Octokit.stub(:commits, build_mock(commits, []) { |repo| + assert_equal @repo, repo }) do - revisions = @scm.revisions(@repo, 'shashato', 'shashafrom', opt ) + revisions = @scm.revisions(@repo, 'shashato', 'shashafrom', options ) assert_equal 3, revisions.size @@ -276,24 +306,25 @@ def test_revisions_Githubのallオプションにtrueが与えられる場合 committer: committer, message: 'commit message') OctokitCommit.new(sha: "shashasha#{i+1}", commit: rev, parents: parents.dup) } - opt = { path: @repo, per_page: 1, all: true, last_committed_id: 'shashasha3'} - Octokit.stub(:commits, build_mock(commits, []) { |repos, rev| - assert_equal @repo, repos + options = { path: @repo, per_page: 1, all: true, last_committed_id: 'shashasha3'} + Octokit.stub(:commits, build_mock(commits, []) { |repo| + assert_equal @repo, repo }) do - revisions = @scm.revisions(@repo, 'shashasha2', 'shashasha3', opt ) + revisions = @scm.revisions(@repo, 'shashasha2', 'shashasha3', options ) assert_equal 0, revisions.size end end - def test_get_filechanges_and_append_to_Githubにrevisionが渡される場合 + def test_get_filechanges_and_append_to_Githubに1つのrevisisonが渡される場合 add_file = TestFile.new(status: "added", filename: "add.md") mod_file = TestFile.new(status: "modified", filename: "mod.md") rev = OctokitRevision.new(identifier: "shashasha", paths: nil) commit = OctokitCommit.new(sha: "shashasha", files: [add_file, mod_file]) - Octokit.stub(:commit, build_mock(commit, []) { |repos, sha| - assert_equal @repo, repos + Octokit.stub(:commit, build_mock(commit, []) { |repo, sha| + assert_equal @repo, repo + assert_equal "shashasha", sha }) do @scm.get_filechanges_and_append_to([rev]) assert_equal 'A', rev.paths[0][:action] @@ -316,14 +347,17 @@ def test_diff_Githubに追加差分のあるファイルパスとコミットSHA "+#{cat}" ] - Octokit.stub(:commit, build_mock(commit, []) { |repos, sha| - assert_equal @repo, repos + Octokit.stub(:commit, build_mock(commit, []) { |repo, identifier_from, options| + assert_equal @repo, repo + assert_equal 'shashasha', identifier_from + assert_equal @repo, options[:path] }) do @scm.stub(:cat, build_mock(cat, []) { |path, identifier| assert_equal 'farend/redmine_github_repo/README.md', path + assert_equal 'shashasha', identifier }) do - diffs = @scm.diff(@repo, "shashasha") - assert_equal added_diffs, diffs + diffs = @scm.diff(@repo, "shashasha") + assert_equal added_diffs, diffs end end end @@ -347,11 +381,17 @@ def test_diff_Githubにファイル名変更差分のあるファイルパスと "+#{cat}" ] - Octokit.stub(:compare, build_mock(compare, []) { |repos, sha| - assert_equal @repo, repos + ids = ['shashafrom', 'shashato'] + + Octokit.stub(:compare, build_mock(compare, []) { |repo, identifier_to, identifier_from, options| + assert_equal @repo, repo + assert_equal 'shashato', identifier_to + assert_equal 'shashafrom', identifier_from + assert_equal @repo, options[:path] }) do @scm.stub(:cat, build_mock(cat, []) { |path, identifier| assert_equal 'farend/redmine_github_repo/README.md', path + assert_equal ids.shift, identifier }) do diffs = @scm.diff(@repo, 'shashafrom', 'shashato') assert_equal renamed_diffs, diffs @@ -379,11 +419,17 @@ def test_diff_Githubに変更差分のあるファイルパスとコミットSHA "+#{cat}" ] - Octokit.stub(:compare, build_mock(compare, []) { |repos, sha| - assert_equal @repo, repos + ids = ['shashafrom', 'shashato'] + + Octokit.stub(:compare, build_mock(compare, []) { |repo, identifier_to, identifier_from, options| + assert_equal @repo, repo + assert_equal 'shashato', identifier_to + assert_equal 'shashafrom', identifier_from + assert_equal @repo, options[:path] }) do @scm.stub(:cat, build_mock(cat, []) { |path, identifier| assert_equal 'farend/redmine_github_repo/README.md', path + assert_equal ids.shift, identifier }) do diffs = @scm.diff(@repo, "shashafrom", "shashato") assert_equal modified_diffs, diffs @@ -412,11 +458,17 @@ def test_diff_Githubに削除差分のあるファイルパスとコミットSHA "-[]" ] - Octokit.stub(:compare, build_mock(compare, []) { |repos, sha| - assert_equal @repo, repos + ids = ['shashafrom', 'shashato'] + + Octokit.stub(:compare, build_mock(compare, []) { |repo, identifier_to, identifier_from, options| + assert_equal @repo, repo + assert_equal 'shashato', identifier_to + assert_equal 'shashafrom', identifier_from + assert_equal @repo, options[:path] }) do @scm.stub(:cat, build_mock(cat, []) { |path, identifier| assert_equal 'farend/redmine_github_repo/README.md', path + assert_equal ids.shift, identifier }) do diffs = @scm.diff(@repo, "shashafrom", "shashato") assert_equal removed_diffs, diffs @@ -426,16 +478,16 @@ def test_diff_Githubに削除差分のあるファイルパスとコミットSHA def test_default_branch_Githubの戻り値が存在する場合 branch = OctokitBranch.new(name: 'main', commit: OctokitCommit.new(sha: 'shashasha')) - Octokit.stub(:branches, build_mock([branch], []) { |repos, rev| - assert_equal @repo, repos + Octokit.stub(:branches, build_mock([branch], []) { |repo| + assert_equal @repo, repo }) do assert_equal 'main', @scm.default_branch end end def test_default_branch_Githubの戻り値が存在しない場合 - Octokit.stub(:branches, build_mock([], []) { |repos, rev| - assert_equal @repo, repos + Octokit.stub(:branches, build_mock([], []) { |repo| + assert_equal @repo, repo }) do assert_equal nil, @scm.default_branch end @@ -445,8 +497,10 @@ def test_entry_Githubに引数を渡す場合 content = OctokitContent.new(name: 'README.md', path: @repo, type: 'file', size: 256) lastrev = OctokitRevision.new(identifier:'shashasha') - Octokit.stub(:contents, build_mock([content], []) { |repos, path, ref| - assert_equal @repo, repos + Octokit.stub(:contents, build_mock([content], []) { |repo, options| + assert_equal @repo, repo + assert_equal 'README.md', options[:path] + assert_equal 'HEAD', options[:ref] }) do @scm.stub(:lastrev, build_mock(lastrev, []) { |repos, rev| assert_equal @repo, repos @@ -461,8 +515,10 @@ def test_entry_Githubに引数を渡す場合 end def test_entry_Githubに引数を渡さない場合 - Octokit.stub(:contents, build_mock([], []) { |repos, path, ref| - assert_equal @repo, repos + Octokit.stub(:contents, build_mock([], []) { |repo, options| + assert_equal @repo, repo + assert_equal @repo, options[:path] + assert_equal 'HEAD', options[:ref] }) do entry = @scm.entry assert_equal 'dir', entry.kind @@ -471,50 +527,56 @@ def test_entry_Githubに引数を渡さない場合 end def test_cat_Githubで取得ファイルのエンコードが不要な場合 - blob = OctokitContent.new(path: @repos, sha: 'shashasha', download_url: 'http://download/url', + blob = OctokitContent.new(path: @repo, sha: 'shashasha', download_url: 'http://download/url', encoding: 'utf-8', content: 'test_content') get = OctokitGet.new(headers:{ "content-type" => 'text/html; charset=utf-8'}) - Octokit.stub(:contents, build_mock(blob, []) { |repos, path, ref| - assert_equal @repo, repos + Octokit.stub(:contents, build_mock(blob, []) { |path, options| + assert_equal @repo, path + assert_equal @repo, options[:path] + assert_equal 'HEAD', options[:ref] }) do Octokit.stub(:get, build_mock(get, []) { |url| assert_equal 'http://download/url', url }) do Octokit.stub(:last_response, build_mock(get, [])) do - assert_equal 'test_content', @scm.cat(@repos) + assert_equal 'test_content', @scm.cat(@repo) end end end end - def test_cat_Githubで取得ファイルがエンコードが必要な場合 - blob = OctokitContent.new(path: @repos, sha: 'shashasha', download_url: 'http://download/url', + def test_cat_Githubで取得ファイルのエンコードが必要な場合 + blob = OctokitContent.new(path: @repo, sha: 'shashasha', download_url: 'http://download/url', encoding: 'base64', content: 'dGVzdF9jb250ZW50') get = OctokitGet.new(headers:{ "content-type" => 'text/html; charset=base64'}) - Octokit.stub(:contents, build_mock(blob, []) { |repos, path, ref| - assert_equal @repo, repos + Octokit.stub(:contents, build_mock(blob, []) { |path, options| + assert_equal @repo, path + assert_equal @repo, options[:path] + assert_equal 'HEAD', options[:ref] }) do Octokit.stub(:get, build_mock(get, []) { |url| assert_equal 'http://download/url', url }) do Octokit.stub(:last_response, build_mock(get, [])) do - assert_equal 'test_content', @scm.cat(@repos) + assert_equal 'test_content', @scm.cat(@repo) end end end end def test_cat_Githubで取得ファイルがバイナリ形式の場合 - blob = OctokitContent.new(path: @repos, sha: 'shashasha', download_url: 'http://download/url') + blob = OctokitContent.new(path: @repo, sha: 'shashasha', download_url: 'http://download/url') get = OctokitGet.new(headers:{ "content-type" => 'binary'}) - Octokit.stub(:contents, build_mock(blob, []) { |repos, path, ref| - assert_equal @repo, repos + Octokit.stub(:contents, build_mock(blob, []) { |path, options| + assert_equal @repo, path + assert_equal @repo, options[:path] + assert_equal 'HEAD', options[:ref] }) do Octokit.stub(:get, build_mock(get, []) { |url| assert_equal 'http://download/url', url }) do Octokit.stub(:last_response, build_mock(get, [])) do - assert_equal '', @scm.cat(@repos) + assert_equal '', @scm.cat(@repo) end end end @@ -524,14 +586,17 @@ def test_cat_Githubで取得ファイルがバイナリ形式の場合 OctokitBranch = Struct.new(:name, :commit, :sha, keyword_init: true) OctokitCommit = Struct.new(:sha, :commit, :parents, :files, keyword_init: true) - OctokitContent = Struct.new(:sha, :name, :path, :type, :size, :download_url, :content, :encoding, keyword_init: true) - OctokitRevision = Struct.new(:identifier, :author, :committer, :tree, :message, :paths, keyword_init: true) + OctokitContent = Struct.new(:sha, :name, :path, :type, :size, :download_url, + :content, :encoding, keyword_init: true) + OctokitRevision = Struct.new(:identifier, :author, :committer, :tree, + :message, :paths, keyword_init: true) OctokitAuthor = Struct.new(:name, keyword_init: true) OctokitCommiter = Struct.new(:date, keyword_init: true) OctokitTree = Struct.new(:tree, :sha, keyword_init: true) OctokitCompare = Struct.new(:base_commit, :commits, :files, keyword_init: true) OctokitGet = Struct.new(:headers, keyword_init: true) - TestFile = Struct.new(:status, :filename, :previous_filename, :from_revision, :patch, keyword_init: true) + TestFile = Struct.new(:status, :filename, :previous_filename, + :from_revision, :patch, keyword_init: true) def build_mock(*returns, &proc) mock = Minitest::Mock.new From e47c4391645f13d5107cabf59791e4b93aca0907 Mon Sep 17 00:00:00 2001 From: HiroyasuTawara Date: Fri, 13 Oct 2023 05:19:59 +0000 Subject: [PATCH 08/17] =?UTF-8?q?github=E3=83=A2=E3=83=87=E3=83=AB?= =?UTF-8?q?=E3=81=AE=E3=83=A1=E3=82=BD=E3=83=83=E3=83=89=E6=A6=82=E8=A6=81?= =?UTF-8?q?=E3=82=B3=E3=83=A1=E3=83=B3=E3=83=88=E3=82=92=E8=BF=BD=E5=8A=A0?= =?UTF-8?q?,=E3=81=8A=E3=82=88=E3=81=B3=E3=83=86=E3=82=B9=E3=83=88?= =?UTF-8?q?=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB=E3=82=92=E4=BD=9C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/repository/github.rb | 13 +++++++++++++ test/unit/github_test.rb | 19 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 test/unit/github_test.rb diff --git a/app/models/repository/github.rb b/app/models/repository/github.rb index f0c0845..7e4eed3 100644 --- a/app/models/repository/github.rb +++ b/app/models/repository/github.rb @@ -34,6 +34,7 @@ def branches scm.branches end + # リモートリポジトリの最新状況を取得し、changesetに反映する def fetch_changesets(options = {}) opts = options.merge({ last_committed_date: extra_info&.send(:[], "last_committed_date"), @@ -56,6 +57,8 @@ def fetch_changesets(options = {}) save(validate: false) end + # revisionオブジェクトの配列を引数に受け取る + # 引数に未反映のrevisionが含まれる場合、changesetオブジェクトを作成し保存・更新を行う def save_revisions!(revisions, revisions_copy) limit = 100 offset = 0 @@ -96,6 +99,8 @@ def save_revisions!(revisions, revisions_copy) end private :save_revisions! + # nameにコミットのSHAを受け取る + # nameにリビジョン名が一致する、もしくは部分一致するscmidを持つchangeset一件を返す def find_changeset_by_name(name) if name.present? changesets.find_by(revision: name.to_s) || @@ -103,6 +108,9 @@ def find_changeset_by_name(name) end end + # pathにファイルパス、identifierにコミットのshaを受け取る + # scmから引数に該当するエントリを配列で返す + # 既にキャッシュが存在し引数が空でないなら、root階層ファイルセットの参照時キャッシュを使用する def scm_entries(path=nil, identifier=nil) is_using_cache = using_root_fileset_cache?(path, identifier) @@ -152,6 +160,8 @@ def scm_entries(path=nil, identifier=nil) entries end + # pathにファイルパス、revにコミットのshaを受け取る + # rev時点のpath以下のファイルに該当するchengesetsを取得し配列で返す def latest_changesets(path, rev, limit = 10) revisions = scm.revisions(path, nil, rev, :limit => limit, :all => false) @@ -177,6 +187,9 @@ def default_branch def properties(path, rev) end + # scm_entries内でroot階層ファイルセットの参照にキャッシュを使用するための判定 + # 引数が与えられなければfalseを返す + # trueを返す場合、identifierにデフォルトブランチを代入する def using_root_fileset_cache?(path, identifier) return false if path.present? return false if identifier.blank? diff --git a/test/unit/github_test.rb b/test/unit/github_test.rb new file mode 100644 index 0000000..22d379c --- /dev/null +++ b/test/unit/github_test.rb @@ -0,0 +1,19 @@ +require File.expand_path('../../test_helper', __FILE__) + +class GithubTest < ActiveSupport::TestCase + def setup + @scm = Redmine::Scm::Adapters::GithubAdapter.new('https://github.com/farend/redmine_github_repo.git') + @repo = "farend/redmine_github_repo" + end + + ## 以下、Octokitのモックに使う部品たち ## + + def build_mock(*returns, &proc) + mock = Minitest::Mock.new + Array.wrap(returns).each do |ret| + mock.expect(:call, ret, &proc) + end + mock + end + +end \ No newline at end of file From 81f5649d888fbe1156dc99c516df93b016866c33 Mon Sep 17 00:00:00 2001 From: HiroyasuTawara Date: Fri, 13 Oct 2023 08:20:59 +0000 Subject: [PATCH 09/17] =?UTF-8?q?github=E3=83=A2=E3=83=87=E3=83=AB?= =?UTF-8?q?=E3=81=AB=E3=83=86=E3=82=B9=E3=83=88=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/unit/github_test.rb | 80 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/test/unit/github_test.rb b/test/unit/github_test.rb index 22d379c..5283c83 100644 --- a/test/unit/github_test.rb +++ b/test/unit/github_test.rb @@ -2,11 +2,89 @@ class GithubTest < ActiveSupport::TestCase def setup - @scm = Redmine::Scm::Adapters::GithubAdapter.new('https://github.com/farend/redmine_github_repo.git') + @repository = Repository::Github.new(project_id: 1, url: 'https://github.com/farend/redmine_github_repo.git', identifier: 'test_project') + @scm = @repository.scm @repo = "farend/redmine_github_repo" end + def test_fetch_changesets_Githubでchangesetsが追加される場合 + author = OctokitAuthor.new(name: 'author_name') + rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: author, paths: nil, time: Time.local(2023, 1, 1, 0, 0, 0, 0), message: 'tmessage') + changesets = [] + changeset = RepositoryChangeset.new( + repository: @repository, + revision: rev.identifier, + scmid: rev.scmid, + comitter: rev.author, + committed_on: rev.time, + comments: rev.message + ) + + @scm.stub(:revisions, build_mock([rev], []) { |path, identifier_from, identifier_to| + assert_equal '', path + assert_equal nil, identifier_from + assert_equal nil, identifier_to + }) do + @repository.stub(:save_revisions!, build_mock([], []) { |revisions, revisions_copy| + assert_equal [rev], revisions + changesets << changeset + }) do + @repository.fetch_changesets + extra_info = changesets[0][:repository][:extra_info] + assert_equal @repository, changesets[0][:repository] + assert_equal '2023-01-01T00:00:00Z', extra_info['last_committed_date'] + assert_equal 'shashasha', extra_info['last_committed_id'] + end + end + end + + def test_fetch_changesets_Githubでchangesetsに変更が加わる場合 + author = OctokitAuthor.new(name: 'author_name') + rev_from = OctokitRevision.new(identifier: 'shashafrom', scmid: 'shashafrom', author: author, paths: nil, time: Time.local(2023, 1, 1, 0, 0, 0, 0), message: 'frommessage') + rev_to = OctokitRevision.new(identifier: 'shashato', scmid: 'shashato', author: author, paths: nil, time: Time.local(2023, 12, 31, 23, 59, 59, 0), message: 'tomessage') + changeset_from = RepositoryChangeset.new( + repository: @repository, + revision: rev_from.identifier, + scmid: rev_from.scmid, + comitter: rev_from.author, + committed_on: rev_from.time, + comments: rev_from.message + ) + changeset_to = RepositoryChangeset.new( + repository: @repository, + revision: rev_to.identifier, + scmid: rev_to.scmid, + comitter: rev_to.author, + committed_on: rev_to.time, + comments: rev_to.message + ) + changesets = [changeset_from] + + @scm.stub(:revisions, build_mock([rev_from, rev_to], []) { |path, identifier_from, identifier_to| + assert_equal '', path + assert_equal nil, identifier_from + assert_equal nil, identifier_to + }) do + @repository.stub(:save_revisions!, build_mock([], []) { |revisions, revisions_copy| + assert_equal [rev_from, rev_to], revisions + changesets[0] = changeset_to + }) do + @repository.fetch_changesets + extra_info = changesets[0][:repository][:extra_info] + assert_equal @repository, changesets[0][:repository] + assert_equal '2023-12-31T23:59:59Z', extra_info['last_committed_date'] + assert_equal 'shashato', extra_info['last_committed_id'] + end + end + end + ## 以下、Octokitのモックに使う部品たち ## + RepositoryChangeset = Struct.new(:repository, :revision, :scmid, :comitter, :committed_on, :comments, keyword_init: true) + + OctokitRevision = Struct.new(:identifier, :scmid, :author, :committer, :tree, + :message, :paths, :time, keyword_init: true) + OctokitAuthor = Struct.new(:name, keyword_init: true) + def build_mock(*returns, &proc) mock = Minitest::Mock.new From 9119cdd8fc17e4be400a248acbb7439824e74df1 Mon Sep 17 00:00:00 2001 From: HiroyasuTawara Date: Tue, 17 Oct 2023 01:12:22 +0000 Subject: [PATCH 10/17] =?UTF-8?q?github=E3=83=A2=E3=83=87=E3=83=AB?= =?UTF-8?q?=E3=81=AE=E3=83=86=E3=82=B9=E3=83=88=E3=83=BBfixture=E3=82=92?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/repository/github.rb | 5 +- lib/redmine/scm/adapters/github_adapter.rb | 2 +- test/fixtures/changesets.yml | 10 + test/fixtures/repositories.yml | 14 + test/test_helper.rb | 17 ++ test/unit/github_test.rb | 289 +++++++++++++++++---- 6 files changed, 282 insertions(+), 55 deletions(-) create mode 100644 test/fixtures/changesets.yml create mode 100644 test/fixtures/repositories.yml diff --git a/app/models/repository/github.rb b/app/models/repository/github.rb index 7e4eed3..42a6dee 100644 --- a/app/models/repository/github.rb +++ b/app/models/repository/github.rb @@ -44,7 +44,7 @@ def fetch_changesets(options = {}) revisions = scm.revisions('', nil, nil, opts) revisions_copy = revisions.clone # revisions will change - + return if revisions.blank? save_revisions!(revisions, revisions_copy) @@ -140,7 +140,6 @@ def scm_entries(path=nil, identifier=nil) # Not found in cache, get entries from SCM if entries.blank? entries = scm.entries(path, identifier, :report_last_commit => report_last_commit) - # Save as cache if changeset.present? GithubAdapterRootFileset.where(repository_id: self.id, revision: identifier).delete_all @@ -169,7 +168,7 @@ def latest_changesets(path, rev, limit = 10) if rev != default_branch # Branch that is not default doesn't be synced automatically. so, save it here. - save_revisions!(revisions, revisions.dup) + save_revisions!(revisions.dup, revisions.dup) end changesets.where(:scmid => revisions.map {|c| c.scmid}).to_a diff --git a/lib/redmine/scm/adapters/github_adapter.rb b/lib/redmine/scm/adapters/github_adapter.rb index c2e36f8..ab4ee41 100644 --- a/lib/redmine/scm/adapters/github_adapter.rb +++ b/lib/redmine/scm/adapters/github_adapter.rb @@ -181,7 +181,7 @@ def revisions(path, identifier_from, identifier_to, options={}) raise CommandFailed, handle_octokit_error(e) end - # 複数のrevisionオブジェクトをを配列として受け取り、該当コミットの変更状況をhashにする + # 複数のrevisionオブジェクトを配列として受け取り、該当コミットの変更状況をhashにする # 作成したhashを各revisionオブジェクトのpathsパラメータに追記する def get_filechanges_and_append_to(revisions) revisions.each do |revision| diff --git a/test/fixtures/changesets.yml b/test/fixtures/changesets.yml new file mode 100644 index 0000000..fdb95c4 --- /dev/null +++ b/test/fixtures/changesets.yml @@ -0,0 +1,10 @@ +default: + id: 1 + repository_id: 1 + revision: 'shashasha' + committer: 'author_name' + committed_on: 2023-01-01 + comments: 'message' + commit_date: 2023-01-01 + scmid: 'shashasha' + user_id: \ No newline at end of file diff --git a/test/fixtures/repositories.yml b/test/fixtures/repositories.yml new file mode 100644 index 0000000..134c53e --- /dev/null +++ b/test/fixtures/repositories.yml @@ -0,0 +1,14 @@ +default: + id: 1 + project_id: 1 + url: 'https://github.com/farend/redmine_github_repo.git' + login: '' + password: '' + identifier: 'test_project' + type: 'Repository::Github' + path_encoding: nil + log_encoding: nil + is_default: true + extra_info: + 'last_committed_date': '' + 'last_committed_id': '' diff --git a/test/test_helper.rb b/test/test_helper.rb index ea19ced..9b8f301 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,3 +1,20 @@ # Load the Redmine helper require 'minitest/mock' require File.expand_path(File.dirname(__FILE__) + '/../../../test/test_helper') + +module Redmine + module PluginFixturesLoader + def self.included(base) + base.class_eval do + def self.plugin_fixtures(*symbols) + ActiveRecord::FixtureSet.create_fixtures(File.dirname(__FILE__) + '/fixtures/', symbols) + end + end + end + end +end + +## ユニットテスト +unless ActiveSupport::TestCase.included_modules.include?(Redmine::PluginFixturesLoader) + ActiveSupport::TestCase.send :include, Redmine::PluginFixturesLoader +end \ No newline at end of file diff --git a/test/unit/github_test.rb b/test/unit/github_test.rb index 5283c83..07c8183 100644 --- a/test/unit/github_test.rb +++ b/test/unit/github_test.rb @@ -1,90 +1,277 @@ require File.expand_path('../../test_helper', __FILE__) class GithubTest < ActiveSupport::TestCase + plugin_fixtures :repositories, :changesets + def setup - @repository = Repository::Github.new(project_id: 1, url: 'https://github.com/farend/redmine_github_repo.git', identifier: 'test_project') + @repository = Repository::Github.find(1) + @changeset = Changeset.find(1) @scm = @repository.scm @repo = "farend/redmine_github_repo" end def test_fetch_changesets_Githubでchangesetsが追加される場合 - author = OctokitAuthor.new(name: 'author_name') - rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: author, paths: nil, time: Time.local(2023, 1, 1, 0, 0, 0, 0), message: 'tmessage') - changesets = [] - changeset = RepositoryChangeset.new( - repository: @repository, - revision: rev.identifier, - scmid: rev.scmid, - comitter: rev.author, - committed_on: rev.time, - comments: rev.message - ) + file = TestFile.new(status: "added", filename: "README.md") + rev = OctokitRevision.new(identifier: 'shashasha2', scmid: 'shashasha2', author: OctokitAuthor.new(name: 'author_name'), + parents: ['shashasha'], paths: nil, time: Time.gm(2023, 2, 1), message: 'added') + commit = OctokitCommit.new(sha: 'shashasha2', files: [file], parents: OctokitCommit.new(sha: 'shashasha')) @scm.stub(:revisions, build_mock([rev], []) { |path, identifier_from, identifier_to| assert_equal '', path assert_equal nil, identifier_from assert_equal nil, identifier_to }) do - @repository.stub(:save_revisions!, build_mock([], []) { |revisions, revisions_copy| - assert_equal [rev], revisions - changesets << changeset + Octokit.stub(:commit, build_mock(commit, []) { |repo, identifier| + assert_equal @repo, repo + assert_equal 'shashasha2', identifier }) do @repository.fetch_changesets - extra_info = changesets[0][:repository][:extra_info] - assert_equal @repository, changesets[0][:repository] + assert_equal 2, @repository.changesets.size + assert_equal @repository.id, @repository.changesets.last[:repository_id] + + extra_info = @repository[:extra_info] + + assert_equal '2023-02-01T00:00:00Z', extra_info['last_committed_date'] + assert_equal 'shashasha2', extra_info['last_committed_id'] + end + end + end + + def test_fetch_changesets_Githubでchangesetsに追加が無い場合 + rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: OctokitAuthor.new(name: 'author_name'), + paths: nil, time: Time.gm(2023, 1, 1), message: 'message') + + @scm.stub(:revisions, build_mock([rev], []) { |path, identifier_from, identifier_to| + assert_equal '', path + assert_equal nil, identifier_from + assert_equal nil, identifier_to + }) do + @repository.fetch_changesets + assert_equal 1, @repository.changesets.size + assert_equal @repository.id, @repository.changesets.last[:repository_id] + + extra_info = @repository[:extra_info] + assert_equal '2023-01-01T00:00:00Z', extra_info['last_committed_date'] assert_equal 'shashasha', extra_info['last_committed_id'] - end end end - def test_fetch_changesets_Githubでchangesetsに変更が加わる場合 - author = OctokitAuthor.new(name: 'author_name') - rev_from = OctokitRevision.new(identifier: 'shashafrom', scmid: 'shashafrom', author: author, paths: nil, time: Time.local(2023, 1, 1, 0, 0, 0, 0), message: 'frommessage') - rev_to = OctokitRevision.new(identifier: 'shashato', scmid: 'shashato', author: author, paths: nil, time: Time.local(2023, 12, 31, 23, 59, 59, 0), message: 'tomessage') - changeset_from = RepositoryChangeset.new( - repository: @repository, - revision: rev_from.identifier, - scmid: rev_from.scmid, - comitter: rev_from.author, - committed_on: rev_from.time, - comments: rev_from.message - ) - changeset_to = RepositoryChangeset.new( - repository: @repository, - revision: rev_to.identifier, - scmid: rev_to.scmid, - comitter: rev_to.author, - committed_on: rev_to.time, - comments: rev_to.message - ) - changesets = [changeset_from] - - @scm.stub(:revisions, build_mock([rev_from, rev_to], []) { |path, identifier_from, identifier_to| + def test_save_revisions_Githubでchangesetsが保存される場合 + rev = OctokitRevision.new(identifier: 'shashasha2', scmid: 'shashasha2', author: OctokitAuthor.new(name: 'author_name'), + parents: ['shashasha'], paths: nil, time: Time.gm(2023, 2, 1), message: 'added') + file = TestFile.new(status: "added", filename: "README.md") + commit = OctokitCommit.new(sha: 'shashasha2', files: [file], parents: OctokitCommit.new(sha: 'shashasha')) + + @scm.stub(:revisions, build_mock([rev], []) { |path, identifier_from, identifier_to| assert_equal '', path assert_equal nil, identifier_from assert_equal nil, identifier_to }) do - @repository.stub(:save_revisions!, build_mock([], []) { |revisions, revisions_copy| - assert_equal [rev_from, rev_to], revisions - changesets[0] = changeset_to + Octokit.stub(:commit, build_mock(commit, []) { |repo, identifier| + assert_equal @repo, repo + assert_equal 'shashasha2', identifier }) do @repository.fetch_changesets - extra_info = changesets[0][:repository][:extra_info] - assert_equal @repository, changesets[0][:repository] - assert_equal '2023-12-31T23:59:59Z', extra_info['last_committed_date'] - assert_equal 'shashato', extra_info['last_committed_id'] + assert_equal 2, @repository.changesets.size + assert_equal @repository.id, @repository.changesets.last[:repository_id] + + extra_info = @repository[:extra_info] + + assert_equal '2023-02-01T00:00:00Z', extra_info['last_committed_date'] + assert_equal 'shashasha2', extra_info['last_committed_id'] end end end - ## 以下、Octokitのモックに使う部品たち ## - RepositoryChangeset = Struct.new(:repository, :revision, :scmid, :comitter, :committed_on, :comments, keyword_init: true) + def test_fetch_changesets_Githubでchangesetsが保存されない場合 + rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: OctokitAuthor.new(name: 'author_name'), + paths: nil, time: Time.gm(2023, 1, 1), message: 'message') + + @scm.stub(:revisions, build_mock([rev], []) { |path, identifier_from, identifier_to| + assert_equal '', path + assert_equal nil, identifier_from + assert_equal nil, identifier_to + }) do + @repository.fetch_changesets + assert_equal 1, @repository.changesets.size + assert_equal @repository.id, @repository.changesets.last[:repository_id] + + extra_info = @repository[:extra_info] + + assert_equal '2023-01-01T00:00:00Z', extra_info['last_committed_date'] + assert_equal 'shashasha', extra_info['last_committed_id'] + end + end + + def test_find_changeset_by_name_Githubで引数にリビジョン名が一致するchangesetが存在する場合 + found_changeset = @repository.find_changeset_by_name('shashasha') + assert_equal @changeset, found_changeset + end + + def test_find_changeset_by_name_Githubで引数にscmidが部分一致するchangesetが存在する場合 + found_changeset = @repository.find_changeset_by_name('sha') + assert_equal @changeset, found_changeset + end + + def test_find_changeset_by_name_Githubで引数に該当するchangesetが存在しない場合 + found_changeset = @repository.find_changeset_by_name('ahsahsahs') + assert_equal nil, found_changeset + end + + def test_scm_entries_Githubでキャッシュが存在しない場合 + rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: OctokitAuthor.new(name: 'author_name'), + paths: nil, time: Time.gm(2023, 1, 1), message: 'message') + entry =RepositoryEntry.new(path: "README.md", size: 256, lastrev: rev.identifier) + + + @scm.stub(:entries, build_mock([entry], []) { |repository_id, revision| + assert_equal 'README.md', repository_id + assert_equal 'shashasha', revision + }) do + entries = @repository.scm_entries('README.md', 'shashasha') + + assert_equal 1, entries.size + assert_equal 'README.md', entries[0].path + assert_equal 256, entries[0].size + assert_equal 'shashasha', entries[0].lastrev + assert_equal 0, GithubAdapterRootFileset.all.size + end + end + + def test_scm_entries_Githubでキャッシュが存在する場合 + rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: OctokitAuthor.new(name: 'author_name'), + paths: nil, time: Time.gm(2023, 1, 1), message: 'message') + entry = RepositoryEntry.new(path: "README.md", size: 256, lastrev: rev.identifier) + + GithubAdapterRootFileset.create!( + repository_id: @repository.id, + revision: rev.identifier, + changeset_id: @changeset.id, + path: entry.path, + size: entry.size, + latest_commitid: rev.identifier + ) + + @scm.stub(:revision_to_sha, build_mock('shashasha', []) { |identifier| + assert_equal 'shashasha', identifier + }) do + @scm.stub(:entries, build_mock([entry], []) { |repository_id, revision| + assert_equal 'README.md', repository_id + assert_equal 'shashasha', revision + }) do + entries = @repository.scm_entries('README.md', 'shashasha') + + assert_equal 1, entries.size + assert_equal 'README.md', entries[0].path + assert_equal 256, entries[0].size + assert_equal 'shashasha', entries[0].lastrev + assert_equal 1, GithubAdapterRootFileset.all.size + end + end + end + + def test_latest_changesets_Githubでchangesetが追加されない場合 + rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: OctokitAuthor.new(name: 'author_name'), + paths: nil, time: Time.gm(2023, 1, 1), message: 'message') + + @scm.stub(:revisions, build_mock([rev], []) { |path, identifier_from, identifier_to| + assert_equal 'README.md', path + assert_equal nil, identifier_from + assert_equal 'shashasha', identifier_to + }) do + @repository.stub(:default_branch, build_mock('shashasha', [])) do + latest_changesets = @repository.latest_changesets('README.md', 'shashasha') + + assert_equal 1, latest_changesets.size + assert_equal 'shashasha', latest_changesets.first.revision + assert_equal 'shashasha', latest_changesets.first.scmid + assert_equal 'message', latest_changesets.first.comments + assert_equal Time.gm(2023, 1, 1), latest_changesets.first.committed_on + end + end + end + def test_latest_changesets_Githubで一件のchangesetが追加される場合 + rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: OctokitAuthor.new(name: 'author_name'), + paths: nil, time: Time.gm(2023, 1, 1), message: 'message') + latest_rev = OctokitRevision.new(identifier: 'shashalatest', scmid: 'shashalatest', author: OctokitAuthor.new(name: 'author_name'), + paths: nil, time: Time.gm(2023, 2, 1), message: 'latest') + @repository.changesets << changeset(latest_rev) + + @scm.stub(:revisions, build_mock([rev, latest_rev], []) { |path, identifier_from, identifier_to| + assert_equal 'README.md', path + assert_equal nil, identifier_from + assert_equal 'shashalatest', identifier_to + }) do + @repository.stub(:default_branch, build_mock('shashalatest', [])) do + latest_changesets = @repository.latest_changesets('README.md', 'shashalatest') + + assert_equal 2, latest_changesets.size + assert_equal 'shashalatest', latest_changesets.first.revision + assert_equal 'shashalatest', latest_changesets.first.scmid + assert_equal 'latest', latest_changesets.first.comments + assert_equal Time.gm(2023, 2, 1), latest_changesets.first.committed_on + end + end + end + + def test_latest_changesets_Githubで対象のpathがデフォルトブランチではない場合 + rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: OctokitAuthor.new(name: 'author_name'), + paths: nil, time: Time.gm(2023, 1, 1), message: 'message') + latest_rev = OctokitRevision.new(identifier: 'shashalatest', scmid: 'shashalatest', author: OctokitAuthor.new(name: 'author_name'), + paths: nil, time: Time.gm(2023, 2, 1), message: 'latest') + file = TestFile.new(status: "added", filename: "README.md") + + commit = OctokitCommit.new(sha: 'shashalatest', files: [file], parents: OctokitCommit.new(sha: 'shashasha')) + + @scm.stub(:revisions, build_mock([rev, latest_rev], []) { |path, identifier_from, identifier_to| + assert_equal 'README.md', path + assert_equal nil, identifier_from + assert_equal 'shashalatest', identifier_to + }) do + @repository.stub(:default_branch, build_mock('main', [])) do + Octokit.stub(:commit, build_mock(commit, []) { |repo, identifier| + assert_equal @repo, repo + assert_equal 'shashalatest', identifier + }) do + latest_changesets = @repository.latest_changesets('README.md', 'shashalatest') + + assert_equal 2, latest_changesets.size + assert_equal 'shashalatest', latest_changesets.first.revision + assert_equal 'shashalatest', latest_changesets.first.scmid + assert_equal 'latest', latest_changesets.first.comments + assert_equal Time.gm(2023, 2, 1), latest_changesets.first.committed_on + end + end + end + end + + ## 以下、Octokitのモックに使う部品たち ## + RepositoryChangeset = Struct.new(:repository, :id, :revision, :scmid, :comitter, + :committed_on, :comments, keyword_init: true) + RepositoryEntry = Struct.new(:path, :size, :lastrev, keyword_init: true) OctokitRevision = Struct.new(:identifier, :scmid, :author, :committer, :tree, - :message, :paths, :time, keyword_init: true) + :message, :paths, :time, :parents, keyword_init: true) + OctokitCommit = Struct.new(:sha, :commit, :parents, :files, keyword_init: true) + OctokitContent = Struct.new(:sha, :name, :path, :type, :size, :download_url, + :content, :encoding, keyword_init: true) OctokitAuthor = Struct.new(:name, keyword_init: true) + RootFilesetCache = Struct.new(:repository_id, :revision, :changeset_id, :path, + :size, :latest_comitted, keyword_init: true) + TestFile = Struct.new(:status, :filename, :previous_filename, + :from_revision, :patch, keyword_init: true) + def changeset(rev) + Changeset.new( + repository: @repository, + revision: rev.identifier, + scmid: rev.scmid, + committer: rev.author, + committed_on: rev.time, + comments: rev.message + ) + end def build_mock(*returns, &proc) mock = Minitest::Mock.new From 04a6e884b83954f2dfd0d7a86d53be733dcbedbc Mon Sep 17 00:00:00 2001 From: HiroyasuTawara Date: Tue, 17 Oct 2023 05:51:18 +0000 Subject: [PATCH 11/17] =?UTF-8?q?=E3=83=86=E3=82=B9=E3=83=88=E3=81=AE?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0=E3=83=BB=E3=82=B3=E3=83=A1=E3=83=B3=E3=83=88?= =?UTF-8?q?=E3=82=92=E5=90=AB=E3=82=81=E4=B8=80=E9=83=A8=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/repository/github.rb | 9 +- lib/redmine/scm/adapters/github_adapter.rb | 5 +- test/unit/github_adapter_test.rb | 28 +-- test/unit/github_test.rb | 206 ++++++++++++++------- 4 files changed, 153 insertions(+), 95 deletions(-) diff --git a/app/models/repository/github.rb b/app/models/repository/github.rb index 42a6dee..70c1864 100644 --- a/app/models/repository/github.rb +++ b/app/models/repository/github.rb @@ -34,7 +34,7 @@ def branches scm.branches end - # リモートリポジトリの最新状況を取得し、changesetに反映する + # リモートリポジトリの最新状況を取得し、changesetsに反映する def fetch_changesets(options = {}) opts = options.merge({ last_committed_date: extra_info&.send(:[], "last_committed_date"), @@ -159,8 +159,9 @@ def scm_entries(path=nil, identifier=nil) entries end - # pathにファイルパス、revにコミットのshaを受け取る + # pathにファイルパス、revにコミットのshaもしくはブランチ名を受け取る # rev時点のpath以下のファイルに該当するchengesetsを取得し配列で返す + # revがデフォルトブランチ名以外の場合、未反映のrevisionを保存しchangesetを追加する def latest_changesets(path, rev, limit = 10) revisions = scm.revisions(path, nil, rev, :limit => limit, :all => false) @@ -187,8 +188,8 @@ def properties(path, rev) end # scm_entries内でroot階層ファイルセットの参照にキャッシュを使用するための判定 - # 引数が与えられなければfalseを返す - # trueを返す場合、identifierにデフォルトブランチを代入する + # 引数が与えられない場合・キャッシュが存在しない場合はfalseを返す + # キャッシュが見つからない場合でも、identifierがデフォルトブランチ名と一致するならtrueを返す def using_root_fileset_cache?(path, identifier) return false if path.present? return false if identifier.blank? diff --git a/lib/redmine/scm/adapters/github_adapter.rb b/lib/redmine/scm/adapters/github_adapter.rb index ab4ee41..d176ade 100644 --- a/lib/redmine/scm/adapters/github_adapter.rb +++ b/lib/redmine/scm/adapters/github_adapter.rb @@ -114,9 +114,9 @@ def get_path_name(path) raise CommandFailed, handle_octokit_error(e) end - # pathにファイル・ディレクトリのパス, identifier_from/identifier_toにコミットのSHAを受け取る - # allオプションがtrueの場合、 + # pathにファイル・ディレクトリのパス, identifier_from/identifier_toにコミットのshaを受け取る # 引数で与えられた条件に合致するコミットをRevisionオブジェクトの配列として返す + # allオプションがtrueの場合、リポジトリの全てのrevisionを取得する # 配列はコミット日時の降順でソートされる def revisions(path, identifier_from, identifier_to, options={}) path ||= '' @@ -132,7 +132,6 @@ def revisions(path, identifier_from, identifier_to, options={}) 0.step do |i| start_page = i * MAX_PAGES + 1 github_commits = Octokit.commits(@repos, api_opts.merge(page: start_page)) - # if fetched latest commit, github_commits.length is 1, and github_commits[0][:sha] == latest_committed_id return [] if i == 0 && github_commits.none?{ |commit| commit.sha != options[:last_committed_id] } diff --git a/test/unit/github_adapter_test.rb b/test/unit/github_adapter_test.rb index 5a8f13e..542d443 100644 --- a/test/unit/github_adapter_test.rb +++ b/test/unit/github_adapter_test.rb @@ -285,7 +285,7 @@ def test_revisions_Githubの戻り値が複数ある場合 assert_equal @repo, repo }) do revisions = @scm.revisions(@repo, 'shashato', 'shashafrom', options ) - + assert_equal 3, revisions.size revisions.each_with_index {|rev, i| @@ -296,26 +296,6 @@ def test_revisions_Githubの戻り値が複数ある場合 end end - def test_revisions_Githubのallオプションにtrueが与えられる場合 - parents = [] - commits = 3.times.map { |i| - author = OctokitAuthor.new(name: "Author#{i}") - committer = OctokitCommiter.new(date: "2023-01-00 0#{i}:00:00") - parents << OctokitCommit.new(sha: "shashasha#{i}") - rev = OctokitRevision.new(identifier: "shashasha#{i+1}", author: author, - committer: committer, message: 'commit message') - OctokitCommit.new(sha: "shashasha#{i+1}", commit: rev, parents: parents.dup) - } - options = { path: @repo, per_page: 1, all: true, last_committed_id: 'shashasha3'} - Octokit.stub(:commits, build_mock(commits, []) { |repo| - assert_equal @repo, repo - }) do - revisions = @scm.revisions(@repo, 'shashasha2', 'shashasha3', options ) - - assert_equal 0, revisions.size - end - end - def test_get_filechanges_and_append_to_Githubに1つのrevisisonが渡される場合 add_file = TestFile.new(status: "added", filename: "add.md") mod_file = TestFile.new(status: "modified", filename: "mod.md") @@ -362,7 +342,7 @@ def test_diff_Githubに追加差分のあるファイルパスとコミットSHA end end - def test_diff_Githubにファイル名変更差分のあるファイルパスとコミットSHAが渡される場合 + def test_diff_Githubにファイル名変更差分のあるファイルパスとコミットshaが渡される場合 file_from = TestFile.new(status: 'added', filename: "farend/redmine_github_repo/README.md") file_to = TestFile.new(status: 'renamed', filename: "farend/redmine_github_repo/RENAME.md", previous_filename: "farend/redmine_github_repo/README.md") cat = "add_line" @@ -399,7 +379,7 @@ def test_diff_Githubにファイル名変更差分のあるファイルパスと end end - def test_diff_Githubに変更差分のあるファイルパスとコミットSHAが渡される場合 + def test_diff_Githubに変更差分のあるファイルパスとコミットshaが渡される場合 file_from = TestFile.new(status: 'added', filename: "farend/redmine_github_repo/README.md") file_to = TestFile.new(status: 'modifies', filename: "farend/redmine_github_repo/README.md", patch:'+mod_line') cat = "add_line" @@ -437,7 +417,7 @@ def test_diff_Githubに変更差分のあるファイルパスとコミットSHA end end - def test_diff_Githubに削除差分のあるファイルパスとコミットSHAが渡される場合 + def test_diff_Githubに削除差分のあるファイルパスとコミットshaが渡される場合 file_from = TestFile.new(status: 'added', filename: "farend/redmine_github_repo/README.md") file_to = TestFile.new(status: 'removed', filename: "farend/redmine_github_repo/README.md", patch:'-add_line') cat = "add_line" diff --git a/test/unit/github_test.rb b/test/unit/github_test.rb index 07c8183..f3703de 100644 --- a/test/unit/github_test.rb +++ b/test/unit/github_test.rb @@ -5,16 +5,17 @@ class GithubTest < ActiveSupport::TestCase def setup @repository = Repository::Github.find(1) - @changeset = Changeset.find(1) + @default_changeset = Changeset.find(1) @scm = @repository.scm @repo = "farend/redmine_github_repo" + @author = OctokitAuthor.new(name: 'author_name') end def test_fetch_changesets_Githubでchangesetsが追加される場合 file = TestFile.new(status: "added", filename: "README.md") - rev = OctokitRevision.new(identifier: 'shashasha2', scmid: 'shashasha2', author: OctokitAuthor.new(name: 'author_name'), + rev = OctokitRevision.new(identifier: 'addedsha', scmid: 'addedsha', author: @author, parents: ['shashasha'], paths: nil, time: Time.gm(2023, 2, 1), message: 'added') - commit = OctokitCommit.new(sha: 'shashasha2', files: [file], parents: OctokitCommit.new(sha: 'shashasha')) + commit = OctokitCommit.new(sha: 'addedsha', files: [file], parents: OctokitCommit.new(sha: 'shashasha')) @scm.stub(:revisions, build_mock([rev], []) { |path, identifier_from, identifier_to| assert_equal '', path @@ -23,7 +24,7 @@ def test_fetch_changesets_Githubでchangesetsが追加される場合 }) do Octokit.stub(:commit, build_mock(commit, []) { |repo, identifier| assert_equal @repo, repo - assert_equal 'shashasha2', identifier + assert_equal 'addedsha', identifier }) do @repository.fetch_changesets assert_equal 2, @repository.changesets.size @@ -31,14 +32,14 @@ def test_fetch_changesets_Githubでchangesetsが追加される場合 extra_info = @repository[:extra_info] - assert_equal '2023-02-01T00:00:00Z', extra_info['last_committed_date'] - assert_equal 'shashasha2', extra_info['last_committed_id'] + assert_equal Time.gm(2023, 2, 1), extra_info['last_committed_date'] + assert_equal 'addedsha', extra_info['last_committed_id'] end end end def test_fetch_changesets_Githubでchangesetsに追加が無い場合 - rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: OctokitAuthor.new(name: 'author_name'), + rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: @author, paths: nil, time: Time.gm(2023, 1, 1), message: 'message') @scm.stub(:revisions, build_mock([rev], []) { |path, identifier_from, identifier_to| @@ -52,16 +53,16 @@ def test_fetch_changesets_Githubでchangesetsに追加が無い場合 extra_info = @repository[:extra_info] - assert_equal '2023-01-01T00:00:00Z', extra_info['last_committed_date'] + assert_equal Time.gm(2023, 1, 1), extra_info['last_committed_date'] assert_equal 'shashasha', extra_info['last_committed_id'] end end - def test_save_revisions_Githubでchangesetsが保存される場合 - rev = OctokitRevision.new(identifier: 'shashasha2', scmid: 'shashasha2', author: OctokitAuthor.new(name: 'author_name'), + def test_save_revisions_Githubでchangesetsが追加される場合 + rev = OctokitRevision.new(identifier: 'addedsha', scmid: 'addedsha', author: @author, parents: ['shashasha'], paths: nil, time: Time.gm(2023, 2, 1), message: 'added') file = TestFile.new(status: "added", filename: "README.md") - commit = OctokitCommit.new(sha: 'shashasha2', files: [file], parents: OctokitCommit.new(sha: 'shashasha')) + commit = OctokitCommit.new(sha: 'addedsha', files: [file], parents: OctokitCommit.new(sha: 'shashasha')) @scm.stub(:revisions, build_mock([rev], []) { |path, identifier_from, identifier_to| assert_equal '', path @@ -70,7 +71,7 @@ def test_save_revisions_Githubでchangesetsが保存される場合 }) do Octokit.stub(:commit, build_mock(commit, []) { |repo, identifier| assert_equal @repo, repo - assert_equal 'shashasha2', identifier + assert_equal 'addedsha', identifier }) do @repository.fetch_changesets assert_equal 2, @repository.changesets.size @@ -78,14 +79,14 @@ def test_save_revisions_Githubでchangesetsが保存される場合 extra_info = @repository[:extra_info] - assert_equal '2023-02-01T00:00:00Z', extra_info['last_committed_date'] - assert_equal 'shashasha2', extra_info['last_committed_id'] + assert_equal Time.gm(2023, 2, 1), extra_info['last_committed_date'] + assert_equal 'addedsha', extra_info['last_committed_id'] end end end - def test_fetch_changesets_Githubでchangesetsが保存されない場合 - rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: OctokitAuthor.new(name: 'author_name'), + def test_fetch_changesets_Githubでchangesetsが追加されない場合 + rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: @author, paths: nil, time: Time.gm(2023, 1, 1), message: 'message') @scm.stub(:revisions, build_mock([rev], []) { |path, identifier_from, identifier_to| @@ -99,19 +100,19 @@ def test_fetch_changesets_Githubでchangesetsが保存されない場合 extra_info = @repository[:extra_info] - assert_equal '2023-01-01T00:00:00Z', extra_info['last_committed_date'] + assert_equal Time.gm(2023, 1, 1), extra_info['last_committed_date'] assert_equal 'shashasha', extra_info['last_committed_id'] end end def test_find_changeset_by_name_Githubで引数にリビジョン名が一致するchangesetが存在する場合 found_changeset = @repository.find_changeset_by_name('shashasha') - assert_equal @changeset, found_changeset + assert_equal @default_changeset, found_changeset end def test_find_changeset_by_name_Githubで引数にscmidが部分一致するchangesetが存在する場合 found_changeset = @repository.find_changeset_by_name('sha') - assert_equal @changeset, found_changeset + assert_equal @default_changeset, found_changeset end def test_find_changeset_by_name_Githubで引数に該当するchangesetが存在しない場合 @@ -119,10 +120,10 @@ def test_find_changeset_by_name_Githubで引数に該当するchangesetが存在 assert_equal nil, found_changeset end - def test_scm_entries_Githubでキャッシュが存在しない場合 - rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: OctokitAuthor.new(name: 'author_name'), - paths: nil, time: Time.gm(2023, 1, 1), message: 'message') - entry =RepositoryEntry.new(path: "README.md", size: 256, lastrev: rev.identifier) + def test_scm_entries_Githubでルートファイルのキャッシュが存在しない場合 + rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: @author, + time: Time.gm(2023, 1, 1), message: 'message') + entry = RepositoryEntry.new(path: "README.md", size: 256, lastrev: rev.identifier) @scm.stub(:entries, build_mock([entry], []) { |repository_id, revision| @@ -139,15 +140,15 @@ def test_scm_entries_Githubでキャッシュが存在しない場合 end end - def test_scm_entries_Githubでキャッシュが存在する場合 - rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: OctokitAuthor.new(name: 'author_name'), - paths: nil, time: Time.gm(2023, 1, 1), message: 'message') + def test_scm_entries_Githubでルートファイルのキャッシュが存在する場合 + rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: @author, + time: Time.gm(2023, 1, 1), message: 'message') entry = RepositoryEntry.new(path: "README.md", size: 256, lastrev: rev.identifier) GithubAdapterRootFileset.create!( repository_id: @repository.id, revision: rev.identifier, - changeset_id: @changeset.id, + changeset_id: @default_changeset.id, path: entry.path, size: entry.size, latest_commitid: rev.identifier @@ -171,17 +172,17 @@ def test_scm_entries_Githubでキャッシュが存在する場合 end end - def test_latest_changesets_Githubでchangesetが追加されない場合 - rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: OctokitAuthor.new(name: 'author_name'), - paths: nil, time: Time.gm(2023, 1, 1), message: 'message') + def test_latest_changesets_Githubで未反映のrevisionが存在せずpathにデフォルトブランチ名が与えられた場合 + rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: @author, + time: Time.gm(2023, 1, 1), message: 'message') @scm.stub(:revisions, build_mock([rev], []) { |path, identifier_from, identifier_to| assert_equal 'README.md', path assert_equal nil, identifier_from - assert_equal 'shashasha', identifier_to + assert_equal 'main', identifier_to }) do - @repository.stub(:default_branch, build_mock('shashasha', [])) do - latest_changesets = @repository.latest_changesets('README.md', 'shashasha') + @repository.stub(:default_branch, build_mock('main', [])) do + latest_changesets = @repository.latest_changesets('README.md', 'main') assert_equal 1, latest_changesets.size assert_equal 'shashasha', latest_changesets.first.revision @@ -192,54 +193,52 @@ def test_latest_changesets_Githubでchangesetが追加されない場合 end end - def test_latest_changesets_Githubで一件のchangesetが追加される場合 - rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: OctokitAuthor.new(name: 'author_name'), - paths: nil, time: Time.gm(2023, 1, 1), message: 'message') - latest_rev = OctokitRevision.new(identifier: 'shashalatest', scmid: 'shashalatest', author: OctokitAuthor.new(name: 'author_name'), - paths: nil, time: Time.gm(2023, 2, 1), message: 'latest') - @repository.changesets << changeset(latest_rev) + def test_latest_changesets_Githubで未反映のrevisionが存在しpathにデフォルトブランチ名が与えられた場合 + rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: @author, + time: Time.gm(2023, 1, 1), message: 'message') + latest_rev = OctokitRevision.new(identifier: 'latestsha', scmid: 'latestsha', author: @author, + time: Time.gm(2023, 2, 1), message: 'latest') @scm.stub(:revisions, build_mock([rev, latest_rev], []) { |path, identifier_from, identifier_to| assert_equal 'README.md', path assert_equal nil, identifier_from - assert_equal 'shashalatest', identifier_to + assert_equal 'main', identifier_to }) do - @repository.stub(:default_branch, build_mock('shashalatest', [])) do - latest_changesets = @repository.latest_changesets('README.md', 'shashalatest') + @repository.stub(:default_branch, build_mock('main', [])) do + latest_changesets = @repository.latest_changesets('README.md', 'main') - assert_equal 2, latest_changesets.size - assert_equal 'shashalatest', latest_changesets.first.revision - assert_equal 'shashalatest', latest_changesets.first.scmid - assert_equal 'latest', latest_changesets.first.comments - assert_equal Time.gm(2023, 2, 1), latest_changesets.first.committed_on + assert_equal 1, latest_changesets.size + assert_equal 'shashasha', latest_changesets.first.revision + assert_equal 'shashasha', latest_changesets.first.scmid + assert_equal 'message', latest_changesets.first.comments + assert_equal Time.gm(2023, 1, 1), latest_changesets.first.committed_on end end end - def test_latest_changesets_Githubで対象のpathがデフォルトブランチではない場合 - rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: OctokitAuthor.new(name: 'author_name'), - paths: nil, time: Time.gm(2023, 1, 1), message: 'message') - latest_rev = OctokitRevision.new(identifier: 'shashalatest', scmid: 'shashalatest', author: OctokitAuthor.new(name: 'author_name'), - paths: nil, time: Time.gm(2023, 2, 1), message: 'latest') + def test_latest_changesets_Githubで未反映のrevisionが存在しpathにコミットのshaが与えられた場合 + rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: @author, + time: Time.gm(2023, 1, 1), message: 'message') + latest_rev = OctokitRevision.new(identifier: 'latestsha', scmid: 'latestsha', author: @author, + time: Time.gm(2023, 2, 1), message: 'latest') file = TestFile.new(status: "added", filename: "README.md") - - commit = OctokitCommit.new(sha: 'shashalatest', files: [file], parents: OctokitCommit.new(sha: 'shashasha')) + commit = OctokitCommit.new(sha: 'latestsha', files: [file], parents: OctokitCommit.new(sha: 'shashasha')) @scm.stub(:revisions, build_mock([rev, latest_rev], []) { |path, identifier_from, identifier_to| assert_equal 'README.md', path assert_equal nil, identifier_from - assert_equal 'shashalatest', identifier_to + assert_equal 'latestsha', identifier_to }) do @repository.stub(:default_branch, build_mock('main', [])) do Octokit.stub(:commit, build_mock(commit, []) { |repo, identifier| assert_equal @repo, repo - assert_equal 'shashalatest', identifier + assert_equal 'latestsha', identifier }) do - latest_changesets = @repository.latest_changesets('README.md', 'shashalatest') + latest_changesets = @repository.latest_changesets('README.md', 'latestsha') assert_equal 2, latest_changesets.size - assert_equal 'shashalatest', latest_changesets.first.revision - assert_equal 'shashalatest', latest_changesets.first.scmid + assert_equal 'latestsha', latest_changesets.first.revision + assert_equal 'latestsha', latest_changesets.first.scmid assert_equal 'latest', latest_changesets.first.comments assert_equal Time.gm(2023, 2, 1), latest_changesets.first.committed_on end @@ -247,16 +246,95 @@ def test_latest_changesets_Githubで対象のpathがデフォルトブランチ end end + def test_latest_changesets_Githubで未反映のrevisionが存在せずpathにコミットのshaが与えられた場合 + rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: @author, + time: Time.gm(2023, 1, 1), message: 'message') + file = TestFile.new(status: "added", filename: "README.md") + commit = OctokitCommit.new(sha: 'shashasha', files: [file], parents: OctokitCommit.new(sha: 'shashasha')) + + @scm.stub(:revisions, build_mock([rev], []) { |path, identifier_from, identifier_to| + assert_equal 'README.md', path + assert_equal nil, identifier_from + assert_equal 'shashasha', identifier_to + }) do + @repository.stub(:default_branch, build_mock('main', [])) do + Octokit.stub(:commit, build_mock(commit, []) { |repo, identifier| + assert_equal @repo, repo + assert_equal 'shashasha', identifier + }) do + latest_changesets = @repository.latest_changesets('README.md', 'shashasha') + + assert_equal 1, latest_changesets.size + assert_equal 'shashasha', latest_changesets.first.revision + assert_equal 'shashasha', latest_changesets.first.scmid + assert_equal 'message', latest_changesets.first.comments + assert_equal Time.gm(2023, 1, 1), latest_changesets.first.committed_on + end + end + end + end + + def test_using_root_fileset_cache_Githubでキャッシュが存在せずidentifierにデフォルトブランチ名を受け取った場合 + rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: @author, + paths: nil, time: Time.gm(2023, 1, 1), message: 'message') + entry = RepositoryEntry.new(path: "README.md", size: 256, lastrev: rev.identifier) + + @scm.stub(:entries, build_mock([entry], []) { |repository_id, revision| + assert_equal 'README.md', repository_id + assert_equal 'main', revision + }) do + @scm.stub(:default_branch, build_mock('main', [])) do + entries = @repository.scm_entries('README.md', 'main') + + assert_equal 1, entries.size + assert_equal 'README.md', entries[0].path + assert_equal 256, entries[0].size + assert_equal 'shashasha', entries[0].lastrev + assert_equal 0, GithubAdapterRootFileset.all.size + end + end + end + + def test_using_root_fileset_cache_Githubでキャッシュが存在しidentifierにデフォルトブランチ名を受け取った場合 + rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: @author, + paths: nil, time: Time.gm(2023, 1, 1), message: 'message') + entry = RepositoryEntry.new(path: "README.md", size: 256, lastrev: rev.identifier) + + GithubAdapterRootFileset.create!( + repository_id: @repository.id, + revision: rev.identifier, + changeset_id: @default_changeset.id, + path: entry.path, + size: entry.size, + latest_commitid: rev.identifier + ) + + @scm.stub(:entries, build_mock([entry], []) { |repository_id, revision| + assert_equal 'README.md', repository_id + assert_equal 'main', revision + }) do + @scm.stub(:default_branch, build_mock('main', [])) do + entries = @repository.scm_entries('README.md', 'main') + + assert_equal 1, entries.size + assert_equal 'README.md', entries[0].path + assert_equal 256, entries[0].size + assert_equal 'shashasha', entries[0].lastrev + assert_equal 1, GithubAdapterRootFileset.all.size + end + end + end + ## 以下、Octokitのモックに使う部品たち ## - RepositoryChangeset = Struct.new(:repository, :id, :revision, :scmid, :comitter, - :committed_on, :comments, keyword_init: true) - RepositoryEntry = Struct.new(:path, :size, :lastrev, keyword_init: true) OctokitRevision = Struct.new(:identifier, :scmid, :author, :committer, :tree, - :message, :paths, :time, :parents, keyword_init: true) + :message, :paths, :time, :parents, keyword_init: true) OctokitCommit = Struct.new(:sha, :commit, :parents, :files, keyword_init: true) OctokitContent = Struct.new(:sha, :name, :path, :type, :size, :download_url, - :content, :encoding, keyword_init: true) + :content, :encoding, keyword_init: true) OctokitAuthor = Struct.new(:name, keyword_init: true) + RepositoryChangeset = Struct.new(:repository, :id, :revision, :scmid, :comitter, + :committed_on, :comments, keyword_init: true) + RepositoryEntry = Struct.new(:path, :size, :lastrev, keyword_init: true) RootFilesetCache = Struct.new(:repository_id, :revision, :changeset_id, :path, :size, :latest_comitted, keyword_init: true) TestFile = Struct.new(:status, :filename, :previous_filename, From e300a0fa091fd7d1402c53af074dcc916af0188c Mon Sep 17 00:00:00 2001 From: HiroyasuTawara Date: Tue, 17 Oct 2023 08:34:59 +0000 Subject: [PATCH 12/17] =?UTF-8?q?revisions=E3=83=A1=E3=82=BD=E3=83=83?= =?UTF-8?q?=E3=83=89=E3=81=AE=E3=83=86=E3=82=B9=E3=83=88=E3=82=92=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/unit/github_adapter_test.rb | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/test/unit/github_adapter_test.rb b/test/unit/github_adapter_test.rb index 542d443..67450b4 100644 --- a/test/unit/github_adapter_test.rb +++ b/test/unit/github_adapter_test.rb @@ -296,6 +296,29 @@ def test_revisions_Githubの戻り値が複数ある場合 end end + def test_revisions_Githubのallオプションにtrueが与えられる場合 + parents = [] + commits = 3.times.map { |i| + author = OctokitAuthor.new(name: "Author#{i}") + committer = OctokitCommiter.new(date: "2023-01-00 0#{i}:00:00") + parents << OctokitCommit.new(sha: "shashasha#{i-1}") if i > 0 + rev = OctokitRevision.new(identifier: "shashasha#{i+1}", author: author, + committer: committer, message: 'commit message') + OctokitCommit.new(sha: "shashasha#{i+1}", commit: rev, parents: parents.dup) + } + options = { path: @repo, per_page: 1, all: true, last_committed_id: 'shashasha3'} + + Octokit.stub(:commits, build_two_mock(commits, []) { |repo| + assert_equal @repo, repo + }) do + revisions = @scm.revisions(@repo, nil, nil, options) + + assert_equal 3, revisions.size + assert_equal ["shashasha0", "shashasha1"], revisions.last.parents + assert_equal 'Author2', revisions.last.author + end + end + def test_get_filechanges_and_append_to_Githubに1つのrevisisonが渡される場合 add_file = TestFile.new(status: "added", filename: "add.md") mod_file = TestFile.new(status: "modified", filename: "mod.md") @@ -585,4 +608,13 @@ def build_mock(*returns, &proc) end mock end + + def build_two_mock(*returns, &proc) + mock = Minitest::Mock.new + Array.wrap(returns).each do |ret| + mock.expect(:call, ret, &proc) + mock.expect(:call, ret, &proc) + end + mock + end end From e426d5288f8613196be3969360c44190f9ba430a Mon Sep 17 00:00:00 2001 From: HiroyasuTawara Date: Wed, 18 Oct 2023 02:31:16 +0000 Subject: [PATCH 13/17] =?UTF-8?q?revisions=E3=83=A1=E3=82=BD=E3=83=83?= =?UTF-8?q?=E3=83=89=E3=81=AE=E3=83=86=E3=82=B9=E3=83=88=E3=82=92=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/unit/github_adapter_test.rb | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/test/unit/github_adapter_test.rb b/test/unit/github_adapter_test.rb index 67450b4..f26cc8a 100644 --- a/test/unit/github_adapter_test.rb +++ b/test/unit/github_adapter_test.rb @@ -306,10 +306,11 @@ def test_revisions_Githubのallオプションにtrueが与えられる場合 committer: committer, message: 'commit message') OctokitCommit.new(sha: "shashasha#{i+1}", commit: rev, parents: parents.dup) } - options = { path: @repo, per_page: 1, all: true, last_committed_id: 'shashasha3'} + options = { path: @repo, per_page: 1, all: true} - Octokit.stub(:commits, build_two_mock(commits, []) { |repo| + Octokit.stub(:commits, build_mock(commits, commits, []) { |repo, api_opts| assert_equal @repo, repo + assert_equal true, api_opts[:all] }) do revisions = @scm.revisions(@repo, nil, nil, options) @@ -608,13 +609,4 @@ def build_mock(*returns, &proc) end mock end - - def build_two_mock(*returns, &proc) - mock = Minitest::Mock.new - Array.wrap(returns).each do |ret| - mock.expect(:call, ret, &proc) - mock.expect(:call, ret, &proc) - end - mock - end end From 2c8309b641b08032a1e42a2d61c7825450806a30 Mon Sep 17 00:00:00 2001 From: tanaka ken Date: Sun, 22 Oct 2023 08:43:18 +0900 Subject: [PATCH 14/17] =?UTF-8?q?github=5Ftest.rb=20=E3=81=AE=E8=87=AA?= =?UTF-8?q?=E5=8B=95=E3=83=86=E3=82=B9=E3=83=88=E3=81=AE=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=E3=83=BB=E4=BB=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/repository/github.rb | 23 +- test/unit/github_test.rb | 437 ++++++++++++++++++++------------ 2 files changed, 285 insertions(+), 175 deletions(-) diff --git a/app/models/repository/github.rb b/app/models/repository/github.rb index 70c1864..43011af 100644 --- a/app/models/repository/github.rb +++ b/app/models/repository/github.rb @@ -44,7 +44,7 @@ def fetch_changesets(options = {}) revisions = scm.revisions('', nil, nil, opts) revisions_copy = revisions.clone # revisions will change - + return if revisions.blank? save_revisions!(revisions, revisions_copy) @@ -58,7 +58,7 @@ def fetch_changesets(options = {}) end # revisionオブジェクトの配列を引数に受け取る - # 引数に未反映のrevisionが含まれる場合、changesetオブジェクトを作成し保存・更新を行う + # changesetsテーブルに保存する(すでに保存済みのrevisionはスキップ) def save_revisions!(revisions, revisions_copy) limit = 100 offset = 0 @@ -99,8 +99,8 @@ def save_revisions!(revisions, revisions_copy) end private :save_revisions! - # nameにコミットのSHAを受け取る - # nameにリビジョン名が一致する、もしくは部分一致するscmidを持つchangeset一件を返す + # nameにコミットのSHA1ハッシュを受け取る + # nameにリビジョン名が一致する、もしくはscmidに先頭一致するchangeset一件を返す def find_changeset_by_name(name) if name.present? changesets.find_by(revision: name.to_s) || @@ -109,8 +109,8 @@ def find_changeset_by_name(name) end # pathにファイルパス、identifierにコミットのshaを受け取る - # scmから引数に該当するエントリを配列で返す - # 既にキャッシュが存在し引数が空でないなら、root階層ファイルセットの参照時キャッシュを使用する + # scmから引数に該当するエントリを取得し配列で返す + # pathが空(ルート)でidentifierがdefault_branchの場合は、ファイルセットの参照時キャッシュを使用する def scm_entries(path=nil, identifier=nil) is_using_cache = using_root_fileset_cache?(path, identifier) @@ -128,9 +128,9 @@ def scm_entries(path=nil, identifier=nil) path: fileset.path, kind: fileset.size.blank? ? 'dir': 'file', size: fileset.size, - author: latest_changeset.committer, lastrev: Redmine::Scm::Adapters::Revision.new( identifier: latest_changeset.identifier, + author: latest_changeset.committer, time: latest_changeset.committed_on ), ) @@ -161,7 +161,7 @@ def scm_entries(path=nil, identifier=nil) # pathにファイルパス、revにコミットのshaもしくはブランチ名を受け取る # rev時点のpath以下のファイルに該当するchengesetsを取得し配列で返す - # revがデフォルトブランチ名以外の場合、未反映のrevisionを保存しchangesetを追加する + # revがデフォルトブランチ以外の場合、未反映のrevisionを保存しchangesetsテーブルに保存する def latest_changesets(path, rev, limit = 10) revisions = scm.revisions(path, nil, rev, :limit => limit, :all => false) @@ -175,6 +175,8 @@ def latest_changesets(path, rev, limit = 10) changesets.where(:scmid => revisions.map {|c| c.scmid}).to_a end + # このリポジトリが削除された場合のクリーンアップ処理 + # 紐づくGithubAdapterRootFilesetを削除する def clear_changesets super GithubAdapterRootFileset.where(repository_id: self.id).delete_all @@ -187,9 +189,8 @@ def default_branch def properties(path, rev) end - # scm_entries内でroot階層ファイルセットの参照にキャッシュを使用するための判定 - # 引数が与えられない場合・キャッシュが存在しない場合はfalseを返す - # キャッシュが見つからない場合でも、identifierがデフォルトブランチ名と一致するならtrueを返す + # scm_entries内でキャッシュを使用するかどうかの判定 + # pathがルートで、identifierがデフォルトブランチ(またはデフォルトブランチのSHA1ハッシュ)の場合、true を返す def using_root_fileset_cache?(path, identifier) return false if path.present? return false if identifier.blank? diff --git a/test/unit/github_test.rb b/test/unit/github_test.rb index f3703de..e17b494 100644 --- a/test/unit/github_test.rb +++ b/test/unit/github_test.rb @@ -13,22 +13,23 @@ def setup def test_fetch_changesets_Githubでchangesetsが追加される場合 file = TestFile.new(status: "added", filename: "README.md") - rev = OctokitRevision.new(identifier: 'addedsha', scmid: 'addedsha', author: @author, + rev = OctokitRevision.new(identifier: 'addedsha', scmid: 'addedsha', author: @author, parents: ['shashasha'], paths: nil, time: Time.gm(2023, 2, 1), message: 'added') + commit = OctokitCommit.new(sha: 'addedsha', files: [file], parents: OctokitCommit.new(sha: 'shashasha')) - @scm.stub(:revisions, build_mock([rev], []) { |path, identifier_from, identifier_to| + @scm.stub(:revisions, build_mock([rev]) { |path, identifier_from, identifier_to| assert_equal '', path assert_equal nil, identifier_from assert_equal nil, identifier_to }) do - Octokit.stub(:commit, build_mock(commit, []) { |repo, identifier| + Octokit.stub(:commit, build_mock(commit) { |repo, identifier| assert_equal @repo, repo assert_equal 'addedsha', identifier }) do @repository.fetch_changesets assert_equal 2, @repository.changesets.size - assert_equal @repository.id, @repository.changesets.last[:repository_id] + assert_equal @repository.id, @repository.changesets.first[:repository_id] extra_info = @repository[:extra_info] @@ -39,17 +40,17 @@ def test_fetch_changesets_Githubでchangesetsが追加される場合 end def test_fetch_changesets_Githubでchangesetsに追加が無い場合 - rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: @author, + rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: @author, paths: nil, time: Time.gm(2023, 1, 1), message: 'message') - @scm.stub(:revisions, build_mock([rev], []) { |path, identifier_from, identifier_to| + @scm.stub(:revisions, build_mock([rev]) { |path, identifier_from, identifier_to| assert_equal '', path assert_equal nil, identifier_from assert_equal nil, identifier_to }) do @repository.fetch_changesets assert_equal 1, @repository.changesets.size - assert_equal @repository.id, @repository.changesets.last[:repository_id] + assert_equal @repository.id, @repository.changesets.first[:repository_id] extra_info = @repository[:extra_info] @@ -59,50 +60,42 @@ def test_fetch_changesets_Githubでchangesetsに追加が無い場合 end def test_save_revisions_Githubでchangesetsが追加される場合 - rev = OctokitRevision.new(identifier: 'addedsha', scmid: 'addedsha', author: @author, + rev = OctokitRevision.new(identifier: 'addedsha', scmid: 'addedsha', author: @author, parents: ['shashasha'], paths: nil, time: Time.gm(2023, 2, 1), message: 'added') file = TestFile.new(status: "added", filename: "README.md") commit = OctokitCommit.new(sha: 'addedsha', files: [file], parents: OctokitCommit.new(sha: 'shashasha')) - @scm.stub(:revisions, build_mock([rev], []) { |path, identifier_from, identifier_to| - assert_equal '', path - assert_equal nil, identifier_from - assert_equal nil, identifier_to + Octokit.stub(:commit, build_mock(commit) { |repo, identifier| + assert_equal @repo, repo + assert_equal 'addedsha', identifier }) do - Octokit.stub(:commit, build_mock(commit, []) { |repo, identifier| - assert_equal @repo, repo - assert_equal 'addedsha', identifier - }) do - @repository.fetch_changesets - assert_equal 2, @repository.changesets.size - assert_equal @repository.id, @repository.changesets.last[:repository_id] - - extra_info = @repository[:extra_info] - - assert_equal Time.gm(2023, 2, 1), extra_info['last_committed_date'] - assert_equal 'addedsha', extra_info['last_committed_id'] - end + @repository.send(:save_revisions!, [rev], [rev]) + + assert_equal 2, @repository.changesets.size + assert_equal @repository.id, @repository.changesets.first[:repository_id] + assert_equal rev.identifier, @repository.changesets.first[:revision] + assert_equal rev.scmid, @repository.changesets.first[:scmid] + assert_equal rev.author.name, @repository.changesets.first[:committer] + assert_equal rev.time, @repository.changesets.first[:committed_on] + assert_equal rev.message, @repository.changesets.first[:comments] + + assert_equal file.filename, @repository.changesets.first.filechanges.first.path + assert_equal "A", @repository.changesets.first.filechanges.first.action + assert_nil @repository.changesets.first.filechanges.first.from_path + + assert_equal 1, @repository.changesets.first.parents.length + assert_equal @default_changeset, @repository.changesets.first.parents.first end end - def test_fetch_changesets_Githubでchangesetsが追加されない場合 - rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: @author, + def test_save_revisions_Githubでchangesetsが追加されない場合 + rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: @author, paths: nil, time: Time.gm(2023, 1, 1), message: 'message') - @scm.stub(:revisions, build_mock([rev], []) { |path, identifier_from, identifier_to| - assert_equal '', path - assert_equal nil, identifier_from - assert_equal nil, identifier_to - }) do - @repository.fetch_changesets - assert_equal 1, @repository.changesets.size - assert_equal @repository.id, @repository.changesets.last[:repository_id] - - extra_info = @repository[:extra_info] + @repository.send(:save_revisions!, [rev], [rev]) - assert_equal Time.gm(2023, 1, 1), extra_info['last_committed_date'] - assert_equal 'shashasha', extra_info['last_committed_id'] - end + assert_equal 1, @repository.changesets.size + assert_equal @default_changeset.id, @repository.changesets.first.id end def test_find_changeset_by_name_Githubで引数にリビジョン名が一致するchangesetが存在する場合 @@ -117,16 +110,15 @@ def test_find_changeset_by_name_Githubで引数にscmidが部分一致するchan def test_find_changeset_by_name_Githubで引数に該当するchangesetが存在しない場合 found_changeset = @repository.find_changeset_by_name('ahsahsahs') - assert_equal nil, found_changeset + assert_nil found_changeset end - def test_scm_entries_Githubでルートファイルのキャッシュが存在しない場合 - rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: @author, + def test_scm_entries_Githubでルートファイルのキャッシュが存在しないし使われない場合 + rev = OctokitRevision.new(identifier: 'mock-value', scmid: 'mock-value', author: @author, time: Time.gm(2023, 1, 1), message: 'message') entry = RepositoryEntry.new(path: "README.md", size: 256, lastrev: rev.identifier) - - @scm.stub(:entries, build_mock([entry], []) { |repository_id, revision| + @scm.stub(:entries, build_mock([entry]) { |repository_id, revision| assert_equal 'README.md', repository_id assert_equal 'shashasha', revision }) do @@ -135,13 +127,14 @@ def test_scm_entries_Githubでルートファイルのキャッシュが存在 assert_equal 1, entries.size assert_equal 'README.md', entries[0].path assert_equal 256, entries[0].size - assert_equal 'shashasha', entries[0].lastrev + assert_equal 'mock-value', entries[0].lastrev + assert_equal 0, GithubAdapterRootFileset.all.size end end - def test_scm_entries_Githubでルートファイルのキャッシュが存在する場合 - rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: @author, + def test_scm_entries_Githubでルートファイルのキャッシュは存在するが使用しない場合 + rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: @author, time: Time.gm(2023, 1, 1), message: 'message') entry = RepositoryEntry.new(path: "README.md", size: 256, lastrev: rev.identifier) @@ -154,203 +147,319 @@ def test_scm_entries_Githubでルートファイルのキャッシュが存在 latest_commitid: rev.identifier ) - @scm.stub(:revision_to_sha, build_mock('shashasha', []) { |identifier| - assert_equal 'shashasha', identifier + @scm.stub(:entries, build_mock([entry]) { |repository_id, revision| + assert_equal 'README.md', repository_id + assert_equal 'shashasha', revision }) do - @scm.stub(:entries, build_mock([entry], []) { |repository_id, revision| - assert_equal 'README.md', repository_id - assert_equal 'shashasha', revision + entries = @repository.scm_entries('README.md', 'shashasha') + + assert_equal 1, entries.size + assert_equal 'README.md', entries[0].path + assert_equal 256, entries[0].size + assert_equal 'shashasha', entries[0].lastrev + + assert_equal 1, GithubAdapterRootFileset.all.size + end + end + + def test_scm_entries_Githubでルートファイルのキャッシュが存在し使用する場合 + main_changeset = Changeset.create!( + repository_id: @repository.id, + revision: "sha1-abc", + committer: 'author_name', + committed_on: '2023-01-01', + comments: 'message', + commit_date: '2023-01-01', + scmid: 'sha1-abc' + ) + GithubAdapterRootFileset.create!( + repository_id: @repository.id, + revision: "sha1-abc", + changeset_id: main_changeset.id, + path: "README.md", + size: 256, + latest_commitid: "shashasha" + ) + + @scm.stub(:default_branch, build_mock('main')) do + @scm.stub(:revision_to_sha, build_mock('sha1-abc') { |identifier| + assert_equal 'main', identifier }) do - entries = @repository.scm_entries('README.md', 'shashasha') + entries = @repository.scm_entries('', 'main') assert_equal 1, entries.size + assert_equal 'README.md', entries[0].name assert_equal 'README.md', entries[0].path + assert_equal 'file', entries[0].kind assert_equal 256, entries[0].size - assert_equal 'shashasha', entries[0].lastrev + assert_equal 'author_name', entries[0].author + assert_equal 'shashasha', entries[0].lastrev.identifier + assert_equal Time.parse("2023-01-01 00:00:00"), entries[0].lastrev.time + assert_equal 1, GithubAdapterRootFileset.all.size end end end - def test_latest_changesets_Githubで未反映のrevisionが存在せずpathにデフォルトブランチ名が与えられた場合 - rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: @author, - time: Time.gm(2023, 1, 1), message: 'message') + def test_scm_entries_Githubでルートファイルのキャッシュは存在しないが使用する場合 + main_changeset = Changeset.create!( + repository_id: @repository.id, + revision: "sha1-abc", + committer: 'author_name', + committed_on: '2023-01-01', + comments: 'message', + commit_date: '2023-01-01', + scmid: 'sha1-abc' + ) + # scm.entries の戻り値 + entry = RepositoryEntry.new(path: "README.md", size: 256, lastrev: OctokitRevision.new( + identifier: 'shashasha', scmid: 'shashasha', author: @author, time: Time.gm(2023, 1, 1), message: 'message' + ) + ) - @scm.stub(:revisions, build_mock([rev], []) { |path, identifier_from, identifier_to| + @scm.stub(:default_branch, build_mock('main')) do + @scm.stub(:revision_to_sha, build_mock('sha1-abc') { |identifier| + assert_equal 'main', identifier + }) do + @scm.stub(:entries, build_mock([entry]) { |path, identifier| + assert_equal '', path + assert_equal 'main', identifier + }) do + entries = @repository.scm_entries('', 'main') + + assert_equal 1, entries.size + assert_equal 'README.md', entries[0].path + assert_equal 256, entries[0].size + assert_equal 'shashasha', entries[0].lastrev.identifier + assert_equal Time.gm(2023, 1, 1), entries[0].lastrev.time + + # 作成された RootFileset の確認 + assert_equal 1, GithubAdapterRootFileset.all.size + assert_equal @repository.id, GithubAdapterRootFileset.first.repository_id + assert_equal 'main', GithubAdapterRootFileset.first.revision + assert_equal main_changeset.id, GithubAdapterRootFileset.first.changeset_id + assert_equal entry.path, GithubAdapterRootFileset.first.path + assert_equal entry.size.to_s, GithubAdapterRootFileset.first.size + assert_equal entry.lastrev.identifier, GithubAdapterRootFileset.first.latest_commitid + end + end + end + end + + def test_latest_changesets_Githubでidentifierにデフォルトブランチ名が与えられ未反映のrevisionが存在しない場合 + rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: @author, + time: Time.parse("2023-01-01 00:00:00"), message: 'message') + + @scm.stub(:revisions, build_mock([rev]) { |path, identifier_from, identifier_to| assert_equal 'README.md', path assert_equal nil, identifier_from assert_equal 'main', identifier_to }) do - @repository.stub(:default_branch, build_mock('main', [])) do - latest_changesets = @repository.latest_changesets('README.md', 'main') - - assert_equal 1, latest_changesets.size - assert_equal 'shashasha', latest_changesets.first.revision - assert_equal 'shashasha', latest_changesets.first.scmid - assert_equal 'message', latest_changesets.first.comments - assert_equal Time.gm(2023, 1, 1), latest_changesets.first.committed_on + @repository.stub(:default_branch, build_mock('main')) do + assert_no_difference 'Changeset.count' do + + latest_changesets = @repository.latest_changesets('README.md', 'main') + + assert_equal 1, latest_changesets.size + assert_equal 'shashasha', latest_changesets.first.revision + assert_equal 'shashasha', latest_changesets.first.scmid + assert_equal 'message', latest_changesets.first.comments + assert_equal Time.parse("2023-01-01 00:00:00"), latest_changesets.first.committed_on + end end end end - def test_latest_changesets_Githubで未反映のrevisionが存在しpathにデフォルトブランチ名が与えられた場合 - rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: @author, - time: Time.gm(2023, 1, 1), message: 'message') - latest_rev = OctokitRevision.new(identifier: 'latestsha', scmid: 'latestsha', author: @author, - time: Time.gm(2023, 2, 1), message: 'latest') + def test_latest_changesets_Githubでidentifierにデフォルトブランチ名が与えられ未反映のrevisionが存在した場合 + rev1 = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: @author, + time: Time.gm(2023, 1, 1), message: 'message') + rev2 = OctokitRevision.new(identifier: 'latestsha', scmid: 'latestsha', author: @author, + time: Time.gm(2023, 1, 1), message: 'latest') + cgs2 = Changeset.create!( + repository_id: @repository.id, + revision: "latestsha", + committer: 'author_name', + committed_on: Time.parse('2023-01-02'), + comments: 'latest message', + commit_date: '2023-01-02', + scmid: 'latestsha' + ) - @scm.stub(:revisions, build_mock([rev, latest_rev], []) { |path, identifier_from, identifier_to| + @scm.stub(:revisions, build_mock([rev1, rev2]) { |path, identifier_from, identifier_to| assert_equal 'README.md', path assert_equal nil, identifier_from assert_equal 'main', identifier_to }) do - @repository.stub(:default_branch, build_mock('main', [])) do - latest_changesets = @repository.latest_changesets('README.md', 'main') - - assert_equal 1, latest_changesets.size - assert_equal 'shashasha', latest_changesets.first.revision - assert_equal 'shashasha', latest_changesets.first.scmid - assert_equal 'message', latest_changesets.first.comments - assert_equal Time.gm(2023, 1, 1), latest_changesets.first.committed_on + @repository.stub(:default_branch, build_mock('main')) do + assert_no_difference 'Changeset.count' do + + latest_changesets = @repository.latest_changesets('README.md', 'main') + + assert_equal 2, latest_changesets.size + assert_equal 'latestsha', latest_changesets.first.revision + assert_equal 'latestsha', latest_changesets.first.scmid + assert_equal 'latest message', latest_changesets.first.comments + assert_equal Time.parse("2023-01-02"), latest_changesets.first.committed_on + + assert_equal 'shashasha', latest_changesets.last.revision + assert_equal 'shashasha', latest_changesets.last.scmid + assert_equal 'message', latest_changesets.last.comments + assert_equal Time.parse("2023-01-01"), latest_changesets.last.committed_on + end end end end - def test_latest_changesets_Githubで未反映のrevisionが存在しpathにコミットのshaが与えられた場合 - rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: @author, - time: Time.gm(2023, 1, 1), message: 'message') - latest_rev = OctokitRevision.new(identifier: 'latestsha', scmid: 'latestsha', author: @author, - time: Time.gm(2023, 2, 1), message: 'latest') - file = TestFile.new(status: "added", filename: "README.md") - commit = OctokitCommit.new(sha: 'latestsha', files: [file], parents: OctokitCommit.new(sha: 'shashasha')) + def test_latest_changesets_GithubでidentifierにデフォルトブランチでないSHA1ハッシュが与えられ未反映のrevisionが存在する場合 + rev1 = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: @author, + time: Time.gm(2023, 1, 1), message: 'message') + rev2 = OctokitRevision.new(identifier: 'latestsha', scmid: 'latestsha', author: @author, + time: Time.gm(2023, 2, 1), message: 'latest') + commit = OctokitCommit.new(sha: 'latestsha', files: [TestFile.new(status: "added", filename: "README.md")], + parents: OctokitCommit.new(sha: 'shashasha')) - @scm.stub(:revisions, build_mock([rev, latest_rev], []) { |path, identifier_from, identifier_to| + @scm.stub(:revisions, build_mock([rev1, rev2]) { |path, identifier_from, identifier_to| assert_equal 'README.md', path assert_equal nil, identifier_from assert_equal 'latestsha', identifier_to }) do - @repository.stub(:default_branch, build_mock('main', [])) do - Octokit.stub(:commit, build_mock(commit, []) { |repo, identifier| + @repository.stub(:default_branch, build_mock('main')) do + Octokit.stub(:commit, build_mock(commit) { |repo, identifier| assert_equal @repo, repo assert_equal 'latestsha', identifier }) do - latest_changesets = @repository.latest_changesets('README.md', 'latestsha') - - assert_equal 2, latest_changesets.size - assert_equal 'latestsha', latest_changesets.first.revision - assert_equal 'latestsha', latest_changesets.first.scmid - assert_equal 'latest', latest_changesets.first.comments - assert_equal Time.gm(2023, 2, 1), latest_changesets.first.committed_on + assert_difference 'Changeset.count', 1 do + + latest_changesets = @repository.latest_changesets('README.md', 'latestsha') + + assert_equal 2, latest_changesets.size + assert_equal 'latestsha', latest_changesets.first.revision + assert_equal 'latestsha', latest_changesets.first.scmid + assert_equal 'latest', latest_changesets.first.comments + assert_equal Time.gm(2023, 2, 1), latest_changesets.first.committed_on + + assert_equal 'shashasha', latest_changesets.last.revision + assert_equal 'shashasha', latest_changesets.last.scmid + assert_equal 'message', latest_changesets.last.comments + assert_equal Time.parse("2023-01-01"), latest_changesets.last.committed_on + end end end end end - def test_latest_changesets_Githubで未反映のrevisionが存在せずpathにコミットのshaが与えられた場合 - rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: @author, - time: Time.gm(2023, 1, 1), message: 'message') - file = TestFile.new(status: "added", filename: "README.md") - commit = OctokitCommit.new(sha: 'shashasha', files: [file], parents: OctokitCommit.new(sha: 'shashasha')) + def test_latest_changesets_GithubでidentifierにデフォルトブランチでないSHA1ハッシュが与えられ未反映のrevisionが存在しない場合 + rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: @author, + time: Time.parse("2023-01-01 00:00:00"), message: 'message') - @scm.stub(:revisions, build_mock([rev], []) { |path, identifier_from, identifier_to| + @scm.stub(:revisions, build_mock([rev]) { |path, identifier_from, identifier_to| assert_equal 'README.md', path assert_equal nil, identifier_from assert_equal 'shashasha', identifier_to }) do - @repository.stub(:default_branch, build_mock('main', [])) do - Octokit.stub(:commit, build_mock(commit, []) { |repo, identifier| - assert_equal @repo, repo - assert_equal 'shashasha', identifier - }) do + @repository.stub(:default_branch, build_mock('main')) do + assert_no_difference 'Changeset.count' do + latest_changesets = @repository.latest_changesets('README.md', 'shashasha') - + assert_equal 1, latest_changesets.size assert_equal 'shashasha', latest_changesets.first.revision assert_equal 'shashasha', latest_changesets.first.scmid assert_equal 'message', latest_changesets.first.comments - assert_equal Time.gm(2023, 1, 1), latest_changesets.first.committed_on + assert_equal Time.parse("2023-01-01 00:00:00"), latest_changesets.first.committed_on end end end end - def test_using_root_fileset_cache_Githubでキャッシュが存在せずidentifierにデフォルトブランチ名を受け取った場合 - rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: @author, - paths: nil, time: Time.gm(2023, 1, 1), message: 'message') - entry = RepositoryEntry.new(path: "README.md", size: 256, lastrev: rev.identifier) + def test_using_root_fileset_cache_Githubでpathが指定されている場合 + is_using_cache = @repository.send(:using_root_fileset_cache?, 'README.md', 'main') - @scm.stub(:entries, build_mock([entry], []) { |repository_id, revision| - assert_equal 'README.md', repository_id - assert_equal 'main', revision - }) do - @scm.stub(:default_branch, build_mock('main', [])) do - entries = @repository.scm_entries('README.md', 'main') + assert !is_using_cache + end - assert_equal 1, entries.size - assert_equal 'README.md', entries[0].path - assert_equal 256, entries[0].size - assert_equal 'shashasha', entries[0].lastrev - assert_equal 0, GithubAdapterRootFileset.all.size - end + def test_using_root_fileset_cache_Githubでキャッシュが存在せずidentifierにデフォルトブランチ名以外を指定した場合 + @scm.stub(:default_branch, build_mock('main')) do + is_using_cache = @repository.send(:using_root_fileset_cache?, '', 'feature_branch') + + assert !is_using_cache + end + end + + def test_using_root_fileset_cache_Githubでキャッシュが存在せずidentifierにデフォルトブランチ名を指定した場合 + @scm.stub(:default_branch, build_mock('main')) do + is_using_cache = @repository.send(:using_root_fileset_cache?, '', 'main') + + assert is_using_cache + end + end + + def test_using_root_fileset_cache_Githubでキャッシュが存在しidentifierとしてキャッシュのrevisionが指定された場合 + GithubAdapterRootFileset.create!( + repository_id: @repository.id, + revision: 'shashasha', + changeset_id: @default_changeset.id, + path: "README.md", + size: 256, + latest_commitid: 'shashasha' + ) + + @scm.stub(:default_branch, build_mock('main')) do + is_using_cache = @repository.send(:using_root_fileset_cache?, '', 'shashasha') + + assert is_using_cache end end def test_using_root_fileset_cache_Githubでキャッシュが存在しidentifierにデフォルトブランチ名を受け取った場合 - rev = OctokitRevision.new(identifier: 'shashasha', scmid: 'shashasha', author: @author, - paths: nil, time: Time.gm(2023, 1, 1), message: 'message') - entry = RepositoryEntry.new(path: "README.md", size: 256, lastrev: rev.identifier) + GithubAdapterRootFileset.create!( + repository_id: @repository.id, + revision: 'shashasha', + changeset_id: @default_changeset.id, + path: "README.md", + size: 256, + latest_commitid: 'shashasha' + ) + + @scm.stub(:default_branch, build_mock('main')) do + is_using_cache = @repository.send(:using_root_fileset_cache?, '', 'main') + assert is_using_cache + end + end + + def test_using_root_fileset_cache_Githubでキャッシュが存在しidentifierに別のコミットIDが指定されている場合 GithubAdapterRootFileset.create!( repository_id: @repository.id, - revision: rev.identifier, + revision: 'shashasha', changeset_id: @default_changeset.id, - path: entry.path, - size: entry.size, - latest_commitid: rev.identifier + path: "README.md", + size: 256, + latest_commitid: 'shashasha' ) - @scm.stub(:entries, build_mock([entry], []) { |repository_id, revision| - assert_equal 'README.md', repository_id - assert_equal 'main', revision - }) do - @scm.stub(:default_branch, build_mock('main', [])) do - entries = @repository.scm_entries('README.md', 'main') + @scm.stub(:default_branch, build_mock('main')) do + is_using_cache = @repository.send(:using_root_fileset_cache?, '', 'othershasha') - assert_equal 1, entries.size - assert_equal 'README.md', entries[0].path - assert_equal 256, entries[0].size - assert_equal 'shashasha', entries[0].lastrev - assert_equal 1, GithubAdapterRootFileset.all.size - end + assert !is_using_cache end end ## 以下、Octokitのモックに使う部品たち ## - OctokitRevision = Struct.new(:identifier, :scmid, :author, :committer, :tree, + OctokitRevision = Struct.new(:identifier, :scmid, :author, :committer, :tree, :message, :paths, :time, :parents, keyword_init: true) OctokitCommit = Struct.new(:sha, :commit, :parents, :files, keyword_init: true) - OctokitContent = Struct.new(:sha, :name, :path, :type, :size, :download_url, + OctokitContent = Struct.new(:sha, :name, :path, :type, :size, :download_url, :content, :encoding, keyword_init: true) OctokitAuthor = Struct.new(:name, keyword_init: true) - RepositoryChangeset = Struct.new(:repository, :id, :revision, :scmid, :comitter, + RepositoryChangeset = Struct.new(:repository, :id, :revision, :scmid, :comitter, :committed_on, :comments, keyword_init: true) RepositoryEntry = Struct.new(:path, :size, :lastrev, keyword_init: true) - RootFilesetCache = Struct.new(:repository_id, :revision, :changeset_id, :path, - :size, :latest_comitted, keyword_init: true) - TestFile = Struct.new(:status, :filename, :previous_filename, + TestFile = Struct.new(:status, :filename, :previous_filename, :from_revision, :patch, keyword_init: true) + # メソッドの定義 + OctokitAuthor.define_method(:to_s) { self.name } - def changeset(rev) - Changeset.new( - repository: @repository, - revision: rev.identifier, - scmid: rev.scmid, - committer: rev.author, - committed_on: rev.time, - comments: rev.message - ) - end - def build_mock(*returns, &proc) mock = Minitest::Mock.new Array.wrap(returns).each do |ret| @@ -359,4 +468,4 @@ def build_mock(*returns, &proc) mock end -end \ No newline at end of file +end From a2e250e18382ff6f12c33c1e468b67185237d918 Mon Sep 17 00:00:00 2001 From: tanaka ken Date: Mon, 23 Oct 2023 15:15:15 +0900 Subject: [PATCH 15/17] =?UTF-8?q?=E8=87=AA=E5=8B=95=E3=83=86=E3=82=B9?= =?UTF-8?q?=E3=83=88=E3=81=AE=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/redmine/scm/adapters/github_adapter.rb | 6 +- test/unit/github_adapter_test.rb | 428 +++++++++++---------- 2 files changed, 219 insertions(+), 215 deletions(-) diff --git a/lib/redmine/scm/adapters/github_adapter.rb b/lib/redmine/scm/adapters/github_adapter.rb index d176ade..69481e5 100644 --- a/lib/redmine/scm/adapters/github_adapter.rb +++ b/lib/redmine/scm/adapters/github_adapter.rb @@ -82,7 +82,7 @@ def revision_to_sha(rev) raise CommandFailed, handle_octokit_error(e) end - # pathにファイル・ディレクトリのパス、revにコミットのSHAもしくはブランチ名を受け取る + # pathにファイル・ディレクトリのパス、revにコミットのSHAもしくはブランチ名を受け取る # revに該当するコミット以前でpath以下に変更があった最新のコミットを取得し、Revisionオブジェクトとして返す # 引数pathが与えられなかった場合、もしくは該当するコミットが存在しない場合nilを返す def lastrev(path, rev) @@ -113,7 +113,7 @@ def get_path_name(path) rescue Octokit::Error => e raise CommandFailed, handle_octokit_error(e) end - + # pathにファイル・ディレクトリのパス, identifier_from/identifier_toにコミットのshaを受け取る # 引数で与えられた条件に合致するコミットをRevisionオブジェクトの配列として返す # allオプションがtrueの場合、リポジトリの全てのrevisionを取得する @@ -287,7 +287,7 @@ def entry(path=nil, identifier=nil) # Root entry Entry.new(:path => '', :kind => 'dir') else - es = entries(path, identifier, {report_last_commit: true }) + es = entries(path, identifier, {report_last_commit: false }) content = es&.find {|e| e.name == path} || es&.first Entry.new({ diff --git a/test/unit/github_adapter_test.rb b/test/unit/github_adapter_test.rb index f26cc8a..4a83268 100644 --- a/test/unit/github_adapter_test.rb +++ b/test/unit/github_adapter_test.rb @@ -38,22 +38,22 @@ def test_branches_Githubの戻り値が1つある場合 end def test_branches_Githubの戻り値が複数ある場合 - multi_branche = ['main', 'dev', 'feat'].sort.map.with_index{ |name, i| + branches = ['main', 'dev', 'feat'].sort.map.with_index{ |name, i| OctokitBranch.new(name: name, commit: OctokitCommit.new(sha: "shashasha#{i}")) } pages = [1, 2] - Octokit.stub(:branches, build_mock(multi_branche, []) { |repo, options| + Octokit.stub(:branches, build_mock(branches, []) { |repo, options| assert_equal @repo, repo assert_equal pages.shift, options[:page] assert_equal 100, options[:per_page] }) do - branches = @scm.branches + results = @scm.branches - assert_equal multi_branche.length, branches.length - branches.each.with_index do |branch,i| - assert_equal multi_branche[i].name, branch.to_s + assert_equal branches.length, results.length + results.each.with_index do |branch,i| + assert_equal branches[i].name, branch.to_s assert_equal "shashasha#{i}", branch.revision assert_equal "shashasha#{i}", branch.scmid end @@ -61,25 +61,25 @@ def test_branches_Githubの戻り値が複数ある場合 end def test_branches_Githubに未ソートのブランチが与えられた場合 - multi_branche = ['bbb', 'ccc', 'aaa'].map{ |name| + branches = ['bbb', 'ccc', 'aaa'].map{ |name| OctokitBranch.new(name: name, commit: OctokitCommit.new(sha: "sha#{name}")) } - sorted_multi_branche = ['aaa', 'bbb', 'ccc'] + sorted_branches = ['aaa', 'bbb', 'ccc'] pages = [1, 2] - Octokit.stub(:branches, build_mock(multi_branche, []) { |repo, options| + Octokit.stub(:branches, build_mock(branches, []) { |repo, options| assert_equal @repo, repo assert_equal pages.shift, options[:page] assert_equal 100, options[:per_page] }) do - branches = @scm.branches + results = @scm.branches - assert_equal multi_branche.length, branches.length - branches.each.with_index do |branch, i| - assert_equal sorted_multi_branche[i], branch.to_s - assert_equal "sha#{sorted_multi_branche[i]}", branch.revision - assert_equal "sha#{sorted_multi_branche[i]}", branch.scmid + assert_equal branches.length, results.length + results.each.with_index do |branch, i| + assert_equal sorted_branches[i], branch.to_s + assert_equal "sha#{sorted_branches[i]}", branch.revision + assert_equal "sha#{sorted_branches[i]}", branch.scmid end end end @@ -97,8 +97,8 @@ def test_entries_Githubの戻り値が空の場合 def test_entries_Githubの戻り値が1つある場合 content = OctokitContent.new(name: 'test.md', path: 'farend/redmine_github_repo', type: 'file', size: 256) - - Octokit.stub(:contents, build_mock([content], []) { |repo, options| + + Octokit.stub(:contents, build_mock([content]) { |repo, options| assert_equal @repo, repo assert_equal nil, options[:path] assert_equal 'HEAD', options[:ref] @@ -116,8 +116,8 @@ def test_entries_Githubの戻り値が複数ある場合 contents = ['test.md', 'test.txt'].sort.map{ |name| OctokitContent.new(name: name, path: 'farend/redmine_github_repo', type: 'file', size: 256) } - - Octokit.stub(:contents, build_mock(contents, []) { |repo, options| + + Octokit.stub(:contents, build_mock(contents) { |repo, options| assert_equal @repo, repo assert_equal nil, options[:path] assert_equal 'HEAD', options[:ref] @@ -131,17 +131,18 @@ def test_entries_Githubの戻り値が複数ある場合 end end - def test_entries_Githubに未ソートのコンテンツが与えられた場合 + def test_entries_Githubに未ソートのコンテンツが返却される場合 contents = ['bbb.md', 'ccc.md', 'aaa.md'].map{ |name| OctokitContent.new(name: name, path: 'farend/redmine_github_repo', type: 'file', size: 256) } - - Octokit.stub(:contents, build_mock(contents, []) { |repo, options| + + Octokit.stub(:contents, build_mock(contents) { |repo, options| assert_equal @repo, repo assert_equal nil, options[:path] assert_equal 'HEAD', options[:ref] }) do entries = @scm.entries + assert_equal 3, entries.size assert_equal 'aaa.md', entries[0].name assert_equal 'bbb.md', entries[1].name assert_equal 'ccc.md', entries[2].name @@ -151,17 +152,18 @@ def test_entries_Githubに未ソートのコンテンツが与えられた場合 def test_entries_Githubのreport_last_commitオプションにtrueが与えられる場合 content = OctokitContent.new(name: 'test.md', path: 'farend/redmine_github_repo', type: 'file', size: 256) lastrev = OctokitRevision.new(identifier: 'shashasha') - - Octokit.stub(:contents, build_mock(content, []) { |repo, options| + + Octokit.stub(:contents, build_mock(content) { |repo, options| assert_equal @repo, repo assert_equal nil, options[:path] assert_equal 'shashasha', options[:ref] }) do - @scm.stub(:lastrev, build_mock(lastrev, []) { |repo, rev| + @scm.stub(:lastrev, build_mock(lastrev) { |repo, rev| assert_equal @repo, repo assert_equal 'shashasha', rev }) do entries = @scm.entries(nil, 'shashasha', {report_last_commit: true}) + assert_equal 'test.md', entries[0].name assert_equal 'shashasha', entries[0].lastrev.identifier end end @@ -169,8 +171,8 @@ def test_entries_Githubのreport_last_commitオプションにtrueが与えら def test_revision_to_sha_GithubにコミットのSHAを渡される場合 commit = OctokitCommit.new(sha: 'shashasha') - - Octokit.stub(:commits, build_mock([commit], []) { |repo, rev, options| + + Octokit.stub(:commits, build_mock([commit]) { |repo, rev, options| assert_equal @repo, repo assert_equal 'shashasha', rev assert_equal 1, options[:per_page] @@ -181,8 +183,8 @@ def test_revision_to_sha_GithubにコミットのSHAを渡される場合 def test_revision_to_sha_Githubにブランチ名を渡される場合 branch = OctokitBranch.new(name: 'main', sha: 'shashasha') - - Octokit.stub(:commits, build_mock([branch], []) { |repo, rev, options| + + Octokit.stub(:commits, build_mock([branch]) { |repo, rev, options| assert_equal @repo, repo assert_equal 'main', rev assert_equal 1, options[:per_page] @@ -191,57 +193,63 @@ def test_revision_to_sha_Githubにブランチ名を渡される場合 end end - def test_lastrev_Githubの戻り値が返ってくる場合 - author = OctokitAuthor.new(name: 'AuthorName') - committer = OctokitCommiter.new(date: '2023-01-01 00:00:00') - rev = OctokitRevision.new(identifier: 'shashasha', author: author, committer: committer) - commit = OctokitCommit.new(sha: 'shashasha', commit: rev ) - - Octokit.stub(:commits, build_mock([commit], []) { |repo, rev, options| + def test_lastrev_GithubのAPIの戻り値が返ってくることを確認 + commit = OctokitCommit.new( + sha: 'shashasha', + commit: OctokitRevision.new( + identifier: 'shashasha', + author: OctokitAuthor.new(name: 'AuthorName'), + committer: OctokitCommiter.new(date: '2023-01-01 00:00:00') + ) + ) + + Octokit.stub(:commits, build_mock([commit]) { |repo, rev, options| assert_equal @repo, repo assert_equal 'shashasha', rev assert_equal @repo, options[:path] assert_equal 1, options[:per_page] }) do revision = @scm.lastrev('farend/redmine_github_repo', 'shashasha') - + assert_equal 'shashasha', revision.identifier assert_equal 'AuthorName', revision.author assert_equal '2023-01-01 00:00:00', revision.time end end - def test_lastrev_Githubの引数pathが与えられない場合 - Octokit.stub(:commits, build_mock([], []) { |repo, rev, options| + def test_lastrev_Githubのpath引数が省略された場合 + Octokit.stub(:commits, build_mock([]) { |repo, rev, options| assert_equal nil, repo assert_equal 'shashasha', rev assert_equal @repo, options[:path] assert_equal 1, options[:per_page] }) do - assert_equal nil, @scm.lastrev(nil, 'shashasha') + assert_nil @scm.lastrev(nil, 'shashasha') end end def test_lastrev_Githubの引数に該当するコミットが存在しない場合 - Octokit.stub(:commits, build_mock([], []) { |repo, rev, options| + Octokit.stub(:commits, build_mock([]) { |repo, rev, options| assert_equal @repo, repo assert_equal 'shashasha', rev assert_equal @repo, options[:path] assert_equal 1, options[:per_page] }) do - assert_equal nil, @scm.lastrev(@repo, 'shashasha') + assert_nil @scm.lastrev(@repo, 'shashasha') end end - def test_get_path_name_Githubの戻り値が存在する場合 - blob = OctokitContent.new(sha: 'shashasha', path: 'farend/redmine_github_repo') - tree = OctokitTree.new(tree:[blob], sha: 'shashasha') + def test_get_path_name_GithubのAPIで取得したトップディレクトリが取得できること + tree = OctokitTree.new( + tree:[OctokitContent.new(sha: 'shashasha', path: 'farend/redmine_github_repo')], + sha: 'shashasha' + ) commit = OctokitCommit.new(sha: 'shashasha', commit: OctokitRevision.new(tree: tree)) - - Octokit.stub(:commits, build_mock([commit], []) { |repo| + + Octokit.stub(:commits, build_mock([commit]) { |repo| assert_equal @repo, repo }) do - Octokit.stub(:tree, build_mock(tree, []) { |repo, sha| + Octokit.stub(:tree, build_mock(tree) { |repo, sha| assert_equal @repo, repo assert_equal 'shashasha', sha }) do @@ -251,16 +259,21 @@ def test_get_path_name_Githubの戻り値が存在する場合 end def test_revisions_Githubの戻り値が1つある場合 - author = OctokitAuthor.new(name: 'AuthorName') - committer = OctokitCommiter.new(date: '2023-01-01 00:00:00') - parent = OctokitCommit.new(sha: 'shashafrom') - rev = OctokitRevision.new(identifier: 'shashato', author: author, committer: committer, message: 'commit message') - commit = OctokitCommit.new(sha: 'shashato', commit: rev, parents: [parent]) - options = { path: @repo, per_page: 1 } + commit = OctokitCommit.new( + sha: 'shashato', + commit: OctokitRevision.new( + identifier: 'shashato', + author: OctokitAuthor.new(name: 'AuthorName'), + committer: OctokitCommiter.new(date: '2023-01-01 00:00:00'), + message: 'commit message' + ), + parents: [OctokitCommit.new(sha: 'shashafrom')] + ) + Octokit.stub(:commits, build_mock([commit], []) { |repo| assert_equal @repo, repo }) do - revisions = @scm.revisions(@repo, 'shashato', 'shashafrom', options ) + revisions = @scm.revisions(@repo, 'shashato', 'shashafrom', { per_page: 1 } ) assert_equal 1, revisions.size assert_equal 'shashato', revisions[0].identifier @@ -270,67 +283,73 @@ def test_revisions_Githubの戻り値が1つある場合 end end - def test_revisions_Githubの戻り値が複数ある場合 - parents = [] + def test_revisions_GithubのAPIレスポンスに複数のコミットがある場合 + parents = [ OctokitCommit.new(sha: "shashasha0") ] commits = 3.times.map { |i| author = OctokitAuthor.new(name: "Author#{i}") committer = OctokitCommiter.new(date: "2023-01-00 0#{i}:00:00") - parents << OctokitCommit.new(sha: "shashasha#{i}") rev = OctokitRevision.new(identifier: "shashasha#{i+1}", author: author, committer: committer, message: 'commit message') - OctokitCommit.new(sha: "shashasha#{i+1}", commit: rev, parents: parents.dup) + commit = OctokitCommit.new(sha: "shashasha#{i+1}", commit: rev, parents: [ parents[i] ]) + parents << commit + commit } - options = { path: @repo, per_page: 1 } - Octokit.stub(:commits, build_mock(commits, []) { |repo| + Octokit.stub(:commits, build_mock(commits) { |repo| assert_equal @repo, repo }) do - revisions = @scm.revisions(@repo, 'shashato', 'shashafrom', options ) + revisions = @scm.revisions(@repo, 'shashato', 'shashafrom', { per_page: 1 }) assert_equal 3, revisions.size revisions.each_with_index {|rev, i| assert_equal "shashasha#{i+1}", rev.identifier assert_equal "2023-01-00 0#{i}:00:00", rev.time - assert_equal i + 1, rev.parents.size + assert_equal 1, rev.parents.length + assert_equal "shashasha#{i}", rev.parents.first } end end def test_revisions_Githubのallオプションにtrueが与えられる場合 - parents = [] + parents = [ OctokitCommit.new(sha: "shashasha0") ] commits = 3.times.map { |i| author = OctokitAuthor.new(name: "Author#{i}") committer = OctokitCommiter.new(date: "2023-01-00 0#{i}:00:00") - parents << OctokitCommit.new(sha: "shashasha#{i-1}") if i > 0 - rev = OctokitRevision.new(identifier: "shashasha#{i+1}", author: author, + rev = OctokitRevision.new(identifier: "shashasha#{i+1}", author: author, committer: committer, message: 'commit message') - OctokitCommit.new(sha: "shashasha#{i+1}", commit: rev, parents: parents.dup) + commit = OctokitCommit.new(sha: "shashasha#{i+1}", commit: rev, parents: [parents[i]]) + parents << commit + commit } - options = { path: @repo, per_page: 1, all: true} - Octokit.stub(:commits, build_mock(commits, commits, []) { |repo, api_opts| assert_equal @repo, repo assert_equal true, api_opts[:all] }) do - revisions = @scm.revisions(@repo, nil, nil, options) - + revisions = @scm.revisions(@repo, nil, nil, { per_page: 1, all: true}) + assert_equal 3, revisions.size - assert_equal ["shashasha0", "shashasha1"], revisions.last.parents + assert_equal 1, revisions.last.parents.size + assert_equal "shashasha2", revisions.last.parents.last assert_equal 'Author2', revisions.last.author end end def test_get_filechanges_and_append_to_Githubに1つのrevisisonが渡される場合 - add_file = TestFile.new(status: "added", filename: "add.md") - mod_file = TestFile.new(status: "modified", filename: "mod.md") - rev = OctokitRevision.new(identifier: "shashasha", paths: nil) - commit = OctokitCommit.new(sha: "shashasha", files: [add_file, mod_file]) - - Octokit.stub(:commit, build_mock(commit, []) { |repo, sha| + commit = OctokitCommit.new( + sha: "shashasha", files: [ + TestFile.new(status: "added", filename: "add.md"), + TestFile.new(status: "modified", filename: "mod.md"), + ] + ) + + Octokit.stub(:commit, build_mock(commit) { |repo, sha| assert_equal @repo, repo assert_equal "shashasha", sha }) do + rev = OctokitRevision.new(identifier: "shashasha", paths: nil) + @scm.get_filechanges_and_append_to([rev]) + assert_equal 'A', rev.paths[0][:action] assert_equal 'add.md', rev.paths[0][:path] assert_equal 'M', rev.paths[1][:action] @@ -338,149 +357,136 @@ def test_get_filechanges_and_append_to_Githubに1つのrevisisonが渡される end end - def test_diff_Githubに追加差分のあるファイルパスとコミットSHAが渡される場合 - file = TestFile.new(status: 'added', filename: "farend/redmine_github_repo/README.md") - cat = "add_line" - commit = OctokitCommit.new(sha: 'shashasha', files: [file]) + def test_diff_GithubAPIで追加差分のあるファイルパスとコミットSHAが返される場合 + filename = "farend/redmine_github_repo/README.md" + commit = OctokitCommit.new(sha: 'shashasha', files: [TestFile.new(status: 'added', filename: filename)]) - added_diffs = [ - "diff", - "--- /dev/null", - "+++ b/#{file.filename}", - "@@ -0,0 +1,2 @@", - "+#{cat}" - ] - - Octokit.stub(:commit, build_mock(commit, []) { |repo, identifier_from, options| + Octokit.stub(:commit, build_mock(commit) { |repo, identifier_from, options| assert_equal @repo, repo assert_equal 'shashasha', identifier_from - assert_equal @repo, options[:path] + assert_equal filename, options[:path] }) do - @scm.stub(:cat, build_mock(cat, []) { |path, identifier| - assert_equal 'farend/redmine_github_repo/README.md', path + @scm.stub(:cat, build_mock("added_content") { |path, identifier| + assert_equal filename, path assert_equal 'shashasha', identifier }) do - diffs = @scm.diff(@repo, "shashasha") - assert_equal added_diffs, diffs + diffs = @scm.diff(filename, "shashasha") + assert_equal [ + "diff", + "--- /dev/null", + "+++ b/#{filename}", + "@@ -0,0 +1,2 @@", + "+added_content" + ], diffs end end end - def test_diff_Githubにファイル名変更差分のあるファイルパスとコミットshaが渡される場合 + def test_diff_GithubAPIでファイル名変更差分のあるファイルパスとコミットshaが返される場合 file_from = TestFile.new(status: 'added', filename: "farend/redmine_github_repo/README.md") file_to = TestFile.new(status: 'renamed', filename: "farend/redmine_github_repo/RENAME.md", previous_filename: "farend/redmine_github_repo/README.md") - cat = "add_line" - commit_from = OctokitCommit.new(sha: 'shashafrom') - commit_to = OctokitCommit.new(sha: 'shashato') - compare = OctokitCompare.new(base_commit: commit_from, commits: [commit_to], files: [file_to, file_from]) - - renamed_diffs = [ - "diff", - "--- a/#{file_from.filename}", - "+++ b/#{file_to.filename}", - "diff", - "--- /dev/null", - "+++ b/#{file_from.filename}", - "@@ -0,0 +1,2 @@", - "+#{cat}" - ] - - ids = ['shashafrom', 'shashato'] - - Octokit.stub(:compare, build_mock(compare, []) { |repo, identifier_to, identifier_from, options| + compare = OctokitCompare.new( + base_commit: OctokitCommit.new(sha: 'shashafrom'), + commits: [OctokitCommit.new(sha: 'shashato')], + files: [file_to, file_from] + ) + + Octokit.stub(:compare, build_mock(compare) { |repo, identifier_to, identifier_from, options| assert_equal @repo, repo assert_equal 'shashato', identifier_to assert_equal 'shashafrom', identifier_from - assert_equal @repo, options[:path] + assert_equal 'farend/redmine_github_repo', options[:path] }) do - @scm.stub(:cat, build_mock(cat, []) { |path, identifier| + @scm.stub(:cat, build_mock("added_content") { |path, identifier| assert_equal 'farend/redmine_github_repo/README.md', path - assert_equal ids.shift, identifier + assert_equal 'shashafrom', identifier }) do - diffs = @scm.diff(@repo, 'shashafrom', 'shashato') - assert_equal renamed_diffs, diffs + diffs = @scm.diff('farend/redmine_github_repo', 'shashafrom', 'shashato') + assert_equal [ + "diff", + "--- a/#{file_from.filename}", + "+++ b/#{file_to.filename}", + "diff", + "--- /dev/null", + "+++ b/#{file_from.filename}", + "@@ -0,0 +1,2 @@", + "+added_content" + ], diffs end end end - def test_diff_Githubに変更差分のあるファイルパスとコミットshaが渡される場合 + def test_diff_GithubAPIで変更差分のあるファイルパスとコミットshaが返される場合 file_from = TestFile.new(status: 'added', filename: "farend/redmine_github_repo/README.md") file_to = TestFile.new(status: 'modifies', filename: "farend/redmine_github_repo/README.md", patch:'+mod_line') - cat = "add_line" - commit_from = OctokitCommit.new(sha: 'shashafrom') - commit_to = OctokitCommit.new(sha: 'shashato') - compare = OctokitCompare.new(base_commit: commit_from, commits: [commit_to], files: [file_to, file_from]) - - modified_diffs = [ - "diff", - "--- a/#{file_from.filename}", - "+++ b/#{file_to.filename}", - "#{file_to.patch}", - "diff", - "--- /dev/null", - "+++ b/#{file_from.filename}", - "@@ -0,0 +1,2 @@", - "+#{cat}" - ] - - ids = ['shashafrom', 'shashato'] - - Octokit.stub(:compare, build_mock(compare, []) { |repo, identifier_to, identifier_from, options| + compare = OctokitCompare.new( + base_commit: OctokitCommit.new(sha: 'shashafrom'), + commits: [OctokitCommit.new(sha: 'shashato')], + files: [file_to, file_from] + ) + + Octokit.stub(:compare, build_mock(compare) { |repo, identifier_to, identifier_from, options| assert_equal @repo, repo assert_equal 'shashato', identifier_to assert_equal 'shashafrom', identifier_from - assert_equal @repo, options[:path] + assert_equal 'farend/redmine_github_repo/README.md', options[:path] }) do - @scm.stub(:cat, build_mock(cat, []) { |path, identifier| + @scm.stub(:cat, build_mock("added_content") { |path, identifier| assert_equal 'farend/redmine_github_repo/README.md', path - assert_equal ids.shift, identifier + assert_equal 'shashafrom', identifier }) do - diffs = @scm.diff(@repo, "shashafrom", "shashato") - assert_equal modified_diffs, diffs + diffs = @scm.diff('farend/redmine_github_repo/README.md', "shashafrom", "shashato") + assert_equal [ + "diff", + "--- a/#{file_from.filename}", + "+++ b/#{file_to.filename}", + "#{file_to.patch}", + "diff", + "--- /dev/null", + "+++ b/#{file_from.filename}", + "@@ -0,0 +1,2 @@", + "+added_content" + ], diffs end end end - def test_diff_Githubに削除差分のあるファイルパスとコミットshaが渡される場合 + def test_diff_GithubAPIに削除差分のあるファイルパスとコミットshaが渡される場合 file_from = TestFile.new(status: 'added', filename: "farend/redmine_github_repo/README.md") file_to = TestFile.new(status: 'removed', filename: "farend/redmine_github_repo/README.md", patch:'-add_line') - cat = "add_line" - commit_from = OctokitCommit.new(sha: 'shashafrom') - commit_to = OctokitCommit.new(sha: 'shashato') - compare = OctokitCompare.new(base_commit: commit_from, commits: [commit_to], files: [file_from, file_to]) - - removed_diffs = [ - "diff", - "--- /dev/null", - "+++ b/#{file_from.filename}", - "@@ -0,0 +1,2 @@", - "+#{cat}", - "diff", - "--- a/#{file_from.filename}", - "+++ /dev/null", - "@@ -1,2 +0,0 @@", - "-[]" - ] - - ids = ['shashafrom', 'shashato'] - - Octokit.stub(:compare, build_mock(compare, []) { |repo, identifier_to, identifier_from, options| + compare = OctokitCompare.new( + base_commit: OctokitCommit.new(sha: 'shashafrom'), + commits: [OctokitCommit.new(sha: 'shashato')], + files: [file_from, file_to] + ) + + Octokit.stub(:compare, build_mock(compare) { |repo, identifier_to, identifier_from, options| assert_equal @repo, repo assert_equal 'shashato', identifier_to assert_equal 'shashafrom', identifier_from - assert_equal @repo, options[:path] + assert_equal 'farend/redmine_github_repo/README.md', options[:path] }) do - @scm.stub(:cat, build_mock(cat, []) { |path, identifier| + @scm.stub(:cat, build_mock('add_line', []) { |path, identifier| assert_equal 'farend/redmine_github_repo/README.md', path - assert_equal ids.shift, identifier }) do - diffs = @scm.diff(@repo, "shashafrom", "shashato") - assert_equal removed_diffs, diffs + diffs = @scm.diff('farend/redmine_github_repo/README.md', "shashafrom", "shashato") + assert_equal [ + "diff", + "--- /dev/null", + "+++ b/#{file_from.filename}", + "@@ -0,0 +1,2 @@", + "+add_line", + "diff", + "--- a/#{file_from.filename}", + "+++ /dev/null", + "@@ -1,2 +0,0 @@", + "-[]" + ], diffs end end end - def test_default_branch_Githubの戻り値が存在する場合 + def test_default_branch_GithubAPIの戻り値が存在する場合 branch = OctokitBranch.new(name: 'main', commit: OctokitCommit.new(sha: 'shashasha')) Octokit.stub(:branches, build_mock([branch], []) { |repo| assert_equal @repo, repo @@ -489,37 +495,32 @@ def test_default_branch_Githubの戻り値が存在する場合 end end - def test_default_branch_Githubの戻り値が存在しない場合 - Octokit.stub(:branches, build_mock([], []) { |repo| + def test_default_branch_GithubAPIの戻り値が存在しない場合 + Octokit.stub(:branches, build_mock([]) { |repo| assert_equal @repo, repo }) do - assert_equal nil, @scm.default_branch + assert_nil @scm.default_branch end end - def test_entry_Githubに引数を渡す場合 + def test_entry_対象ファイルのpathを引数として渡す場合 content = OctokitContent.new(name: 'README.md', path: @repo, type: 'file', size: 256) - lastrev = OctokitRevision.new(identifier:'shashasha') - Octokit.stub(:contents, build_mock([content], []) { |repo, options| + Octokit.stub(:contents, build_mock([content]) { |repo, options| assert_equal @repo, repo assert_equal 'README.md', options[:path] assert_equal 'HEAD', options[:ref] }) do - @scm.stub(:lastrev, build_mock(lastrev, []) { |repos, rev| - assert_equal @repo, repos - }) do - entry = @scm.entry('README.md') - assert_equal 'README.md', entry.name - assert_equal 'file', entry.kind - assert_equal @repo, entry.path - assert_equal 256, entry.size - end + entry = @scm.entry('README.md') + assert_equal 'README.md', entry.name + assert_equal 'file', entry.kind + assert_equal @repo, entry.path + assert_equal 256, entry.size end end - def test_entry_Githubに引数を渡さない場合 - Octokit.stub(:contents, build_mock([], []) { |repo, options| + def test_entry_path引数を渡さない場合 + Octokit.stub(:contents, build_mock([]) { |repo, options| assert_equal @repo, repo assert_equal @repo, options[:path] assert_equal 'HEAD', options[:ref] @@ -530,57 +531,60 @@ def test_entry_Githubに引数を渡さない場合 end end - def test_cat_Githubで取得ファイルのエンコードが不要な場合 + def test_cat_GithubAPIでテキストファイルを取得する場合 blob = OctokitContent.new(path: @repo, sha: 'shashasha', download_url: 'http://download/url', encoding: 'utf-8', content: 'test_content') - get = OctokitGet.new(headers:{ "content-type" => 'text/html; charset=utf-8'}) - Octokit.stub(:contents, build_mock(blob, []) { |path, options| + last_response = OctokitGet.new(headers:{ "content-type" => 'text/html; charset=utf-8'}) + Octokit.stub(:contents, build_mock(blob) { |path, options| assert_equal @repo, path assert_equal @repo, options[:path] assert_equal 'HEAD', options[:ref] }) do - Octokit.stub(:get, build_mock(get, []) { |url| + Octokit.stub(:get, build_mock(nil) { |url| assert_equal 'http://download/url', url }) do - Octokit.stub(:last_response, build_mock(get, [])) do - assert_equal 'test_content', @scm.cat(@repo) + Octokit.stub(:last_response, build_mock(last_response)) do + body = @scm.cat(@repo) + assert_equal 'test_content', body end end end end - def test_cat_Githubで取得ファイルのエンコードが必要な場合 + def test_cat_GithubAPIでbase64エンコードされたテキストファイルを取得する場合 blob = OctokitContent.new(path: @repo, sha: 'shashasha', download_url: 'http://download/url', encoding: 'base64', content: 'dGVzdF9jb250ZW50') - get = OctokitGet.new(headers:{ "content-type" => 'text/html; charset=base64'}) + last_response = OctokitGet.new(headers:{ "content-type" => 'text/html; charset=base64'}) Octokit.stub(:contents, build_mock(blob, []) { |path, options| assert_equal @repo, path assert_equal @repo, options[:path] assert_equal 'HEAD', options[:ref] }) do - Octokit.stub(:get, build_mock(get, []) { |url| + Octokit.stub(:get, build_mock(nil) { |url| assert_equal 'http://download/url', url }) do - Octokit.stub(:last_response, build_mock(get, [])) do - assert_equal 'test_content', @scm.cat(@repo) + Octokit.stub(:last_response, build_mock(last_response)) do + body = @scm.cat(@repo) + assert_equal 'test_content', body end end end end - def test_cat_Githubで取得ファイルがバイナリ形式の場合 + def test_cat_GithubAPIでバイナリファイルを取得する場合 blob = OctokitContent.new(path: @repo, sha: 'shashasha', download_url: 'http://download/url') - get = OctokitGet.new(headers:{ "content-type" => 'binary'}) + last_response = OctokitGet.new(headers:{ "content-type" => 'binary'}) Octokit.stub(:contents, build_mock(blob, []) { |path, options| assert_equal @repo, path assert_equal @repo, options[:path] assert_equal 'HEAD', options[:ref] }) do - Octokit.stub(:get, build_mock(get, []) { |url| + Octokit.stub(:get, build_mock(nil) { |url| assert_equal 'http://download/url', url }) do - Octokit.stub(:last_response, build_mock(get, [])) do - assert_equal '', @scm.cat(@repo) + Octokit.stub(:last_response, build_mock(last_response)) do + body = @scm.cat(@repo) + assert_equal '', body end end end @@ -590,16 +594,16 @@ def test_cat_Githubで取得ファイルがバイナリ形式の場合 OctokitBranch = Struct.new(:name, :commit, :sha, keyword_init: true) OctokitCommit = Struct.new(:sha, :commit, :parents, :files, keyword_init: true) - OctokitContent = Struct.new(:sha, :name, :path, :type, :size, :download_url, + OctokitContent = Struct.new(:sha, :name, :path, :type, :size, :download_url, :content, :encoding, keyword_init: true) - OctokitRevision = Struct.new(:identifier, :author, :committer, :tree, + OctokitRevision = Struct.new(:identifier, :author, :committer, :tree, :message, :paths, keyword_init: true) OctokitAuthor = Struct.new(:name, keyword_init: true) OctokitCommiter = Struct.new(:date, keyword_init: true) OctokitTree = Struct.new(:tree, :sha, keyword_init: true) OctokitCompare = Struct.new(:base_commit, :commits, :files, keyword_init: true) - OctokitGet = Struct.new(:headers, keyword_init: true) - TestFile = Struct.new(:status, :filename, :previous_filename, + OctokitGet = Struct.new(:headers, keyword_init: true) + TestFile = Struct.new(:status, :filename, :previous_filename, :from_revision, :patch, keyword_init: true) def build_mock(*returns, &proc) From e0b2d2595d3bdd06fdedea9e5151ffd9faef4de3 Mon Sep 17 00:00:00 2001 From: xketanaka Date: Mon, 23 Oct 2023 20:00:57 +0900 Subject: [PATCH 16/17] =?UTF-8?q?=E8=87=AA=E5=8B=95=E3=83=86=E3=82=B9?= =?UTF-8?q?=E3=83=88=E3=81=AE=E8=BF=BD=E5=8A=A0=20(#22)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add github actions --- .github/workflows/ci.yml | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..c8c3d87 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,35 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. +# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake +# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby + +name: Run plugin Test + +on: push + +jobs: + test: + runs-on: ubuntu-latest + container: + image: redmine:4.2.10-bullseye + env: + RAILS_ENV: test + steps: + - name: Setup Env + run: | + ln -s /usr/src/redmine ./redmine + git config --global --add safe.directory /usr/src/redmine/plugins/redmine_github_adapter + - uses: actions/checkout@v3 + with: + path: ./redmine/plugins/redmine_github_adapter + - name: Run tests + run: | + cd redmine + /docker-entrypoint.sh rails s --help + bundle config unset without --local + bundle install + bundle exec rake redmine:plugins:migrate + bundle exec rake redmine:plugins:test RAILS_ENV=test + From 004a15da5ebd8b33bd4e260ed5e9ea38799d0974 Mon Sep 17 00:00:00 2001 From: tanaka ken Date: Mon, 23 Oct 2023 20:08:53 +0900 Subject: [PATCH 17/17] =?UTF-8?q?github=20actions=20=E3=82=92=E8=87=AA?= =?UTF-8?q?=E5=8B=95=E7=94=9F=E6=88=90=E3=81=97=E3=81=AA=E3=81=84=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB=E3=83=87=E3=82=A3=E3=83=AC=E3=82=AF=E3=83=88?= =?UTF-8?q?=E3=83=AA=E5=90=8D=E3=82=92=E3=83=AA=E3=83=8D=E3=83=BC=E3=83=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- {.github => dot.github}/workflows/ci.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {.github => dot.github}/workflows/ci.yml (100%) diff --git a/.github/workflows/ci.yml b/dot.github/workflows/ci.yml similarity index 100% rename from .github/workflows/ci.yml rename to dot.github/workflows/ci.yml