Unverified Commit 2c94a72f authored by Bradley Hilton's avatar Bradley Hilton Committed by GitHub
Browse files

Convert to a cli (#15)

* Start the move to a cli instead of an environment

* Add the package command :)

* Add a deploy command

* We are a cli package, so preferGlobal

* Change the packaging done on deploy to packaged

* If the deploymentResult wasn't a success, show the error

* Add the create subcommand with basic items and show it compiles by compiling

* Add the .gitignore to the created files

* Change the main class file to not be so generic

* Generate a readme with some information and links
parent d8178347
---
version: 2
jobs:
node-latest: &test
docker:
- image: node:latest
working_directory: ~/cli
steps:
- checkout
- restore_cache: &restore_cache
keys:
- v1-npm-{{checksum ".circleci/config.yml"}}-{{ checksum "package-lock.json"}}
- v1-npm-{{checksum ".circleci/config.yml"}}
- run:
name: Install dependencies
command: .circleci/greenkeeper
- run: ./bin/run --version
- run: ./bin/run --help
- run:
name: Testing
command: npm test
- run:
name: Submitting code coverage to codecov
command: |
./node_modules/.bin/nyc report --reporter text-lcov > coverage.lcov
curl -s https://codecov.io/bash | bash
node-8:
<<: *test
docker:
- image: node:8
release:
<<: *test
steps:
- add_ssh_keys
- checkout
- restore_cache: *restore_cache
- run:
name: Install dependencies
command: |
npm install -g @oclif/semantic-release@3 semantic-release@15
npm install
- run:
name: Cutting release
command: |
semantic-release -e @oclif/semantic-release
- save_cache:
key: v1-yarn-{{checksum ".circleci/config.yml"}}-{{checksum "yarn.lock"}}
paths:
- ~/cli/node_modules
- ~/.npm
- /usr/local/lib/node_modules
workflows:
version: 2
"@rocket.chat/apps-cli":
jobs:
- node-latest
- node-8
- release:
context: org-global
filters:
branches: {only: master}
requires:
- node-latest
- node-8
#!/usr/bin/env bash
set -ex
PATH=/usr/local/share/.config/yarn/global/node_modules/.bin:$PATH
if [[ "$CIRCLE_BRANCH" != greenkeeper/* ]]; then
yarn
# yarn check
exit 0
fi
if [[ ! -z "$GIT_EMAIL" ]] & [[ ! -z "$GIT_USERNAME" ]]; then
git config --global push.default simple
git config --global user.email "$GIT_EMAIL"
git config --global user.name "$GIT_USERNAME"
fi
if [[ ! -x "$(command -v greenkeeper-lockfile-update)" ]]; then
yarn global add greenkeeper-lockfile@1
fi
greenkeeper-lockfile-update
yarn
greenkeeper-lockfile-upload
......@@ -5,10 +5,12 @@ root = true
# Unix-style newlines with a newline ending every file
[*]
indent_style = space
indent_size = 4
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
# 4 space indentation
[**.*]
indent_style = space
indent_size = 4
[*.md]
trim_trailing_whitespace = false
{
"extends": "eslint:recommended",
"env": {
"browser": false,
"commonjs": true,
"es6": true,
"node": true
},
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"sourceType": "module"
},
"rules": {
"semi": ["error", "always"],
"no-console": "off",
"no-unused-vars": "error"
}
}
* text=auto
*.js text eol=lf
*.ts text eol=lf
# Created by https://www.gitignore.io/api/node
### Node ###
# Logs
logs
*.log
......@@ -40,14 +37,12 @@ jspm_packages
# Optional REPL history
.node_repl_history
### Typings ###
## Ignore downloaded typings
# Ignore downloaded typings
/typings
## Ignore distribution folder
# Ignore distribution folder
dist/
## dev env items
.server-dist/
.server-data/
.tmp/
# Various others
/lib
/tmp
{
"extension": [
".ts"
],
"include": [
"src/**/*.ts"
],
"exclude": [
"**/*.d.ts"
],
"all": true
}
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Rocket.Chat App",
"description": "A Rocket.Chat App declaration for usage inside of Rocket.Chat.",
"type": "object",
"properties": {
"id": {
"description": "The App's unique identifier in uuid v4 format. This is optional, although recommended, however if you are going to publish on the App store, you will be assigned one.",
"type": "string",
"pattern": "^[0-9a-fA-f]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$",
"minLength": 36,
"maxLength": 36
},
"name": {
"description": "The public visible name of this App.",
"type": "string"
},
"nameSlug": {
"description": "A url friendly slugged version of your App's name.",
"type": "string",
"pattern": "^([a-z]|\\-)+$",
"minLength": 3
},
"version": {
"description": "The version of this App which will be used for display publicly and letting users know there is an update. This uses the semver format.",
"type": "string",
"pattern": "\\bv?(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)(?:-[\\da-z\\-]+(?:\\.[\\da-z\\-]+)*)?(?:\\+[\\da-z\\-]+(?:\\.[\\da-z\\-]+)*)?\\b",
"minLength": 5
},
"description": {
"description": "A description of this App, used to explain what this App does and provides for the user.",
"type": "string"
},
"requiredApiVersion": {
"description": "The required version of the App's API which this App depends on. This uses the semver format.",
"type": "string",
"pattern": "\\bv?(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)(?:-[\\da-z\\-]+(?:\\.[\\da-z\\-]+)*)?(?:\\+[\\da-z\\-]+(?:\\.[\\da-z\\-]+)*)?\\b",
"minLength": 5
},
"author": {
"type": "object",
"properties": {
"name": {
"description": "The author's name who created this App.",
"type": "string"
},
"support": {
"description": "The place where people can get support for this App, whether email or website.",
"type": "string"
},
"homepage": {
"description": "The homepage for this App, it can be a Github or the author's website.",
"type": "string",
"format": "uri"
}
},
"required": ["name", "support"]
},
"classFile": {
"type": "string",
"description": "The name of the file which contains your App TypeScript source code.",
"pattern": "^.*\\.(ts)$"
},
"iconFile": {
"type": "string",
"description": "The name of the file to use as the icon.",
"pattern": "^.*\\.(png|jpg|jpeg|gif)$"
},
"assetsFolder": {
"type": "string",
"description": "The name of the folder which contains all of your resources, it should not start with a period."
}
},
"required": ["id", "name", "nameSlug", "version", "description", "requiredApiVersion", "author", "classFile", "iconFile"]
}
# Apps Folder
Create a new folder per App, the name of the folder won't really matter since the zip file produced will be named `name_id_version`.
import { GimmeCommand } from './commands/GimmeCommand';
import { LennyCommand } from './commands/LennyCommand';
import { ShrugCommand } from './commands/ShrugCommand';
import { TableflipCommand } from './commands/TableflipCommand';
import { UnflipCommand } from './commands/UnflipCommand';
import {
IConfigurationExtend,
IConfigurationModify,
IEnvironmentRead,
IHttp,
IRead,
} from '@rocket.chat/apps-ts-definition/accessors';
import { App } from '@rocket.chat/apps-ts-definition/App';
import { ISetting, SettingType } from '@rocket.chat/apps-ts-definition/settings';
export class AsciiArtCommandsApp extends App {
private gimmeId = 'gimmie_cmd';
private lennyId = 'lenny_cmd';
private shrugId = 'shrug_cmd';
private flipId = 'flip_cmd';
private unflipId = 'unflip_cmd';
public async onEnable(environmentRead: IEnvironmentRead, configModify: IConfigurationModify): Promise<boolean> {
const sets = environmentRead.getSettings();
await this.enableOrDisableCommand(this.gimmeId, await sets.getValueById(this.gimmeId), configModify);
await this.enableOrDisableCommand(this.lennyId, await sets.getValueById(this.lennyId), configModify);
await this.enableOrDisableCommand(this.shrugId, await sets.getValueById(this.shrugId), configModify);
await this.enableOrDisableCommand(this.flipId, await sets.getValueById(this.flipId), configModify);
await this.enableOrDisableCommand(this.unflipId, await sets.getValueById(this.unflipId), configModify);
return true;
}
public async onSettingUpdated(setting: ISetting, configModify: IConfigurationModify, read: IRead, http: IHttp): Promise<void> {
await this.enableOrDisableCommand(setting.id, setting.value as boolean, configModify);
}
protected async extendConfiguration(configuration: IConfigurationExtend): Promise<void> {
await configuration.settings.provideSetting({
id: this.gimmeId,
type: SettingType.BOOLEAN,
packageValue: true,
required: false,
public: false,
i18nLabel: 'Enable_Gimme_Command',
i18nDescription: 'Enable_Gimme_Command_Description',
});
await configuration.settings.provideSetting({
id: this.lennyId,
type: SettingType.BOOLEAN,
packageValue: true,
required: false,
public: false,
i18nLabel: 'Enable_Lenny_Command',
i18nDescription: 'Enable_Lenny_Command_Description',
});
await configuration.settings.provideSetting({
id: this.shrugId,
type: SettingType.BOOLEAN,
packageValue: true,
required: false,
public: false,
i18nLabel: 'Enable_Shrug_Command',
i18nDescription: 'Enable_Shrug_Command_Description',
});
await configuration.settings.provideSetting({
id: this.flipId,
type: SettingType.BOOLEAN,
packageValue: true,
required: false,
public: false,
i18nLabel: 'Enable_Tableflip_Command',
i18nDescription: 'Enable_Tableflip_Command_Description',
});
await configuration.settings.provideSetting({
id: this.unflipId,
type: SettingType.BOOLEAN,
packageValue: true,
required: false,
public: false,
i18nLabel: 'Enable_Unflip_Table_Command',
i18nDescription: 'Enable_Unflip_Table_Command_Description',
});
await configuration.slashCommands.provideSlashCommand(new GimmeCommand());
await configuration.slashCommands.provideSlashCommand(new LennyCommand());
await configuration.slashCommands.provideSlashCommand(new ShrugCommand());
await configuration.slashCommands.provideSlashCommand(new TableflipCommand());
await configuration.slashCommands.provideSlashCommand(new UnflipCommand());
}
private async enableOrDisableCommand(id: string, doEnable: boolean, configModify: IConfigurationModify): Promise<void> {
switch (id) {
case this.gimmeId:
if (doEnable) {
await configModify.slashCommands.enableSlashCommand(GimmeCommand.CommandName);
} else {
await configModify.slashCommands.disableSlashCommand(GimmeCommand.CommandName);
}
return;
case this.lennyId:
if (doEnable) {
await configModify.slashCommands.enableSlashCommand(LennyCommand.CommandName);
} else {
await configModify.slashCommands.disableSlashCommand(LennyCommand.CommandName);
}
return;
case this.shrugId:
if (doEnable) {
await configModify.slashCommands.enableSlashCommand(ShrugCommand.CommandName);
} else {
await configModify.slashCommands.disableSlashCommand(ShrugCommand.CommandName);
}
return;
case this.flipId:
if (doEnable) {
await configModify.slashCommands.enableSlashCommand(TableflipCommand.CommandName);
} else {
await configModify.slashCommands.disableSlashCommand(TableflipCommand.CommandName);
}
return;
case this.unflipId:
if (doEnable) {
await configModify.slashCommands.enableSlashCommand(UnflipCommand.CommandName);
} else {
await configModify.slashCommands.disableSlashCommand(UnflipCommand.CommandName);
}
return;
}
}
}
{
"id": "92f68653-ef9e-44fe-9284-4bd807c8fd78",
"name": "ASCII Art Commands",
"nameSlug": "asciiart-commands",
"description": "Provides neat little asciiart commands for fun usage.",
"version": "1.0.3",
"requiredApiVersion": "^0.9.13",
"author": {
"name": "Bradley Hilton",
"homepage": "https://github.com/graywolf336/temporary-apps-dev-environment",
"support": "https://github.com/graywolf336/temporary-apps-dev-environment/issues"
},
"classFile": "AsciiArtCommandsApp.ts",
"iconFile": "icon.png"
}
import { IHttp, IModify, IRead } from '@rocket.chat/apps-ts-definition/accessors';
import { ISlashCommand, SlashCommandContext } from '@rocket.chat/apps-ts-definition/slashcommands';
export class GimmeCommand implements ISlashCommand {
public static CommandName = 'gimme';
public command: string = GimmeCommand.CommandName;
public i18nParamsExample: string = 'your_message_optional';
public i18nDescription: string = 'Slash_Gimme_Description';
public providesPreview: boolean = false;
public async executor(context: SlashCommandContext, read: IRead, modify: IModify, http: IHttp): Promise<void> {
const builder = modify.getCreator().startMessage()
.setSender(context.getSender()).setRoom(context.getRoom())
.setText('༼ つ ◕_◕ ༽つ ' + context.getArguments().join(' '));
await modify.getCreator().finish(builder);
}
}
import { IHttp, IModify, IRead, ISettingRead } from '@rocket.chat/apps-ts-definition/accessors';
import { ISlashCommand, SlashCommandContext } from '@rocket.chat/apps-ts-definition/slashcommands';
export class LennyCommand implements ISlashCommand {
public static CommandName = 'lennyface';
public command: string = LennyCommand.CommandName;
public i18nParamsExample: string = 'your_message_optional';
public i18nDescription: string = 'Slash_LennyFace_Description';
public providesPreview: boolean = false;
public async executor(context: SlashCommandContext, read: IRead, modify: IModify, http: IHttp): Promise<void> {
await modify.getCreator().finish(modify.getCreator().startMessage({
id: 'this-will-be-removed(whoops)',
room: context.getRoom(),
sender: context.getSender(),
text: context.getArguments().join(' ') + (context.getArguments().length === 0 ? '' : ' ') + ' ( ͡° ͜ʖ ͡°)',
}));
}
}
import { IHttp, IModify, IRead, ISettingRead } from '@rocket.chat/apps-ts-definition/accessors';
import { ISlashCommand, SlashCommandContext } from '@rocket.chat/apps-ts-definition/slashcommands';
export class ShrugCommand implements ISlashCommand {
public static CommandName = 'shrug';
public command: string = ShrugCommand.CommandName;
public i18nParamsExample: string = 'your_message_optional';
public i18nDescription: string = 'Slash_Shrug_Description';
public providesPreview: boolean = false;
public async executor(context: SlashCommandContext, read: IRead, modify: IModify, http: IHttp): Promise<void> {
const msgBuilder = modify.getCreator().startMessage()
.setSender(context.getSender()).setRoom(context.getRoom())
.setText(context.getArguments().join(' ') +
(context.getArguments().length === 0 ? '' : ' ') +
'¯\\_(ツ)_/¯');
await modify.getCreator().finish(msgBuilder);
}
}
import { IHttp, IModify, IRead, ISettingRead } from '@rocket.chat/apps-ts-definition/accessors';
import { ISlashCommand, SlashCommandContext } from '@rocket.chat/apps-ts-definition/slashcommands';
export class TableflipCommand implements ISlashCommand {
public static CommandName = 'tableflip';
public command: string = TableflipCommand.CommandName;
public i18nParamsExample: string = 'your_message_optional';
public i18nDescription: string = 'Slash_Tableflip_Description';
public providesPreview: boolean = false;
public async executor(context: SlashCommandContext, read: IRead, modify: IModify, http: IHttp): Promise<void> {
const msgBuilder = modify.getCreator().startMessage()
.setSender(context.getSender()).setRoom(context.getRoom())
.setText(context.getArguments().join(' ') +
(context.getArguments().length === 0 ? '' : ' ') +
'(╯°□°)╯︵ ┻━┻');
await modify.getCreator().finish(msgBuilder);
}
}
import { IHttp, IModify, IRead, ISettingRead } from '@rocket.chat/apps-ts-definition/accessors';
import { ISlashCommand, SlashCommandContext } from '@rocket.chat/apps-ts-definition/slashcommands';
export class UnflipCommand implements ISlashCommand {
public static CommandName = 'unflip';
public command: string = UnflipCommand.CommandName;
public i18nParamsExample: string = 'your_message_optional';
public i18nDescription: string = 'Slash_TableUnflip_Description';
public providesPreview: boolean = false;
public async executor(context: SlashCommandContext, read: IRead, modify: IModify, http: IHttp): Promise<void> {
const msgBuilder = modify.getCreator().startMessage()
.setSender(context.getSender()).setRoom(context.getRoom())
.setText(context.getArguments().join(' ') +
(context.getArguments().length === 0 ? '' : ' ') +
'┬─┬ ノ( ゜-゜ノ)');
await modify.getCreator().finish(msgBuilder);
}
}
{
"Enable_Gimme_Command": "Enable the Gimme Command",
"Enable_Gimme_Command_Description": "Whether or not the `/gimme` command should be enabled.",
"Enable_Lenny_Command": "Enable the Lenny Command",
"Enable_Lenny_Command_Description": "Whether or not the `/lenny` command should be enabled.",
"Enable_Shrug_Command": "Enable the Shrug Command",
"Enable_Shrug_Command_Description": "Whether or not the `/shrug` command should be enabled.",
"Enable_Tableflip_Command": "Enable the Tableflip Command",
"Enable_Tableflip_Command_Description": "Whether or not the `/tableflip` command should be enabled.",
"Enable_Unflip_Table_Command": "Enable the Unflip Table Command",
"Enable_Unflip_Table_Description": "Whether or not the `/unflip` command should be enabled."
}
import {
IConfigurationExtend,
IEnvironmentRead,
ILogger,
} from '@rocket.chat/apps-ts-definition/accessors';
import { App } from '@rocket.chat/apps-ts-definition/App';
import { IAppInfo } from '@rocket.chat/apps-ts-definition/metadata';
import { GiphyCommand } from './commands/GiphyCommand';
import { GifGetter } from './helpers/GifGetter';
export class GiphyApp extends App {
private gifGetter: GifGetter;
constructor(info: IAppInfo, logger: ILogger) {
super(info, logger);
this.gifGetter = new GifGetter();
}
public getGifGetter(): GifGetter {
return this.gifGetter;
}
protected async extendConfiguration(configuration: IConfigurationExtend, environmentRead: IEnvironmentRead): Promise<void> {
await configuration.slashCommands.provideSlashCommand(new GiphyCommand(this));
}
}
{
"id": "497f2898-7f55-424c-88af-f42c08a1b25d",
"name": "Giphy",
"nameSlug": "giphy",
"version": "0.1.4",
"requiredApiVersion": "^0.9.13",
"description": "Giphy Rocket.Chat App",
"author": {
"name": "Bradley Hilton",
"support": "https://github.com/RocketChat/Rocket.Chat.Apps-ts-definitions/issues"
},
"classFile": "Giphy.ts",
"iconFile": "icon.jpg"
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment