This is my first post to this group so apologies if I'm not following the 
"usual process" for this request. 

I implemented a new custom (and very simple) trigger for the "email-ext" 
plugin and was wondering if it was possible to integrate this into the 
official plugin. The new trigger is named "Status Changed" and will send a 
message as soon as the status (not_built, successful, failure, unstable, 
aborted) of a job changes. The initial intent is to only notify status 
changes and avoid spamming developers when there are a lot of build 
failures (I know that ideally builds should be fixed quickly but ...). 

I attached the source for the new trigger and the associated unit test 
class. This successfully compiled against email-ext 2.34.

Note: Despite having an account to access the Wiki, I'm unable to log onto 
JIRA and couldn't find how to have my access "fixed" by an admin hence this 
post. If you could point me to a solution to access JIRA, I'd be grateful 
(I already reset my password 3-4 times without success).

-- 
You received this message because you are subscribed to the Google Groups 
"Jenkins Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.
package hudson.plugins.emailext.plugins.trigger;

import hudson.Extension;
import hudson.model.AbstractBuild;
import hudson.model.Result;
import hudson.model.TaskListener;
import hudson.plugins.emailext.plugins.EmailTrigger;
import hudson.plugins.emailext.plugins.EmailTriggerDescriptor;

import java.io.IOException;
import javax.servlet.ServletException;
import org.kohsuke.stapler.DataBoundConstructor;

import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;

public class StatusChangedTrigger extends EmailTrigger {

    public static final String TRIGGER_NAME = "Status Changed";

    @DataBoundConstructor
    public StatusChangedTrigger(boolean sendToList, boolean sendToDevs, boolean sendToRequestor, boolean sendToCulprits, String recipientList,
            String replyTo, String subject, String body, String attachmentsPattern, int attachBuildLog, String contentType) {

        super(sendToList, sendToDevs, sendToRequestor, sendToCulprits, recipientList, replyTo, subject, body, attachmentsPattern, attachBuildLog, contentType);
    }

    @Override
    public boolean trigger(AbstractBuild<?, ?> build, TaskListener listener) {
        final Result buildResult = build.getResult();

        if (buildResult != null) {
            final AbstractBuild<?, ?> prevBuild = build.getPreviousBuild();

            if (prevBuild == null) {
            	// Notify at the first status defined
            	return true;
            }

            return (build.getResult() != prevBuild.getResult());
        }

        return false;
    }

    @Extension
    public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();

    @Override
    public EmailTriggerDescriptor getDescriptor() {
        return DESCRIPTOR;
    }

    public static final class DescriptorImpl extends EmailTriggerDescriptor {

        public DescriptorImpl() {
            addTriggerNameToReplace(UnstableTrigger.TRIGGER_NAME);
        }

        @Override
        public String getDisplayName() {
            return TRIGGER_NAME;
        }

        @Override
        public void doHelp(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
            rsp.getWriter().println("An email will be sent when the build status changes");
        }

        @Override
        public boolean getDefaultSendToDevs() {
            return true;
        }

        @Override
        public boolean getDefaultSendToList() {
            return false;
        }
    }
}
package hudson.plugins.emailext.plugins.trigger;

import hudson.model.Result;
import hudson.plugins.emailext.plugins.EmailTrigger;

import java.io.IOException;

import org.junit.Test;

/**
 * Unit tests for the Calypso-specific "Status changed" trigger.
 *
 * @author francois_ritaly
 */
public class StatusChangedTriggerTest extends TriggerTestBase {

	@Override
	EmailTrigger newInstance() {
		return new StatusChangedTrigger(true, true, true, false, "", "", "", "", "", 0, "project");
	}

	// --- Transitions from <no-status> to <status> --- //

	@Test
	public void testTrigger_Success() throws IOException, InterruptedException {
		// Notification expected since this is the first build status defined
		assertTriggered(Result.SUCCESS);
	}

	@Test
	public void testTrigger_Aborted() throws IOException, InterruptedException {
		// Notification expected since this is the first build status defined
		assertTriggered(Result.ABORTED);
	}

	@Test
	public void testTrigger_Failure() throws IOException, InterruptedException {
		// Notification expected since this is the first build status defined
		assertTriggered(Result.FAILURE);
	}

	@Test
	public void testTrigger_NotBuilt() throws IOException, InterruptedException {
		// Notification expected since this is the first build status defined
		assertTriggered(Result.NOT_BUILT);
	}

	@Test
	public void testTrigger_Unstable() throws IOException, InterruptedException {
		// Notification expected since this is the first build status defined
		assertTriggered(Result.UNSTABLE);
	}

	// --- Transitions between 2 statuses --- //

