Skip to content

Commit

Permalink
Auto-merge for PR #868 via VersionBot
Browse files Browse the repository at this point in the history
Add push command which starts a build on remote resin servers
  • Loading branch information
resin-io-versionbot[bot] committed May 10, 2018
2 parents 6d8086c + c88dd22 commit 22e7498
Show file tree
Hide file tree
Showing 10 changed files with 445 additions and 3 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file
automatically by Versionist. DO NOT EDIT THIS FILE MANUALLY!
This project adheres to [Semantic Versioning](http://semver.org/).

## v7.4.0 - 2018-05-10

* Add push command which starts a build on remote resin servers #868 [Cameron Diver]

## v7.3.8 - 2018-05-03

* Catch require errors and provide helpful instructions #874 [Tim Perry]
Expand Down
1 change: 1 addition & 0 deletions lib/actions/index.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,4 @@ module.exports =
deploy: require('./deploy')
util: require('./util')
preload: require('./preload')
push: require('./push')
142 changes: 142 additions & 0 deletions lib/actions/push.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/*
Copyright 2016-2017 Resin.io
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import { CommandDefinition } from 'capitano';
import { ResinSDK } from 'resin-sdk';
import { stripIndent } from 'common-tags';

async function getAppOwner(sdk: ResinSDK, appName: string) {
const {
exitWithExpectedError,
selectFromList,
} = await import('../utils/patterns');
const _ = await import('lodash');

const applications = await sdk.models.application.getAll({
$expand: {
user: {
$select: ['username'],
},
},
$filter: {
app_name: appName,
},
$select: ['id'],
});

if (applications == null || applications.length === 0) {
exitWithExpectedError(
stripIndent`
No applications found with name: ${appName}.
This could mean that the application does not exist, or you do
not have the permissions required to access it.`,
);
}

if (applications.length === 1) {
return _.get(applications, '[0].user[0].username');
}

// If we got more than one application with the same name it means that the
// user has access to a collab app with the same name as a personal app. We
// present a list to the user which shows the fully qualified application
// name (user/appname) and allows them to select
const entries = _.map(applications, app => {
const username = _.get(app, 'user[0].username');
return {
name: `${username}/${appName}`,
extra: username,
};
});

const selected = await selectFromList(
`${
entries.length
} applications found with that name, please select the application you would like to push to`,
entries,
);

return selected.extra;
}

export const push: CommandDefinition<
{
application: string;
},
{
source: string;
}
> = {
signature: 'push <application>',
description: 'Start a remote build on the resin.io cloud build servers',
help: stripIndent`
This command can be used to start a build on the remote
resin.io cloud builders. The given source directory will be sent to the
resin.io builder, and the build will proceed. This can be used as a drop-in
replacement for git push to deploy.
Examples:
$ resin push myApp
$ resin push myApp --source <source directory>
$ resin push myApp -s <source directory>
`,
permission: 'user',
options: [
{
signature: 'source',
alias: 's',
description:
'The source that should be sent to the resin builder to be built (defaults to the current directory)',
parameter: 'source',
},
],
async action(params, options, done) {
const sdk = (await import('resin-sdk')).fromSharedOptions();
const Bluebird = await import('bluebird');
const remote = await import('../utils/remote-build');
const { exitWithExpectedError } = await import('../utils/patterns');

const app: string | null = params.application;
if (app == null) {
exitWithExpectedError('You must specify an application');
}

const source = options.source || '.';
if (process.env.DEBUG) {
console.log(`[debug] Using ${source} as build source`);
}

Bluebird.join(
sdk.auth.getToken(),
sdk.settings.get('resinUrl'),
getAppOwner(sdk, app),
(token, baseUrl, owner) => {
const args = {
app,
owner,
source,
auth: token,
baseUrl,
sdk,
};

return remote.startRemoteBuild(args);
},
).nodeify(done);
},
};
3 changes: 3 additions & 0 deletions lib/app.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,9 @@ capitano.command(actions.internal.osInit)
capitano.command(actions.build)
capitano.command(actions.deploy)

#------------ Push/remote builds -------
capitano.command(actions.push.push)

update.notify()

cli = capitano.parse(process.argv)
Expand Down
2 changes: 1 addition & 1 deletion lib/utils/compose.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ toPosixPath = (systemPath) ->
path = require('path')
systemPath.replace(new RegExp('\\' + path.sep, 'g'), '/')

tarDirectory = (dir) ->
exports.tarDirectory = tarDirectory = (dir) ->
tar = require('tar-stream')
klaw = require('klaw')
path = require('path')
Expand Down
3 changes: 3 additions & 0 deletions lib/utils/compose.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import * as Stream from 'stream';

export function tarDirectory(source: string): Promise<Stream.Readable>;
19 changes: 19 additions & 0 deletions lib/utils/patterns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ import chalk from 'chalk';
import validation = require('./validation');
import messages = require('./messages');

export interface ListSelectionEntry {
name: string;
extra: any;
}

export function authenticate(options: {}): Promise<void> {
return form
.run(
Expand Down Expand Up @@ -245,6 +250,20 @@ export function inferOrSelectDevice(preferredUuid: string) {
});
}

export function selectFromList(
message: string,
selections: ListSelectionEntry[],
): Promise<ListSelectionEntry> {
return form.ask({
message,
type: 'list',
choices: _.map(selections, s => ({
name: s.name,
value: s,
})),
});
}

export function printErrorMessage(message: string) {
console.error(chalk.red(message));
console.error(chalk.red(`\n${messages.getHelp}\n`));
Expand Down
Loading

0 comments on commit 22e7498

Please sign in to comment.