Jenkins execute shell on job's executor during CONFIGURATION time (and access workspace)

1k Views Asked by At

I would like to create a simple Jenkins plugin.

Basically it is a custom build step (Builder extension) with a dropdown list. The trick is that I want to fill this dropdown list from the result of a shell script/command executed during configuration time.

Here is my method stub.

    public ListBoxModel doFill...Items(@AncestorInPath AbstractProject project) {
        // determine workspace
        // project.getSomeWorkspace() or project.getSomeWorkspace().getRemote()
        ...
        // invoke some shell commands
        String[] results = ...

        ListBoxModel items = new ListBoxModel();
        for (String item : results) {
            items.add(item);
        }
        return items;
    }    

My questions are the following:

  1. If there are slaves too, does Jenkins maintain 2 workspaces (so the freshest source code will exist both locations?
    My understanding is that (after the first build) there are always two workspaces: on the master there are meta informations (and source code too?), on the slave there are the source code and the build intermediates, information, artifacts. (unless we extract artifacts or use the copy-to-slave-plugin)

  2. Where will be the workspace what I get with the project.getSomeWorkspace() or project.getSomeWorkspace().getRemote()? (master/slave?)

  3. How can I invoke a shell command on the machine that WILL execute the build? Or at least is there a way to choose the master / one of the slaves particularly? (Suppose that I already configured a label on which group of machines I want to run the job.)
    I don't have access to AbstractBuild, BuildListener and Launcher (since they don't exist yet...)

  4. How can I find out which properties can I get with @AncestorInPath.
    I understand that this is a shorthand, an injection from the StaplerRequest invoked by Jenkins? How can I see the request?

It is important where the execution of the shell command takes place, even if there are two identical workspaces on master and slave. In my case there may be a Windows master (in the future) and an OSX slave. I do need the OSX to run my commands. (Currently there is only a master on OSX.)

EDIT:

Here is an example, part of what I am trying to do. I created a simple Xcode project in Swift (JenkinsSwift). In terminal from the project's directory I can issue the following command: xcodebuild -project JenkinsSwift.xcodeproj -list

And get the following response:

Targets:
    JenkinsSwift
    JenkinsSwiftTests

Build Configurations:
    Debug
    Release

If no build configuration is specified and -scheme is not passed then "Release" is used.

Schemes:
    JenkinsSwift

During configuration time I want to navigate to the project workspace on an OS X machine I want to issue the previous command. This way I could parse this response and allow the users to choose a Target / Configuration / Scheme during configuration. (Of course this can be done manually from with bash scripts, but I wanted to make it easier.)

1

There are 1 best solutions below

1
On BEST ANSWER
  1. This works differently, there is no workspace for a job by default. One is allocated as soon as build is run on the build machine (be it master or a slave). There can be any number of workspaces for a given job based on where and how many times the job run. Though, there is no guarantee there will be some on master. Do not confuse terms workspace (living on build machine) and build result directory on master.
  2. Project#getSomeWorkspace(), gives you a workspace used by some past build. Note, this is done on purely best effort bases as there might be none.
  3. There is no way to know where the build will run at the configuration time unless you tie the job to one particular machine. See hudson.model.Node#createLauncher(TaskListener) on how to run processes in Jenkins grid.
  4. @AncestorInPath allows you to inject some of the domain object that ware traversed by stapler during URL binding. You should not try to inject anything that might not be part of the url. There is no way known to me for you to inject the request, stapler uses the one that initiated the action method invocation.

The bottom line is that what you try sounds highly unusual. Perhaps there is an easier way to solve your original problem.