	// There are 5 possible statuses (success, aborted, failure, not_built and unstable)
	// so we must test 5x5 = 25 transitions

	// Transitions from the "success" status

	@Test
	public void testTrigger_SuccessSuccess() throws IOException, InterruptedException {
		assertNotTriggered(Result.SUCCESS, Result.SUCCESS);
	}

	@Test
	public void testTrigger_SuccessAborted() throws IOException, InterruptedException {
		assertTriggered(Result.SUCCESS, Result.ABORTED);
	}

	@Test
	public void testTrigger_SuccessFailure() throws IOException, InterruptedException {
		assertTriggered(Result.SUCCESS, Result.FAILURE);
	}

	@Test
	public void testTrigger_SuccessNotBuilt() throws IOException, InterruptedException {
		assertTriggered(Result.SUCCESS, Result.NOT_BUILT);
	}

	@Test
	public void testTrigger_SuccessUnstable() throws IOException, InterruptedException {
		assertTriggered(Result.SUCCESS, Result.UNSTABLE);
	}

	// Transitions from the "aborted" status

	@Test
	public void testTrigger_AbortedSuccess() throws IOException, InterruptedException {
		assertTriggered(Result.ABORTED, Result.SUCCESS);
	}

	@Test
	public void testTrigger_AbortedAborted() throws IOException, InterruptedException {
		assertNotTriggered(Result.ABORTED, Result.ABORTED);
	}

	@Test
	public void testTrigger_AbortedFailure() throws IOException, InterruptedException {
		assertTriggered(Result.ABORTED, Result.FAILURE);
	}

	@Test
	public void testTrigger_AbortedNotBuilt() throws IOException, InterruptedException {
		assertTriggered(Result.ABORTED, Result.NOT_BUILT);
	}

	@Test
	public void testTrigger_AbortedUnstable() throws IOException, InterruptedException {
		assertTriggered(Result.ABORTED, Result.UNSTABLE);
	}

	// Transitions from the "failure" status

	@Test
	public void testTrigger_FailureSuccess() throws IOException, InterruptedException {
		assertTriggered(Result.FAILURE, Result.SUCCESS);
	}

	@Test
	public void testTrigger_FailureAborted() throws IOException, InterruptedException {
		assertTriggered(Result.FAILURE, Result.ABORTED);
	}

	@Test
	public void testTrigger_FailureFailure() throws IOException, InterruptedException {
		assertNotTriggered(Result.FAILURE, Result.FAILURE);
	}

	@Test
	public void testTrigger_FailureNotBuilt() throws IOException, InterruptedException {
		assertTriggered(Result.FAILURE, Result.NOT_BUILT);
	}

	@Test
	public void testTrigger_FailureUnstable() throws IOException, InterruptedException {
		assertTriggered(Result.FAILURE, Result.UNSTABLE);
	}

	// Transitions from the "not_built" status

	@Test
	public void testTrigger_NotBuiltSuccess() throws IOException, InterruptedException {
		assertTriggered(Result.NOT_BUILT, Result.SUCCESS);
	}

	@Test
	public void testTrigger_NotBuiltAborted() throws IOException, InterruptedException {
		assertTriggered(Result.NOT_BUILT, Result.ABORTED);
	}

	@Test
	public void testTrigger_NotBuiltFailure() throws IOException, InterruptedException {
		assertTriggered(Result.NOT_BUILT, Result.FAILURE);
	}

	@Test
	public void testTrigger_NotBuiltNotBuilt() throws IOException, InterruptedException {
		assertNotTriggered(Result.NOT_BUILT, Result.NOT_BUILT);
	}

	@Test
	public void testTrigger_NotBuiltUnstable() throws IOException, InterruptedException {
		assertTriggered(Result.NOT_BUILT, Result.UNSTABLE);
	}

	// Transitions from the "unstable" status

	@Test
	public void testTrigger_UnstableSuccess() throws IOException, InterruptedException {
		assertTriggered(Result.UNSTABLE, Result.SUCCESS);
	}

	@Test
	public void testTrigger_UnstableAborted() throws IOException, InterruptedException {
		assertTriggered(Result.UNSTABLE, Result.ABORTED);
	}

	@Test
	public void testTrigger_UnstableFailure() throws IOException, InterruptedException {
		assertTriggered(Result.UNSTABLE, Result.FAILURE);
	}

	@Test
	public void testTrigger_UnstableNotBuilt() throws IOException, InterruptedException {
		assertTriggered(Result.UNSTABLE, Result.NOT_BUILT);
	}

	@Test
	public void testTrigger_UnstableUnstable() throws IOException, InterruptedException {
		assertNotTriggered(Result.UNSTABLE, Result.UNSTABLE);
	}
}

Reply via email to