Joomla extension package is a combination of core, sub-extension, libraries, layouts, core folder, etc.
Many of Techjoomla’s extensions are shipped with other Techjoomla extensions and infrastructure extensions. For eg:-JTicketing is shipped with JLike along with TJ Vendor, TJ Notifications and TJ Reports. Let's assume that each extension code is maintained in separate GitHub repositories.
Now, when it comes to package building it's a tedious task to remember the branch name of each extension, acquire the latest code from different repositories and then build the package manually.
No more worries as we have written a script which will make your life easier.
Here are some prerequisites you need to know before creating the package.
Let’s look at the example of Techjoomla JGive(It’s our own crowdfunding extension) package.
JGive package contains
Here libraries, plugins, and sub extensions have their own GitHub repository.
Create package.json file, this file will tell the script source of extension, libraries, plugins, etc and destination in the package.
Path: your_github_repo/build/package.json
{ "package_name": "name_of_the_package", "core_files": { "src": "source of the package core files", "dest": "builds/(No change here)" }, "subextensions": [ // List of subextensons: Components, libraries, plugins etc. { "name": "Github repository name", "repoUrl": "Github repository clone url", "src": "Source code folder path", "dest": "builds/destination folder path", "zip_name": "optional: if sub extension needs to be compressed", "format": "zip/folder ('zip': if file to be compressed otherwise use 'folder')" "include/exclude":[ "Folder to include/exclude" ] } ], "versions": { "1.0.0 (Package version number)": { "Github repository name(must be exactly same used above in subextensions)": { "version": "Github Tag", "branch": "Github branch name" } } } }
package_name: Name of the package
core_files: The core files. E.g layout, modules that are maintained in the same repository of the core component.
sub extensions: List of extensions contained in the package.
versions: This gives us the flexibility to build the package for any version. Version object should have version property for each version and extension branch.
E.g
{ "package_name": "pkg_jgive", "core_files": { "src": "./jgive/src/*", "dest": "builds/" }, "subextensions": [ { "name": "jgive", "repoUrl": "[email protected]:techjoomla/jgive.git", "src": "./jgive/src/com_jgive/*", "dest": "builds/com_jgive", "zip_name": "com_jgive", "format": "zip" }, { "name": "plg_tjassetsloader", "repoUrl": "[email protected]:techjoomla/plg_tjassetsloader.git", "src": "./plg_tjassetsloader/src/*", "dest": "builds/plugins/system/tjassetsloader", "format": "folder" }, { "name": "joomla-payments", "repoUrl": "[email protected]:techjoomla/joomla-payments.git", "src": "joomla-payments/code/plugins/", "dest": "builds/plugins/payment/", "format": "folder", "include": [ "2checkout", "alphauserpoints", "authorizenet", "bycheck", "byorder", "jomsocialpoints", "paypal" ] }, { "name": "com_activitystream", "repoUrl": "[email protected]:techjoomla/com_activitystream.git", "src": "./com_activitystream/src/*", "dest": "builds/packages/com_activitystream", "zip_name": "com_activitystream", "format": "zip" } ], "versions": { "2.3.0": { "jgive": { "branch": "release-2.3.0" }, "plg_tjassetsloader": { "branch": "master" }, "joomla-payments": { "branch": "release-1.0" }, "com_activitystream": { "branch": “release-3.0" } } }
Create a package.groovy file, just update the version value whichever you want to build and paste the code as it is.
path: your_github_repo/build/pipelines/package.groovy
//!/usr/bin/env groovy // Get / Set release name def version = '2.3.0' echo version pipeline { agent any stages { stage('Cleanup') { steps { script { // Cleanup previous stuff sh("rm -rf scm") sh("rm -rf builds") // Cleanup jlike git folder, files sh("rm -rf .git") sh("rm -rf .gitlab/merge_request_templates") sh("rm -rf build") // Make directories needed to generate build sh("mkdir builds") sh("mkdir scm") } } } stage('Checkout') { steps { script { // This is important, we need clone into different folder here, // Because, as part of tag based pull, we will be cloning same repo again dir('scm') { checkout scm } } } } stage('Cleanup-repos') { steps { script { def props = readJSON file: 'scm/build/package.json' props['subextensions'].eachWithIndex { item, index -> // cleaup subextensions sh("rm -rf $item.name") } } } } stage('Init') { steps { script { def props = readJSON file: 'scm/build/package.json' // Do clone all subextensions repos by checking out corresponding release branch props['subextensions'].eachWithIndex { item, index -> sh("git clone --branch " + props['versions'][version][item.name]["branch"] + " --depth 1 $item.repoUrl") } } } } stage('Copy files & Make zip of subextension') { steps { script { def props = readJSON file: 'scm/build/package.json' // Copy core files sh("cp -r " + props["core_files"].src + " " + props['core_files'].dest) // Copy Make the zips props['subextensions'].eachWithIndex { item, index -> sh("mkdir -p " + item.dest) if (item.include && item.exclude) { error "Use either include or exclude. Both together not supported!." } def simple_copy = 0 if (item.include) { def count = item.include.size() if (count > 0) { def include = item.include.collect { "$item.src/$it" }.join(' ') sh("cp -r $include $item.dest") } else { simple_copy = 1 } } else if(item.exclude) { def count = item.exclude.size() if (count > 0) { def exclude = item.exclude.collect { "--exclude $it" }.join(' ') sh("rsync -avz $exclude $item.src $item.dest") } else { simple_copy = 1 } } else { simple_copy = 1 } if (simple_copy == 1) { sh("cp -r $item.src $item.dest") } // Create subextension zip and remove folder which is not needed after zip if (item.format == "zip") { sh("cd $item.dest && zip -rq ../$item.zip_name" + ".zip .") sh("rm -rf $item.dest") } } } } } stage('Build Package') { steps { script { // // Get commit id // // @TODO - needs to define shortGitCommit at global level def gitCommit = '' def shortGitCommit = '' def props = readJSON file: 'scm/build/package.json' // // For branch based build - we need the revision number of tag checked out, // Custom DIR dir('scm') { gitCommit = sh(returnStdout: true, script: 'git rev-parse HEAD').trim().take(8) shortGitCommit = gitCommit[0..7] echo gitCommit echo shortGitCommit } // Now we are good to create zip for component sh('cd builds && zip -rq ../' + props['package_name'] + '_v' + version + "_" + shortGitCommit + '.zip .') archiveArtifacts props['package_name'] + '_v' + version + "_" + shortGitCommit + '.zip' } } } stage('Cleanup folders') { steps { script { // Cleanup, so next time we get fresh files sh("rm -r builds") } } } } }
Setup the Jenkins job to run the pipeline script, set the script path as build/pipelines/package.groovy, run the job and your package will be ready within a couple of minutes:-).
Do let us know if you are using anything cool to build the package.
When you subscribe to the blog, we will send you an e-mail when there are new updates on the site so you wouldn't miss them.