Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
In the CFML world, there are no global conventions for where to install things to nor where to store dependencies. Therefore, CommandBox for the most part will just stick packages in the root of your site unless you tell it otherwise. It may not be pretty, but it's as good as stock CFML apps can get. That means a lot of the cool things other package managers like NPM can do simply won't be available to you.
If you're using the ColdBox MVC Platform, congratulation! You just unlocked advanced mode! ColdBox uses conventions that tells you where to put stuff, and most importantly it has modularity as a first class citizen. Not only that, but modules can be nested infinitely to nicely encapsulate dependencies and WireBox will automatically find and register each module's models for your application to use.
Modules are basically smart packages and when CommandBox installs or uninstalls modules it will behave a bit differently to take advantage of the functionality only available to the CFML world via the ColdBox Platform.
When installing a module, it will be placed in the modules/ directory. That means the cbvalidation module will install here:
The cbvalidation module has dependencies of its own but it is an island unto itself and will encapsulate these. Therefore the cbi18n module will be installed in a modules/ folder inside cbvalidation.
You'll be able to see a nice representation of this when you use the list
command.
What this opens the door for is more than one module to depend on different versions of the same second module. Both can be installed and nested under the respective parent. In the near future, WireBox will be smart enough to present these nested modules only to their parents so they are fully encapsulated.
The idea is that a module can "see" and use another module installed at the same level or higher in the hierarchy, but not lower. That makes dependencies a bit of a black box to their parents. This also allows us to bypass some redundancy. For instance, when installing a module, if a satisfying version of that module already exists at a higher level, we skip the installation. Consider this example:
We know that cbvaliation requires cbi18n, but since it is already installed in the root modules folder, we won't install it again under cbvalidation.
The last way modules are better than sliced papusas is in how they uninstall. We talked about how non-modules install-- just littered in the web root in a jumble of dependencies. When uninstalling a non-module package, CommandBox will recursively go through the dependencies and remove them as well. However, when uninstalling a module, that module's folder is simply deleted and that's it. Since all dependencies are contained in the "black box", there's no need to go hunting for them.
There are several factors that determine where a package gets installed to. Here are the ways CommandBox determines the install location in order of importance.
The value of the directory
parameter passed into the install
command by the user.
The value of the installPaths.packageName
property set in the project's main box.json by the user. Where packageName
is the name of the package you are installing like logbox
.
The value of the directory
property in the package's box.json by the package author. Note, this must be a path relative to the current working directory (CWD).
Based on the package type convention if the package is a command, coldbox module, commandbox module, plugin, or interceptor.
If the package being installed is of type lucee-extensions
and if the current working directory is found to have a Lucee server in it, the lex file will instead be installed to the server context's deploy folder.
The current working directory (CWD)
Once the installation directory is determined, a folder is created that matches the package's slug which is where the package is finally copied to. If the package's createPackageDirectory property is set to false in the box.json, the package will be copied to the root of the installation directory. An example of this would be a complete application that needs to go in the web root.
The install command is used to tell CommandBox what you want. Here we ask for the stable release of the ColdBox MVC Platform. "coldbox" is the name of the ForgeBox slug.
Packages should always have a box.json
descriptor file inside them. This is especially true of packages installed from endpoints other than Forgebox since they don't have any other metadata available. CommandBox will install any zip file even if it doesn't have a box.json
, but this isn't ideal since the name, version, and type of the package must be guessed in that instance.
If you find a package on the internet that doesn't have a box.json
, please contact the maintainer and request that they add one or submit a pull request!
ForgeBox supports semantic version ranges for installing packages. Here are some examples:
When you install a package, here are the steps that are taken. Most all of this should be evident by the output streamed to the console during the install process. To get even more juicy details, use the --verbose
flag while installing.
CommandBox inspects the ID passed to the install
command to determine the endpoint to use.
The matching endpoint is asked to fetch the package represented by the ID.
For example, the ForgeBox endpoint checks the local artifact cache and possibly downloads the package.
If ForgeBox is offline, the best match package will be looked for in your artifacts.
The package is unzipped and its box.json
is read
Installation directory is finalized
Contents of package are copied based on the ignore
and --production
flag
The package is saved as a dependency in the root box.json
The package's dependencies are installed
For CommandBox to be able to install packages for you it needs to connect to package registry where packages are stored so it can download them for installation. CommandBox integrates seamlessly with ForgeBox, our community of ColdFusion (CFML) projects. CommandBox also integrates with HTTP(S), local file/folder, and Git endpoints.
Here is a list of the package endpoints currently supported by CommandBox.
ForgeBox - Cloud-based packages (Read more)
HTTP(S) - Point to a hosted zip file containing a package (Read more)
File - A local file containing a package (Read more)
Folder - A local folder containing a package (Read more)
Git - Any Git repo containing a package (Read more)
Java - Install OpenJDK for your servers (Read more)
Jar - A jar file hosted via HTTP that's not contained in a zip file (Read more)
Lex- A Lucee Extension hosted via HTTP that's not contained in a zip file (Read more)
S3 - A package zip stored in a private S3 bucket (Read more)
CFLib - UDFs posted on CFLib.org (Read more)
Gist - A package hosted as a Gist from gist.github.com (Read more)
CommandBox functions as a package manager which means you can use it to locate and install code packages for you. This gives you a consistent and scriptable method to install the libraries you need in a simple manner.
By default, the list of available packages is on ForgeBox, our CFML code sharing site. Additional endpoints such as Git, HTTP/HTTPS, and local file/folder are also available. When a package is installed, all of its dependencies are automatically installed for you for quick, easy experience.
You can easily create your own packages and register them on ForgeBox so the whole community can start using them.
There are several options you can use to control how a package is installed.
By default, any package you install will be saved as a dependency. To save it as a development dependency instead, use the --saveDev
flag.
If you DON'T want the package you're installing to be saved as a dependency pass save=false
or negate the save flag as --!save
.
When you install a package, all dependencies will be installed. If you want to skip development dependencies, use the --production
flag. This will also cause CommandBox to obey the package's ignore
property in its box.json.
If you're a glutton for information, or perhaps you just want to debug what's going on, set the --verbose
flag to get extra debugging information out of the install command including a list of every file that's installed.
If CommandBox sees the directory that it was going to install into already exists with a newer or equal version of the package inside, it will decline to install again since it would be overwriting what's already there. If you want to install anyway, use the --force
flag.
Packages that are either stored locally on your machine or are accessible via a network drive in an unzipped folder can be installed by using their file system path. The path can be absolute or relative.
Make sure your package folder has a box.json
inside of it so CommandBox can tell the version and name of the package. If there is no box.json
, the name of the last folder in the path will be used as the package name.
To install a package from a local folder, use the path like so:
Note if using Windows, you need to escape backslashes in the command parameter.
Relative paths will start in the directory where the command is being run from.
You can specify packages from folder endpoints as dependencies in your box.json
in this format. Remember, JSON requires that backslashes be escaped.
Packages that are either stored locally on your machine or are accessible via a network drive as a zip file can be installed by using their file system path. The path can be absolute or relative.
Make sure your package zip file has a box.json
inside of it so CommandBox can tell the version and name of the package. If there is no box.json
, the name of the file without the extension will be used as the package name.
To install a package from a local file, use the path like so:
Note if using Windows, you need to escape backslashes in the command parameter.
Relative paths will start in the directory where the command is being run from.
You can specify packages from file endpoints as dependencies in your box.json
in this format. Remember, JSON requires that backslashes be escaped.
CommandBox can install UDFs from the popular site CFLib.org. Each project on CFLib is a single CFML function. You can find UDFs via the web site and copy the URL slug for a given UDF to use in your installation.
For example, if the URL to a given UDF is http://www.cflib.org/udf/CalculateWindChill
, the slug you'll want to use would be CalculateWindChill
.
To install a package from CFLib, use the slug from the website's URL like so:
This will create a folder in your installation directory named after the UDF containing a .cfm
file of the same name. The above command would create the following folder:
That file contains a single function that you can call. It is up to you to include that file where ever you want to use the UDF.
If you're using ColBox, you can use a slightly different version of the CFLib endpoint called CFLib-ColdBox
which will wrap up the UDF inside a CFC and place it in an ad-hoc module which automatically registers the model with WireBox.
This frees you up from needing to manually include the file. Once you install the module, you can immediately ask WireBox for the UDF using the convention UDFName@cflib
. WireBox will register this mapping by convention so there is no additional setup required to use the UDF.
Or inject the wrapped UDF to use in your handlers or models.
Packages installed from the CFLib endpoint don't have any way to get new version information. They will always show as outdated using the outdated
or update
commands and their downloads will not get stored in the artifact cache.
You can specify packages from the CFLib endpoint as dependencies in your box.json
in this format.
Packages hosted in private S3 buckets can be installed directly from S3 URLs.
To install a package from a S3 bucket, use a URL like so:
The S3 endpoint will automatically determine which region your bucket is in order to download your package. You can, however, bypass this automatic bucket region resolution by encoding the region of your bucket into the S3 path by using a :
after the bucket name:
Info If your S3 path does not end in
.zip
the S3 endpoint will make a HEAD request to S3 for the package path to determine if your package exists at that location. If it does not, then.zip
will be appended to your S3 path and that new path will be used as the location of your package. This means it is possible for you to specify a package without adding the.zip
extension:s3://my-private-bucket/myPackage
.
You can specify packages from S3 endpoints as dependencies in your box.json
in this format:
In order for S3 endpoints to be resolved, CommandBox needs an AWS access key and AWS secret key belonging to an AWS IAM user or role that has permission to get objects from the S3 bucket where the package is stored. The access and secret keys can be set in CommandBox settings either globally:
or on a per bucket basis:
If aws_access_key_id
and aws_secret_access_key
are not set in your CommandBox settings, the S3 endpoint checks for credentials in the same places and order as the AWS CLI and SDKs:
It checks for AWS_ACCESS_KEY_ID
and AWS_SECRET_ACCESS_KEY
environment variables containing the credentials.
It checks for an AWS credentials ini file. (If you use the AWS CLI, this file is created by the CLI when you enter your credentials during setup. The default location for this file is at~/.aws/credentials
.)
Info The location of the credentials ini file can be overwritten by setting an
AWS_SHARED_CREDENTIALS_FILE
environment variable to an alternate file path (this can also be set in your CommandBox settings:endpoint.s3.aws_shared_credentials_file
). Further, the AWS credentials file has the concept of "profiles", where the default profile is named "default". The profile to use can be changed from "default" by setting an alternate profile name in anAWS_PROFILE
environment variable or CommandBox endpoint setting (endpoint.s3.aws_profile
).
Finally the S3 endpoint will check for the presence of an IAM role from which credentials can be obtained. This credential location is only valid on AWS EC2 instances.
The full list of possible credential locations and the order in which they are checked is as follows:
Per bucket credentials in your CommandBox endpoint settings
Global credentials in your CommandBox endpoint settings
Environment variables
AWS credentials file
IAM role
ForgeBox allows you to publish packages that only you can see and install. You'll be able to view your private package from the CLI, in the ForgeBox.io search, and in your ForgeBox.io profile, but these packages will now show up for any other users.
To create a private package, set the private
property to true
in your box.json
prior to publishing.
Replace forgeBoxUser
with your actual ForgeBox username. When you install the package, you'll need to use the full slug like so:
You can install specific versions or version ranges as you would expect:
Private packages will be a paid feature for ForgeBox Pro subscribers, though the feature is currently available to all users for free.
Lucee Extensions
If you have external Lucee Extensions that need downloaded into your Lucee Server, you can use the lex:
endpoint to download them. The lex endpoint does not expect the download to be contained in a zip file or to have a box.json. As such, there is no real package slug or name, so CommandBox will "guess" the name based on the name of the lex based on the URL.
The Lex endpoint can also be used to install local lex files.
Please note that if a Lucee extension is already hosted on ForgeBox, you do not need the Lex extension, as you can simply use the ForgeBox slug just like you would any other page and get the same result but with the addition of semantic versioning.
Files from the lex:
endpoint will be placed in a folder named the same as the package by default unless you provide another folder for installation. If the current working directory is found to have a Lucee server in it, the lex file will instead be installed to the server context's deploy folder. Note the Lucee server will need to have been started at least once so CommandBox "knows" about it, but it need not be running at the time.
You can specify a lex as dependencies in your box.json
in this format.
This means you can run a box install
on a fresh project to pull down extensions needed for your app to run.
CommandBox can be extended by modules installed from external locations. When you install a CommandBox module, it will automatically be placed in the correct modules location (inside your CommandBox installation) regardless of where you run the install
command from.
Later, if you want to view, uninstall, update, or otherwise interact with these system modules, you can just use the standard package management commands, but add the --system
flag to them. Any time you add that flag, the current working directory will be ignored, and you'll be interacting with the core modules installed into CommandBox.
The package commands that accept a --system
flag are as follows:
package install
package uninstall
package outdated
package list
package update
package show
package set
package clear
You can define a struct in your box.json
called scripts
that correspond to the interception points in CommandBox. Any script defined there will be ran on during that interception point. This allows you to prescribe arbitrary commands on a package-by-package basis. You may wish to set your package location any time you bump
a package version or perform a !git push
on publish
. Below is an example of some scripts
in a box.json
.
Package scripts can be named after any valid interception point and can contain any valid command that you can run from the interactive shell.
Note: server-related package scripts can also be placed directly in the server.json
for a server. Read more here.
You can also create ad-hoc scripts with arbitrary names that contain a collection of often-run commands.
Call these scripts at any time with the run-script
command
Before any package script is run, CommandBox will look for another package script with the same name, but prefixed with pre
. After any package script is run, CommandBox will look for another package script with the same name, but prefixed with Post
. So if you have a package that contains 3 package scripts: foo
, preFoo
, and postFoo
, they will run in this order.
preFoo
foo
postFoo
This works for built-in package script names as well as as doc package scripts. It also works on any level. In the example above, if you created a 4th package script called prePreFoo
, it would run prior to preFoo
.
Any package script fired by an internal interception announcement in CommandBox will have access to any intercept data via environment variables in the shell. All intercept data will be prefixed with interceptData.
and will use "dot notation" for nested structs. You can see if the docs on what intercept data is available to each interception point.
For example, a preCommand
interception announcement receives a struct called commandInfo
with a key called commandString
which means your package script can access that via the following environment variable:
You can see this in action with this simple package script:
Or if you wanted to simply debug what is available to you, use the env show
command in your package script to dump out all environment variables to the console.
Here's another example that writes a file to the server home directory when a server starts, using an environment variable to dynamically obtain the proper path.
CommandBox can install a Github Gist from gist.github.com as a package.
Make sure the root of your Git repo has a box.json
inside of it so CommandBox can tell the version and name of the package. If there is no box.json
, the name of the Gist ID will be used as the package name.
To install a package from a Github Gist, you must pass the Gist ID from gist.github.com:
The Github username is optional.
You can target a specific commit
by adding a "commit-ish" after the Gist ID.
You can specify packages from folder endpoints as dependencies in your box.json
in this format. Remember, JSON requires that backslashes be escaped.
Entire Git repos that represent a package can be installed via the Git endpoint. This can be a public Git server like GitHub or Bitbucket, or a private Git repo behind your firewall.
Make sure the root of your Git repo has a box.json
inside of it so CommandBox can tell the version and name of the package. If there is no box.json
, the name of the repo will be used as the package name.
To install a package from a Git repo, use the URL like so:
You can target a specific branch
, tag
, or commit
by adding a "commit-ish" to the end of the URL.
If the repo you wish to install is located on Github.com, you can use this shortcut to specifying the package.
You can specify packages from folder endpoints as dependencies in your box.json
in this format. Remember, JSON requires that backslashes be escaped.
Git repos that allow anonymous pulls do not require any additional configuration for authentication. CommandBox's Git endpoint supports SSH authentication via public/private keys by using the git+ssh://
protocol.
Some Git endpoints (like private Github repos) need a user before the site name in the url string like below:
Info Note the git+ssh URL is a little different than a HTTP(S) URL. There is a colon (
:
) after the host instead of a forward slash (/
).
The git+ssh
endpoint will look for a private SSH key in your ~/.ssh
directory named id_rsa
, id_dsa
, or identity
. If you are using a multi-key setup with a ~/.ssh/config
file, it will be read, and the appropriate key will be used for the host. The matching public key needs to be registered in the Git server.
Info If you are deploying to a server and you have not previously logged into the Git server from the new machine you will need to make sure the Git server is added to your
known_hosts
file. The quickest way to do this is to usegit clone git@github.com/user/repo.git
from the terminal OR add the line from your local machine to the server.
If you receive an invalid private key exception (Error cloning git+ssh repository and com.jcraft.jsch.JSchException: Auth fail), check your version of SSH. OpenSSH (7.8 and newer) generates keys in the new OpenSSH format, which starts with -----BEGIN OPENSSH PRIVATE KEY-----. JGit does not support this key format. Generate your key in the classic format using the following:
You can authenticate to a Git repo over HTTP using a username/password combination or a personal access token. The format looks like this:
Github personal access tokens can be specified as either
or just the personal access token like
and they both appear to work the same. It appears that a private Github repo requires the “repo” scope selected for the personal access token.
GitLab seems to want a username, but it doesn’t seem to matter what the username is.
You can use environment variables from the CLI or in your box.json to protect sensitive information like passwords and keys.
We also support the NetRC file format. Just create a files in your user's home directory called ~/.netrc
or ~/_netrc
with the following format:
CommandBox will find this file, match the hostname to the Git repo being cloned, and use the username and password as specified.
We do not support any of these username/password options over HTTP as it just seems unwise. Please use HTTPS.
Some users of Circle-CI have reported the following error when trying to clone a Git repo over HTTPS.
It is changing the https github url to ssh in the call. You can remove the config setting like so:
ForgeBox is an online registry of packages run by Ortus Solutions. The web UI for ForgeBox is located at http://forgebox.io. Signing up for a ForgeBox account is quick, easy, and free. You will need your own account to post packages, but anyone can browse and install packages anonymously.
Every package on ForgeBox has a unique slug. To install a package, use the slug like so:
You can also specify the version of a package you want to install from Forgebox.
Given the install command above, if the file ~/.CommandBox/artifacts/coldbox/3.8.1/coldbox.zip
exists on your hard drive, the installation will not connect to Forgebox at all. It will be a completely offline installation. This only works when you type an exact version that includes a major, minor, and patch number.
You can specify packages from ForgeBox as dependencies in your box.json
in this format:
info The caret
^
means that theupdate
command will update minor releases but not major releases.
If the package being installed from ForgeBox is of type lucee-extensions
and if the current working directory is found to have a Lucee server in it, the lex file will instead be installed to the server context's deploy folder. Note the Lucee server will need to have been started at least once so CommandBox "knows" about it, but it need not be running at the time.
For companies who want to host internal code endpoints for private packages, we will soon support an Enterprise version of ForgeBox that can be installed behind your company's firewall. Please contact us if this feature interests you.
Inside CommandBox, use the forgebox namespace to search for packages or show packages of your choosing.
The first command to try out is "forgebox search". It takes a single parameter which is a string to perform a case-insensitive search for. Any entry whose title, summary or author name contains that text will be displayed:
The "forgebox show" command takes several parameters and is pretty flexible. The first way to use it is to just view the details of a single entry using the slug.
You can get lists of items filtered by package type (modules, interceptors, caching, etc) and ordered by popular, new, or recent. Here's some examples:
Too many results on one page? Use the built-in pagination options:
Or just pipe the output into the built-in "more" or "grep" command.
If you have troubles remembering the valid types or order by's, remember you can always hit "tab" for autocomplete within the interactive shell. Adding "help" to the end of any command will also show you the specific help for that command.
The list of types in ForgeBox is dynamic so we don't list them out in the help. Instead, we made a handy "forgebox types" command to pull the latest list of types for you.
If you have external jars that need downloaded into your project, you can use the jar:
endpoint to download them. The jar endpoint does not expect the jars to be contained in a zip file or to have a box.json. As such, there is no real package slug or name, so CommandBox will "guess" the name based on the name of the jar (if a jar name appears in the path or query string).
Files from the jar:
endpoint will be placed in a lib/
folder by default unless you provide another folder for installation.
You can specify jars as dependencies in your box.json
in this format.
Note this installation method does not include any dependencies of the jar like a Maven installation would. That will be a future endpoint.
The jar endpoint will make the following assumptions about what version of a jar a particular URL may point to:
It tries and parse a semantic version from the URL's path
It will store that version in the package's box.json (0.0.0
if not found)
It will use that version when checking for updates to the jar
This will be reflected in what you see in the package list and outdated commands.
So for example, if you install a jar dependency like so:
CommandBox will parse out the 1.24.0
from the path of the URL and will assume that as the version of the package. When checking for outdated dependencies, that version will be used to compare to the current URL in your box.json
which means an unchanged URL will know it is not out of date.
The main goal of semver is to create a common ground among developers and their projects for describing the status of their releases and help users get the versions they want. Semver describes how a proper version number can be formatted as well as a special syntax for describing ranges of versions. There are many ways to describe a version number and semver is just one of them. We chose semver for CommandBox due to its popularity and usage among other common tools like npm. In fact, we've copied the npm flavor or semver specifically which you can read about here.
If you only get one thing out of all this, at least understand the basic parts of a version. Everything but the major number is optional so remember a version can be as simple or complex as you like and there are rules for dealing with the missing pieces.
Let's digest that bit by bit:
major - This is the major version number of the software. Increase this number when making major changes or breaking compatibility with previous releases.
minor - This number gets incremented when you add new features and improvements to software that doesn't break compat. Resets to 0 on a major bump.
patch - This number gets incremented for small bug fixes. Resets to 0 on major and minor bumps.
prerReleaseID - The presence of this means the version is not stable. This string can be anything, but is typically "rc" for release candidate, "snapshot", "alpha", "beta", etc. You can have more than one prerelease with "beta.1", "beta.2", "beta.3", etc.
build - This is a number that usually comes from your build server and increments every time a commit is made that triggers a build. It can be used to track a very specific release, but should not be used for semver range comparisons. It's really just for information.
So let's take a look at some valid semantic versions.
When writing a package, we recommend using a full version number just to be as descriptive as possible. You may not wish to have a build number if you don't run an automated build. And of course, don't include a prereleaseID unless the package isn't stable. Set your package's version like so:
Ok, so far we've only talked about exact versions. Semantic versioning also gives a very powerful syntax for addressing a range of versions. This can be very useful when installing or updating if you don't care about the exact package version that you get, but you have a few parameters. One of the main ideas behind semver ranges is that you can quickly and easily upgrade 3rd party libraries to the latest version that still works with your code without breaking anything. Ranges would be used when installing a package with the install command
Or in your box.json to show what versions of a particular dependency you're willing to accept.
Let's look at the basic formats for version ranges.
Major, minor, and patch numbers can be replaced with an X (or omitted entirely) meaning you don't care what value you get.
You can use <, >, <=, and >= operators just like you would expect to request all versions above, below, or between other versions.
These are just a variation of greater/less than but easier to type. Hyphen ranges are inclusive of the start and end version.
Now we get a little interesting. These last two types of ranges are designed to allow you to keep updating a package version to get compatible versions, but stopping short of getting a breaking update on accident. You usually see these in a box.json file to control what happens when the update command is run. A tilde in front of the version will allow patch upgrades when a minor version is specified and will allow minor upgrades when only a major version is specified.
This is the default ranged used by CommandBox in your box.json when you install packages from ForgeBox which matches npm's default behavior. A caret allows changes that do not modify the left-most non-zero digit. In other words, this allows patch and minor updates for versions 1.0.0 and above, patch updates for versions 0.1.0, and no updates for versions 0.0.X. The reason for the left-most non-zero digit caveat is for authors who have a whole series of 0.x version releases before ever making it to a full major release. It allows us to essentially treat the minor version as the major version until a "real" major version exists.
And one final trick. You can string together any of the ranges we showed above with two pipe characters ( || ) and each range will be evaluated until a matching one is found.
If you want more reading or examples, check out the home page for semver as well as the docs for the npm semver library. You can also peruse the unit test suite I have for the CommandBox semver library here which tests every possible combination.
CommandBox automatically keeps a local copy of every package it downloads called an artifact. These are stored in the ~/.CommandBox/artifacts/
folder. The next time you install the same package, the file in your local artifacts cache will be used to prevent another download.
When installing a package, CommandBox will check its local artifacts first and use the zip file found there first. If nothing is found, the package will be downloaded from the ForgeBox download URL and then cached in the artifacts directory for next time.
Artifacts are organized by folders named after the package slug, and then folders inside named after the version. You can get a list of all your artifacts with the artifacts list
command.
You can clear individual artifacts by slug and version with the artifacts remove
command. Or just wipe all of them with artifacts clean
.
info The artifact cache is only used by the ForgeBox endpoint. It is the only remote endpoint capable of telling CommandBox what the latest version of a package is without downloading it again.
CommandBox will cache snapshot package versions in the artifacts cache, but it will still download them every time. A snapshot version is one that has a preReleaseID of snapshot
.
The reason we store it in the artifacts directory is because it might still get used if you attempt to do an offline install. CommandBox will check the artifacts folder as a last-ditch attempt if ForgeBox is down.
You can control where your artifact cache is stored with the artifactsDirectory
config setting. This can be useful to keep your primary drive from filling up, or to point your files to a shared network drive that your coworkers can share.
ForgeBox.io can be used as a general purpose community extension provider for Lucee 5 compatible extensions. All you need to do is publish your extensions to Forgebox just like you would with any other package, and then anyone who adds https://www.forgebox.io to their Lucee server as an extension provider will be able to see you extension and install any version of it that they choose. This allows anyone to share their extensions with the world without the need to create, host, and maintain their own publish extension provider.
In order to publish you extension (or any other package for that matter) to ForgeBox you just need three things
A forgebox account (use forgebox register
if you don’t have one)
A box.json with the correct metadata in your package.
Run the publish
command from that folder.
A new package will be created if it doesn’t exist, otherwise it will be updated. A new version will also be created if it doesn’t exist matching the version in your box.json
or it will be updated. Review our generic docs on how to creating and publishing packages here: https://ortus.gitbooks.io/commandbox-documentation/content/packages/creating_packages/creating_packages.html
In your box.json
, you’ll want to minimally have the following properties set:
The slug
property in your box.json
to be the unique GUID of your extension from your manifest file. Lucee's docs state this needs to be a UUID. It needs to match what’s in your manifest or updates won’t work.
The version
needs to be the current version of your package that you want to publish. To add a new version, you’ll just update the json and re-run the publish
command. One thing to watch out for is that Lucee likes to use the x.y.z.q
version format which does not quite match the npm-style x.y.z-prerelease+build
format of ForgeBox. I usually stick with just three digits x.y.z
so it’s compatible across the board.
You want the type
property in your json to be lucee-extensions
Set your publicly-acessable thumbnail URL in a thumbnail
property in the json
The actual download URL of the lex file needs to be set in the location
property in the json. Please note Lucee has some bugs where it doesn’t like servers that don’t set the right content type that it expects. Someone else I was helping had to rename it to a zip file on GitHub so get Lucee to accept it. (A lex file is just a zip file) Perhaps go give a vote on this ticket.
Fill out any other info like name
(human readable), author
, etc
The publish
command will pick up any readme.md
file in your current directory where you run the publish
command and will put it on ForgeBox as the description. This is very handy so make sure you have a good readme so your package home looks good. If you want to update it, simply edit the readme file and re-run the publish
command at any time.
Here is the box.json
file used for the Ortus Couchbase Extension.
Lucee extensions have additional metadata that can be provided in their manifest that an extension provider reports. These additional properties can be specified in your box.json
and the ForgeBox Lucee Extension provider will pick them up and report them. Please refer to the Lucee docs on what each of these do.
lucee-extension-category
lucee-extension-releasetype
lucee-extension-minloaderversion
lucee-extension-mincoreversion
lucee-extension-price
lucee-extension-currency
lucee-extension-disablefull
lucee-extension-trial
lucee-extension-promotionlevel
lucee-extension-promotiontext
Packages hosted on a website as a zip file can be installed by using the direct URL to the package. Both HTTP and HTTPS URLs are supported. If the URL returns a 301
or 302
redirect, it will be followed until the package is reached.
Make sure your package zip file has a box.json
inside of it so CommandBox can tell the version and name of the package. If there is no box.json
, the following rules will be decided to determine the name of the package:
If the URL has the zip file name in it, the name without ".zip" is used.
If the URL contains github.com
, the repo name will be used.
Otherwise, the entire URL will have non alpha-numeric characters removed and used.
To install a package from a website, use the full URL like so:
You can specify packages from HTTP(S) endpoints as dependencies in your box.json
in this format:
If you know a given URL will always return the exact same package, then you can request CommandBox to cache the download in local artifacts to speed up builds. To do so, use an endpoint name of https+cached
or http+cached
in your install ID.
Or
Cached artifacts will be stored under the slug HTTP_Cached
and can be viewed like so:
The Java endpoint is capable of downloading and installing any version of Java in the AdoptOpenJDK API. Use the java search
command to search the API to find what Java versions are available. The endpoint will use the local artifacts cache.
NOTE: If you simply want to start a server with a given version of OpenJDK, you don't need to use this endpoint directly, You can ask CommandBox to use a specific java version and it will handle the installation for you as well as re-using identical Java installs across servers. For example:
The installation ID consists of a series of identifiers separated by underscores that describe the Java version, type, JVM, etc that you want installed.
An example utilizing every option would be
However, everything is optional except the major version. These are also valid installation IDs
Here are the possible options for each section of the ID.
version - openjdk8, openjdk9, openjdk10, etc...
type - jdk, jre
arch - x64, x32, ppc64, s390x, ppc64le, aarch64, arm etc...
os - windows, linux, mac, solaris, alpine-linux (openjdk11+ only)
jvm-implementation - hotspot
release - latest, jdk8u172, jdk8u172-b00, etc...
For items not specified in the endpoint ID, the endpoint will default as follows:
type - jre
arch - Whatever the current OS arch is
os - Whatever the current OS is
JVM-implementation - hotspot
release - latest
When java is installed as a package endpoint, the name of the folder that it is installed into will mirror the ID you use. This means two different installation IDs that resolve to the exact same Java version may end up in different folders. We do this for a couple reasons. One of which is simplicity, the other is that if you have configuration expecting a specific folder name, Mac users and Windows users may get a different download, but if the id is simple java:openjdk8_jdk
, they would both install into a folder called openjdk8_jdk
.
This endpoint will NOT edit your registry, create any symlinks, or add environment variables. It will simply drop the Java installation into a folder so you can point servers at it. You are free to use one of these Java installations in such a manner, but we don't do this by default so you can install as many java versions as you like and they don't fight with each other.
The following box.json properties provide basic information about what your package is.
string
Name of the package. Short, but descriptive.
string
The unique slug for this package. Cannot contain spaces or special characters. Can contain a hyphen. Use the forgebox slugcheck
command to see if this slug is already in use. This is what people will use when installing your package from ForgeBox.
string
The semantic version of your package following the pattern major.minor.patch.build
. Ex: 2.3.5.0012
string
The name of the author of the module as a string.
string
Describes what this package is in a couple sentences. Save the dissertation for the description
.
boolean
A flag that designates if this package is a ForgeBox private package. ForgeBox private packages are not publicly accessible, but offer all the benefits of ForgeBox. Private packages will be a paid feature for ForgeBox Pro subscribers, though the feature is currently available to all users for free.
We've seen how any folder can be turned into a package with the init
command. Initial properties can be set as named parameters to the init
command.
The init
command can be called more than once on a package and it will keep existing properties and only overwrite the ones you specify.
Once you've created your box.json, you can edit the file directly, or there are other commands to help manage it programmatically.
Each of these commands support tab-complete that is dynamic based on what properties are currently in your box.json.
The package show
command can be used to out put any part of the box.json. You can specifiy any property name from your box.json.
Outputs package name and keywords
Nested attributes may be accessed by specifying dot-delimited names or using array notation. If the accessed property is a complex value, the JSON representation will be displayed
Outputs testbox runner(s)
Outputs the first testbox notify E-mail
Output the entire box.json
using JmesPath with package show
Any property in your box.json can be set from the command line with the package set
command.
Set package name
Nested attributes may be set by specifying dot-delimited names or using array notation. If the set value is JSON, it will be stored as a complex value in the box.json.
Set the repository type.
Set first testbox notify E-mail.
Set multiple params at once by passing as many named parameters as you like.
Set a complex value as JSON.
Objects and arrays can be appended to using the append
parameter. This only works if the property and incoming value are both of the same complex type.
Add an additional contributor to the existing contributors
array.
Add an additional dependency to the existing dependencies
object.
If you need to remove a property entirely from your box.json, use the package clear
command. It also works on nested properties using "dot" or array notation.
Remove the package description entirely.
These properties go a little farther in describing your package and what it is.
string
The full description of your package. Feel free to use line breaks, HTML, or football analogies.
string
Tell the user how to install and use your package.
string
A list of the changes this package has gone through.
array
List words that describe your package as an array of keywords.
array of objects
Let the world know what license your package is released under. This property is an array of objects where each object represents a single license. Your package can have more than once license.
The license object will have a type
and URL
key. Examples of license types are MIT, GPL, Apache 2.0, etc. A valid list of licenses might look like this:
array
Give a shout-out here to everyone who helped with your package. This is an array, and you can put strings it containing names and/or E-mail addresses, or you a objects to the array containing keys such as name
and email
.
There are a number of URLs associated with your package that you can specify with these properties.
string
The location of where to download this package. Needs to point to a zip file containing the package.
string
The homepage for your product. It's fine if this is just the GitHub page. A nice readme can make for a good homepage.
string
This is where users can go to find documentation on how to use your package. Can be a wiki, HTML docs, etc.
object
This describes the repository used for source control with this package. Object needs a type
and URL
key. Examples of type
would be Git, SVN, Mercurial, etc.
string
This is the URL where developers can go to report bugs in your package. We know you NEVER write bugs in your software, but it's just a formality so humor us :)
string
This is the URL you visit to browse to this actual project code once it is running.
These properties affect how the embedded server starts. These settings are now deprecated in favor of the new server.json file.
number
This is the HTTP port the server will be started on when you use the start
command. Specifying the port
parameter on the start
command will override this.
This setting is deprecated in favor of the port
property of server.json
. CommandBox will use this setting still if there is no port in server.json and a port argument is not specified with the start
command.
array of objects
This represents a list of CF engines your project supports and their version with a semvar range.
This data is informational only and not yet used by the embedded server
string
The default CF engine for the start
command to use.
This data is informational only and not yet used by the embedded server
object
This object stored configuration information used by the TestBox BDD and xUnit testing library. The data is accessed by commands in the testbox
command namespace.
string or array
testbox.runner
can be a simple string that contains the full runner URL.
testbox.runner
can alternatively be an array of objects containing "named" runner URLs.
Our box.json template shows other placeholder properties inside the testbox
object, but only runner
is implemented for now.
In the future, the testbox
object may be moved into a separate JSON file for organizational purposes.
Packages are quite simply a folder that contains some code and a box.json
file. A package can be a simple CFC, a self-contained library, or even an entire application. ColdBox and ContentBox modules also make great "smart" packages.
Remember, packages aren't just the things you install into your application, but your application is a package too! That's why when you install something in your app, we'll create a /box.json if it doesn't exist to start tracking your dependencies.
Your box.json
file describes your package, dependencies, and how to install it. To turn a boring folder into a sweet package just run the init
command in the root of the folder.
That's it. Your folder now has extra meta data in the box.json
file that describes it in a way that is meaningful to ForgeBox and CommandBox.
When making a package available on ForgeBox, each version of that package has its own location. Most download locations point to a zip file, that when extracted, contains a folder with a box.json in it. The box.json designates the root of the package. However, the location
property of your box.json can be any valid endpoint ID. An example would be:
In that case, the location
for version 1.0.0
of this package is the v1.0.0
tag in that GitHub repository.
ForgeBox can store the binaries for your packages in the ForgeBox Cloud. This provides you with an easy way to store multiple versions of your package distributed across the globe.
To utilize ForgeBox Storage, simply set forgeboxStorage
as the value of your package's location
.
When you publish a package, CommandBox will automatically zip up your package and send it to ForgeBox.
publish
CommandWhen you run the publish
command from the root of a package, the package will be created on ForgeBox. If the package already exists in ForgeBox, the new version will be added. If the version already exists, the package metadata will be updated.
Most of the data about a package exists in the box.json
such as name, slug, version, etc. There are also some files read from disk by convention. The publish
command looks by convention for the following files (case insensitive) when publishing
readme
- Maps to Package Description
instructions
- Maps to Installation Instructions
changelog
- Maps to Change Log
Every file is checked for .md
, .txt
, and no extension in that order.
Below is an example of the commands that would take you from scratch to a published package:
ForgeBox supports private packages. Private packages are only visible to the user who created it.
To create a private package, pass the private
flag to the package init
command.
One of the more important pieces of information for a package is the version. We encourage people to use semantic versioning for their packages. The spec for this can be read here:
The spec involves a lot of possible variations, but to simplify, the basics involve having a three-part version number.
And constructed with the following guidelines:
Breaking backward compatibility or major features bumps the major (and resets the minor and patch)
New additions without breaking backward compatibility bumps the minor (and resets the patch)
Bug fixes and misc changes bumps the patch
An example would be 1.0.0
When you initialize a folder as a package with the init
command, the version will be set to 0.0.0
by default. You can use init --wizard
to be asked what version you'd like to use, among other questions.
The version is stored in your package's box.json
and you can check it at any time by running
To override the version at any time, pass the new version into the package version
command like so:
As a handy shortcut, you can have CommandBox automatically bump the version for you after making changes to your package.
If you just fixed a small bug or UI change in your package, run this to bump the minor patch. For example, this would change 2.3.7
to be 2.3.8
.
Let's say you've added a few nice features or enhancements to your project but it's still backwards compatible with previous versions. Run this to bump the minor version. Note this will reset your patch version to 0
. For example, this would change 2.3.7
to be 2.4.0
.
Now, you really got busy over the weekend and made a major overhaul to your project-- specifically introducing some changes that introduce backwards compatibility. Now it's time to bump the major version. Note this will reset your minor and patch version to 0
. For example, this would change 2.3.7
to be 3.0.0
.
Info Each part of the version doesn't have to be one digit. For instance, 1.0.9 patch-bumps to 1.0.10 and doesn't ever "roll over".
In CommandBox, when you use the package version
command (aliased as bump
), if you are running the command in a Git repository and the working directory is clean, CommandBox will create a tag for you that's named after the version and commit it. You can supply a custom message if you like each time or set a global setting with your desired tag message.
If you do not want this feature, you can turn it off with a config setting flag.
object
This object tracks the other packages that are required to run the project. Packages are added here automatically by the install ID
command, but you can also manually add them and just type install
to install them.
The key is the unique slug of the package and the value is the a semvar range, local directory, URL to a zip, or a source control URL.
object
Development dependencies operate the same as regular ones, expect they are not required to use this project. Instead, they are only required if you plan to do development on the project. These usually including testing libraries, etc.
The install
command will save dependencies here when you use the --saveDev
flag. These packages will be skipped when you run install --production
The box.json
file must be in your root of your project and it is a JSON file that describes your project, dependencies, development dependencies, installation data, and CommandBox command data.
Note Please note that you can add as many settings or alter the
box.json
structure to meet your needs when developing commands. This makes our descriptor incredibly flexible.
To initialize any folder as a package, run the init
command.
You can pass as many properties to the init
command as you want using named parameters.
You can also do a question/answer style wizard by adding the --wizard
flag.
Below you will see all the possible options that we currently support in CommandBox. Note, not all have been implemented yet. If you have suggestions or updates to our package descriptor, please do not hesitate to Contact Us!
Dependencies are other packages that are required by another package for it to run. A simple package may have no dependencies, or it may have many. There are two types of dependencies: a regular dependency or a development dependency. Regular dependencies are ones required for operation of the main package. Development dependencies are optional and only necessary if you plan on making changes to the package you're installing. Dev dependencies would include testing frameworks or build tools.
When a package is installed, CommandBox will read its dependencies (from the box.json) and recursively install them as well. This encourages developers to write small, reusable libraries for everyone to use. When installing via a package manager, you don't have to worry about getting all the pieces installed.
Dependencies and development dependencies are stored in an object with the slug for the key and a version range for the value. The are several options available for these version ranges and more information can be found in the section on Semantic versioning.
When you install a dependency , it will be automatically added to your box.json. Use the --saveDev
flag to save a development dependency. Uninstalling a dependency will remove it from your box.json unless you set the save
parameter to false.
When you distribute a package for others to use, you should omit it dependencies. This will reduce the size of your repository and will prevent you from having to mess with the 3rd party code. As long as they are saved in your box.json, you're good.
When someone installs your package, CommandBox will automatically get the latest dependencies for them. If you're sharing an entire project that other people will download or clone from GitHub, they can simply run the install
command with no parameters.
This basically installs the root box.json as the current package, which means all dependencies that don't exist already will be installed. Now your project should be assembled and ready to run!
These properties affect how and where the package is installed.
string
The directory, relative to the web root, that the package will be installed to. This will override the convention directory based on the type
property. See package installation for more details on where packages install to.
string
The ForgeBox type of the package. See list of available types with the forgebox types
command. This can determine the directory the package is installed to. For instance, a type of modules
goes in the site's /modules
directory.
array
An array of file/folder globbing patterns that follow the .gitIgnore syntax to NOT be copied when doing a --production
install.
End a pattern with a slash to only match a directory. Start a pattern with a slash to start in the root.
foo
will match any file or folder in the directory tree
/foo
will only match a file or folder in the root
foo/
will only match a directory anywhere in the directory tree
/foo/
will only match a folder in the root
Use a single *
to match zero or more characters INSIDE a file or folder name (won't match a slash).
foo*
will match any file or folder starting with foo
foo*.txt
will match any file or folder starting with foo
and ending with .txt
*foo
will match any file or folder ending with foo
a/*/z
will match a/b/z
but not a/b/c/z
Use a double **
to match zero or more characters including slashes. This allows a pattern to span directories.
a/**/z
will match a/z
and a/b/z
and a/b/c/z
object
This is an object of string values where each key is the slug of an installed package and the value is the path the package is installed to. In most cases, this will be managed automatically by the install
and uninstall
command. If you want to override the directory
property on one of your dependencies, you can configured an install path prior to installing the package and it will be used.
Install paths can be a directory relative to the web root (no leading slash) or a full path starting with a drive root.
or
boolean
By default when a package is installed, a directory is created in the install path that is named after the package slug. Setting createPackageDirectory
to false
will skip the creation of that folder and dump the contents of the package right into the install path.
An example of this would be a full application that is the entire web root. Another example would be an interceptor that gets put directly in the interceptors
folder.
Note, when this is set to false
, no path will be added to the installpaths
directory and the package cannot be removed by the uninstall
command.
string
By default when a package is installed, a directory is created in the install path that is named after the package slug. If a packageDirectory
property is set, the folder is named after it instead of the slug.
An example would be the coldbox-be
slug that still needs to install into a folder called coldbox
. You shouldn't need to use this setting.
CommandBox does more than help you install packages. It also helps you keep them up to date as well. Remember, you can always get a quick list of all the dependencies installed your app with the list
command.
To check and see if any of your installed packages can be updated to a newer version, run the update
command.
Entering "yes" will install the newest version of the package. Use the --force flag to automatically answer "yes". It is also possible to get a list of outdated dependencies without the prompt to update them with the outdated
command.
The table of information in the outdated
and update
command has several different version numbers. This is what they mean:
Package - This contains the slug and semver range you've put in your box.json
file. i.e., what version you "asked" for.
Installed - This is the exact version installed right now in your project
Update - This is the newest possible version of the package that satisfies the semver range in your box.json
. Not there may be newer versions of the library not shown here depending on what your semver range is allowing. A red highlight in this columns means a new version is available.
Latest - This is the absolute latest stable version of this package regardless of your semver range. In order to update to this version, you may need to run the install
command again and ask specifically for it. An orange highlight in this column means a new major update is available.
Note, updating to a new major version of a library may contain breaking changes. This is why the default semver range is the caret (^) range which will prompt you with patch and minor updates, but NOT major updates. Those upgrades require manual intervention by default.
If you are using a ForgeBox package, the update
command will comply with the semantic versioning range you specify. For example, if you have a dependency installed with a version saved of ^2.0.0
it will update you all the way to 2.9.9
but it will never install 3.0.0
until you ask it to. This is because breaking changes come in major versions, but minor releases are supposed to be compatible.
The way CommandBox determines whether there is a new version of a package differs based on the endpoint that installed the package. Versions are always treated as a semantic version (Major.Minor.Patch).
ForgeBox - The ForgeBox REST API is used to get the latest package version.
HTTP(S) - Package is always considered outdated, and re-downloaded.
File - The box.json's version is used from the zip. If box.json doesn't exist, the package is always considered outdated.
Folder - The box.json's version is used from the folder. If box.json doesn't exist, the package is always considered outdated.
Git - Package is always considered outdated, and re-cloned.
If you want to integrate your package updates with an external process, you can get this data back as JSON so it can be parsed and used by another system.