Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

This page is created to call an attention to this, and to discuss how you can migrate away from those deprecated methods.

How to modernize the code

To retrieve a list of projects from names, use Items.fromNameList(itemGroup, names, type).

To retrieve a project from a name use jenkins.getItem(relativeName, itemGroup, type). First parameter name may look confusing, but this method supports path names in general, including absolute names like "/foo/bar".

In all those both cases, the main question is to think what your contextual ItemGroup is, and where to get it from. Here are typical ways you do it:

...

From builds and projects

If you are in the context of a build, the project that owns that build is the right context: build.getProject().getParent()

...

From Descriptor

If you are writing AJAX method, form validation methods, and so on on your Descriptor, you can access the contextual ItemGroup by adding @AncestorInPath ItemGroup context to your parameter list.

(@AncestorInPath annotation refers to the nearest ancestor object of the given type in the URL that led to the call to your method, so for example you can instead do @AncestorInPath AbstractProject project)

From constructors of Describable

Most Describables (such as Builder or JobProperty) are long-running instances. Therefore it is not a good idea to resolve names to Item in your constructor. The job that the name refers to might get renamed, or might not be created/loaded yet.

Instead, keep the name as name, then attempt to resolve it later when you actually need it.

When there's no context

In some places, there really are no contextual ItemGroup. A good example of this is a CLI build command. In those cases, you should supply the root Jenkins object as the context, to make all relative path names resolve like absolute path names.

Oops, I've used '/' already

Some plugins have already used '/' as a separator between item name and something else. For example, copy-artifacts plugin had used '/' to separate the job name from extra information one can attach to it (see this)

In this case, you should choose a different delimiter (':' is a good delimiter. Any other characters that's not allowed in file system would do, too), then define a separate field to store the value that uses the new delimiter. For example,

No Format

class Foo {
    /*
     * this is where you used to store "foo/N"
     * @deprecated
     */
    private transient String data;

    // this is where you now store "foo:N"
    private String newData;

    protected Object readResolve() {
        if (data!=null && newData==null)
            newData = data.replace('/','#');
        return this;
    }
}

The readResolve method gets called when you are resurrected from the persisted state, so you do the data conversion there. In this way, you can change the delimiter without breaking existing configurations. See Hint on retaining backward compatibility for more details.

Examples

Here are some samples of changes done to support hierarchical projects: