Commit 9e9f02c4 authored by Hunter Loftis's avatar Hunter Loftis

yoga: flexible and powerful

parent b659a6ce
...@@ -8,10 +8,30 @@ status() { ...@@ -8,10 +8,30 @@ status() {
} }
protip() { protip() {
tip=$1
url=$2
echo echo
echo "PRO TIP: $*" | indent echo "PRO TIP: $tip" | indent
echo "See https://devcenter.heroku.com/articles/nodejs-support" | indent echo "See ${url:-https://devcenter.heroku.com/articles/nodejs-support}" | indent
echo }
file_contents() {
if test -f $1; then
echo "$(cat $1)"
else
echo ""
fi
}
package_json() {
if test -f $build_dir/package.json; then
local result="$(cat $build_dir/package.json | $bp_dir/vendor/jq -r $1)"
if [ "$result" == "null" ]; then echo ""
else echo "$result"
fi
else
echo ""
fi
} }
# sed -l basically makes sed replace and buffer through stdin to stdout # sed -l basically makes sed replace and buffer through stdin to stdout
...@@ -29,6 +49,13 @@ cat_npm_debug_log() { ...@@ -29,6 +49,13 @@ cat_npm_debug_log() {
test -f $build_dir/npm-debug.log && cat $build_dir/npm-debug.log test -f $build_dir/npm-debug.log && cat $build_dir/npm-debug.log
} }
tail_error_log() {
echo ""
echo " ! Build failure:"
echo ""
tail -n 500 $logfile | indent
}
export_env_dir() { export_env_dir() {
env_dir=$1 env_dir=$1
whitelist_regex=${2:-''} whitelist_regex=${2:-''}
......
#!/usr/bin/env bash #!/usr/bin/env bash
####### Configure environment
set -e # fail fast set -e # fail fast
set -o pipefail # don't ignore exit codes when piping output set -o pipefail # don't ignore exit codes when piping output
# set -x # enable debugging # set -x # enable debugging
bp_version="64"
# Configure directories # Configure directories
build_dir=$1 build_dir=$1
cache_dir=$2 cache_dir=$2
env_dir=$3 env_dir=$3
bp_dir=$(cd $(dirname $0); cd ..; pwd) bp_dir=$(cd $(dirname $0); cd ..; pwd)
heroku_dir=$build_dir/.heroku
logfile=/tmp/node-log.txt
# Load some convenience functions like status(), echo(), and indent() # Load some convenience functions like status(), echo(), and indent()
source $bp_dir/bin/common.sh source $bp_dir/bin/common.sh
# Fix leak # Output version
status "Resetting git environment" status "Node.js Buildpack v$bp_version"
# Avoid GIT_DIR leak from previous build steps
unset GIT_DIR unset GIT_DIR
# Output npm debug info on error # Create directories & log file
trap cat_npm_debug_log ERR mkdir -p $heroku_dir/node
echo "" > $logfile
# Look in package.json's engines.node field for a semver range # Trap errors
semver_range=$(cat $build_dir/package.json | $bp_dir/vendor/jq -r .engines.node) trap tail_error_log ERR
# Resolve node version using semver.io # Load config vars into environment; start with defaults
node_version=$(curl --silent --get --data-urlencode "range=${semver_range}" https://semver.io/node/resolve) export NPM_CONFIG_PRODUCTION=true
export BUILD_CLEAN=false
# Recommend using semver ranges in a safe manner if [ -d "$env_dir" ]; then
if [ "$semver_range" == "null" ]; then export_env_dir $env_dir
protip "Specify a node version in package.json"
semver_range=""
elif [ "$semver_range" == "*" ]; then
protip "Avoid using semver ranges like '*' in engines.node"
elif [ ${semver_range:0:1} == ">" ]; then
protip "Avoid using semver ranges starting with '>' in engines.node"
fi fi
# Output info about requested range and resolved node version ####### Determine current state
if [ "$semver_range" == "" ]; then
status "Defaulting to latest stable node: $node_version" # Which version of the buildpack did we use last time?
else bp_previous=$(file_contents "$cache_dir/node/bp-version")
status "Requested node range: $semver_range"
status "Resolved node version: $node_version" # What's the requested semver range for node?
node_engine=$(package_json ".engines.node")
node_previous=$(file_contents "$cache_dir/node/node-version")
# What's the requested semver range for npm?
npm_engine=$(package_json ".engines.npm")
npm_previous=$(file_contents "$cache_dir/node/npm-version")
# How does this app start?
if test -f $build_dir/Procfile; then start_method="Procfile"
elif [[ $(package_json ".scripts.start") != "" ]]; then start_method="npm start"
elif [ -f $build_dir/server.js ]; then start_method="server.js"
else start_method=""
fi fi
# Download node from Heroku's S3 mirror of nodejs.org/dist # What's the source-of-truth for node_modules?
status "Downloading and installing node" if test -d $build_dir/node_modules; then modules_source="prebuilt"
node_url="http://s3pository.heroku.com/node/v$node_version/node-v$node_version-linux-x64.tar.gz" elif test -f $build_dir/npm-shrinkwrap.json; then modules_source="npm-shrinkwrap.json"
curl $node_url -s -o - | tar xzf - -C $build_dir elif test -f $build_dir/package.json; then modules_source="package.json"
else modules_source=""
fi
# What does our cache look like?
test -d $cache_dir/node/node_modules && modules_cached=true || modules_cached=false
####### Provide debugging info and feedback
echo ""
status "Node engine: ${node_engine:-unspecified}"
status "Npm engine: ${npm_engine:-default}"
status "Start mechanism: ${start_method:-none}"
status "node_modules source: ${modules_source:-none}"
status "node_modules cached: $modules_cached"
# Move node (and npm) into ./vendor and make them executable echo ""
mkdir -p $build_dir/vendor
mv $build_dir/node-v$node_version-linux-x64 $build_dir/vendor/node
chmod +x $build_dir/vendor/node/bin/*
PATH=$build_dir/vendor/node/bin:$PATH
# Run subsequent node/npm commands from the build path status "NPM_CONFIG_PRODUCTION=$NPM_CONFIG_PRODUCTION"
status "BUILD_CLEAN=$BUILD_CLEAN"
source $bp_dir/bin/warnings.sh
####### Vendor in binaries
echo ""
# Resolve non-specific node versions using semver.io
if ! [[ "$node_engine" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
status "Resolving node version ${node_engine:-(latest stable)} via semver.io..."
node_engine=$(curl --silent --get --data-urlencode "range=${node_engine}" https://semver.io/node/resolve)
fi
# Download node from Heroku's S3 mirror of nodejs.org/dist
status "Downloading and installing node $node_engine..."
node_url="http://s3pository.heroku.com/node/v$node_engine/node-v$node_engine-linux-x64.tar.gz"
curl $node_url -s -o - | tar xzf - -C /tmp
# Move node (and npm) into .heroku/node and make them executable
mv /tmp/node-v$node_engine-linux-x64/* $heroku_dir/node
chmod +x $heroku_dir/node/bin/*
PATH=$heroku_dir/node/bin:$PATH
# Optionally bootstrap a different npm version
if [ "$npm_engine" != "" ]; then
if ! [[ "$npm_engine" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
status "Resolving npm version ${npm_engine} via semver.io..."
npm_engine=$(curl --silent --get --data-urlencode "range=${npm_engine}" https://semver.io/npm/resolve)
fi
status "Downloading and installing npm $npm_engine (replacing version `npm --version`)..."
npm install -g npm@$npm_engine >> $logfile 2>&1
fi
# Run subsequent commands from the build directory
cd $build_dir cd $build_dir
# If node_modules directory is checked into source control then ####### Build the project's dependencies
# rebuild any native deps. Otherwise, restore from the build cache.
if test -d $build_dir/node_modules; then # Did we bust the cache?
status "Found existing node_modules directory; skipping cache" if ! $modules_cached; then
status "Rebuilding any native dependencies" cache_busted=true
npm rebuild 2>&1 | indent elif [ "$node_previous" != "" ] && [ "$node_engine" != "$node_previous" ]; then
elif test -d $cache_dir/node/node_modules; then status "Node version changed ($node_previous => $node_engine); invalidating cache"
status "Restoring node_modules directory from cache" cache_busted=true
elif [ "$npm_previous" != "" ] && [ "$npm_engine" != "$npm_previous" ]; then
status "Npm version changed ($npm_previous => $npm_engine); invalidating cache"
cache_busted=true
elif [ "$bp_version" != "$bp_previous" ]; then
status "Buildpack version changed (${bp_previous:-none} => $bp_version); invalidating cache"
cache_busted=true
else
cache_busted=false
fi
if [ "$modules_source" == "" ]; then
status "Skipping dependencies"
elif [ $modules_source == "prebuilt" ]; then
status "Rebuilding any native modules for this architecture"
npm rebuild >> $logfile 2>&1
elif ! $BUILD_CLEAN && ! $cache_busted; then
status "Restoring node modules from cache"
cp -r $cache_dir/node/node_modules $build_dir/ cp -r $cache_dir/node/node_modules $build_dir/
status "Pruning unused dependencies"
npm prune >> $logfile 2>&1
status "Installing any new modules"
npm install --userconfig $build_dir/.npmrc >> $logfile 2>&1
status "Pruning cached dependencies not specified in package.json" else
npm prune --production 2>&1 | indent status "Installing node modules"
touch $build_dir/.npmrc
npm install --userconfig $build_dir/.npmrc >> $logfile 2>&1
status "Deduping dependency tree"
npm dedupe >> $logfile 2>&1
fi
if test -f $cache_dir/node/.heroku/node-version && [ $(cat $cache_dir/node/.heroku/node-version) != "$node_version" ]; then ####### Create a Procfile if possible
status "Node version changed since last build; rebuilding dependencies"
npm rebuild 2>&1 | indent
fi
if [ "$start_method" == "npm start" ]; then
status "No Procfile found; Adding 'web: npm start' to new Procfile"
echo "web: npm start" > $build_dir/Procfile
elif [ "$start_method" == "server.js" ]; then
status "No Procfile found; Adding 'web: node server.js' to new Procfile"
echo "web: node server.js" > $build_dir/Procfile
fi fi
# Scope config var availability only to `npm install` ####### Create the runtime environment (profile.d)
(
if [ -d "$env_dir" ]; then status "Building runtime environment"
status "Exporting config vars to environment" mkdir -p $build_dir/.profile.d
export_env_dir $env_dir
fi
status "Installing dependencies" # Runtime & Multi-buildpack exports
# Make npm output to STDOUT instead of its default STDERR export_path="export PATH=\"\$HOME/.heroku/node/bin:\$HOME/bin:\$HOME/node_modules/.bin:\$PATH\""
npm install --userconfig $build_dir/.npmrc --production 2>&1 | indent export_home="export NODE_HOME=\"\$HOME/.heroku/node\""
) echo $export_path > $build_dir/.profile.d/nodejs.sh
echo $export_home >> $build_dir/.profile.d/nodejs.sh
echo $export_path > $bp_dir/export
echo $export_home >> $bp_dir/export
# Persist goodies like node-version in the slug ####### Clean up
mkdir -p $build_dir/.heroku
# Save resolved node version in the slug for later reference status "Cleaning up build artifacts"
echo $node_version > $build_dir/.heroku/node-version
# Purge node-related cached content, being careful not to purge the top-level # Clean up after npm
# cache, for the sake of heroku-buildpack-multi apps. rm -rf "$build_dir/.node-gyp"
rm -rf "$build_dir/.npm"
# Clear the cache
rm -rf $cache_dir/node_modules # (for apps still on the older caching strategy) rm -rf $cache_dir/node_modules # (for apps still on the older caching strategy)
rm -rf $cache_dir/node rm -rf $cache_dir/node
####### Build successful! Store results in cache
# Create the cache
mkdir -p $cache_dir/node mkdir -p $cache_dir/node
# If app has a node_modules directory, cache it. echo $node_engine > $cache_dir/node/node-version
echo $npm_engine > $cache_dir/node/npm-version
echo $bp_version > $cache_dir/node/bp-version
if test -d $build_dir/node_modules; then if test -d $build_dir/node_modules; then
status "Caching node_modules directory for future builds" status "Caching node_modules for future builds"
cp -r $build_dir/node_modules $cache_dir/node cp -r $build_dir/node_modules $cache_dir/node
fi fi
# Copy goodies to the cache ####### Summary output
cp -r $build_dir/.heroku $cache_dir/node
status "Cleaning up node-gyp and npm artifacts"
rm -rf "$build_dir/.node-gyp"
rm -rf "$build_dir/.npm"
# If Procfile is absent, try to create one using `npm start`
if [ ! -e $build_dir/Procfile ]; then
npm_start=$(cat $build_dir/package.json | $bp_dir/vendor/jq -r .scripts.start)
# If `scripts.start` is set in package.json, or a server.js file
# is present in the app root, then create a default Procfile
if [ "$npm_start" != "null" ] || [ -f $build_dir/server.js ]; then
status "No Procfile found; Adding npm start to new Procfile"
echo "web: npm start" > $build_dir/Procfile
else
status "Procfile not found and npm start script is undefined"
protip "Create a Procfile or specify a start script in package.json"
fi
fi
# Update the PATH # Show the final dependency tree
status "Building runtime environment" echo ""
mkdir -p $build_dir/.profile.d npm ls
echo "export PATH=\"\$HOME/vendor/node/bin:\$HOME/bin:\$HOME/node_modules/.bin:\$PATH\";" > $build_dir/.profile.d/nodejs.sh
# Post package.json to nomnom service
# Use a subshell so failures won't break the build.
(
curl \
--data @$build_dir/package.json \
--fail \
--silent \
--request POST \
--header "content-type: application/json" \
https://nomnom.heroku.com/?request_id=$REQUEST_ID \
> /dev/null
) &
...@@ -14,118 +14,237 @@ testDetectWithoutPackageJson() { ...@@ -14,118 +14,237 @@ testDetectWithoutPackageJson() {
testNoVersion() { testNoVersion() {
compile "no-version" compile "no-version"
assertCaptured "Node engine: unspecified"
assertCaptured "PRO TIP: Specify a node version in package.json" assertCaptured "PRO TIP: Specify a node version in package.json"
assertCaptured "Defaulting to latest stable node" assertCaptured "Resolving node version (latest stable) via semver.io"
assertCaptured "Downloading and installing node 0.10"
assertCapturedSuccess assertCapturedSuccess
} }
testDangerousRangeStar() { testSpecificVersion() {
compile "dangerous-range-star" compile "specific-version"
assertCaptured "PRO TIP: Avoid using semver ranges like '*'" assertNotCaptured "Resolving node version"
assertCaptured "Requested node range: *" assertCaptured "Downloading and installing node 0.10.29"
assertCaptured "Resolved node version: 0.10"
assertCapturedSuccess assertCapturedSuccess
} }
testDangerousRangeGreaterThan() { testStableVersion() {
compile "dangerous-range-greater-than" compile "stable-node"
assertCaptured "PRO TIP: Avoid using semver ranges starting with '>'" assertCaptured "Downloading and installing node 0.10"
assertCaptured "Requested node range: >"
assertCaptured "Resolved node version: 0.10."
assertCapturedSuccess assertCapturedSuccess
} }
testRangeWithSpace() { testUnstableVersion() {
compile "range-with-space" compile "unstable-version"
assertCaptured "Requested node range: >= 0.8.x" assertCaptured "Resolving node version >0.11.0 via semver.io"
assertCaptured "Resolved node version: 0.10." assertCaptured "Downloading and installing node 0.11"
assertCapturedSuccess assertCapturedSuccess
} }
testStableVersion() { testDangerousRangeStar() {
compile "stable-node" compile "dangerous-range-star"
assertNotCaptured "PRO TIP: Avoid using semver" assertCaptured "PRO TIP: Avoid semver ranges like '*'"
assertNotCaptured "PRO TIP: Specify" assertCaptured "Node engine: *"
assertCaptured "Resolved node version" assertCaptured "Resolving node version * via semver.io"
assertCaptured "Downloading and installing node 0.10"
assertCapturedSuccess assertCapturedSuccess
} }
testUnstableVersion() { testDangerousRangeGreaterThan() {
compile "unstable-version" compile "dangerous-range-greater-than"
assertCaptured "Requested node range: >0.11.0" assertCaptured "PRO TIP: Avoid semver ranges starting with '>'"
assertCaptured "Resolved node version: 0.11." assertCaptured "Resolving node version >0.4 via semver.io"
assertCaptured "Downloading and installing node 0.10"
assertCapturedSuccess assertCapturedSuccess
} }
testProfileCreated() { testRangeWithSpace() {
compile "stable-node" compile "range-with-space"
assertCaptured "Building runtime environment" assertCaptured "Resolving node version >= 0.8.x via semver.io"
assertFile "export PATH=\"\$HOME/vendor/node/bin:\$HOME/bin:\$HOME/node_modules/.bin:\$PATH\";" ".profile.d/nodejs.sh" assertCaptured "Downloading and installing node 0.10"
assertCapturedSuccess assertCapturedSuccess
} }
testInvalidDependency() { testInvalidDependency() {
compile "invalid-dependency" compile "invalid-dependency"
assertCaptured "not in the npm registry" assertCaptured "npm ERR! 404"
assertCapturedError 1 "" assertCapturedError 1 ""
} }
testNodeModulesCached() { testNodeModulesCached() {
cache=$(mktmpdir) cache=$(mktmpdir)
compile "caching" $cache compile "caching" $cache
assertCaptured "Caching node" assertCaptured "Caching node_modules for future builds"
assertEquals "1" "$(ls -1 $cache/ | wc -l)" assertEquals "1" "$(ls -1 $cache/ | wc -l)"
} }
testBuildWithCache() {
cache=$(mktmpdir)
compile "stable-node" $cache
assertCaptured "node_modules cached: false"
assertCaptured "Caching node_modules for future builds"
assertCapturedSuccess
compile "stable-node" $cache
assertCaptured "node_modules cached: true"
assertCaptured "Restoring node modules from cache"
assertCapturedSuccess
}
testModulesCheckedIn() { testModulesCheckedIn() {
compile "modules-checked-in" compile "modules-checked-in"
assertCaptured "Found existing node_modules directory; skipping cache" assertCaptured "node_modules source: prebuilt"
assertCaptured "Rebuilding any native dependencies" assertCaptured "Rebuilding any native modules for this architecture"
assertNotCaptured "Restoring node modules"
assertNotCaptured "Pruning unused dependencies"
assertNotCaptured "Installing any new modules"
assertNotCaptured "Installing node modules"
assertNotCaptured "Deduping dependency tree"
assertCapturedSuccess assertCapturedSuccess
} }
testUserConfig() { testUserConfig() {
compile "userconfig" compile "userconfig"
assertCaptured "https://www.google.com/" assertCaptured "www.google.com"
assertCaptured "registry error" assertCaptured "registry error"
assertCapturedError 1 "" assertCapturedError 1 ""
} }
testProcfile() {
compile "procfile-present-only"
assertCaptured "Start mechanism: Procfile"
assertNotCaptured "new Procfile"
assertCapturedSuccess
}
testProcfileAbsentNpmStartPresent() { testProcfileAbsentNpmStartPresent() {
compile "procfile-absent-npm-start-present" compile "procfile-absent-npm-start-present"
assertCaptured "No Procfile found; Adding npm start to new Procfile" assertCaptured "Start mechanism: npm start"
assertCaptured "No Procfile found; Adding 'web: npm start' to new Procfile"
assertFile "web: npm start" "Procfile" assertFile "web: npm start" "Procfile"
assertCapturedSuccess assertCapturedSuccess
} }
testProcfileAbsentNpmStartAbsent() { testProcfileAbsentNpmStartAbsent() {
compile "procfile-absent-npm-start-absent" compile "procfile-absent-npm-start-absent"
assertCaptured "Create a Procfile or specify a start script in package.json" assertCaptured "Start mechanism: none"
assertNotCaptured "new Procfile"
assertCapturedSuccess assertCapturedSuccess
} }
testProcfileAbsentNpmStartPresent() { testProcfileAbsentServerPresent() {
compile "procfile-absent-npm-start-present" compile "procfile-absent-server-present"
assertCaptured "No Procfile found; Adding npm start to new Procfile" assertCaptured "Start mechanism: server.js"
assertFile "web: npm start" "Procfile" assertCaptured "'web: node server.js' to new Procfile"
assertFile "web: node server.js" "Procfile"
assertCapturedSuccess assertCapturedSuccess
} }
testEnvDirNotImported() { testServerPresentOnly() {
compile "stable-node" compile "server-present-only"
assertNotCaptured "Exporting config vars to environment" assertCaptured "PRO TIP: Use 'npm init'"
assertCaptured "'web: node server.js' to new Procfile"
assertFile "web: node server.js" "Procfile"
assertCapturedSuccess
}
testEnvVars() {
env_dir=$(mktmpdir)
echo "false" > $env_dir/NPM_CONFIG_PRODUCTION
compile "stable-node" "$(mktmpdir)" $env_dir
assertCaptured "NPM_CONFIG_PRODUCTION=false"
assertCapturedSuccess assertCapturedSuccess
} }
testEnvDirExported() { testNoEnvVars() {
env_dir=$(mktmpdir) env_dir=$(mktmpdir)
echo "chicken" > $env_dir/birds
echo "koi" > $env_dir/fish
compile "stable-node" "$(mktmpdir)" $env_dir compile "stable-node" "$(mktmpdir)" $env_dir
assertCaptured "Exporting config vars to environment" assertCaptured "NPM_CONFIG_PRODUCTION=true"
assertCapturedSuccess assertCapturedSuccess
} }
testNoDevDependencies() {
compile "dev-dependencies"
assertNotCaptured "lodash"
assertCapturedSuccess
}
testDevDependencies() {
env_dir=$(mktmpdir)
echo "false" > $env_dir/NPM_CONFIG_PRODUCTION
compile "dev-dependencies" "$(mktmpdir)" $env_dir
assertCaptured "lodash"
assertCapturedSuccess
}
testBuildClean() {
cache=$(mktmpdir)
env_dir=$(mktmpdir)
compile "build-clean-1" $cache
assertCaptured "lodash@1.0.0"
assertCapturedSuccess
compile "build-clean-2" $cache
assertCaptured "lodash@1.0.0"
assertCapturedSuccess
echo "true" > $env_dir/BUILD_CLEAN
compile "build-clean-2" $cache $env_dir
assertCaptured "lodash@1.3.1"
assertCapturedSuccess
}
testNpmrc() {
compile "dev-dependencies"
assertNotCaptured "lodash"
assertCapturedSuccess
compile "dev-dependencies-npmrc"
assertCaptured "lodash"
assertCapturedSuccess
}
testShrinkwrap() {
compile "shrinkwrap"
assertCaptured "express@4.10.4"
assertCaptured "mime-db@1.2.0"
assertCaptured "etag@1.5.1"
assertCaptured "lodash@2.4.1"
assertNotCaptured "mocha"
assertCapturedSuccess
}
testNpmVersionRange() {
compile "npm-version-range"
assertCaptured "Resolving npm version"
assertCaptured "installing npm 1.4."
assertCapturedSuccess
}
testNpmVersionSpecific() {
compile "npm-version-specific"
assertCaptured "installing npm 2.1.11"
assertNotCaptured "Resolving npm version"
assertCapturedSuccess
}
testProfileExport() {
compile "stable-node"
assertCaptured "Building runtime environment"
assertFileContains "export PATH=\"\$HOME/.heroku/node/bin:\$HOME/bin:\$HOME/node_modules/.bin:\$PATH\"" "${compile_dir}/.profile.d/nodejs.sh"
assertFileContains "export NODE_HOME=\"\$HOME/.heroku/node\"" "${compile_dir}/.profile.d/nodejs.sh"
assertCapturedSuccess
}
testMultiExport() {
compile "stable-node"
assertFileContains "export PATH=\"\$HOME/.heroku/node/bin:\$HOME/bin:\$HOME/node_modules/.bin:\$PATH\"" "${bp_dir}/export"
assertFileContains "export NODE_HOME=\"\$HOME/.heroku/node\"" "${bp_dir}/export"
assertCapturedSuccess
}
# Utils # Utils
pushd $(dirname 0) >/dev/null pushd $(dirname 0) >/dev/null
......
if [ "$node_engine" == "" ]; then
protip "Specify a node version in package.json" "https://devcenter.heroku.com/articles/nodejs-support#specifying-a-node-js-version"
elif [ "$node_engine" == "*" ]; then
protip "Avoid semver ranges like '*' in engines.node" "https://devcenter.heroku.com/articles/nodejs-support#specifying-a-node-js-version"
elif [ ${node_engine:0:1} == ">" ]; then
protip "Avoid semver ranges starting with '>' in engines.node" "https://devcenter.heroku.com/articles/nodejs-support#specifying-a-node-js-version"
fi
if [ "$modules_source" == "prebuilt" ]; then
protip "Avoid checking node_modules into source control" "https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-"
elif [ "$modules_source" == "" ]; then
protip "Use 'npm init' and 'npm install --save' to define dependencies"
fi
if [ "$start_method" == "" ]; then
protip "Include a Procfile, package.json start script, or server.js file to start your app" "https://devcenter.heroku.com/articles/nodejs-support#runtime-behavior"
fi
A fake README, to keep npm from polluting stderr.
\ No newline at end of file
{
"name": "node-buildpack-test-app",
"version": "0.0.1",
"description": "node buildpack integration test app",
"repository": {
"type": "git",
"url": "http://github.com/example/example.git"
},
"dependencies": {
"lodash": "1.0.0"
},
"engines": {
"node": "~0.10.0"
}
}
A fake README, to keep npm from polluting stderr.
\ No newline at end of file
{
"name": "node-buildpack-test-app",
"version": "0.0.1",
"description": "node buildpack integration test app",
"repository": {
"type": "git",
"url": "http://github.com/example/example.git"
},
"dependencies": {
"lodash": "^1.0.0"
},
"engines": {
"node": "~0.10.0"
}
}
A fake README, to keep npm from polluting stderr.
\ No newline at end of file
{
"name": "node-buildpack-test-app",
"version": "0.0.1",
"description": "node buildpack integration test app",
"repository": {
"type": "git",
"url": "http://github.com/example/example.git"
},
"dependencies": {
},
"engines": {
"node": "~0.10.0"
},
"devDependencies": {
"lodash": "^2.4.1"
}
}
A fake README, to keep npm from polluting stderr.
\ No newline at end of file
{
"name": "node-buildpack-test-app",
"version": "0.0.1",
"description": "node buildpack integration test app",
"repository": {
"type": "git",
"url": "http://github.com/example/example.git"
},
"dependencies": {
"hashish": "*"
},
"engines": {
"node": "~0.10.0"
},
"devDependencies": {
"lodash": "^2.4.1"
}
}
A fake README, to keep npm from polluting stderr.
\ No newline at end of file
{
"name": "node-buildpack-test-app",
"version": "0.0.1",
"description": "node buildpack integration test app",
"repository" : {
"type" : "git",
"url" : "http://github.com/example/example.git"
},
"engines": {
"node": "0.10.33",
"npm": "1.4.x"
}
}
A fake README, to keep npm from polluting stderr.
\ No newline at end of file
{
"name": "node-buildpack-test-app",
"version": "0.0.1",
"description": "node buildpack integration test app",
"repository" : {
"type" : "git",
"url" : "http://github.com/example/example.git"
},
"dependencies": {
"hashish": "*"
},
"engines": {
"node": "~0.10.0",
"npm": "2.1.11"
}
}
A fake README, to keep npm from polluting stderr.
\ No newline at end of file
{
"name": "node-buildpack-test-app",
"version": "0.0.1",
"description": "node buildpack integration test app",
"repository" : {
"type" : "git",
"url" : "http://github.com/example/example.git"
},
"dependencies": {
"hashish": "*"
},
"engines": {
"node": "~0.10.0"
}
}
A fake README, to keep npm from polluting stderr.
\ No newline at end of file
A fake README, to keep npm from polluting stderr.
\ No newline at end of file
A fake README, to keep npm from polluting stderr.
\ No newline at end of file
{
"name": "node-buildpack-test-app",
"version": "0.0.1",
"dependencies": {
"express": {
"version": "4.10.4",
"from": "express@4.10.4",
"resolved": "https://registry.npmjs.org/express/-/express-4.10.4.tgz",
"dependencies": {
"accepts": {
"version": "1.1.3",
"from": "accepts@~1.1.3",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.1.3.tgz",
"dependencies": {
"mime-types": {
"version": "2.0.3",
"from": "mime-types@~2.0.3",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.0.3.tgz",
"dependencies": {
"mime-db": {
"version": "1.2.0",
"from": "mime-db@~1.2.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.2.0.tgz"
}
}
},
"negotiator": {
"version": "0.4.9",
"from": "negotiator@0.4.9",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.4.9.tgz"
}
}
},
"content-disposition": {
"version": "0.5.0",
"from": "content-disposition@0.5.0",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.0.tgz"
},
"cookie-signature": {
"version": "1.0.5",
"from": "cookie-signature@1.0.5",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.5.tgz"
},
"debug": {
"version": "2.1.0",
"from": "debug@~2.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.1.0.tgz",
"dependencies": {
"ms": {
"version": "0.6.2",
"from": "ms@0.6.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-0.6.2.tgz"
}
}
},
"depd": {
"version": "1.0.0",
"from": "depd@~1.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.0.0.tgz"
},
"escape-html": {
"version": "1.0.1",
"from": "escape-html@1.0.1",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.1.tgz"
},
"etag": {
"version": "1.5.1",
"from": "etag@~1.5.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.5.1.tgz",
"dependencies": {
"crc": {
"version": "3.2.1",
"from": "crc@3.2.1",
"resolved": "https://registry.npmjs.org/crc/-/crc-3.2.1.tgz"
}
}
},
"finalhandler": {
"version": "0.3.2",
"from": "finalhandler@0.3.2",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.3.2.tgz"
},
"fresh": {
"version": "0.2.4",
"from": "fresh@0.2.4",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.2.4.tgz"
},
"media-typer": {
"version": "0.3.0",
"from": "media-typer@0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz"
},
"methods": {
"version": "1.1.0",
"from": "methods@1.1.0",
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.0.tgz"
},
"on-finished": {
"version": "2.1.1",
"from": "on-finished@~2.1.1",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.1.1.tgz",
"dependencies": {
"ee-first": {
"version": "1.1.0",
"from": "ee-first@1.1.0",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.0.tgz"
}
}
},
"parseurl": {
"version": "1.3.0",
"from": "parseurl@~1.3.0",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.0.tgz"
},
"path-to-regexp": {
"version": "0.1.3",
"from": "path-to-regexp@0.1.3",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.3.tgz"
},
"proxy-addr": {
"version": "1.0.4",
"from": "proxy-addr@~1.0.4",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.0.4.tgz",
"dependencies": {
"forwarded": {
"version": "0.1.0",
"from": "forwarded@~0.1.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.0.tgz"
},
"ipaddr.js": {
"version": "0.1.5",
"from": "ipaddr.js@0.1.5",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-0.1.5.tgz"
}
}
},
"qs": {
"version": "2.3.3",
"from": "qs@2.3.3",
"resolved": "https://registry.npmjs.org/qs/-/qs-2.3.3.tgz"
},
"range-parser": {
"version": "1.0.2",
"from": "range-parser@~1.0.2",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.0.2.tgz"
},
"send": {
"version": "0.10.1",
"from": "send@0.10.1",
"resolved": "https://registry.npmjs.org/send/-/send-0.10.1.tgz",
"dependencies": {
"destroy": {
"version": "1.0.3",
"from": "destroy@1.0.3",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.3.tgz"
},
"mime": {
"version": "1.2.11",
"from": "mime@1.2.11",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz"
},
"ms": {
"version": "0.6.2",
"from": "ms@0.6.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-0.6.2.tgz"
}
}
},
"serve-static": {
"version": "1.7.1",
"from": "serve-static@~1.7.1",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.7.1.tgz"
},
"type-is": {
"version": "1.5.3",
"from": "type-is@~1.5.3",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.5.3.tgz",
"dependencies": {
"mime-types": {
"version": "2.0.3",
"from": "mime-types@~2.0.3",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.0.3.tgz",
"dependencies": {
"mime-db": {
"version": "1.2.0",
"from": "mime-db@~1.2.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.2.0.tgz"
}
}
}
}
},
"vary": {
"version": "1.0.0",
"from": "vary@~1.0.0",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.0.0.tgz"
},
"cookie": {
"version": "0.1.2",
"from": "cookie@0.1.2",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.2.tgz"
},
"merge-descriptors": {
"version": "0.0.2",
"from": "merge-descriptors@0.0.2",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-0.0.2.tgz"
},
"utils-merge": {
"version": "1.0.0",
"from": "utils-merge@1.0.0",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz"
}
}
},
"lodash": {
"version": "2.4.1",
"from": "lodash@2.4.1",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.1.tgz"
}
}
}
{
"name": "node-buildpack-test-app",
"version": "0.0.1",
"description": "node buildpack integration test app",
"repository": {
"type": "git",
"url": "http://github.com/example/example.git"
},
"dependencies": {
"express": "4.10.4",
"lodash": "2.4.1"
},
"engines": {
"node": "~0.10.0"
},
"devDependencies": {
"mocha": "2.0.1"
}
}
A fake README, to keep npm from polluting stderr.
\ No newline at end of file
{
"name": "node-buildpack-test-app",
"version": "0.0.1",
"description": "node buildpack integration test app",
"repository" : {
"type" : "git",
"url" : "http://github.com/example/example.git"
},
"dependencies": {
"hashish": "*"
},
"engines": {
"node": "0.10.29"
}
}
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