Skip to content

Instantly share code, notes, and snippets.

@jbuncle
Last active October 23, 2020 09:14
Show Gist options
  • Save jbuncle/8e479343cfeb785046e3c6fe1a73dcce to your computer and use it in GitHub Desktop.
Save jbuncle/8e479343cfeb785046e3c6fe1a73dcce to your computer and use it in GitHub Desktop.
PHP Script to upload/push a composer project to a Nexus Repository Manager (that supports composer).

Composer Nexus Upload/Push

Quick Usage

php <(curl -s https://gist.githubusercontent.com/jbuncle/8e479343cfeb785046e3c6fe1a73dcce/raw/nexus-upload.php) \
         --repository=https://example.nexus.repo.com/repository/composer-repo/ \
         --username=publisher-user \
         --password=$NEXUS_PASS \
         --version=$CI_COMMIT_TAG

CLI Arguments

Argument Description
repository The nexus composer repository URL
username The nexus user name
password The nexus user password
version The composer version

Files exclusion

To exclude files from the uploaded zip#

"extra": {
        "nexus-upload": {
            "ignore": [
                "node_modules/",
                "*.css.map",
                "*.ts",
                "*.zip",
                "webpack.config.js",
                "*.json",
                "*.less"
            ]
        }
    }
#!/usr/bin/env php
<?php
/**
* PHP Script to upload/push a composer project to a Nexus Repository Manager (that supports composer).
*
*/
/**
*
* @param type $path
* @param type $ignoreList
* @return boolean
*/
function isIgnorebale($path, $ignoreList) {
foreach ($ignoreList as $pattern) {
if (preg_match($pattern, $path)) {
return true;
}
}
return false;
}
/**
*
* @param string $directory
* @param string $zipPath
* @param callable $fileFilter
*/
function zipDirectory($directory, $zipPath, $fileFilter) {
// Get real path for our folder
$rootRealPath = realpath($directory);
// Initialize archive object
$zipArchive = new ZipArchive();
$zipArchive->open($zipPath, ZipArchive::CREATE | ZipArchive::OVERWRITE);
/** @var SplFileInfo[] $files */
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($rootRealPath),
RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($files as $file) {
if ($file->isDir()) {
// Skip directories (they would be added automatically)
continue;
}
$realpath = $file->getRealPath();
$relativePath = substr($realpath, strlen($rootRealPath) + 1);
// Decide whether file should be included
if (\call_user_func($fileFilter, $relativePath)) {
$zipArchive->addFile($realpath, $relativePath);
}
}
$zipArchive->close();
}
function curlPutFile($url, $filename, $username, $password) {
$filestream = fopen($filename, "rb");
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 2);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1);
curl_setopt($ch, CURLOPT_USERPWD, $username . ":" . $password);
curl_setopt($ch, CURLOPT_PUT, 1);
curl_setopt($ch, CURLOPT_INFILE, $filestream);
curl_setopt($ch, CURLOPT_INFILESIZE, filesize($filename));
$result = curl_exec($ch);
curl_close($ch);
return $result !== false;
}
function getPackageName($projectUrl) {
return getComposerJson($projectUrl)['name'];
}
$projectDir = getcwd();
$packageName = getPackageName($projectDir);
/**
* Get composer JSON Object
* @staticvar array<stdClass> $composerJsons
* @param string $projectUrl
*
* @return array
*/
function getComposerJson($projectUrl) {
static $composerJsons;
if (!isset($composerJson)) {
$composerJsons = [];
}
if (!array_key_exists($projectUrl, $composerJsons)) {
$composerJsonPath = $projectUrl . '/composer.json';
$fileContents = file_get_contents($composerJsonPath);
$composerJson = \json_decode($fileContents, true);
$composerJsons[$projectUrl] = $composerJson;
}
return $composerJsons[$projectUrl];
}
function getComposerOption($projectUrl, $option) {
$json = getComposerJson($projectUrl);
if (!isset($json['extra'])) {
return null;
}
if (!isset($json['extra']['nexus-upload'])) {
return null;
}
if (!isset($json['extra']['nexus-upload'][$option])) {
return null;
}
return $json['extra']['nexus-upload'][$option];
}
/**
* Get option from CLI.
*
* @staticvar array $options
* @param array<string> $option
*
* @return string
*/
function getCliOption($option) {
static $options;
if (!isset($options)) {
// Followed by single colon = required
// Followed by double colon = optional
$options = getopt(
'',
[
'repository:',
'username:',
'password:',
'version:',
'ignore:',
]
);
}
if (array_key_exists($option, $options)) {
return $options[$option];
} else {
return null;
}
}
function getOption($projectUrl, $option) {
$cliOption = getCliOption($option);
if ($cliOption !== null) {
return $cliOption;
} else {
return getComposerOption($projectUrl, $option);
}
}
$nexusRepo = getOption($projectDir, 'repository');
$username = getOption($projectDir, 'username');
$password = getOption($projectDir, 'password');
$version = getOption($projectDir, 'version');
$ignore = getOption($projectDir, 'ignore');
$stdIgnore = "/^(\.git|vendor|composer\.lock|\.gitignore)/";
if (is_array($ignore)) {
$ignore[] = $stdIgnore;
} else {
$ignore = [
$stdIgnore, // Standard PHP ignores
$ignore
];
}
// Process
$ignoreList = array_map(function($value) {
if ($value === null) {
return false;
}
if (strpos($value, '/') !== 0) {
// Quote the string
$value = preg_quote($value);
// Escape slashes
$value = str_replace('/', '\/', $value);
// Allow * wildcards
$value = str_replace('\*', '.*', $value);
return '/^' . $value . '/';
} else {
return $value;
}
}, $ignore);
$ignoreList = array_filter($ignoreList);
echo "Running with:\n";
echo "\tRepository: $nexusRepo\n";
echo "\tUsername: $username\n";
echo "\tPassword: " . (!empty($password)) ? '(provided)' : 'missing' . "\n";
echo "\tVersion: $version\n";
echo "\tIgnore patterns: " . implode(', ', $ignoreList) . "\n";
echo "\n";
if (empty($version)) {
echo "Version is empty\n";
exit();
}
$zipFileName = getcwd() . DIRECTORY_SEPARATOR . str_replace('/', '-', $packageName) . '-' . $version . '.zip';
echo "Zipping '$projectDir' as '$zipFileName'\n";
zipDirectory($projectDir, $zipFileName, function($path) use ($ignoreList) {
if (isIgnorebale($path, $ignoreList)) {
return false;
}
echo "Adding '" . $path . "' \n";
return true;
});
echo "Created '$zipFileName'\n";
$url = $nexusRepo . "packages/upload/" . $packageName . '/' . $version;
echo "\n";
echo "Uploading '$zipFileName' to '$url'\n";
$success = curlPutFile($url, $zipFileName, $username, $password);
if (!$success) {
echo "Failed to upload zip to repository\n";
} else {
echo "Finished\n";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment