Greasemonkey

We deploy a lot of packages, so when we create a new release it often becomes a pain to click “Last” on each package individually, in case we need to deploy last (not latest) versions of them.

So I created a Greasemonkey script which selects all “Last” or all “Latest” radio buttons once you click on the “Last” or “Latest” column header in the table.

However, this doesn’t seem to work - perhaps something is not propagated in Angular. Can anyone take a look please? Hopefully I’m missing something small here!


// ==UserScript==
// @name Octomonkey
// @namespace https://octopus.example.com
// @version 0.1
// @description Bulk click on the radio buttons in Release Editor
// @grant none
// @include https://octopus.example.com/*
// @require http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
// ==/UserScript==
(function() {
‘use strict’;
function whenLoaded(selector, callback) {
var retry = function(repeats, callback) {
if($(selector).length > 0) {
callback();
return;
}

        var maxRepeats = 5;
        console.log('[Octomonkey] selector not found: ' + selector);
        if (repeats < maxRepeats) {
            repeats++;
            setTimeout(function() { retry(repeats, callback); }, 500);
        }
    }

    $(document).ready(function() {
        retry(0, callback);
    });
}

// 1. Release editor:
//      when "Last" clicked select all last packages
//      when "Latest" clicked select all latest packages
whenLoaded("release-editor", function() {
    $('abbr').on('click', function() {
        var versionType = $(this).text().toLowerCase();
        
        //uncheck all and check only the version type ones
        $(":radio[ng-model='pack.VersionType']").prop('checked', false);
        var items = $(":radio[value=" + versionType + "]");
        items.prop('checked', true);
        
        //update ng model
        for (var i = 0; i < items.length; i++) {
            var itemScope = angular.element(items[i]).scope();
            var newVersion = (versionType === "last") ? itemScope.pack.LastReleaseVersion : itemScope.pack.LatestReleaseVersion; 
            itemScope.packageVersionChanged(itemScope.pack, newVersion);
        }
    });
});

})();

Thanks for your email.

I’m currently Out of Office with limited access to emails, and will be back on Monday, January 2.

In my absence please contact Sergey Stoyan sergey.stoyan@massive.co

Thanks,
Andrew

Hi Andrew,

I’ve tested your script in Chrome (with the Tampermonkey extension) and it seems to work correctly for me without modification (I did see that there was a missing ; on line 26 but it worked without it anyway), when I click the Last header it selects all the packages in the Last column and if I click the Latest header it selects all the packages in the Latest column.

Could you let me know what browser you are using?

Thanks,
Henrik

Hi Henrik,

Yeah the radio buttons do get selected - but the changes are not propagated to the release.

Ie, by default “Latest” items are selected. Then I click on the “Last” column header and Greasemonkey selects “Last” items for all packages. But when I click “Create Release” I see that Octopus picked up “latest” packages to deploy, not the “last” ones.

I think it’s not enough to select radio buttons on the UI, the script needs to update Angular models - which is why I added “//update ng model” code. But looks like it’s not enough.

If some UI developer from Octopus team could advise that would be great!

Hi,

On line 44, you need to add .trigger('click') and that should resolve the issue for you (you should also be able to get rid of lines 46-51 after making that change).

Thanks,
Henrik

Henrik - thanks, works like a blast now!

One more thing, the script seems to break Dashboard with the following:

TypeError: domElement.popover is not a function
    at HTMLSpanElement.<anonymous> (https://octopus.massivision.com/octopus.min.js?v=3.5.1:165:27217)
    at Function.each (eval at <anonymous> (:2:297), <anonymous>:8:5257)
    at init.each (eval at <anonymous> (:2:297), <anonymous>:8:2013)
    at Object.bindPopovers (https://octopus.massivision.com/octopus.min.js?v=3.5.1:165:27167)
    at fullRender (https://octopus.massivision.com/octopus.min.js?v=3.5.1:155:18606)
    at Octopus.ReleaseMatrix.matrix.render (https://octopus.massivision.com/octopus.min.js?v=3.5.1:155:18371)
    at https://octopus.massivision.com/octopus.min.js?v=3.5.1:155:17096
    at Function._.each._.forEach (https://octopus.massivision.com/octopus.min.js?v=3.5.1:95:5280)
    at renderDashboard (https://octopus.massivision.com/octopus.min.js?v=3.5.1:155:16189)
    at fullRender (https://octopus.massivision.com/octopus.min.js?v=3.5.1:155:11276)

Is it something I could fix in the script to prevent the problem?

Hi,

If you update the @include URL to have /*/projects/*/releases/create instead of just *, the script will only run on the release creation screen.

I’ve created this UserVoice ticket to provide first class support for your scenario and see what the community thinks about it, as we don’t generally recommend writing these types of scripts as it may (as you’ve seen) interfere with other parts of the app.

Thanks,
Henrik

Thanks for the uservoice ticket!

Speaking of @include, it doesn’t seem to work for me - possibly because Tampermonkey doesn’t understand urls with hashes as per https://forum.tampermonkey.net/viewtopic.php?t=822

(ie. if I put @include https://our.octopus/*/projects/*/releases/create the script doesn’t show up on the Create Release page at all)

Hi,

I tested this in Tampermonkey on Chrome before suggesting it to you and it worked fine for me so I’m not sure why it doesn’t work for you sorry.

Thank you,
Henrik