{"action":"created","comment":{"url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/pulls/comments/85139306","pull_request_review_id":5871581,"id":85139306,"diff_hunk":"@@ -0,0 +1,446 @@\n+/**\n+ * Copyright 2016 The University of North Carolina at Chapel Hill\n+ *\n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ *         http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+package edu.unc.lib.deposit.fcrepo4;\n+\n+import static edu.unc.lib.dl.test.TestHelpers.setField;\n+import static org.mockito.Matchers.any;\n+import static org.mockito.Matchers.anyInt;\n+import static org.mockito.Matchers.anyString;\n+import static org.mockito.Matchers.eq;\n+import static org.mockito.Mockito.mock;\n+import static org.mockito.Mockito.never;\n+import static org.mockito.Mockito.times;\n+import static org.mockito.Mockito.verify;\n+import static org.mockito.Mockito.when;\n+import static org.mockito.MockitoAnnotations.initMocks;\n+\n+import java.io.File;\n+import java.io.InputStream;\n+import java.util.ArrayList;\n+import java.util.HashMap;\n+import java.util.List;\n+import java.util.Map;\n+\n+import org.apache.commons.io.FileUtils;\n+import org.junit.Before;\n+import org.junit.Test;\n+\n+import com.hp.hpl.jena.query.Dataset;\n+import com.hp.hpl.jena.rdf.model.Bag;\n+import com.hp.hpl.jena.rdf.model.Model;\n+import com.hp.hpl.jena.rdf.model.ModelFactory;\n+import com.hp.hpl.jena.rdf.model.Property;\n+import com.hp.hpl.jena.rdf.model.Resource;\n+import com.hp.hpl.jena.rdf.model.Statement;\n+import com.hp.hpl.jena.rdf.model.StmtIterator;\n+import com.hp.hpl.jena.tdb.TDBFactory;\n+import com.hp.hpl.jena.vocabulary.RDF;\n+\n+import edu.unc.lib.deposit.work.JobFailedException;\n+import edu.unc.lib.dl.fcrepo4.ContentObject;\n+import edu.unc.lib.dl.fcrepo4.FolderObject;\n+import edu.unc.lib.dl.fcrepo4.RepositoryPathConstants;\n+import edu.unc.lib.dl.fcrepo4.WorkObject;\n+import edu.unc.lib.dl.fedora.PID;\n+import edu.unc.lib.dl.rdf.Cdr;\n+import edu.unc.lib.dl.rdf.CdrDeposit;\n+import edu.unc.lib.dl.rdf.PcdmModels;\n+import edu.unc.lib.dl.util.RedisWorkerConstants.DepositField;\n+\n+/**\n+ * \n+ * @author bbpennel\n+ *\n+ */\n+public class IngestContentObjectsJobTest extends AbstractDepositJobTest {\n+\n+\tprivate IngestContentObjectsJob job;\n+\n+\tprivate PID depositPid;\n+\n+\tprivate PID destinationPid;\n+\n+\tprivate FolderObject destinationObj;\n+\n+\t@Before\n+\tpublic void init() throws Exception {\n+\t\tinitMocks(this);\n+\n+\t\tDataset dataset = TDBFactory.createDataset();\n+\n+\t\tjob = new IngestContentObjectsJob();\n+\t\tjob.setJobUUID(jobUUID);\n+\t\tjob.setDepositUUID(depositUUID);\n+\t\tjob.setDepositDirectory(depositDir);\n+\t\tjob.setRepository(repository);\n+\t\tsetField(job, \"dataset\", dataset);\n+\t\tsetField(job, \"depositsDirectory\", depositsDirectory);\n+\t\tsetField(job, \"depositStatusFactory\", depositStatusFactory);\n+\t\tsetField(job, \"jobStatusFactory\", jobStatusFactory);\n+\t\tsetField(job, \"metricsClient\", metricsClient);\n+\t\tjob.init();\n+\n+\t\tdepositPid = job.getDepositPID();\n+\n+\t\tsetupDestination();\n+\n+\t\tFileUtils.copyDirectory(new File(\"src/test/resources/examples\"), depositDir);\n+\t}\n+\n+\tprivate void setupDestination() {\n+\t\t// Establish a destination object to deposit to\n+\t\tdestinationPid = makePid(RepositoryPathConstants.CONTENT_BASE);\n+\n+\t\tMap<String, String> depositStatus = new HashMap<>();\n+\t\tdepositStatus.put(DepositField.containerId.name(), destinationPid.getQualifiedId());\n+\n+\t\twhen(depositStatusFactory.get(anyString())).thenReturn(depositStatus);\n+\n+\t\tdestinationObj = mock(FolderObject.class);\n+\t\twhen(repository.getContentObject(eq(destinationPid))).thenReturn(destinationObj);\n+\t}\n+\n+\t/**\n+\t * Test that an empty folder is successfully deposited\n+\t */\n+\t@Test\n+\tpublic void ingestEmptyFolderTest() {\n+\n+\t\tFolderObject folder = mock(FolderObject.class);\n+\t\twhen(repository.createFolderObject(any(PID.class), any(Model.class))).thenReturn(folder);\n+\n+\t\tModel model = job.getWritableModel();\n+\t\tBag depBag = model.createBag(depositPid.getRepositoryPath());\n+\n+\t\tPID folderPid = makePid(RepositoryPathConstants.CONTENT_BASE);\n+\t\tBag folderBag = model.createBag(folderPid.getRepositoryPath());\n+\t\tfolderBag.addProperty(RDF.type, Cdr.Folder);\n+\n+\t\tdepBag.add(folderBag);\n+\n+\t\tjob.closeModel();\n+\n+\t\tjob.run();\n+\n+\t\tverify(repository).createFolderObject(eq(folderPid), any(Model.class));\n+\t\tverify(destinationObj).addMember(eq(folder));\n+\t\tverify(jobStatusFactory).incrCompletion(eq(jobUUID), eq(1));\n+\t}\n+\n+\tprivate Bag setupWork(PID workPid, WorkObject work, Model model) {\n+\t\twhen(repository.createWorkObject(any(PID.class), any(Model.class))).thenReturn(work);\n+\t\twhen(work.getPid()).thenReturn(workPid);\n+\n+\t\tBag depBag = model.createBag(depositPid.getRepositoryPath());\n+\n+\t\tBag workBag = model.createBag(workPid.getRepositoryPath());\n+\t\tworkBag.addProperty(RDF.type, Cdr.Work);\n+\n+\t\tdepBag.add(workBag);\n+\n+\t\treturn workBag;\n+\t}\n+\n+\t/**\n+\t * Test that a deposit involving a work containing two files is successful\n+\t */\n+\t@Test\n+\tpublic void ingestWorkObjectTest() {\n+\t\tPID workPid = makePid(RepositoryPathConstants.CONTENT_BASE);\n+\t\tModel model = job.getWritableModel();\n+\t\tWorkObject work = mock(WorkObject.class);\n+\t\tBag workBag = setupWork(workPid, work, model);\n+\n+\t\tString mainLoc = \"pdf.pdf\";\n+\t\tString mainMime = \"application/pdf\";\n+\t\tPID mainPid = addFileObject(workBag, mainLoc, mainMime);\n+\t\tString supLoc = \"text.txt\";\n+\t\tString supMime = \"text/plain\";\n+\t\tPID supPid = addFileObject(workBag, supLoc, supMime);\n+\n+\t\tworkBag.asResource().addProperty(Cdr.primaryObject,\n+\t\t\t\tmodel.getResource(mainPid.getRepositoryPath()));\n+\n+\t\tjob.closeModel();\n+\n+\t\tjob.run();\n+\n+\t\tverify(repository).createWorkObject(eq(workPid), any(Model.class));\n+\t\tverify(destinationObj).addMember(eq(work));\n+\n+\t\tverify(work).addDataFile(eq(mainPid), any(InputStream.class), eq(mainLoc),\n+\t\t\t\teq(mainMime), anyString());\n+\t\tverify(work).addDataFile(eq(supPid), any(InputStream.class), eq(supLoc),\n+\t\t\t\teq(supMime), anyString());\n+\t\tverify(work).setPrimaryObject(mainPid);\n+\n+\t\tverify(jobStatusFactory, times(3)).incrCompletion(eq(jobUUID), eq(1));\n+\t}\n+\n+\t/**\n+\t * Test that the deposit fails if a file object is specified but not given a\n+\t * staging location\n+\t */\n+\t@Test(expected = JobFailedException.class)\n+\tpublic void ingestWorkWithFileWithoutLocation() {\n+\t\tPID workPid = makePid(RepositoryPathConstants.CONTENT_BASE);\n+\t\tModel model = job.getWritableModel();\n+\t\tWorkObject work = mock(WorkObject.class);\n+\t\tBag workBag = setupWork(workPid, work, model);\n+\n+\t\tPID filePid = makePid(RepositoryPathConstants.CONTENT_BASE);\n+\n+\t\tResource fileResc = model.createResource(filePid.getRepositoryPath());\n+\t\tfileResc.addProperty(RDF.type, Cdr.FileObject);\n+\t\tfileResc.addProperty(CdrDeposit.mimetype, \"text/plain\");\n+\t\tworkBag.add(fileResc);\n+\n+\t\tjob.closeModel();\n+\n+\t\tjob.run();\n+\t}\n+\n+\t/**\n+\t * Test that deposit fails if depositing a file path that doesn't exist\n+\t */\n+\t@Test(expected = JobFailedException.class)\n+\tpublic void ingestWorkWithFileDoesNotExist() {\n+\t\tPID workPid = makePid(RepositoryPathConstants.CONTENT_BASE);\n+\t\tModel model = job.getWritableModel();\n+\t\tWorkObject work = mock(WorkObject.class);\n+\t\tBag workBag = setupWork(workPid, work, model);\n+\n+\t\taddFileObject(workBag, \"doesnotexist.txt\", \"text/plain\");\n+\n+\t\tjob.closeModel();\n+\n+\t\tjob.run();\n+\t}\n+\n+\t/**\n+\t * Test that a standalone file object ingested to a destination which is not\n+\t * a work successfully ingests as the child of a generated work object\n+\t */\n+\t@Test\n+\tpublic void ingestFileObjectAsWorkTest() {\n+\t\tPID workPid = makePid(RepositoryPathConstants.CONTENT_BASE);\n+\t\twhen(repository.mintContentPid()).thenReturn(workPid);\n+\t\tWorkObject work = mock(WorkObject.class);\n+\t\twhen(work.getPid()).thenReturn(workPid);\n+\t\twhen(repository.createWorkObject(eq(workPid), any(Model.class))).thenReturn(work);\n+\n+\t\tModel model = job.getWritableModel();\n+\t\tBag depBag = model.createBag(depositPid.getRepositoryPath());\n+\n+\t\tString fileLoc = \"text.txt\";\n+\t\tString fileMime = \"text/plain\";\n+\t\tPID filePid = addFileObject(depBag, fileLoc, fileMime);\n+\n+\t\tjob.closeModel();\n+\n+\t\tjob.run();\n+\n+\t\t// Verify that a work object was generated and added to the destination\n+\t\tverify(repository).mintContentPid();\n+\t\tverify(repository).createWorkObject(eq(workPid), any(Model.class));\n+\t\tverify(destinationObj).addMember(eq(work));\n+\n+\t\t// Verify that a FileObject was added to the generated work as primary obj\n+\t\tverify(work).setPrimaryObject(filePid);\n+\t\tverify(work).addDataFile(eq(filePid), any(InputStream.class), eq(fileLoc),\n+\t\t\t\teq(fileMime), anyString());\n+\n+\t\t// Only one ticket should register since the work object is generated\n+\t\tverify(jobStatusFactory).incrCompletion(eq(jobUUID), eq(1));\n+\t}\n+\n+\t@Test(expected = JobFailedException.class)\n+\tpublic void ingestfileObjectAsWorkNoStaging() {\n+\t\tPID workPid = makePid(RepositoryPathConstants.CONTENT_BASE);\n+\t\twhen(repository.mintContentPid()).thenReturn(workPid);\n+\t\tWorkObject work = mock(WorkObject.class);\n+\t\twhen(work.getPid()).thenReturn(workPid);\n+\t\twhen(repository.createWorkObject(eq(workPid), any(Model.class))).thenReturn(work);\n+\n+\t\tModel model = job.getWritableModel();\n+\t\tBag depBag = model.createBag(depositPid.getRepositoryPath());\n+\n+\t\tPID filePid = makePid(RepositoryPathConstants.CONTENT_BASE);\n+\n+\t\tResource fileResc = model.createResource(filePid.getRepositoryPath());\n+\t\tfileResc.addProperty(RDF.type, Cdr.FileObject);\n+\t\tfileResc.addProperty(CdrDeposit.mimetype, \"text/plain\");\n+\t\tdepBag.add(fileResc);\n+\n+\t\tjob.closeModel();\n+\n+\t\tjob.run();\n+\t}\n+\n+\t/**\n+\t * Test resuming a Work ingest where the work and the main file were already\n+\t * ingested\n+\t */\n+\t@Test\n+\tpublic void resumeIngestWorkObjectTest() {\n+\t\t// Mark the deposit as resumed\n+\t\twhen(depositStatusFactory.isResumedDeposit(anyString())).thenReturn(true);\n+\n+\t\tPID workPid = makePid(RepositoryPathConstants.CONTENT_BASE);\n+\t\tModel model = job.getWritableModel();\n+\t\tWorkObject work = mock(WorkObject.class);\n+\t\tBag workBag = setupWork(workPid, work, model);\n+\t\twhen(repository.getWorkObject(eq(workPid))).thenReturn(work);\n+\n+\t\tModel workModel = ModelFactory.createDefaultModel();\n+\t\tResource workResc = workModel.createResource(workPid.getRepositoryPath())\n+\t\t\t\t.addProperty(RDF.type, Cdr.Work);\n+\t\twhen(work.getResource()).thenReturn(workResc);\n+\n+\t\tString mainLoc = \"pdf.pdf\";\n+\t\tString mainMime = \"application/pdf\";\n+\t\tPID mainPid = addFileObject(workBag, mainLoc, mainMime);\n+\t\tString supLoc = \"text.txt\";\n+\t\tString supMime = \"text/plain\";\n+\t\tPID supPid = addFileObject(workBag, supLoc, supMime);\n+\n+\t\tworkBag.asResource().addProperty(Cdr.primaryObject,\n+\t\t\t\tmodel.getResource(mainPid.getRepositoryPath()));\n+\n+\t\tjob.closeModel();\n+\n+\t\twhen(repository.objectExists(eq(workPid))).thenReturn(true);\n+\t\twhen(repository.objectExists(eq(mainPid))).thenReturn(true);\n+\n+\t\tjob.run();\n+\n+\t\t// Check that the work object was retrieved rather than created\n+\t\tverify(repository).objectExists(eq(workPid));\n+\t\tverify(repository, never()).createWorkObject(any(PID.class));\n+\t\tverify(repository).getWorkObject(any(PID.class));\n+\n+\t\t// Main file object should not be touched\n+\t\tverify(repository).objectExists(eq(mainPid));\n+\t\tverify(work, never()).addDataFile(eq(mainPid), any(InputStream.class),\n+\t\t\t\tanyString(), anyString(), anyString());\n+\t\tverify(repository, never()).getFileObject(eq(mainPid));\n+\n+\t\t// Supplemental file should be created\n+\t\tverify(repository).objectExists(eq(supPid));\n+\t\tverify(repository, never()).getFileObject(eq(supPid));\n+\t\tverify(work).addDataFile(eq(supPid), any(InputStream.class), eq(supLoc),\n+\t\t\t\teq(supMime), anyString());\n+\n+\t\t// Ensure that the primary object still got set\n+\t\tverify(work).setPrimaryObject(mainPid);\n+\n+\t\tverify(jobStatusFactory).setCompletion(eq(jobUUID), eq(2));\n+\t\tverify(jobStatusFactory).incrCompletion(eq(jobUUID), eq(1));\n+\t}\n+\n+\t@Test\n+\tpublic void resumeIngestFileObjectAsWorkTest() {\n+\t\t// Mark the deposit as resumed\n+\t\twhen(depositStatusFactory.isResumedDeposit(anyString())).thenReturn(true);\n+\n+\t\tModel model = job.getWritableModel();\n+\t\tBag depBag = model.createBag(depositPid.getRepositoryPath());\n+\n+\t\tString fileLoc = \"text.txt\";\n+\t\tString fileMime = \"text/plain\";\n+\t\tPID filePid = addFileObject(depBag, fileLoc, fileMime);\n+\n+\t\twhen(repository.objectExists(eq(filePid))).thenReturn(true);\n+\n+\t\tjob.closeModel();\n+\n+\t\tjob.run();\n+\n+\t\t// Check that the generated work was neither generated nor linked\n+\t\tverify(repository, never()).createWorkObject(any(PID.class), any(Model.class));\n+\t\tverify(destinationObj, never()).addMember(any(ContentObject.class));\n+\n+\t\t// Only tick should be from preprocessing\n+\t\tverify(jobStatusFactory, never()).incrCompletion(eq(jobUUID), anyInt());\n+\t\tverify(jobStatusFactory).setCompletion(eq(jobUUID), eq(1));\n+\t}\n+\n+\t/**\n+\t * Check that no significant deposit behaviors change with a file object as\n+\t * work deposit due to resume being turned on\n+\t */\n+\t@Test\n+\tpublic void resumeIngestNoCompleteTest() {\n+\t\t// Mark the deposit as resumed\n+\t\twhen(depositStatusFactory.isResumedDeposit(anyString())).thenReturn(true);\n+\n+\t\tingestFileObjectAsWorkTest();\n+\n+\t\t// No preprocessing ticks\n+\t\tverify(jobStatusFactory).setCompletion(eq(jobUUID), eq(0));\n+\t}\n+\n+\t@Test\n+\tpublic void permTest() {","path":"deposit/src/test/java/edu/unc/lib/deposit/fcrepo4/IngestContentObjectsJobTest.java","position":397,"original_position":397,"commit_id":"379d0d6f73a741ae5f2d58d9a6ab89378efb3682","original_commit_id":"379d0d6f73a741ae5f2d58d9a6ab89378efb3682","user":{"login":"harringj","id":21954788,"avatar_url":"https://avatars.githubusercontent.com/u/21954788?v=3","gravatar_id":"","url":"https://api.github.com/users/harringj","html_url":"https://github.com/harringj","followers_url":"https://api.github.com/users/harringj/followers","following_url":"https://api.github.com/users/harringj/following{/other_user}","gists_url":"https://api.github.com/users/harringj/gists{/gist_id}","starred_url":"https://api.github.com/users/harringj/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/harringj/subscriptions","organizations_url":"https://api.github.com/users/harringj/orgs","repos_url":"https://api.github.com/users/harringj/repos","events_url":"https://api.github.com/users/harringj/events{/privacy}","received_events_url":"https://api.github.com/users/harringj/received_events","type":"User","site_admin":false},"body":"What is this testing?","created_at":"2016-10-26T14:46:11Z","updated_at":"2016-10-26T14:46:11Z","html_url":"https://github.com/UNC-Libraries/Carolina-Digital-Repository/pull/529#discussion_r85139306","pull_request_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/pulls/529","_links":{"self":{"href":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/pulls/comments/85139306"},"html":{"href":"https://github.com/UNC-Libraries/Carolina-Digital-Repository/pull/529#discussion_r85139306"},"pull_request":{"href":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/pulls/529"}}},"pull_request":{"url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/pulls/529","id":90899089,"html_url":"https://github.com/UNC-Libraries/Carolina-Digital-Repository/pull/529","diff_url":"https://github.com/UNC-Libraries/Carolina-Digital-Repository/pull/529.diff","patch_url":"https://github.com/UNC-Libraries/Carolina-Digital-Repository/pull/529.patch","issue_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/issues/529","number":529,"state":"open","locked":false,"title":"Fcrepo4 ingest deposit job","user":{"login":"bbpennel","id":969810,"avatar_url":"https://avatars.githubusercontent.com/u/969810?v=3","gravatar_id":"","url":"https://api.github.com/users/bbpennel","html_url":"https://github.com/bbpennel","followers_url":"https://api.github.com/users/bbpennel/followers","following_url":"https://api.github.com/users/bbpennel/following{/other_user}","gists_url":"https://api.github.com/users/bbpennel/gists{/gist_id}","starred_url":"https://api.github.com/users/bbpennel/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bbpennel/subscriptions","organizations_url":"https://api.github.com/users/bbpennel/orgs","repos_url":"https://api.github.com/users/bbpennel/repos","events_url":"https://api.github.com/users/bbpennel/events{/privacy}","received_events_url":"https://api.github.com/users/bbpennel/received_events","type":"User","site_admin":false},"body":"Adds the ingest deposit job along with clients (and changes to clients) to support it, as well as adding unit and integration tests for the job.\r\n\r\nThis PR does not address updating of the non-test spring context files so that this can be run as a service, which will be addressed in another PR.  It also doesn't remove the superseded fcrepo3 clients.","created_at":"2016-10-25T21:51:39Z","updated_at":"2016-10-26T14:46:11Z","closed_at":null,"merged_at":null,"merge_commit_sha":"208fc58ac729c717f8c8638b965eeb112bcc4f85","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/pulls/529/commits","review_comments_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/pulls/529/comments","review_comment_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/pulls/comments{/number}","comments_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/issues/529/comments","statuses_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/statuses/379d0d6f73a741ae5f2d58d9a6ab89378efb3682","head":{"label":"UNC-Libraries:f4-ingest-deposit","ref":"f4-ingest-deposit","sha":"379d0d6f73a741ae5f2d58d9a6ab89378efb3682","user":{"login":"UNC-Libraries","id":552066,"avatar_url":"https://avatars.githubusercontent.com/u/552066?v=3","gravatar_id":"","url":"https://api.github.com/users/UNC-Libraries","html_url":"https://github.com/UNC-Libraries","followers_url":"https://api.github.com/users/UNC-Libraries/followers","following_url":"https://api.github.com/users/UNC-Libraries/following{/other_user}","gists_url":"https://api.github.com/users/UNC-Libraries/gists{/gist_id}","starred_url":"https://api.github.com/users/UNC-Libraries/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/UNC-Libraries/subscriptions","organizations_url":"https://api.github.com/users/UNC-Libraries/orgs","repos_url":"https://api.github.com/users/UNC-Libraries/repos","events_url":"https://api.github.com/users/UNC-Libraries/events{/privacy}","received_events_url":"https://api.github.com/users/UNC-Libraries/received_events","type":"Organization","site_admin":false},"repo":{"id":2357859,"name":"Carolina-Digital-Repository","full_name":"UNC-Libraries/Carolina-Digital-Repository","owner":{"login":"UNC-Libraries","id":552066,"avatar_url":"https://avatars.githubusercontent.com/u/552066?v=3","gravatar_id":"","url":"https://api.github.com/users/UNC-Libraries","html_url":"https://github.com/UNC-Libraries","followers_url":"https://api.github.com/users/UNC-Libraries/followers","following_url":"https://api.github.com/users/UNC-Libraries/following{/other_user}","gists_url":"https://api.github.com/users/UNC-Libraries/gists{/gist_id}","starred_url":"https://api.github.com/users/UNC-Libraries/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/UNC-Libraries/subscriptions","organizations_url":"https://api.github.com/users/UNC-Libraries/orgs","repos_url":"https://api.github.com/users/UNC-Libraries/repos","events_url":"https://api.github.com/users/UNC-Libraries/events{/privacy}","received_events_url":"https://api.github.com/users/UNC-Libraries/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/UNC-Libraries/Carolina-Digital-Repository","description":"Carolina Digital Repository","fork":false,"url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository","forks_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/forks","keys_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/keys{/key_id}","collaborators_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/teams","hooks_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/hooks","issue_events_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/issues/events{/number}","events_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/events","assignees_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/assignees{/user}","branches_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/branches{/branch}","tags_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/tags","blobs_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/git/refs{/sha}","trees_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/git/trees{/sha}","statuses_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/statuses/{sha}","languages_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/languages","stargazers_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/stargazers","contributors_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/contributors","subscribers_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/subscribers","subscription_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/subscription","commits_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/commits{/sha}","git_commits_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/git/commits{/sha}","comments_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/comments{/number}","issue_comment_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/issues/comments{/number}","contents_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/contents/{+path}","compare_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/compare/{base}...{head}","merges_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/merges","archive_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/downloads","issues_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/issues{/number}","pulls_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/pulls{/number}","milestones_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/milestones{/number}","notifications_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/labels{/name}","releases_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/releases{/id}","deployments_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/deployments","created_at":"2011-09-09T20:22:21Z","updated_at":"2016-10-25T19:45:37Z","pushed_at":"2016-10-25T21:56:27Z","git_url":"git://github.com/UNC-Libraries/Carolina-Digital-Repository.git","ssh_url":"git@github.com:UNC-Libraries/Carolina-Digital-Repository.git","clone_url":"https://github.com/UNC-Libraries/Carolina-Digital-Repository.git","svn_url":"https://github.com/UNC-Libraries/Carolina-Digital-Repository","homepage":"http://www.lib.unc.edu/blogs/cdr/index.php/about/","size":102427,"stargazers_count":7,"watchers_count":7,"language":"Java","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":10,"mirror_url":null,"open_issues_count":4,"forks":10,"open_issues":4,"watchers":7,"default_branch":"master"}},"base":{"label":"UNC-Libraries:fcrepo4","ref":"fcrepo4","sha":"3491d3f56d446a8ce6aed5633608c3fdd9df2484","user":{"login":"UNC-Libraries","id":552066,"avatar_url":"https://avatars.githubusercontent.com/u/552066?v=3","gravatar_id":"","url":"https://api.github.com/users/UNC-Libraries","html_url":"https://github.com/UNC-Libraries","followers_url":"https://api.github.com/users/UNC-Libraries/followers","following_url":"https://api.github.com/users/UNC-Libraries/following{/other_user}","gists_url":"https://api.github.com/users/UNC-Libraries/gists{/gist_id}","starred_url":"https://api.github.com/users/UNC-Libraries/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/UNC-Libraries/subscriptions","organizations_url":"https://api.github.com/users/UNC-Libraries/orgs","repos_url":"https://api.github.com/users/UNC-Libraries/repos","events_url":"https://api.github.com/users/UNC-Libraries/events{/privacy}","received_events_url":"https://api.github.com/users/UNC-Libraries/received_events","type":"Organization","site_admin":false},"repo":{"id":2357859,"name":"Carolina-Digital-Repository","full_name":"UNC-Libraries/Carolina-Digital-Repository","owner":{"login":"UNC-Libraries","id":552066,"avatar_url":"https://avatars.githubusercontent.com/u/552066?v=3","gravatar_id":"","url":"https://api.github.com/users/UNC-Libraries","html_url":"https://github.com/UNC-Libraries","followers_url":"https://api.github.com/users/UNC-Libraries/followers","following_url":"https://api.github.com/users/UNC-Libraries/following{/other_user}","gists_url":"https://api.github.com/users/UNC-Libraries/gists{/gist_id}","starred_url":"https://api.github.com/users/UNC-Libraries/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/UNC-Libraries/subscriptions","organizations_url":"https://api.github.com/users/UNC-Libraries/orgs","repos_url":"https://api.github.com/users/UNC-Libraries/repos","events_url":"https://api.github.com/users/UNC-Libraries/events{/privacy}","received_events_url":"https://api.github.com/users/UNC-Libraries/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/UNC-Libraries/Carolina-Digital-Repository","description":"Carolina Digital Repository","fork":false,"url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository","forks_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/forks","keys_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/keys{/key_id}","collaborators_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/teams","hooks_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/hooks","issue_events_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/issues/events{/number}","events_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/events","assignees_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/assignees{/user}","branches_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/branches{/branch}","tags_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/tags","blobs_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/git/refs{/sha}","trees_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/git/trees{/sha}","statuses_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/statuses/{sha}","languages_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/languages","stargazers_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/stargazers","contributors_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/contributors","subscribers_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/subscribers","subscription_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/subscription","commits_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/commits{/sha}","git_commits_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/git/commits{/sha}","comments_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/comments{/number}","issue_comment_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/issues/comments{/number}","contents_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/contents/{+path}","compare_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/compare/{base}...{head}","merges_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/merges","archive_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/downloads","issues_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/issues{/number}","pulls_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/pulls{/number}","milestones_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/milestones{/number}","notifications_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/labels{/name}","releases_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/releases{/id}","deployments_url":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/deployments","created_at":"2011-09-09T20:22:21Z","updated_at":"2016-10-25T19:45:37Z","pushed_at":"2016-10-25T21:56:27Z","git_url":"git://github.com/UNC-Libraries/Carolina-Digital-Repository.git","ssh_url":"git@github.com:UNC-Libraries/Carolina-Digital-Repository.git","clone_url":"https://github.com/UNC-Libraries/Carolina-Digital-Repository.git","svn_url":"https://github.com/UNC-Libraries/Carolina-Digital-Repository","homepage":"http://www.lib.unc.edu/blogs/cdr/index.php/about/","size":102427,"stargazers_count":7,"watchers_count":7,"language":"Java","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":10,"mirror_url":null,"open_issues_count":4,"forks":10,"open_issues":4,"watchers":7,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/pulls/529"},"html":{"href":"https://github.com/UNC-Libraries/Carolina-Digital-Repository/pull/529"},"issue":{"href":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/issues/529"},"comments":{"href":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/issues/529/comments"},"review_comments":{"href":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/pulls/529/comments"},"review_comment":{"href":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/pulls/529/commits"},"statuses":{"href":"https://api.github.com/repos/UNC-Libraries/Carolina-Digital-Repository/statuses/379d0d6f73a741ae5f2d58d9a6ab89378efb3682"}}}}
{"actor":{"display_login":"harringj"}}