Skip to content
This repository has been archived by the owner on Jul 25, 2023. It is now read-only.

Commit

Permalink
feat: Initial commit PROV from gitlab
Browse files Browse the repository at this point in the history
  • Loading branch information
cristianvasquez committed Mar 16, 2023
1 parent 46aae93 commit cdc233f
Show file tree
Hide file tree
Showing 4 changed files with 182 additions and 2 deletions.
60 changes: 60 additions & 0 deletions lib/appendGitlabProv.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import rdf from 'rdf-ext'
import { Transform } from 'readable-stream'
import { provFromGitlab } from './metadata/produceProv.js'
import { prov } from './namespaces.js'

const typePredicate = rdf.namedNode(
'http://www.w3.org/1999/02/22-rdf-syntax-ns#type')

class ProvMetadata extends Transform {
constructor (context, { subjectsWithClass, graph }) {
super({ objectMode: true })

this.type = subjectsWithClass
this.provPointer = provFromGitlab()
this.graph = graph
}

_transform (quad, encoding, callback) {
if (quad.predicate.equals(typePredicate) && quad.object.equals(this.type)) {
this.provPointer.addOut(prov.generates, quad.subject)
}

callback(null, quad)
}

async _flush (callback) {
try {
for (const quad of [...this.provPointer.dataset]) {
if (this.graph) {
this.push(
rdf.quad(quad.subject, quad.predicate, quad.object, this.graph))
} else {
this.push(quad)
}
}
} catch (err) {
this.destroy(err)
} finally {
callback()
}
}
}

function toNamedNode (item) {
if (item && item.term) {
return item.term
}
return typeof item === 'string' ? rdf.namedNode(item) : item
}

async function appendGitlabProv ({
subjectsWithClass, graph = undefined
} = {}) {
return new ProvMetadata(this, {
subjectsWithClass: toNamedNode(subjectsWithClass),
graph: toNamedNode(graph)
})
}

export default appendGitlabProv
118 changes: 118 additions & 0 deletions lib/metadata/produceProv.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import namespace from '@rdfjs/namespace'
import rdf from 'rdf-ext'
import { xsd, schema, prov } from '../namespaces.js'

const withoutLastSegment = url => url.split('/')
.splice(0, url.split('/').length - 1)
.join('/')

const ex = namespace('http://example.org/')

const type = rdf.namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type')

function validateVars () {
if (!process.env.CI_JOB_URL) {
throw Error('required environment variable CI_JOB_URL')
}
if (!process.env.CI_JOB_STARTED_AT) {
throw Error('required environment variable CI_JOB_STARTED_AT')
}
if (!process.env.CI_PROJECT_URL) {
throw Error('required environment variable CI_PROJECT_URL')
}
if (!process.env.CI_COMMIT_SHA) {
throw Error('required environment variable CI_COMMIT_SHA')
}
if (!process.env.CI_PIPELINE_URL) {
throw Error('required environment variable CI_PIPELINE_URL')
}
if (!process.env.CI_PIPELINE_CREATED_AT) {
throw Error('required environment variable CI_PIPELINE_CREATED_AT')
}
}

function provFromGitlab () {
validateVars()

// Job
const jobUrl = process.env.CI_JOB_URL
const jobStartTime = process.env.CI_JOB_STARTED_AT
const jobUri = rdf.namedNode(jobUrl)

// Codebase
const projectUrl = process.env.CI_PROJECT_URL
const codebaseUri = rdf.namedNode(projectUrl)

// Commit
const commitSha = process.env.CI_COMMIT_SHA
const commitUri = rdf.namedNode(`${projectUrl}/-/commit/${commitSha}`)

// All the jobs that were triggered by this commit, the pipelineRun. Might include download files
const pipelineRun = process.env.CI_PIPELINE_URL
const pipelineRunStartTime = process.env.CI_PIPELINE_CREATED_AT
const pipelineRunUri = rdf.namedNode(pipelineRun)

// all the pipelines for the codebase
const pipelinesUri = rdf.namedNode(withoutLastSegment(pipelineRun))

const pointer = rdf.clownface({ dataset: rdf.dataset(), term: jobUri })

pointer.node(codebaseUri)
.addOut(type, ex.Codebase)
.addOut(ex.hasPipelines, pipelinesUri)

pointer.node(commitUri)
.addOut(type, ex.Commit)
.addOut(ex.triggered, pipelineRunUri)

pointer.node(pipelinesUri).addOut(ex.contains, pipelineRunUri)

pointer.node(pipelineRunUri)
.addOut(type, ex.PipelineRun)
.addOut(prov.startedAtTime, rdf.literal(pipelineRunStartTime, xsd.dateTime))
.addOut(ex.hasJob, jobUri)

pointer.node(jobUri)
.addOut(type, ex.Activity)
.addOut(prov.startedAtTime, rdf.literal(jobStartTime, xsd.dateTime))
.addOut(prov.wasTriggeredBy, commitUri)

// Job Optionals
const environment = process.env.CI_BUILD_REF_SLUG
if (environment) {
const environmentUri = ex[`environment/${environment}`]
pointer.node(jobUri).addOut(ex.hasEnvironment, environmentUri)
}

// Codebase optionals
const codebaseDescription = process.env.CI_PROJECT_DESCRIPTION
if (codebaseDescription) {
pointer.node(codebaseUri).addOut(schema.description, codebaseDescription)
}

const codebaseName = process.env.CI_PROJECT_NAME
if (codebaseName) {
pointer.node(codebaseUri).addOut(schema.name, codebaseName)
}

// Commit Optionals
const commitName = process.env.CI_COMMIT_TITLE
if (commitName) {
pointer.node(commitUri).addOut(schema.name, commitName)
}

const commitAuthor = process.env.CI_COMMIT_AUTHOR
if (commitAuthor) {
pointer.node(commitUri).addOut(ex.author, commitAuthor)
}

const commitTime = process.env.CI_COMMIT_TIMESTAMP
if (commitTime) {
pointer.node(commitUri)
.addOut(prov.atTime, rdf.literal(commitTime, xsd.dateTime))
}

return pointer
}

export { provFromGitlab }
3 changes: 2 additions & 1 deletion lib/namespaces.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ const _void = namespace('http://rdfs.org/ns/void#')
const dcat = namespace('http://www.w3.org/ns/dcat#')
const schema = namespace('http://schema.org/')
const dcterms = namespace('http://purl.org/dc/terms/')
const prov = namespace('http://www.w3.org/ns/prov#')

export { cube, rdf, rdfs, sh, xsd, _void, dcat, schema, dcterms }
export { cube, rdf, rdfs, sh, xsd, _void, dcat, schema, dcterms, prov }
3 changes: 2 additions & 1 deletion metadata.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import append from './lib/append.js'
import appendGitlabProv from './lib/appendGitlabProv.js'
import voidStats from './lib/voidStats.js'

export { append, voidStats }
export { append, voidStats, appendGitlabProv }

0 comments on commit cdc233f

Please sign in to comment.