Skip to content

Commit

Permalink
Merge pull request #350 from vdice/ci/publish-schema
Browse files Browse the repository at this point in the history
feat(ci): publish versioned schema
  • Loading branch information
vdice authored Mar 27, 2020
2 parents 630cb9c + d7ffba8 commit a208228
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 108 deletions.
9 changes: 7 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
BASE_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
VALIDATOR_IMG := deislabs/cnab-spec.ajv
VERSION ?= $(shell git describe --tags 2> /dev/null || echo v0)
BASE_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
VALIDATOR_IMG := deislabs/cnab-spec.ajv

.PHONY: build-validator
build-validator:
Expand Down Expand Up @@ -31,3 +32,7 @@ validate-local: build-validator-local
validate-url-local: build-validator-local
./scripts/validate-url.sh

# AZURE_STORAGE_CONNECTION_STRING will be used for auth in the following target
.PHONY: publish
publish:
@az storage blob upload-batch -d schema/$(VERSION) -s schema
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ The specification is licensed under [OWF Contributor License Agreement 1.0 - Cop

We operate a [mailing list](https://lists.jointdevelopment.org/g/CNAB-Main) via the Joint Development Foundation.

## Versioned Schema URLs

CNAB Spec schema defined in this repo (under `/schema`) will be hosted for all tagged versions. This way, implementations can require specific schema versions for validation and assert compatibility with the corresponding versions.

Note that some tagged versions don't directly map to official schema versions. For instance, a Git SHA may be appended if the spec is still in a Draft state, e.g. `cnab-claim-1.0.0-DRAFT+abc1234`. Again, this facilitates the ability for implementations to pin to a certain tag whilst a spec is under heavy development with many breaking changes.

The schema files are hosted via `https://cnab.io/schema/<VERSION>/<SCHEMA>.schema.json`, e.g. https://cnab.io/schema/cnab-core-1.0/bundle.schema.json

## Notational Conventions

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" are to be interpreted as described in [RFC 2119][rfc2119].
Expand Down
149 changes: 43 additions & 106 deletions brigade.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,36 @@
const { events, Job, Group } = require("brigadier");
const { Check } = require("@brigadecore/brigade-utils");

const projectName = "cnab-spec";
// Currently a very lenient regex.
// Could be made more strict. Some examples: cnab-core-1.0.0, cnab-claim-1.0.0-DRAFT+abc1234
const releaseTagRegex = /^refs\/tags\/(.*)/;

// Event handlers

events.on("exec", (e, p) => {
return Group.runAll([
validate(e, p),
validateURL(e, p)
validate(),
validateURL()
]);
});
events.on("check_suite:requested", runSuite);
events.on("check_suite:rerequested", runSuite);
events.on("check_run:rerequested", runSuite);
events.on("issue_comment:created", handleIssueComment);
events.on("issue_comment:edited", handleIssueComment);
events.on("issue_comment:created", (e, p) => Check.handleIssueComment(e, p, runSuite));
events.on("issue_comment:edited", (e, p) => Check.handleIssueComment(e, p, runSuite));
events.on("push", (e, p) => {
let matchStr = e.revision.ref.match(releaseTagRegex);
if (matchStr) {
let matchTokens = Array.from(matchStr);
let version = matchTokens[1];
return publish(p, version).run();
}
});

// Functions/Helpers

function validate(e, project) {
function validate() {
var validator = new Job(`${projectName}-validate`, "node:8-alpine");
validator.streamLogs = true;

Expand All @@ -28,10 +40,10 @@ function validate(e, project) {
"make validate-local",
];

return validator
return validator;
}

function validateURL(e, project) {
function validateURL() {
var validator = new Job(`${projectName}-validate-url`, "node:8-alpine");
validator.streamLogs = true;

Expand All @@ -41,116 +53,41 @@ function validateURL(e, project) {
"make validate-url-local",
];

return validator
return validator;
}

function publish(p, version) {
var publisher = new Job(`${projectName}-publish`, "node:8-alpine");

publisher.env.AZURE_STORAGE_CONNECTION_STRING = p.secrets.azureStorageConnectionString;
publisher.tasks.push(
"apk add --update make curl",
// Fetch az cli needed for publishing
"curl -sLO https://github.com/carolynvs/az-cli/releases/download/v0.3.2/az-linux-amd64 && \
chmod +x az-linux-amd64 && \
mv az-linux-amd64 /usr/local/bin/az",
"cd /src",
`VERSION=${version} make publish`
);

return publisher;
}

// Here we can add additional Check Runs, which will run in parallel and
// report their results independently to GitHub
function runSuite(e, p) {
return runValidation(e, p)
return runValidation(e, p, validate)
.then(() => {
if (e.revision.ref == "master") {
validateURL(e, p).run();
validateURL().run();
}
})
.catch(e => {console.error(e.toString())});
}

// runValidation is a Check Run that is ran as part of a Checks Suite
function runValidation(e, p) {
// Create Notification object (which is just a Job to update GH using the Checks API)
var note = new Notification(`validation`, e, p);
note.conclusion = "";
note.title = "Run Validation";
note.summary = "Running the schema validation for " + e.revision.commit;
note.text = "Ensuring all bundle.json files adhere to json schema specs"

// Send notification, then run, then send pass/fail notification
return notificationWrap(validate(e, p), note)
}

// handleIssueComment handles an issue_comment event, parsing the comment
// text and determining whether or not to trigger a corresponding action
function handleIssueComment(e, p) {
if (e.payload) {
payload = JSON.parse(e.payload);

// Extract the comment body and trim whitespace
comment = payload.body.comment.body.trim();

// Here we determine if a comment should provoke an action
switch(comment) {
case "/brig run":
return runSuite(e, p);
default:
console.log(`No applicable action found for comment: ${comment}`);
}
}
function runValidation(e, p, jobFunc) {
var check = new Check(e, p, jobFunc(),
`https://brigadecore.github.io/kashti/builds/${e.buildID}`);
return check.run();
}

// A GitHub Check Suite notification
class Notification {
constructor(name, e, p) {
this.proj = p;
this.payload = e.payload;
this.name = name;
this.externalID = e.buildID;
this.detailsURL = `https://brigadecore.github.io/kashti/builds/${ e.buildID }`;
this.title = "running check";
this.text = "";
this.summary = "";

// count allows us to send the notification multiple times, with a distinct pod name
// each time.
this.count = 0;

// One of: "success", "failure", "neutral", "cancelled", or "timed_out".
this.conclusion = "neutral";
}

// Send a new notification, and return a Promise<result>.
run() {
this.count++
var j = new Job(`${ this.name }-${ this.count }`, "brigadecore/brigade-github-check-run:v0.1.0");
j.env = {
CHECK_CONCLUSION: this.conclusion,
CHECK_NAME: this.name,
CHECK_TITLE: this.title,
CHECK_PAYLOAD: this.payload,
CHECK_SUMMARY: this.summary,
CHECK_TEXT: this.text,
CHECK_DETAILS_URL: this.detailsURL,
CHECK_EXTERNAL_ID: this.externalID
}
return j.run();
}
}

// Helper to wrap a job execution between two notifications.
async function notificationWrap(job, note, conclusion) {
if (conclusion == null) {
conclusion = "success"
}
await note.run();
try {
let res = await job.run()
const logs = await job.logs();

note.conclusion = conclusion;
note.summary = `Task "${ job.name }" passed`;
note.text = note.text = "```" + res.toString() + "```\nTest Complete";
return await note.run();
} catch (e) {
const logs = await job.logs();
note.conclusion = "failure";
note.summary = `Task "${ job.name }" failed for ${ e.buildID }`;
note.text = "```" + logs + "```\nFailed with error: " + e.toString();
try {
return await note.run();
} catch (e2) {
console.error("failed to send notification: " + e2.toString());
console.error("original error: " + e.toString());
return e2;
}
}
}
5 changes: 5 additions & 0 deletions brigade.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"dependencies": {
"@brigadecore/brigade-utils": "0.4.1"
}
}

0 comments on commit a208228

Please sign in to comment.