Remove all the TypeScript code to start over again with something different
This commit is contained in:
parent
55824515ce
commit
d55f7f60ca
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
* This test file will verify the parsing behavior of the configure block
|
||||
*/
|
||||
|
||||
import { MIN_PIPELINE, parse } from '../utils';
|
||||
|
||||
describe('configure {}', () => {
|
||||
it('should pass without a configure block', () => {
|
||||
expect(parse(MIN_PIPELINE)).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should pass with an empty configure block', () => {
|
||||
expect(parse(`configure {} ${MIN_PIPELINE}`)).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should pass on an empty settings block within the configure {}', () => {
|
||||
expect(parse(`configure { github {} } ${MIN_PIPELINE}`)).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should fail on a missing block', () => {
|
||||
expect(parse(`configure { github } ${MIN_PIPELINE}`)).not.toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should pass on a settings block within the configure {}', () => {
|
||||
expect(parse(`configure { github { account = 'rtyler' } } ${MIN_PIPELINE}`)).toHaveLength(0);
|
||||
});
|
||||
it('should pass on a many settings within the configure {}', () => {
|
||||
expect(parse(`configure { github { account = 'rtyler' endpoint = 'api.github.com' } } ${MIN_PIPELINE}`)).toHaveLength(0);
|
||||
});
|
||||
});
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
* This test file will verify the parsing behavior of the pipeline block
|
||||
*/
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
import { MIN_PIPELINE, parse } from '../utils';
|
||||
|
||||
describe('pipeline {}', () => {
|
||||
it('should pass with the minimum viable pipeline', () => {
|
||||
expect(parse(MIN_PIPELINE)).toHaveLength(0);
|
||||
});
|
||||
|
||||
describe('with full examples', () => {
|
||||
const examples_dir = path.join(__dirname, '..', '..', 'examples');
|
||||
fs.readdirSync(examples_dir).filter(filename => filename.endsWith('.otto')).map((filename) => {
|
||||
it(`should be able to parse ${filename}`, () => {
|
||||
const buffer = fs.readFileSync(path.join(examples_dir, filename), 'utf8');
|
||||
expect(parse(buffer)).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
* This test file will verify the parsing behavior of the use block
|
||||
*/
|
||||
|
||||
import { MIN_PIPELINE, parse } from '../utils';
|
||||
|
||||
describe('use {}', () => {
|
||||
it('should fail on an empty string', () => {
|
||||
expect(parse('')).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('should pass on an empty use block', () => {
|
||||
expect(parse(`use {} ${MIN_PIPELINE}`)).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should pass on a use with stdlib', () => {
|
||||
expect(parse(`use { stdlib } ${MIN_PIPELINE}`)).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should fail on a use with another symbol', () => {
|
||||
expect(parse(`use { koopa } ${MIN_PIPELINE}`)).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('should pass with a string', () => {
|
||||
expect(parse(`use { 'some/path' } ${MIN_PIPELINE}`)).toHaveLength(0);
|
||||
});
|
||||
});
|
|
@ -1,55 +0,0 @@
|
|||
import antlr from 'antlr4';
|
||||
|
||||
import { ErrorListener } from 'antlr4/error/ErrorListener';
|
||||
import { OttoLexer } from './build/parser/JavaScript/OttoLexer';
|
||||
import { OttoListener } from './build/parser/JavaScript/OttoListener';
|
||||
import { Otto } from './build/parser/JavaScript/Otto';
|
||||
|
||||
export const MIN_PIPELINE = 'pipeline { stages { stage { } } }';
|
||||
|
||||
class Visitor {
|
||||
visitChildren(ctx) {
|
||||
if (!ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.children) {
|
||||
return ctx.children.map(child => {
|
||||
if (child.children && child.children.length != 0) {
|
||||
return child.accept(this);
|
||||
} else {
|
||||
return child.getText();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class JestListener extends ErrorListener {
|
||||
public errors: Array<any> = [];
|
||||
|
||||
syntaxError(recognizer, offendingSymbol, line, column, msg, e) {
|
||||
this.errors.push({
|
||||
line: line,
|
||||
column: column,
|
||||
error: e,
|
||||
message: msg,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function parse(buffer) {
|
||||
let chars = new antlr.InputStream(buffer);
|
||||
let lexer = new OttoLexer(chars);
|
||||
let tokens = new antlr.CommonTokenStream(lexer);
|
||||
let parser = new Otto(tokens);
|
||||
parser.buildParseTrees = true;
|
||||
parser.removeErrorListeners();
|
||||
|
||||
const errorListener = new JestListener();
|
||||
parser.addErrorListener(errorListener);
|
||||
|
||||
let tree = parser.pipeline();
|
||||
tree.accept(new Visitor());
|
||||
return errorListener.errors;
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
moduleNameMapper: {
|
||||
"^@otto/grammar/(.*)$": "<rootDir>/grammar/build/parser/JavaScript/$1",
|
||||
"^@otto/(.*)$": "<rootDir>/lib/src/$1",
|
||||
"^@otto-orchestrator/(.*)$": "<rootDir>/services/orchestrator/src/$1",
|
||||
"^@otto-parser/(.*)$": "<rootDir>/services/parser/src/$1",
|
||||
},
|
||||
};
|
|
@ -1,18 +0,0 @@
|
|||
/**
|
||||
* The logger package will create a simple default logger for use with feathers
|
||||
* services
|
||||
*/
|
||||
|
||||
import { createLogger, format, transports } from 'winston'
|
||||
|
||||
export default createLogger({
|
||||
// To see more detailed errors, change this to 'debug'
|
||||
format: format.combine(
|
||||
format.splat(),
|
||||
format.simple(),
|
||||
),
|
||||
level: process.env.LOG_LEVEL || 'info',
|
||||
transports: [
|
||||
new transports.Console(),
|
||||
],
|
||||
})
|
|
@ -1,29 +0,0 @@
|
|||
/**
|
||||
* This module acts as the simple wrapper for serving any feathers application
|
||||
* in the project
|
||||
*/
|
||||
|
||||
import logger from '@otto/logger'
|
||||
|
||||
import { Application } from '@feathersjs/express'
|
||||
|
||||
/**
|
||||
* The serveApp function expects a Feathers application which it can start
|
||||
* serving on its configured port
|
||||
*
|
||||
* This method is *asynchronous* and will not return a success or fail
|
||||
*
|
||||
* @param app An instantiated feathers application
|
||||
*/
|
||||
export function serveApp(app: Application) {
|
||||
const port: Number = app.get('port')
|
||||
const server: any = app.listen(port)
|
||||
|
||||
process.on('unhandledRejection', (reason, p) =>
|
||||
logger.error('Unhandled Rejection at: Promise ', p, reason),
|
||||
)
|
||||
|
||||
server.on('listening', () =>
|
||||
logger.info('Feathers application started on http://%s:%d', app.get('host'), port),
|
||||
)
|
||||
}
|
File diff suppressed because it is too large
Load Diff
51
package.json
51
package.json
|
@ -1,51 +0,0 @@
|
|||
{
|
||||
"name": "otto",
|
||||
"version": "0.0.1",
|
||||
"description": "Your friendly continuous delivery companion",
|
||||
"main": "index.js",
|
||||
"directories": {
|
||||
"example": "examples"
|
||||
},
|
||||
"dependencies": {
|
||||
"@feathersjs/configuration": "^2.0.6",
|
||||
"@feathersjs/express": "^1.3.1",
|
||||
"@feathersjs/feathers": "^3.3.1",
|
||||
"@types/feathersjs__configuration": "^1.0.3",
|
||||
"@types/feathersjs__express": "^1.1.6",
|
||||
"@types/jest": "^24.0.15",
|
||||
"antlr4": "^4.7.2",
|
||||
"compression": "^1.7.4",
|
||||
"cors": "^2.8.5",
|
||||
"dredd": "^11.2.9",
|
||||
"helmet": "^3.18.0",
|
||||
"module-alias": "^2.2.0",
|
||||
"nodemon": "^1.19.1",
|
||||
"ts-lint": "^4.5.1",
|
||||
"tslib": "^1.10.0",
|
||||
"typescript": "^3.5.2",
|
||||
"uuid": "^3.3.2",
|
||||
"winston": "^3.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"jest": "^24.8.0",
|
||||
"ts-jest": "^24.0.2"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"test": "jest"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/rtyler/otto.git"
|
||||
},
|
||||
"author": "R Tyler Croy",
|
||||
"license": "AGPL-3.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/rtyler/otto/issues"
|
||||
},
|
||||
"homepage": "https://github.com/rtyler/otto#readme",
|
||||
"_moduleAliases": {
|
||||
"@root": ".",
|
||||
"@otto": "build/lib/src/"
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
= Otto Orchestrator
|
||||
|
||||
The Otto Orchestration service is responsible for provisioning agents to do their
|
||||
necessary work.
|
|
@ -1,54 +0,0 @@
|
|||
import modalias from 'module-alias'
|
||||
modalias()
|
||||
|
||||
import configuration from '@feathersjs/configuration'
|
||||
import express from '@feathersjs/express'
|
||||
import feathers from '@feathersjs/feathers'
|
||||
|
||||
import logger from '@otto/logger'
|
||||
import { serveApp } from '@otto/server'
|
||||
|
||||
logger.info('Starting orchestrator')
|
||||
|
||||
const app = express(feathers())
|
||||
// We need to fish out the orchestrator specific settings
|
||||
const settings = configuration()(app)
|
||||
app.configure(() => {
|
||||
// tslint:disable:no-string-literal
|
||||
Object.keys(settings['orchestrator']).forEach((key) => {
|
||||
app.set(key, settings['orchestrator'][key])
|
||||
})
|
||||
// tslint:enable:no-string-literal
|
||||
})
|
||||
|
||||
app.configure(express.rest())
|
||||
|
||||
app.configure(() => {
|
||||
const service = {
|
||||
get: (id: feathers.Id) => {
|
||||
logger.info(`Invoking get for ${id}`)
|
||||
const response = {
|
||||
ops: [
|
||||
{
|
||||
context: '0x1',
|
||||
data: {
|
||||
env: {},
|
||||
script: 'echo "Hello World"',
|
||||
timeout_s: 600,
|
||||
},
|
||||
id: '0xdeadbeef',
|
||||
type: 'RUNPROC',
|
||||
},
|
||||
],
|
||||
self: id,
|
||||
services: {
|
||||
datastore: 'http://localhost:3031/',
|
||||
},
|
||||
}
|
||||
return Promise.resolve(response)
|
||||
},
|
||||
}
|
||||
app.use('/v1/manifest', service)
|
||||
})
|
||||
|
||||
serveApp(app)
|
|
@ -1,134 +0,0 @@
|
|||
= Otto Parser
|
||||
|
||||
The Otto Parser service is responsible for taking a buffer, typically the
|
||||
contents of a `.otto` file and converting that into the internal representation
|
||||
that Otto uses for a configured pipeline.
|
||||
|
||||
|
||||
== Internal Representation
|
||||
|
||||
The requirements for the internal representation of a continuous delivery
|
||||
pipeline are as follows:
|
||||
|
||||
* Configuration data must be kept all in one place
|
||||
* It should be possible to reason about the runtime resources, and
|
||||
opportunities for re-use ahead of time.
|
||||
* Runtime resource allocation must be separable from everything else, in
|
||||
effect, Otto must be able to send off resource allocation requests as soon as
|
||||
possible, with only pointers back to the specific pipeline
|
||||
* The path of execution must be numbered and trackable within the system. Other
|
||||
components will need to be able to refer back to the internal representation to
|
||||
determine where in the execution of the pipeline the process is currently.
|
||||
|
||||
=== Example
|
||||
|
||||
Below is an example of a simple Otto pipeline, and its corresponding internal
|
||||
representation.
|
||||
|
||||
.Simple.otto
|
||||
[source, otto]
|
||||
----
|
||||
use {
|
||||
stdlib
|
||||
}
|
||||
|
||||
configure {
|
||||
slack {
|
||||
channel = '#otto'
|
||||
}
|
||||
}
|
||||
|
||||
pipeline {
|
||||
stages {
|
||||
stage {
|
||||
name = 'Build'
|
||||
runtime {
|
||||
docker {
|
||||
image = 'ruby:latest'
|
||||
}
|
||||
}
|
||||
|
||||
cache {
|
||||
gems = ['vendor/']
|
||||
}
|
||||
|
||||
steps {
|
||||
sh 'ruby --version'
|
||||
}
|
||||
}
|
||||
|
||||
stage {
|
||||
name = 'Test'
|
||||
runtime {
|
||||
from 'Build'
|
||||
}
|
||||
cache {
|
||||
use gems
|
||||
}
|
||||
steps {
|
||||
sh 'env'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
The description of this internal representation is YAML for the convenience of
|
||||
this documentation, there is _zero_ guarantee that the actual internal
|
||||
representation is stored in this fashion
|
||||
====
|
||||
|
||||
.Simple.otto-internal
|
||||
[source,yaml]
|
||||
----
|
||||
ottoVersion: 1
|
||||
libraries:
|
||||
- type: builtin
|
||||
ref: stdlib
|
||||
configuration:
|
||||
slack:
|
||||
settings:
|
||||
channel:
|
||||
encrypted: false
|
||||
value: '#otto'
|
||||
runtimes:
|
||||
# Most dynamically provisioned runtimes will not have any user-specified
|
||||
# named
|
||||
- name:
|
||||
type: docker
|
||||
args:
|
||||
image: 'ruby:latest'
|
||||
# Stages are indexed based on when they are parsed, not necessarily when they
|
||||
# are expected to execute, which may be in parallel
|
||||
stages:
|
||||
- name: 'Build'
|
||||
before:
|
||||
after:
|
||||
runtime: 0
|
||||
steps:
|
||||
- type: 'sh'
|
||||
args:
|
||||
- 'ruby --version'
|
||||
# `capture` and `restore` both would support archiving of artifacts and
|
||||
# caching of files and directories between the different stages
|
||||
capture:
|
||||
gems:
|
||||
- path: 'gems/'
|
||||
type: 'directory'
|
||||
restore:
|
||||
- name: 'Test'
|
||||
before:
|
||||
# Reference the stage by index
|
||||
after: 0
|
||||
runtime: 0
|
||||
steps:
|
||||
- type: 'sh'
|
||||
args:
|
||||
- 'env'
|
||||
capture:
|
||||
restore:
|
||||
- gems
|
||||
----
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
|
||||
import Orf from '../src/Orf'
|
||||
|
||||
describe('Orf', () => {
|
||||
it('should instantiate', () => {
|
||||
expect(new Orf()).toBeTruthy()
|
||||
})
|
||||
|
||||
it('should have a version', () => {
|
||||
expect((new Orf()).version).toBeGreaterThan(0)
|
||||
})
|
||||
|
||||
describe('when serialized', () => {
|
||||
it('should serialize by default', () => {
|
||||
const o = new Orf()
|
||||
expect(JSON.stringify(o)).toBeTruthy()
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,8 +0,0 @@
|
|||
|
||||
import ParseListener from '../src/ParseListener'
|
||||
|
||||
describe('ParseListener', () => {
|
||||
it('should instantiate', () => {
|
||||
expect(new ParseListener()).toBeTruthy()
|
||||
})
|
||||
})
|
|
@ -1,79 +0,0 @@
|
|||
/*
|
||||
* Otto Representation Format: this file contains the necessary to maintain the
|
||||
* internal representation of a parsed .otto file.
|
||||
*
|
||||
* See the parser README for more information
|
||||
*/
|
||||
|
||||
// tslint:disable:max-classes-per-file
|
||||
enum LibraryType {
|
||||
Builtin,
|
||||
FileReference,
|
||||
}
|
||||
|
||||
class Library {
|
||||
protected readonly libraryType: LibraryType
|
||||
protected readonly libraryRef: string
|
||||
}
|
||||
|
||||
class Setting {
|
||||
protected readonly encrypted: Boolean
|
||||
protected readonly value: any
|
||||
}
|
||||
|
||||
class Configuration {
|
||||
protected readonly settings: Map<string, Setting>
|
||||
}
|
||||
|
||||
interface Runtime {
|
||||
}
|
||||
|
||||
interface Step {
|
||||
}
|
||||
|
||||
interface FileCapture {
|
||||
}
|
||||
|
||||
class Stage {
|
||||
protected readonly name: string
|
||||
protected before: Stage
|
||||
protected after: Stage
|
||||
protected runtime: Runtime
|
||||
protected steps: Step[] = []
|
||||
protected capture: Map<string, FileCapture>
|
||||
protected restore: String[]
|
||||
}
|
||||
|
||||
/**
|
||||
* Orf is the Otto Representation Format and acts as the parsed and serialized
|
||||
* format of a .otto file, suitable for consumption by components within Otto.
|
||||
*/
|
||||
export default class Orf {
|
||||
/** The version field is for system compatibility */
|
||||
public readonly version = 1
|
||||
/**
|
||||
* An array of libraries which must be loaded at runtime
|
||||
*/
|
||||
protected libraries: Library[] = []
|
||||
|
||||
/**
|
||||
* A map of configuration objects for configuring arbitrary
|
||||
* steps/libraries/etc
|
||||
*/
|
||||
protected configuration: Map<string, Configuration>
|
||||
|
||||
/**
|
||||
* An ordered array of runtimes which will be used throughout the process
|
||||
*/
|
||||
protected runtimes: Runtime[] = []
|
||||
|
||||
/**
|
||||
* An ordered array of stages as they have been parsed, not necessary how
|
||||
* they will be executed which may be more of a directed graph.
|
||||
*/
|
||||
protected stages: Stage[] = []
|
||||
|
||||
constructor() {
|
||||
this.configuration = new Map<string, Configuration>()
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
/*
|
||||
* The ParseListener is the initial entrypoint for building the graph
|
||||
*/
|
||||
import { Otto } from '@otto/grammar/Otto'
|
||||
import { OttoLexer } from '@otto/grammar/OttoLexer'
|
||||
import { OttoListener } from '@otto/grammar/OttoListener'
|
||||
|
||||
export default class ParseListener extends OttoListener {
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"alwaysStrict" : true,
|
||||
"baseUrl" : ".",
|
||||
"outDir": "./build",
|
||||
"module" : "commonjs",
|
||||
"lib" : ["es2017"],
|
||||
"moduleResolution": "node",
|
||||
"esModuleInterop": true,
|
||||
"importHelpers" : true,
|
||||
"target": "es2015",
|
||||
"sourceMap": true,
|
||||
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"noUnusedLocals": false,
|
||||
"strictNullChecks": true,
|
||||
"skipLibCheck": true,
|
||||
|
||||
"paths": {
|
||||
"@otto-orchestrator/*": ["./services/orchestrator/src/*"],
|
||||
"@otto-parser/*": ["./services/parser/src/*"],
|
||||
"@otto/grammar/*": ["./grammar/build/parser/JavaScript/*"],
|
||||
"@otto/*": ["./lib/src/*"]
|
||||
},
|
||||
|
||||
"typeRoots" : [
|
||||
"./node_modules/@types"
|
||||
]
|
||||
},
|
||||
"exclude": [
|
||||
"**/__tests__/*.ts"
|
||||
]
|
||||
}
|
12
tslint.json
12
tslint.json
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"extends": [
|
||||
"tslint:recommended"
|
||||
],
|
||||
"jsRules": {},
|
||||
"rules": {
|
||||
"semicolon" : false,
|
||||
"quotemark" : false,
|
||||
"interface-name" : false
|
||||
},
|
||||
"rulesDirectory": []
|
||||
}
|
Loading…
Reference in New Issue