Это будет совет / обходной путь
https://<<yourjenkinsdomain>>/job/<<yourjobname>>/configure (will open the configuration of your job)
Однако
https://<<yourjenkinsdomain>>/job/<<yourjobname>>/config.xml (will give the job configuration in an xml format)
Вы можете скачать этот xml через curl во время выполнения или с помощью jenkins cli и использовать grep с опцией -B найти описание по значению.
Учитывая, что вы скопировали с именем "config.xml"
cat config.xml | grep -B 1 "description"
Дадим вам описание и имя параметра сборки
Grep command
-B NUM, --before-context=NUM
Print NUM lines of leading context before matching lines.
Places a line containing a group separator (--) between
contiguous groups of matches. With the -o or --only-matching
option, this has no effect and a warning is given.
Пример вывода:
cat config.xml | grep -B 1 "description"
<actions/>
<description>Job description : Automation </description>
--
<name>branch</name>
<description>mandatory parameter , used for automation</description>
-
Альтернатива:
jenkins cli имеет опцию для установки значения
set-build-description Sets the description of a build.
set-build-parameter Update/set the build parameter of the current build in progress. [deprecated]
, вы можете написать небольшой скрипт и получить значения в переменные и использовать их
Престижность за проверку параметра метода, Вы дали мне новую идею для наших быстрых API. Я ненавидел наши проверки предварительного условия так или иначе...
Я создал систему расширяемости для нового продукта в разработке, где можно бегло описать доступные команды, элементы пользовательского интерфейса и т.д. Это работает сверху StructureMap и FluentNHibernate, которые являются хорошими API также.
MenuBarController mb;
// ...
mb.Add(Resources.FileMenu, x =>
{
x.Executes(CommandNames.File);
x.Menu
.AddButton(Resources.FileNewCommandImage, Resources.FileNew, Resources.FileNewTip, y => y.Executes(CommandNames.FileNew))
.AddButton(null, Resources.FileOpen, Resources.FileOpenTip, y =>
{
y.Executes(CommandNames.FileOpen);
y.Menu
.AddButton(Resources.FileOpenFileCommandImage, Resources.OpenFromFile, Resources.OpenFromFileTop, z => z.Executes(CommandNames.FileOpenFile))
.AddButton(Resources.FileOpenRecordCommandImage, Resources.OpenRecord, Resources.OpenRecordTip, z => z.Executes(CommandNames.FileOpenRecord));
})
.AddSeperator()
.AddButton(null, Resources.FileClose, Resources.FileCloseTip, y => y.Executes(CommandNames.FileClose))
.AddSeperator();
// ...
});
И можно настроить все команды, доступные как это:
Command(CommandNames.File)
.Is<DummyCommand>()
.AlwaysEnabled();
Command(CommandNames.FileNew)
.Bind(Shortcut.CtrlN)
.Is<FileNewCommand>()
.Enable(WorkspaceStatusProviderNames.DocumentFactoryRegistered);
Command(CommandNames.FileSave)
.Bind(Shortcut.CtrlS)
.Enable(WorkspaceStatusProviderNames.DocumentOpen)
.Is<FileSaveCommand>();
Command(CommandNames.FileSaveAs)
.Bind(Shortcut.CtrlShiftS)
.Enable(WorkspaceStatusProviderNames.DocumentOpen)
.Is<FileSaveAsCommand>();
Command(CommandNames.FileOpen)
.Is<FileOpenCommand>()
.Enable(WorkspaceStatusProviderNames.DocumentFactoryRegistered);
Command(CommandNames.FileOpenFile)
.Bind(Shortcut.CtrlO)
.Is<FileOpenFileCommand>()
.Enable(WorkspaceStatusProviderNames.DocumentFactoryRegistered);
Command(CommandNames.FileOpenRecord)
.Bind(Shortcut.CtrlShiftO)
.Is<FileOpenRecordCommand>()
.Enable(WorkspaceStatusProviderNames.DocumentFactoryRegistered);
Наше представление настраивает их средства управления для стандартных команд меню редактирования с помощью сервиса, данного им рабочей областью, где они просто говорят этому наблюдать их:
Workspace
.Observe(control1)
.Observe(control2)
Если пользовательские вкладки к средствам управления, рабочая область автоматически получает соответствующий адаптер для управления и обеспечивает операции буфера обмена и отмена/восстановление.
Это помогло нам уменьшить код установки существенно и делает это еще более читаемым.
Я забыл говорить о библиотеке, которой мы пользуемся в наших предъявителях модели WinForms MVP для проверки представлений: FluentValidation. Действительно легкий, действительно тестируемый, действительно хороший!
Это - на самом деле первый раз, когда я услышал термин "быстрый интерфейс". Но двумя примерами, которые приходят на ум, является LINQ и неизменные наборы.
Под покрытиями LINQ является рядом методов, большинство которых является дополнительными методами, которые берут по крайней мере один IEnumerable и возвращают другой IEnumerable. Это позволяет, чтобы очень мощный метод объединил в цепочку
var query = someCollection.Where(x => !x.IsBad).Select(x => x.Property1);
Неизменные типы и более конкретно наборы имеют очень похожий шаблон. Неизменные Наборы возвращают новый набор для того, что обычно было бы операцией видоизменения. Так создание набора часто превращается в серию цепочечных вызовов метода.
var array = ImmutableCollection<int>.Empty.Add(42).Add(13).Add(12);
Я люблю быстрый интерфейс в CuttingEdge. Условия.
От их образца:
// Check all preconditions:
id.Requires("id")
.IsNotNull() // throws ArgumentNullException on failure
.IsInRange(1, 999) // ArgumentOutOfRangeException on failure
.IsNotEqualTo(128); // throws ArgumentException on failure
Я нашел, что это намного легче считать и делает меня намного более эффективным при проверке моих предварительных условий (и условия сообщения) в методах чем тогда, когда я имею 50 если операторы для обработки тех же проверок.
Вот тот, который я сделал только вчера. Дальнейшее размышление может привести меня изменять подход, но даже если так, "быстрый" подход позволил мне выполнить что-то, что я иначе не мог бы иметь.
Во-первых, некоторый фон. Я недавно изучил (здесь на StackOverflow) способ передать значение методу, таким образом, что метод сможет определить и имя и значение. Например, одно общее использование для проверки параметра. Например:
public void SomeMethod(Invoice lastMonthsInvoice)
{
Helper.MustNotBeNull( ()=> lastMonthsInvoice);
}
Примечание там не является никакой строкой, содержащей "lastMonthsInvoice", который хорош, потому что строки сосут для рефакторинга. Однако в сообщении об ошибке может быть сказано, что что-то как "Параметр 'lastMonthsInvoice' не должно быть пустым". Вот сообщение, которое объясняет, почему это работает и указывает на сообщение в блоге парня.
Но это - просто фон. Я использую то же понятие, но по-другому. Я пишу некоторые модульные тесты, и я хочу разгрузить определенные значения свойств в консоль, таким образом, они обнаруживаются в выводе модульного теста. Я устал от записи этого:
Console.WriteLine("The property 'lastMonthsInvoice' has the value: " + lastMonthsInvoice.ToString());
... потому что я должен назвать свойство как строку и затем обратиться к нему. Таким образом, я сделал его, где я мог ввести это:
ConsoleHelper.WriteProperty( ()=> lastMonthsInvoice );
И получите этот вывод:
Property [lastMonthsInvoice] is: <whatever ToString from Invoice
производит>
Теперь, вот то, где быстрый подход позволил мне делать что-то, что я иначе не мог сделать.
Я хотел сделать ConsoleHelper. WriteProperty берут массив параметров, таким образом, он мог вывести много таких значений свойств к консоли. Чтобы сделать это, его подпись была бы похожа на это:
public static void WriteProperty<T>(params Expression<Func<T>>[] expr)
Таким образом, я мог сделать это:
ConsoleHelper.WriteProperty( ()=> lastMonthsInvoice, ()=> firstName, ()=> lastName );
Однако это не работает из-за вывода типа. Другими словами, все эти выражения не возвращают тот же тип. lastMonthsInvoice является Счет. firstName и lastName являются строками. Они не могут привыкнуть в том же вызове к WriteProperty, потому что T не является тем же через всех них.
Это - то, где быстрый подход пришел на помощь. Я сделал WriteProperty (), возвращают что-то. Тип, который это возвратило, является чем-то, на чем я могу звонить И (). Это дает мне этот синтаксис:
ConsoleHelper.WriteProperty( ()=> lastMonthsInvoice)
.And( ()=> firstName)
.And( ()=> lastName);
Это - случай, где быстрый подход позволил что-то, что иначе не будет возможно (или по крайней мере не удобно).
Вот полное внедрение. Как я сказал, я вчера записал это. Вы будете, вероятно, видеть простор для совершенствования или возможно еще лучшие подходы. Я приветствую это.
public static class ConsoleHelper
{
// code where idea came from ...
//public static void IsNotNull<T>(Expression<Func<T>> expr)
//{
// // expression value != default of T
// if (!expr.Compile()().Equals(default(T)))
// return;
// var param = (MemberExpression)expr.Body;
// throw new ArgumentNullException(param.Member.Name);
//}
public static PropertyWriter WriteProperty<T>(Expression<Func<T>> expr)
{
var param = (MemberExpression)expr.Body;
Console.WriteLine("Property [" + param.Member.Name + "] = " + expr.Compile()());
return null;
}
public static PropertyWriter And<T>(this PropertyWriter ignored, Expression<Func<T>> expr)
{
ConsoleHelper.WriteProperty(expr);
return null;
}
public static void Blank(this PropertyWriter ignored)
{
Console.WriteLine();
}
}
public class PropertyWriter
{
/// <summary>
/// It is not even possible to instantiate this class. It exists solely for hanging extension methods off.
/// </summary>
private PropertyWriter() { }
}
В дополнение к тем указанным здесь, платформа насмешки модульного теста popuplar RhinoMocks использует быстрый синтаксис для определения ожиданий по фиктивным объектам:
// Expect mock.FooBar method to be called with any paramter and have it invoke some method
Expect.Call(() => mock.FooBar(null))
.IgnoreArguments()
.WhenCalled(someCallbackHere);
// Tell mock.Baz property to return 5:
SetupResult.For(mock.Baz).Return(5);
SubSonic 2.1 имеет достойный для запроса API:
DB.Select()
.From<User>()
.Where(User.UserIdColumn).IsEqualTo(1)
.ExecuteSingle<User>();
tweetsharp делает широкое применение быстрого API также:
var twitter = FluentTwitter.CreateRequest()
.Configuration.CacheUntil(2.Minutes().FromNow())
.Statuses().OnPublicTimeline().AsJson();
И Быстрый NHibernate является всем гневом в последнее время:
public class CatMap : ClassMap<Cat>
{
public CatMap()
{
Id(x => x.Id);
Map(x => x.Name)
.WithLengthOf(16)
.Not.Nullable();
Map(x => x.Sex);
References(x => x.Mate);
HasMany(x => x.Kittens);
}
}
Ninject использует их также, но я не мог найти пример быстро.
Именование метода
Быстрые интерфейсы предоставляют себя удобочитаемости, пока имена методов выбраны разумно.
Имея это в виду, я хотел бы назначить этот конкретный API "антибыстрым":
Система. Ввести. IsInstanceOfType
Это - член System.Type
и берет объект и возвращает true, если объект является экземпляром типа. К сожалению, Вы естественно склонны читать его слева направо как это:
o.IsInstanceOfType(t); // wrong
Когда это - на самом деле другой путь:
t.IsInstanceOfType(o); // right, but counter-intuitive
Но не все методы мог возможно быть назван (или расположен в BCL) ожидать, как они могли бы появиться в "псевдоанглийском" коде, таким образом, это не действительно критика. Я просто указываю на другой аспект быстрых интерфейсов - выбор имен методов для порождения наименьшего количества удивления.
Объектные инициализаторы
Со многими примерами, данными здесь, единственная причина, быстрый интерфейс используется, состоит в том так, чтобы несколько свойств недавно выделенного объекта могли быть инициализированы в отдельном выражении.
Но C# имеет функцию языка, которая очень часто делает это ненужным - объектный синтаксис инициализатора:
var myObj = new MyClass
{
SomeProperty = 5,
Another = true,
Complain = str => MessageBox.Show(str),
};
Это, возможно, объяснило бы, почему опытные пользователи C# менее знакомы с термином "быстрый интерфейс" для объединения в цепочку запросов к тому же объекту - это не необходимо вполне так часто в C#.
Поскольку свойства могли кодировать рукой методы set, это - возможность назвать несколько методов на недавно созданном объекте, не имея необходимость заставлять каждый метод возвратить тот же объект.
Ограничения:
Я хотел бы его, если мы могли бы назвать методы и поступить на службу в события, а также присвоить свойствам в объектном блоке инициализатора.
var myObj = new MyClass
{
SomeProperty = 5,
Another = true,
Complain = str => MessageBox.Show(str),
DoSomething()
Click += (se, ev) => MessageBox.Show("Clicked!"),
};
И почему такой блок модификаций должен только сразу быть применимым после конструкции? Мы могли иметь:
myObj with
{
SomeProperty = 5,
Another = true,
Complain = str => MessageBox.Show(str),
DoSomething(),
Click += (se, ev) => MessageBox.Show("Clicked!"),
}
with
было бы новое ключевое слово, которое воздействует на объект некоторого типа и производит тот же объект, и тип - отмечают, что это было бы выражением, не оператором. Таким образом, это точно получило бы идею объединить в цепочку в "быстром интерфейсе".
Таким образом, Вы могли использовать синтаксис стиля инициализатора независимо от того, был ли у Вас объект от a new
выражение или из МОК или метода фабрики, и т.д.
На самом деле Вы могли использовать with
после полного new
и это было бы эквивалентно текущему стилю объектного инициализатора:
var myObj = new MyClass() with
{
SomeProperty = 5,
Another = true,
Complain = str => MessageBox.Show(str),
DoSomething(),
Click += (se, ev) => MessageBox.Show("Clicked!"),
};
И поскольку Charlie указывает в комментариях:
public static T With(this T with, Action<T> action)
{
if (with != null)
action(with);
return with;
}
Вышеупомянутая обертка просто вынуждает действие невозврата возвратить что-то, и эй престо - что-либо может быть "быстрым" в этом смысле.
Эквивалентный из инициализатора, но с включением в список события:
var myObj = new MyClass().With(w =>
{
w.SomeProperty = 5;
w.Another = true;
w.Click += (se, ev) => MessageBox.Show("Clicked!");
};
И на методе фабрики вместо a new
:
var myObj = Factory.Alloc().With(w =>
{
w.SomeProperty = 5;
w.Another = true;
w.Click += (se, ev) => MessageBox.Show("Clicked!");
};
Я не мог сопротивляться предоставлению его, "возможно, монада" - разрабатывает проверку на пустой указатель также, поэтому если у Вас есть что-то, что могло бы возвратиться null
, можно все еще подать заявку With
к нему и затем проверяют его на null
- мыс.
API Критериев в NHibernate имеет хороший быстрый интерфейс, который позволяет Вам делать интересный материал как это:
Session.CreateCriteria(typeof(Entity))
.Add(Restrictions.Eq("EntityId", entityId))
.CreateAlias("Address", "Address")
.Add(Restrictions.Le("Address.StartDate", effectiveDate))
.Add(Restrictions.Disjunction()
.Add(Restrictions.IsNull("Address.EndDate"))
.Add(Restrictions.Ge("Address.EndDate", effectiveDate)))
.UniqueResult<Entity>();
Новым HttpClient Предварительного просмотра Стартового набора REST WCF 2 является большой быстрый API. посмотрите мое сообщение в блоге для демонстрационного http://bendewey.wordpress.com/2009/03/14/connecting-to-live-search-using-the-httpclient/
Как @John Sheehan упомянул, Ninject использует этот тип API для определения привязки. Вот некоторый пример кода из их руководства пользователя:
Bind<IWeapon>().To<Sword>();
Bind<Samurai>().ToSelf();
Bind<Shogun>().ToSelf().Using<SingletonBehavior>();