| #!/usr/bin/python3 |
| # |
| # Copyright (C) 2020 The Android Open Source Project |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| # |
| |
| import unittest |
| import os |
| from GitClient import * |
| |
| class GitClientTestImpl(GitClient): |
| def __init__(self, workingDir): |
| self.workingDir = workingDir |
| self.gitRoot = self.findGitDirInParentFilepath(workingDir) |
| if self.gitRoot == None: |
| self.gitRoot = workingDir |
| self.commandReplies = {} |
| |
| def executeCommand(self, command): |
| if command in self.commandReplies: |
| return self.commandReplies[command] |
| else: |
| print_e('FAILED: The following command was not given a reply for the mock GitClient: \n%s\n ' % command) |
| return None |
| |
| def addReply(self, command, reply): |
| self.commandReplies[command] = reply |
| |
| class TestGitClient(unittest.TestCase): |
| |
| def test_gitClientFindsGitDir(self): |
| gitClient = GitClientTestImpl(os.getcwd()) |
| self.assertTrue(os.path.exists(gitClient.gitRoot + "/.git")) |
| |
| def test_parseMalformattedReleaseNoteLine(self): |
| projectDir = "group/artifact" |
| commitWithABugFixString = """ |
| _CommitStart |
| Here is an explanation of my commit that changes a kotlin file |
| |
| Relnote: "Missing close quote in the release note block. |
| This is the second line of the release notes. It should not be included in the |
| release notes because this commit is missing the closing quote. |
| |
| Bug: 111111, 222222 |
| Test: ./gradlew buildOnServer |
| Change-Id: myChangeId |
| """ + \ |
| projectDir + "/a.java" |
| commitWithABugFix = Commit( |
| commitWithABugFixString, |
| projectDir |
| ) |
| self.assertEqual( |
| "Missing close quote in the release note block.", |
| commitWithABugFix.releaseNote |
| ) |
| |
| def test_parseAPICommitWithMultiLineReleaseNote(self): |
| commitWithApiChangeString = """ |
| _CommitStart |
| _CommitSHA:mySha |
| _Author:[email protected] |
| _Date:Tue Aug 6 15:05:55 2019 -0700 |
| _Subject:Added a new API! |
| _Body:Also fixed some other bugs |
| |
| Here is an explanation of my commit |
| |
| "This is a quote about why it's great!" |
| |
| Relnote: "Added a new API that does something awesome and does a whole bunch |
| of other things that are also awesome and I just can't elaborate enough how |
| incredible this API is" |
| |
| "This is an extra set of quoted text" |
| |
| Bug: 123456 |
| Bug: b/1234567 |
| Fixes: 123123 |
| Test: ./gradlew buildOnServer |
| |
| Change-Id: myChangeId |
| |
| projectdir/a.java |
| projectdir/b.java |
| projectdir/androidTest/c.java |
| projectdir/api/some_api_file.txt |
| projectdir/api/current.txt |
| """ |
| commitWithApiChange = Commit(commitWithApiChangeString, "/projectdir/") |
| self.assertEqual("mySha", commitWithApiChange.sha) |
| self.assertEqual("[email protected]", commitWithApiChange.authorEmail) |
| self.assertEqual("myChangeId", commitWithApiChange.changeId) |
| self.assertEqual("Added a new API!", commitWithApiChange.summary) |
| self.assertEqual(CommitType.API_CHANGE, commitWithApiChange.changeType) |
| self.assertEqual([123456, 1234567, 123123], commitWithApiChange.bugs) |
| self.assertEqual([ |
| "projectdir/a.java", |
| "projectdir/b.java", |
| "projectdir/androidTest/c.java", |
| "projectdir/api/some_api_file.txt", |
| "projectdir/api/current.txt" |
| ], |
| commitWithApiChange.files |
| ) |
| self.assertEqual( |
| "Added a new API that does something awesome and does a whole bunch\n" + |
| " of other things that are also awesome and I just can't elaborate " + |
| "enough how\n incredible this API is", |
| commitWithApiChange.releaseNote |
| ) |
| |
| def test_parseAPICommitWithDefaultDelimiters(self): |
| commitWithApiChangeString = """ |
| _CommitStart |
| _CommitSHA:mySha |
| _Author:[email protected] |
| _Date:Tue Aug 6 15:05:55 2019 -0700 |
| _Subject:Added a new API! |
| _Body:Also fixed some other bugs |
| |
| Here is an explanation of my commit |
| |
| "This is a quote about why it's great!" |
| |
| Bug: 123456 |
| Bug: b/1234567 |
| Fixes: 123123 |
| Test: ./gradlew buildOnServer |
| |
| Relnote: Added an awesome new API! |
| |
| Change-Id: myChangeId |
| |
| projectdir/a.java |
| projectdir/b.java |
| projectdir/androidTest/c.java |
| projectdir/api/some_api_file.txt |
| projectdir/api/current.txt |
| """ |
| commitWithApiChange = Commit(commitWithApiChangeString, "/projectdir/") |
| self.assertEqual("mySha", commitWithApiChange.sha) |
| self.assertEqual("[email protected]", commitWithApiChange.authorEmail) |
| self.assertEqual("myChangeId", commitWithApiChange.changeId) |
| self.assertEqual("Added a new API!", commitWithApiChange.summary) |
| self.assertEqual(CommitType.API_CHANGE, commitWithApiChange.changeType) |
| self.assertEqual([123456, 1234567, 123123], commitWithApiChange.bugs) |
| self.assertEqual([ |
| "projectdir/a.java", |
| "projectdir/b.java", |
| "projectdir/androidTest/c.java", |
| "projectdir/api/some_api_file.txt", |
| "projectdir/api/current.txt" |
| ], |
| commitWithApiChange.files |
| ) |
| self.assertEqual("Added an awesome new API!", commitWithApiChange.releaseNote) |
| |
| def test_parseAPICommitWithDefaultDelimitersAndNonstandardQuoteCharacters(self): |
| commitWithApiChangeString = """ |
| _CommitStart |
| _CommitSHA:mySha |
| _Author:[email protected] |
| _Date:Tue Aug 6 15:05:55 2019 -0700 |
| _Subject:Added a new API! |
| _Body:Also fixed some other bugs |
| |
| Here is an explanation of my commit |
| |
| "This is a quote about why it's great!" |
| |
| Bug: 123456 |
| Bug: b/1234567 |
| Fixes: 123123 |
| Test: ./gradlew buildOnServer |
| |
| Relnote: “Added an awesome new API! |
| It will make your life easier.” |
| |
| Change-Id: myChangeId |
| |
| projectdir/a.java |
| projectdir/b.java |
| projectdir/androidTest/c.java |
| projectdir/api/some_api_file.txt |
| projectdir/api/current.txt |
| """ |
| commitWithApiChange = Commit(commitWithApiChangeString, "/projectdir/") |
| self.assertEqual("mySha", commitWithApiChange.sha) |
| self.assertEqual("[email protected]", commitWithApiChange.authorEmail) |
| self.assertEqual("myChangeId", commitWithApiChange.changeId) |
| self.assertEqual("Added a new API!", commitWithApiChange.summary) |
| self.assertEqual(CommitType.API_CHANGE, commitWithApiChange.changeType) |
| self.assertEqual([123456, 1234567, 123123], commitWithApiChange.bugs) |
| self.assertEqual([ |
| "projectdir/a.java", |
| "projectdir/b.java", |
| "projectdir/androidTest/c.java", |
| "projectdir/api/some_api_file.txt", |
| "projectdir/api/current.txt" |
| ], |
| commitWithApiChange.files |
| ) |
| self.assertEqual("Added an awesome new API!\n" + \ |
| " It will make your life easier." |
| , commitWithApiChange.releaseNote) |
| |
| def test_parseAPICommitWithDefaultDelimitersAndUncapitalizedRelnoteTag(self): |
| commitWithApiChangeString = """ |
| _CommitStart |
| _CommitSHA:mySha |
| _Author:[email protected] |
| _Date:Tue Aug 6 15:05:55 2019 -0700 |
| _Subject:Added a new API! |
| _Body:Also fixed some other bugs |
| |
| Here is an explanation of my commit |
| |
| "This is a quote about why it's great!" |
| |
| Bug: 123456 |
| Bug: b/1234567 |
| Fixes: 123123 |
| Test: ./gradlew buildOnServer |
| |
| relnote: Added an awesome new API! |
| |
| Change-Id: myChangeId |
| |
| projectdir/a.java |
| projectdir/b.java |
| projectdir/androidTest/c.java |
| projectdir/api/some_api_file.txt |
| projectdir/api/current.txt |
| """ |
| commitWithApiChange = Commit(commitWithApiChangeString, "/projectdir/") |
| self.assertEqual("mySha", commitWithApiChange.sha) |
| self.assertEqual("[email protected]", commitWithApiChange.authorEmail) |
| self.assertEqual("myChangeId", commitWithApiChange.changeId) |
| self.assertEqual("Added a new API!", commitWithApiChange.summary) |
| self.assertEqual(CommitType.API_CHANGE, commitWithApiChange.changeType) |
| self.assertEqual([123456, 1234567, 123123], commitWithApiChange.bugs) |
| self.assertEqual([ |
| "projectdir/a.java", |
| "projectdir/b.java", |
| "projectdir/androidTest/c.java", |
| "projectdir/api/some_api_file.txt", |
| "projectdir/api/current.txt" |
| ], |
| commitWithApiChange.files |
| ) |
| self.assertEqual("Added an awesome new API!", commitWithApiChange.releaseNote) |
| |
| def test_parseAPICommitWithDefaultDelimitersAndCapitalizedRelnoteTag(self): |
| commitWithApiChangeString = """ |
| _CommitStart |
| _CommitSHA:mySha |
| _Author:[email protected] |
| _Date:Tue Aug 6 15:05:55 2019 -0700 |
| _Subject:Added a new API! |
| _Body:Also fixed some other bugs |
| |
| Here is an explanation of my commit |
| |
| "This is a quote about why it's great!" |
| |
| Bug: 123456 |
| Bug: b/1234567 |
| Fixes: 123123 |
| Test: ./gradlew buildOnServer |
| |
| RelNotE: Added an awesome new API! |
| |
| Change-Id: myChangeId |
| |
| projectdir/a.java |
| projectdir/b.java |
| projectdir/androidTest/c.java |
| projectdir/api/some_api_file.txt |
| projectdir/api/current.txt |
| """ |
| commitWithApiChange = Commit(commitWithApiChangeString, "/projectdir/") |
| self.assertEqual("mySha", commitWithApiChange.sha) |
| self.assertEqual("[email protected]", commitWithApiChange.authorEmail) |
| self.assertEqual("myChangeId", commitWithApiChange.changeId) |
| self.assertEqual("Added a new API!", commitWithApiChange.summary) |
| self.assertEqual(CommitType.API_CHANGE, commitWithApiChange.changeType) |
| self.assertEqual([123456, 1234567, 123123], commitWithApiChange.bugs) |
| self.assertEqual([ |
| "projectdir/a.java", |
| "projectdir/b.java", |
| "projectdir/androidTest/c.java", |
| "projectdir/api/some_api_file.txt", |
| "projectdir/api/current.txt" |
| ], |
| commitWithApiChange.files |
| ) |
| self.assertEqual("Added an awesome new API!", commitWithApiChange.releaseNote) |
| |
| def test_parseBugFixCommitWithCustomDelimiters(self): |
| commitSHADelimiter = "_MyCommitSHA:" |
| authorEmailDelimiter = "_MyAuthor:" |
| subjectDelimiter = "_MySubject:" |
| projectDir = "group/artifact" |
| commitWithABugFixString = "_CommitStart\n" + \ |
| commitSHADelimiter + "mySha\n" + \ |
| authorEmailDelimiter + "[email protected]\n" + \ |
| "_Date:Tue Aug 6 15:05:55 2019 -0700\n" + \ |
| subjectDelimiter + "Fixed a bug!\n" + \ |
| """ |
| _Body:Also fixed some other bugs |
| |
| Here is an explanation of my commit that changes a kotlin file |
| |
| Relnote: "Fixed a critical bug" |
| |
| Bug: 111111, 222222 |
| Test: ./gradlew buildOnServer |
| |
| Change-Id: myChangeId |
| """ + \ |
| projectDir + "/a.java\n" + \ |
| projectDir + "/b.kt\n" + \ |
| projectDir + "/androidTest/c.java\n" |
| commitWithABugFix = Commit( |
| gitCommit = commitWithABugFixString, |
| projectDir = projectDir, |
| commitSHADelimiter = commitSHADelimiter, |
| subjectDelimiter = subjectDelimiter, |
| authorEmailDelimiter = authorEmailDelimiter |
| ) |
| self.assertEqual("mySha", commitWithABugFix.sha) |
| self.assertEqual("[email protected]", commitWithABugFix.authorEmail) |
| self.assertEqual("myChangeId", commitWithABugFix.changeId) |
| self.assertEqual("Fixed a bug!", commitWithABugFix.summary) |
| self.assertEqual(CommitType.BUG_FIX, commitWithABugFix.changeType) |
| self.assertEqual([111111, 222222], commitWithABugFix.bugs) |
| self.assertEqual([ |
| projectDir + "/a.java", |
| projectDir + "/b.kt", |
| projectDir + "/androidTest/c.java" |
| ], |
| commitWithABugFix.files |
| ) |
| self.assertEqual("Fixed a critical bug", commitWithABugFix.releaseNote) |
| |
| def test_parseExternalContributorCommitWithCustomDelimiters(self): |
| commitSHADelimiter = "_MyCommitSHA:" |
| subjectDelimiter = "_MySubject:" |
| authorEmailDelimiter = "_MyAuthor:" |
| projectDir = "group/artifact" |
| commitFromExternalContributorString = "_CommitStart\n" + \ |
| commitSHADelimiter + "mySha\n" + \ |
| authorEmailDelimiter + "[email protected]\n" + \ |
| "_Date:Thurs Aug 8 15:05:55 2019 -0700\n" + \ |
| subjectDelimiter + "New compat API!\n" + \ |
| """ |
| _Body:Also fixed some other bugs |
| |
| Here is an explanation of my commit that changes a java file |
| |
| Relnote: Added a new compat API! |
| |
| Bug: 111111, 222222 |
| Test: ./gradlew buildOnServer |
| |
| Change-Id: myChangeId |
| """ + \ |
| projectDir + "/a.java\n" + \ |
| projectDir + "/b.java\n" + \ |
| projectDir + "/androidTest/c.java\n" + \ |
| projectDir + "/api/current.txt\n" + \ |
| projectDir + "/api/1.2.0-alpha04.txt\n" |
| commitFromExternalContributor = Commit( |
| commitFromExternalContributorString, |
| projectDir, |
| commitSHADelimiter = commitSHADelimiter, |
| subjectDelimiter = subjectDelimiter, |
| authorEmailDelimiter = authorEmailDelimiter |
| ) |
| self.assertEqual("mySha", commitFromExternalContributor.sha) |
| self.assertEqual("[email protected]", commitFromExternalContributor.authorEmail) |
| self.assertEqual("myChangeId", commitFromExternalContributor.changeId) |
| self.assertEqual("New compat API!", commitFromExternalContributor.summary) |
| self.assertEqual(CommitType.EXTERNAL_CONTRIBUTION, commitFromExternalContributor.changeType) |
| self.assertEqual([111111, 222222], commitFromExternalContributor.bugs) |
| self.assertEqual([ |
| projectDir + "/a.java", |
| projectDir + "/b.java", |
| projectDir + "/androidTest/c.java", |
| projectDir + "/api/current.txt", |
| projectDir + "/api/1.2.0-alpha04.txt" |
| ], |
| commitFromExternalContributor.files |
| ) |
| self.assertEqual("Added a new compat API!", commitFromExternalContributor.releaseNote) |
| |
| def test_parseGitLog(self): |
| mockGitRootDir = "gitRoot" |
| gitClient = GitClientTestImpl(mockGitRootDir) |
| # This is the default set-up boilerplate from `GitClientImpl.getGitLog` to set up the |
| # default git log command (gitLogCmd) |
| commitStartDelimiter = "_CommitStart" |
| commitSHADelimiter = "_CommitSHA:" |
| subjectDelimiter = "_Subject:" |
| authorEmailDelimiter = "_Author:" |
| dateDelimiter = "_Date:" |
| bodyDelimiter = "_Body:" |
| projectDir = "group/artifact" |
| gitLogOptions = "--pretty=format:" + \ |
| commitStartDelimiter + "\%n" + \ |
| commitSHADelimiter + "\%H\%n" + \ |
| authorEmailDelimiter + "\%ae\%n" + \ |
| dateDelimiter + "\%ad\%n" + \ |
| subjectDelimiter + "\%s\%n" + \ |
| bodyDelimiter + "\%b" + \ |
| " --no-merges" |
| fullProjectDir = os.path.join(mockGitRootDir, projectDir) |
| gitLogCmd = GIT_LOG_CMD_PREFIX + " %s %s..%s -- %s" % (gitLogOptions, "sha", "topSha", fullProjectDir) |
| # Check with default delimiters |
| gitLogString = """ |
| _CommitStart |
| _CommitSHA:topSha |
| _Author:[email protected] |
| _Date:Tue Aug 6 15:05:55 2019 -0700 |
| _Subject:Added a new API! |
| _Body:Also fixed some other bugs |
| |
| Here is an explanation of my commit |
| |
| Bug: 123456 |
| Bug: b/1234567 |
| Fixes: 123123 |
| Test: ./gradlew buildOnServer |
| |
| Change-Id: myChangeId\n |
| """ + \ |
| projectDir + "/a.java\n" + \ |
| projectDir + "/b.java\n" + \ |
| projectDir + "/androidTest/c.java\n" + \ |
| projectDir + "/api/some_api_file.txt\n" + \ |
| projectDir + "/api/current.txt\n" + \ |
| """ |
| _CommitStart |
| _CommitSHA:midSha |
| _Author:[email protected] |
| _Date:Tue Aug 6 15:05:55 2019 -0700 |
| _Subject:Fixed a bug! |
| _Body:Also fixed some other bugs |
| |
| Here is an explanation of my commit |
| |
| Bug: 111111, 222222 |
| Test: ./gradlew buildOnServer |
| |
| Change-Id: myChangeId\n |
| """ + \ |
| projectDir + "/a.java\n" + \ |
| projectDir + "/b.java\n" + \ |
| projectDir + "/androidTest/c.java\n" + \ |
| """ |
| _CommitStart |
| _CommitSHA:sha |
| _Author:[email protected] |
| _Date:Thurs Aug 8 15:05:55 2019 -0700 |
| _Subject:New compat API! |
| _Body:Also fixed some other bugs |
| |
| Here is an explanation of my commit |
| |
| Bug: 111111, 222222 |
| Test: ./gradlew buildOnServer |
| |
| Change-Id: myChangeId\n |
| """ + \ |
| projectDir + "/a.java\n" + \ |
| projectDir + "/b.java\n" + \ |
| projectDir + "/androidTest/c.java\n" + \ |
| projectDir + "/api/current.txt\n" + \ |
| projectDir + "/api/1.2.0-alpha04.txt\n" |
| |
| gitClient.addReply( |
| gitLogCmd, |
| gitLogString |
| ) |
| |
| commitWithAPIChange = Commit("", projectDir) |
| commitWithAPIChange.sha = "topSha" |
| commitWithAPIChange.authorEmail = "[email protected]" |
| commitWithAPIChange.changeId = "myChangeId" |
| commitWithAPIChange.summary = "Added a new API!" |
| commitWithAPIChange.type = CommitType.API_CHANGE |
| commitWithAPIChange.bugs = [123456, 1234567, 123123] |
| commitWithAPIChange.files = [ |
| projectDir + "/a.java", |
| projectDir + "/b.java", |
| projectDir + "/androidTest/c.java", |
| projectDir + "/api/some_api_file.txt", |
| projectDir + "/api/current.txt" |
| ] |
| |
| commitWithBugFix = Commit("", projectDir) |
| commitWithBugFix.sha = "midSha" |
| commitWithBugFix.authorEmail = "[email protected]" |
| commitWithBugFix.changeId = "myChangeId" |
| commitWithBugFix.summary = "Fixed a bug!" |
| commitWithBugFix.type = CommitType.BUG_FIX |
| commitWithBugFix.bugs = [111111, 222222] |
| commitWithBugFix.files = [ |
| projectDir + "/a.java", |
| projectDir + "/b.java", |
| projectDir + "/androidTest/c.java" |
| ] |
| |
| commitFromExternalContributor = Commit("", projectDir) |
| commitFromExternalContributor.sha = "sha" |
| commitFromExternalContributor.authorEmail = "[email protected]" |
| commitFromExternalContributor.changeId = "myChangeId" |
| commitFromExternalContributor.summary = "New compat API!" |
| commitFromExternalContributor.type = CommitType.EXTERNAL_CONTRIBUTION |
| commitFromExternalContributor.bugs = [111111, 222222] |
| commitFromExternalContributor.files = [ |
| projectDir + "/a.java", |
| projectDir + "/b.java", |
| projectDir + "/androidTest/c.java", |
| projectDir + "/api/current.txt", |
| projectDir + "/api/1.2.0-alpha04.txt" |
| ] |
| # In this test case, we pass an empty string as the subProjectDir because "group/artifact" |
| # is the git root dir and the git client will prepend that to the subProjectDir. |
| gitLogList = gitClient.getGitLog( |
| fromExclusiveSha = "sha", |
| untilInclusiveSha = "topSha", |
| keepMerges = False, |
| subProjectDir = projectDir |
| ) |
| self.assertEqual(3, len(gitLogList)) |
| for commit in gitLogList: |
| if commit.sha == "topSha": |
| self.assertCommitsAreEqual(commitWithAPIChange, commit) |
| elif commit.sha == "midSha": |
| self.assertCommitsAreEqual(commitWithBugFix, commit) |
| elif commit.sha == "sha": |
| self.assertCommitsAreEqual(commitFromExternalContributor, commit) |
| else: |
| self.assertFalse("Unable to parse commit") |
| |
| def test_checkLatestCommitExists(self): |
| # Do not use the MockCommandRunner because it's a better test to check the validity of |
| # the git command against the actual git in the repo |
| gitClient = GitClient(os.getcwd()) |
| subProjectDir = os.getcwd().split("frameworks/support/")[1] |
| commitList = gitClient.getGitLog( |
| fromExclusiveSha = "", |
| untilInclusiveSha = "HEAD", |
| keepMerges = False, |
| subProjectDir = subProjectDir, |
| n = 1 |
| ) |
| self.assertEqual(1, len(commitList)) |
| |
| def test_gitLogFailsWhenPassedAnAbsolutePath(self): |
| # Tests that you cannot pass an absolute file path to git log |
| gitClient = GitClient(os.getcwd()) |
| subProjectDir = os.getcwd().split("frameworks/support/")[1] |
| subProjectDir = '/' + subProjectDir |
| self.assertRaises(RuntimeError, gitClient.getGitLog, |
| fromExclusiveSha = "", |
| untilInclusiveSha = "HEAD", |
| keepMerges = False, |
| subProjectDir = subProjectDir, |
| n = 1 |
| ) |
| |
| def assertCommitsAreEqual(self, commitA, commitB): |
| self.assertEqual(commitA.summary, commitB.summary) |
| self.assertEqual(commitA.files, commitB.files) |
| self.assertEqual(commitA.sha, commitB.sha) |
| self.assertEqual(commitA.changeId, commitB.changeId) |
| self.assertEqual(commitA.authorEmail, commitB.authorEmail) |
| self.assertEqual(commitA.type, commitB.changeType) |
| self.assertEqual(commitA.projectDir, commitB.projectDir) |
| self.assertEqual(commitA.summary, commitB.summary) |
| self.assertEqual(commitA.releaseNote, commitB.releaseNote) |
| |
| |
| if __name__ == '__main__': |
| unittest.main() |