This repository contains materials for recreating and building upon the results published in the following paper:
The main results are summarised in Table 2 on page 11, and this page (Section 2) provides instructions for reproducing them. We also provide the data underlying the experimental testing of our new PTX MCM (Section 3).
This repository is maintained on GitHub.
The Alloy models in this repository are divided into four subdirectories:
hw
: architecture-level memory consistency models
sw
: language-level memory consistency models
mappings
: language-to-architecture compiler mappings
tests
: questions about memory consistency models and the
relationships between them
The diagram below depicts how the models build on one another (an arrow from model A to model B indicates that A imports model B):
Most of our models rely only on the basic Alloy tool, but some depend on the higher-order quantification that is only supported in the AlloyStar tool. An unofficial copy of AlloyStar (incorporating a couple of minor tweaks) can be downloaded from our GitHub repository.
Set the solver to Glucose or Plingeling (via Options → Solver
). Set the maximum memory usage and stack size as high as possible,
e.g. 4GB of memory and 64MB of stack (via Options → Maximum memory
and Options → Maximum stack
). Set the maximum number of
CEGIS iterations to 0, which indicates ‘no maximum’ (via Options → Max CEGIS iterations
).
Open an Alloy model file, e.g. tests/Q2_c11_simp_orig.als
(via
File → Open...
).
Run a command by picking it from the Execute
menu (e.g. Execute → Run gp for exactly 1 Exec, 5 E expect 1
).
Alloy will respond with either “No instance found” or “Instance found”. In the latter case, click on “Instance” to load the Alloy Visualizer.
When opening an instance in the Alloy Visualizer, change the
Projection
setting from none
to Exec
. This greatly improves
readability. If the instance involves two executions, click on the
<<
and >>
buttons at the bottom to switch between them. If the
instance involves separate hardware and software executions, project
over both types of execution at the same time for maximum
readability.
In the Alloy Visualizer, the Theme
button allows nodes and edges
to be hidden or restyled according to their type.
In the table below, the Task column refers to the row in Table 2
on
page 11 of the paper.
The File column refers to a file in this repository, and
the Command column gives the command in that file that should be
executed (by selecting it from the Execute
menu). The Solver
column identifies the SAT solver that was found to provide the fastest
result. The Time column gives the number of seconds to encode
(first number) and to solve (second number) the task. These numbers
were obtained on a 64-bit Linux machine with four 16-core 2.1 GHz AMD
Opteron processors and 128 GB of RAM; results obtained on different
machines may vary considerably given the highly unpredictable nature
of SAT solving. Finally, the Instance? column reports whether an
instance is found or not.
| Task | File | Command | Solver | Time /s | Instance? |
|---|---|---|---|---|---|
| 1 | tests/Q2_c11_sra_simp.als |
2nd | Glucose | 0.7+0.6 | yes |
| 2 | tests/Q2_c11_swrf_simp.als |
3rd | Glucose | 0.8+625 | no |
| 3 | tests/Q2_c11_swrf_simp.als |
1st | Plingeling | 2+214 | yes |
| 4 | tests/Q2_c11_simp_orig.als |
2nd | Glucose | 0.4+0.3 | yes |
| 5 | tests/Q2_x86_mca.als |
2nd | Plingeling | 0.8+607 | no |
| 6 | tests/Q2_ppc_mca.als |
2nd | Glucose | 1.5+0.06 | yes |
| 7 | tests/Q2_sc_c11nodrf.als |
1st | Glucose | 0.4+0.04 | yes |
| 8 | tests/Q2_ptx.als |
2nd | Glucose | 0.7+4 | yes |
| 9 | tests/Q3_c11_seq.als |
1st | MiniSat | 0.5+163 | no |
| 10 | tests/Q3_c11_seq.als |
2nd | Plingeling | 0.7+5 | yes |
| 11 | tests/Q3_c11_mo.als |
2nd | Glucose | 0.9+51 | yes |
| 12 | tests/Q4_c11_x86a.als |
1st | Plingeling | 0.7+13029 | no |
| 13 | tests/Q4_c11_ppc_trimmed.als |
1st | Plingeling | 8+91 | yes |
| 14 | tests/Q4_opencl_amd.als |
2nd | Glucose | 6+1355 | yes |
| 15 | tests/Q4_opencl_amd.als |
1st | Plingeling | 16+4743 | yes |
| 16 | tests/Q4_opencl_ptx_orig.als |
2nd | Plingeling | 2+11 | yes |
| 17 | tests/Q4_opencl_ptx_cumul.als |
1st | Plingeling | 4+9719 | no |
Existing test results There are a total of 12 tests with 7 events that are allowed under PTX1 but disallowed under PTX2 and for which Alglave et al. provide testing results. In no case is the weak behaviour observed.
New test results There are a total of 2 tests with 7 events that are allowed under PTX1 but disallowed under PTX2, and for which Alglave et al. do not provide testing results. We ran these two tests on a GTX Titan using Alglave et al.'s GPU-litmus tool. We do not observe the weak behaviour.
| Test shape | GPU config | GTX Titan |
|---|---|---|
| RWC + membar.cta + membar.gl (single-address) | P0 |cta (P1 |warp P2) | 0/100k |
| WRR+2W + membar.cta + membar.gl (single-address) | P0 |cta (P1 |warp P2) | 0/100k |
Existing test results Alloy found 10 tests with 8 events that are allowed under PTX1 but disallowed under PTX2 and for which Alglave et al. provide testing results. In no case do we observe the weak behaviour.
| Test shape | GPU config | GTX 540 | GTX 660 | GTX 750 Ti | GTX Titan | Tesla C2075 |
|---|---|---|---|---|---|---|
| IRIW + membar.cta + membar.gl | P0 |cta (P1 |warp P2 |warp P3) | 0/50k | 0/100k | 0/50k | 0/50k | 0/50k |
| IRIW + membar.gl + membar.cta | P0 |cta (P1 |warp P2 |warp P3) | 0/50k | 0/100k | 0/50k | 0/50k | 0/50k |
| IRRWIW + membar.cta + membar.gl | P0 |cta (P1 |warp P2 |warp P3) | 0/50k | 0/100k | 0/50k | 0/50k | 0/50k |
| IRRWIW + membar.gl + membar.cta | P0 |cta (P1 |warp P2 |warp P3) | 0/50k | 0/100k | 0/50k | 0/50k | 0/50k |
| IRRWIW + membar.gl + membar.cta | P2 |cta (P0 |warp P1 |warp P3) | 0/50k | 0/100k | 0/50k | 0/50k | 0/50k |
| IRRWIW + membar.cta + membar.gl | P2 |cta (P0 |warp P1 |warp P3) | 0/50k | 0/100k | 0/50k | 0/50k | 0/50k |
| IRWIW + membar.cta + membar.gl | P0 |cta (P1 |warp P2 |warp P3) | 0/50k | 0/100k | 0/50k | 0/50k | 0/50k |
| IRWIW + membar.gl + membar.cta | P0 |cta (P1 |warp P2 |warp P3) | 0/50k | 0/100k | 0/50k | 0/50k | 0/50k |
New test results There are a total of 2 tests with 8 events that are allowed under PTX1 but disallowed under PTX2, and for which Alglave et al. do not provide testing results. We ran these two tests on a GTX Titan using Alglave et al.'s GPU-litmus tool. We do not observe the weak behaviour.
| Test shape | GPU config | GTX Titan |
|---|---|---|
| IRIW + membar.cta + membar.gl (single-address) | P0 |cta (P1 |warp P2 |warp P3) | 0/100k |
| IRRWIW + membar.cta + membar.gl (single-address) | P0 |cta (P1 |warp P2 |warp P3) | 0/100k |


{{ story1Title }}
{{ story1P1 }}
{{ story1P1 }}
{{ story1P2 }}
{{ story1P3 }}
{{ story1P4 }}
{{ story1P5 }}
{{ story1P6 }}
{{ story1P8 }}
{{ story1P9 }}
{{ story1P10 }}
{{ story1P11 }}
{{ story1P12 }}
{{ story1P13 }}
{{ story1P15 }}
{{ story1P16 }}
{{ story1P17 }}
{{ story1P18 }}
{{ story1P19 }}


../../res/layout/uv_article_layout.xml:17: Placing a <WebView> in a parent element that uses a wrap_content size can lead to subtle bugs; use match_parent
Explanation: Ensures that WebViews are not placed in parents with wrap_content layout.
The WebView implementation has certain performance optimizations which will not work correctly if the parent view is using wrap_content rather than match_parent. This can lead to subtle UI bugs.
../../AndroidManifest.xml:7: Not targeting the latest versions of Android; compatibility modes apply. Consider testing and updating this version. Consult the android.os.Build.VERSION_CODES javadoc for details.
Explanation: Checks that the manifest specifies a targetSdkVersion that is recent.
When your application runs on a version of Android that is more recent than your targetSdkVersion specifies that it has been tested with, various compatibility modes kick in. This ensures that your application continues to work, but it may look out of place. For example, if the targetSdkVersion is less than 14, your app may get an option button in the UI.
To fix this issue, set the targetSdkVersion to the highest available value. Then test your app to make sure everything works correctly. You may want to consult the compatibility notes to see what changes apply to each version you are adding support for: http://developer.android.com/reference/android/os/Build.VERSION_CODES.html
Explanation: Finds usages of attributes that will not be used (read) on all targeted versions.
This check finds attributes set in XML files that were introduced in a version newer than the oldest version targeted by your application (with the the minSdkVersion attribute).
This is not an error; the application will simply ignore the attribute. However, if the attribute is important to the appearance of functionality of your application, you should consider finding an alternative way to achieve the same result with only available attributes, and then you can optionally create a copy of the layout in a layout-vNN folder which will be used on API NN or higher where you can take advantage of the newer attribute.
Explanation: Ensures that a proper parent context is passed to a layout inflater.
When inflating a layout, avoid passing in null as the parent view, since otherwise any layout parameters on the root of the inflated layout will be ignored.
Explanation: Looks for old or obsolete Gradle library dependencies.
This detector looks for usages of libraries where the version you are using is not the current stable release. Using older versions is fine, and there are cases where you deliberately want to stick with an older version. However, you may simply not be aware that a more recent version is available, and that is what this lint check helps find.
Note: This issue has an associated quickfix operation in Eclipse/ADT
Priority: 2 / 10
Category: Correctness
Severity: Warning
Explanation: Looks for use of the px dimension.
For performance reasons and to keep the code simpler, the Android system uses pixels as the standard unit for expressing dimension or coordinate values. That means that the dimensions of a view are always expressed in the code using pixels, but always based on the current screen density. For instance, if myView.getWidth() returns 10, the view is 10 pixels wide on the current screen, but on a device with a higher density screen, the value returned might be 15. If you use pixel values in your application code to work with bitmaps that are not pre-scaled for the current screen density, you might need to scale the pixel values that you use in your code to match the un-scaled bitmap source.
Explanation: Checks for missing quantity strings relevant to each locale.
Different languages have different rules for grammatical agreement with quantity. In English, for example, the quantity 1 is a special case. We write "1 book", but for any other quantity we'd write "n books". This distinction between singular and plural is very common, but other languages make finer distinctions.
This lint check looks at each translation of a <plural> and makes sure that all the quantity strings considered by the given language are provided by this translation.
For example, an English translation must provide a string for quantity="one". Similarly, a Czech translation must provide a string for quantity="few".
69 <string name="uv_yes">Yes</string>
70 <string name="uv_very_yes">Yes!</string>
71 <string name="uv_helpful_article_message_question">Do you still want to send a message?</string>
72 <string name="uv_unhelpful_article_message_question">Would you like to send us a message?</string> 73 <string name="uv_idea_description_heading">Describe your idea in more detail</string>
74 <string name="uv_category">Category</string>
105 <string name="uv_confirm">Confirm</string>
106 <string name="uv_msg_confirm_discard_idea">Are you sure you want to discard your idea?</string>
107 <string name="uv_msg_confirm_discard_message">Are you sure you want to discard your message?</string>
108 <string name="uv_post_an_idea">Post an idea</string> 109 <string name="uv_password_dialog_title">Please enter your password</string>
110 <string name="uv_article_browse_question">Was this article helpful?</string>
106 <string name="uv_msg_confirm_discard_idea">Are you sure you want to discard your idea?</string>
107 <string name="uv_msg_confirm_discard_message">Are you sure you want to discard your message?</string>
108 <string name="uv_post_an_idea">Post an idea</string>
109 <string name="uv_password_dialog_title">Please enter your password</string> 110 <string name="uv_article_browse_question">Was this article helpful?</string>
111 <string name="uv_thanks">Thanks!</string>
107 <string name="uv_msg_confirm_discard_message">Are you sure you want to discard your message?</string>
108 <string name="uv_post_an_idea">Post an idea</string>
109 <string name="uv_password_dialog_title">Please enter your password</string>
110 <string name="uv_article_browse_question">Was this article helpful?</string> 111 <string name="uv_thanks">Thanks!</string>
112 <string name="uv_powered_by_uservoice">Powered by UserVoice</string>
108 <string name="uv_post_an_idea">Post an idea</string>
109 <string name="uv_password_dialog_title">Please enter your password</string>
110 <string name="uv_article_browse_question">Was this article helpful?</string>
111 <string name="uv_thanks">Thanks!</string> 112 <string name="uv_powered_by_uservoice">Powered by UserVoice</string>
113 <string name="uv_android_sdk">Android SDK</string>
../../res/values/strings.xml:112: "uv_powered_by_uservoice" is not translated in "cs" (Czech), "fr" (French), "nl" (Dutch), "ru" (Russian), "zh-rTW" (Chinese: Taiwan, Province of China)
109 <string name="uv_password_dialog_title">Please enter your password</string>
110 <string name="uv_article_browse_question">Was this article helpful?</string>
111 <string name="uv_thanks">Thanks!</string>
112 <string name="uv_powered_by_uservoice">Powered by UserVoice</string> 113 <string name="uv_android_sdk">Android SDK</string>
114 <string name="uv_msg_bad_email_format">Please enter a valid email address.</string>
../../res/values/strings.xml:113: "uv_android_sdk" is not translated in "cs" (Czech), "fr" (French), "nl" (Dutch), "ru" (Russian), "zh-rTW" (Chinese: Taiwan, Province of China)
110 <string name="uv_article_browse_question">Was this article helpful?</string>
111 <string name="uv_thanks">Thanks!</string>
112 <string name="uv_powered_by_uservoice">Powered by UserVoice</string>
113 <string name="uv_android_sdk">Android SDK</string> 114 <string name="uv_msg_bad_email_format">Please enter a valid email address.</string>
115 <string name="uv_ranked">Ranked %1$s</string>
../../res/values/strings.xml:115: "uv_ranked" is not translated in "cs" (Czech), "de" (German), "fr" (French), "hr" (Croatian), "nl" (Dutch), "pt" (Portuguese), "ru" (Russian), "zh-rTW" (Chinese: Taiwan, Province of China)
112 <string name="uv_powered_by_uservoice">Powered by UserVoice</string>
113 <string name="uv_android_sdk">Android SDK</string>
114 <string name="uv_msg_bad_email_format">Please enter a valid email address.</string>
115 <string name="uv_ranked">Ranked %1$s</string> 116 117 </resources>
Note: This issue has an associated quickfix operation in Eclipse/ADT
Priority: 8 / 10
Category: Correctness:Messages
Severity: Fatal
Explanation: Checks for incomplete translations where not all strings are translated.
If an application has more than one locale, then all the strings declared in one language should also be translated in all other languages.
If the string should not be translated, you can add the attribute translatable="false" on the <string> element, or you can define all your non-translatable strings in a resource file called donottranslate.xml. Or, you can ignore the issue with a tools:ignore="MissingTranslation" attribute.
By default this detector allows regions of a language to just provide a subset of the strings and fall back to the standard language strings. You can require all regions to provide a full translation by setting the environment variable ANDROID_LINT_COMPLETE_REGIONS.
You can tell lint (and other tools) which language is the default language in your res/values/ folder by specifying tools:locale="languageCode" for the root <resources> element in your resource file. (The tools prefix refers to the namespace declaration http://schemas.android.com/tools.)
96 <string name="uv_post_idea_continue_button">Я всё ещё хочу отправить свою идею</string>
97 <string name="uv_contact_continue_button">Я всё ещё хочу отправить сообщение</string>
98 <string name="uv_i_want_this">Да, я хочу!</string>
99 <string name="uv_number_of_subscribers_format">%1$s хотят этого</string> 100 <string name="uv_post_a_comment">Отправить комментарий</string>
101 <string name="uv_all_results_filter">ВСЕ</string>
Priority: 6 / 10
Category: Correctness:Messages
Severity: Fatal
Explanation: Checks for translations that appear to be unused (no default language string)
If a string appears in a specific language translation file, but there is no corresponding string in the default locale, then this string is probably unused. (It's technically possible that your application is only intended to run in a specific locale, but it's still a good idea to provide a fallback.).
Note that these strings can lead to crashes if the string is looked up on any locale not providing a translation, so it's important to clean them up.
../../res/values-hr/strings.xml:4: The quantity 'one' matches more than one specific number in this locale, but the message did not include a formatting argument (such as %d). This is usually an internationalization error. See full issue explanation for more.
../../res/values-fr/strings.xml:5: The quantity 'one' matches more than one specific number in this locale, but the message did not include a formatting argument (such as %d). This is usually an internationalization error. See full issue explanation for more.
../../res/values-hr/strings.xml:8: The quantity 'one' matches more than one specific number in this locale, but the message did not include a formatting argument (such as %d). This is usually an internationalization error. See full issue explanation for more.
../../res/values-fr/strings.xml:10: The quantity 'one' matches more than one specific number in this locale, but the message did not include a formatting argument (such as %d). This is usually an internationalization error. See full issue explanation for more.
../../res/values-hr/strings.xml:12: The quantity 'one' matches more than one specific number in this locale, but the message did not include a formatting argument (such as %d). This is usually an internationalization error. See full issue explanation for more.
../../res/values-fr/strings.xml:15: The quantity 'one' matches more than one specific number in this locale, but the message did not include a formatting argument (such as %d). This is usually an internationalization error. See full issue explanation for more.
../../res/values-hr/strings.xml:16: The quantity 'one' matches more than one specific number in this locale, but the message did not include a formatting argument (such as %d). This is usually an internationalization error. See full issue explanation for more.
../../res/values-fr/strings.xml:20: The quantity 'one' matches more than one specific number in this locale, but the message did not include a formatting argument (such as %d). This is usually an internationalization error. See full issue explanation for more.
../../res/values-fr/strings.xml:25: The quantity 'one' matches more than one specific number in this locale, but the message did not include a formatting argument (such as %d). This is usually an internationalization error. See full issue explanation for more.
Explanation: Looks for quantity string translations which do not include the quantity.
Plural strings should generally include a %s or %d formatting argument. In locales like English, the one quantity only applies to a single value, 1, but that's not true everywhere. For example, in Slovene, the one quantity will apply to 1, 101, 201, 301, and so on. Similarly, there are locales where multiple values match the zero and two quantities.
In these locales, it is usually an error to have a message which does not include a formatting argument (such as '%d'), since it will not be clear from the grammar what quantity the quantity string is describing.
Explanation: Checks for quantity string translations which are not used in this language.
Android defines a number of different quantity strings, such as zero, one, few and many. However, many languages do not distinguish grammatically between all these different quantities.
This lint check looks at the quantity strings defined for each translation and flags any quantity strings that are unused (because the language does not make that quantity distinction, and Android will therefore not look it up.).
For example, in Chinese, only the other quantity is used, so even if you provide translations for zero and one, these strings will not be returned when getQuantityString() is called, even with 0 or 1.
../../AndroidManifest.xml: Should explicitly set android:allowBackup to true or false (it's true by default, and that can have some security implications for the application's data)
Note: This issue has an associated quickfix operation in Eclipse/ADT
Priority: 3 / 10
Category: Security
Severity: Warning
Explanation: Ensure that allowBackup is explicitly set in the application's manifest.
By default, this flag is set to true. When this flag is set to true, application data can be backed up and restored by the user using adb backup and adb restore.
This may have security consequences for an application. adb backup allows users who have enabled USB debugging to copy application data off of the device. Once backed up, all application data can be read by the user. adb restore allows creation of application data from a source specified by the user. Following a restore, applications should not assume that the data, file permissions, and directory permissions were created by the application itself.
Setting allowBackup="false" opts an application out of both backup and restore.
To fix this warning, decide whether your application should support backup, and explicitly set android:allowBackup=(true|false)"
Note: This issue has an associated quickfix operation in Eclipse/ADT
Priority: 3 / 10
Category: Performance
Severity: Warning
Explanation: Looks for inefficient weight declarations in LinearLayouts.
When only a single widget in a LinearLayout defines a weight, it is more efficient to assign a width/height of 0dp to it since it will absorb all the remaining space anyway. With a declared width/height of 0dp it does not have to measure its own size first.
../../res/layout/uv_divider.xml:6: Possible overdraw: Root element paints background #20000000 with a theme that also paints a background (inferred theme is @android:style/Theme.Holo)
Explanation: Looks for overdraw issues (where a view is painted only to be fully painted over)
If you set a background drawable on a root view, then you should use a custom theme where the theme background is null. Otherwise, the theme background will be painted first, only to have your custom background completely cover it; this is called "overdraw".
NOTE: This detector relies on figuring out which layouts are associated with which activities based on scanning the Java code, and it's currently doing that using an inexact pattern matching algorithm. Therefore, it can incorrectly conclude which activity the layout is associated with and then wrongly complain that a background-theme is hidden.
If you want your custom background on multiple pages, then you should consider making a custom theme with your custom background and just using that theme instead of a root element background.
Of course it's possible that your custom drawable is translucent and you want it to be mixed with the background. However, you will get better performance if you pre-mix the background with your drawable and use that resulting image or color as a custom theme background instead.
4 Customize dimensions originally defined in res/values/dimens.xml (such as
5 screen margins) for sw720dp devices (e.g. 10" tablets) in landscape here.
6 -->
7 <dimen name="activity_horizontal_margin">128dp</dimen> 8 9 </resources>
../../res/values/strings.xml:67: The resource R.string.uv_suggestion_instant_answer_question appears to be unused
64 <string name="uv_msg_ticket_created">Your message has been sent</string>
65 <string name="uv_msg_idea_created">Your idea has been created</string>
66 <string name="uv_article_instant_answer_question">Is this article helpful?</string>
67 <string name="uv_suggestion_instant_answer_question">Is this idea helpful?</string> 68 <string name="uv_no">No</string>
69 <string name="uv_yes">Yes</string>
78 <string name="uv_idea_form_help">When you post an idea on our forum, others will be able to subscribe to it and make comments. When we respond to the idea, you\'ll get notified.</string>
79 <string name="uv_contact_us">Contact us</string>
80 <string name="uv_close">Close</string>
81 <string name="uv_new_comment">New comment</string> 82 <string name="uv_error">Error</string>
83 <string name="uv_msg_user_identity_validation">Please enter your email address</string>
Note: This issue has an associated quickfix operation in Eclipse/ADT
Priority: 2 / 10
Category: Performance
Severity: Warning
Explanation: Checks whether a parent layout can be removed.
A layout with children that has no siblings, is not a scrollview or a root layout, and does not have a background, can be removed and have its children moved directly into the parent for a flatter and more efficient layout hierarchy.
Explanation: Ensures that icons across densities provide roughly the same density-independent size.
Checks the all icons which are provided in multiple densities, all compute to roughly the same density-independent pixel (dip) size. This catches errors where images are either placed in the wrong folder, or icons are changed to new sizes but some folders are forgotten.
Explanation: Checks for uses of showAsAction="always" and suggests showAsAction="ifRoom" instead.
Using showAsAction="always" in menu XML, or MenuItem.SHOW_AS_ACTION_ALWAYS in Java code is usually a deviation from the user interface style guide.Use ifRoom or the corresponding MenuItem.SHOW_AS_ACTION_IF_ROOM instead.
If always is used sparingly there are usually no problems and behavior is roughly equivalent to ifRoom but with preference over other ifRoom items. Using it more than twice in the same menu is a bad idea.
This check looks for menu XML files that contain more than two always actions, or some always actions and no ifRoom actions. In Java code, it looks for projects that contain references to MenuItem.SHOW_AS_ACTION_ALWAYS and no references to MenuItem.SHOW_AS_ACTION_IF_ROOM.
Note: This issue has an associated quickfix operation in Eclipse/ADT
Priority: 3 / 10
Category: Accessibility
Severity: Warning
Explanation: Ensures that image widgets provide a contentDescription.
Non-textual widgets like ImageViews and ImageButtons should use the contentDescription attribute to specify a textual description of the widget such that screen readers and other accessibility tools can adequately describe the user interface.
Note that elements in application screens that are purely decorative and do not provide any content or enable a user action should not have accessibility content descriptions. In this case, just suppress the lint warning with a tools:ignore="ContentDescription" attribute.
../../res/layout/uv_comment_item.xml:51: [I18N] Hardcoded string "We are looking into this. Please check back and leave additional comments and we will be in touch!", should use @string resource
48 android:layout_width="wrap_content"
49 android:layout_height="wrap_content"
50 android:paddingTop="2dp"
51android:text="We are looking into this. Please check back and leave additional comments and we will be in touch!" 52 android:textColor="#999999"
53 android:textSize="12sp" />
14 android:layout_height="wrap_content"
15 android:paddingLeft="5dp"
16 android:paddingRight="5dp"
17android:text="Make the app more Android friendly" 18 android:textAppearance="?android:attr/textAppearanceLarge" />
19
+ 15 More Occurrences...
../../res/layout/uv_idea_dialog_header.xml:27: [I18N] Hardcoded string "Badges are cool, and we'd like to give them out to our active users.", should use @string resource
24 android:paddingLeft="5dp"
25 android:paddingRight="5dp"
26 android:paddingTop="10dp"
27android:text="Badges are cool, and we'd like to give them out to our active users." 28 android:textAppearance="?android:attr/textAppearanceSmall"
29 android:textColor="#999999" />
../../res/layout/uv_idea_dialog_header.xml:153: [I18N] Hardcoded string "We are looking into this. Please check back and leave additional comments and we will be in touch!", should use @string resource
150 android:layout_width="wrap_content"
151 android:layout_height="wrap_content"
152 android:paddingTop="2dp"
153android:text="We are looking into this. Please check back and leave additional comments and we will be in touch!" 154 android:textColor="#999999"
155 android:textSize="12sp" />
Note: This issue has an associated quickfix operation in Eclipse/ADT
Priority: 5 / 10
Category: Internationalization
Severity: Warning
Explanation: Looks for hardcoded text attributes which should be converted to resource lookup.
Hardcoding text attributes directly in layout files is bad for several reasons:
* When creating configuration variations (for example for landscape or portrait)you have to repeat the actual text (and keep it up to date when making changes)
* The application cannot be translated to other languages by just adding new translations for existing string resources.
In Android Studio and Eclipse there are quickfixes to automatically extract this hardcoded string into a resource lookup.
The following issues were not run by lint, either because the check is not enabled by default, or because it was disabled with a command line flag or via one or more lint.xml configuration files in the project directories.
Explanation: Looks for Back buttons, which are not common on the Android platform.
According to the Android Design Guide,
"Other platforms use an explicit back button with label to allow the user to navigate up the application's hierarchy. Instead, Android uses the main action bar's app icon for hierarchical navigation and the navigation bar's back button for temporal navigation."
This check is not very sophisticated (it just looks for buttons with the label "Back"), so it is disabled by default to not trigger on common scenarios like pairs of Back/Next buttons to paginate through screens.
An "easter egg" is code deliberately hidden in the code, both from potential users and even from other developers. This lint check looks for code which looks like it may be hidden from sight.
Explanation: Suggests replacing uses of getters with direct field access within a class.
Accessing a field within the class that defines a getter for that field is at least 3 times faster than calling the getter. For simple getters that do nothing other than return the field, you might want to just reference the local field directly instead.
NOTE: As of Android 2.3 (Gingerbread), this optimization is performed automatically by Dalvik, so there is no need to change your code; this is only relevant if you are targeting older versions of Android.
Explanation: Looks for dependencies using a dynamic version rather than a fixed version.
Using + in dependencies lets you automatically pick up the latest available version rather than a specific, named version. However, this is not recommended; your builds are not repeatable; you may have tested with a slightly different version than what the build server used. (Using a dynamic version as the major version number is more problematic than using it in the minor version position.)
More info:
To suppress this error, use the issue id "GradleDynamicVersion" as explained in the Suppressing Warnings and Errors section.
Explanation: Ensures that launcher icons, notification icons etc have the correct size.
There are predefined sizes (for each density) for launcher icons. You should follow these conventions to make sure your icons fit in with the overall look of the platform.
Explanation: Looks for Gradle library dependencies that can be replaced by newer versions.
This detector checks with a central repository to see if there are newer versions available for the dependencies used by this project.
This is similar to the GradleDependency check, which checks for newer versions available in the Android SDK tools and libraries, but this works with any MavenCentral dependency, and connects to the library every time, which makes it more flexible but also much slower.
More info:
To suppress this error, use the issue id "NewerVersionAvailable" as explained in the Suppressing Warnings and Errors section.
RtlCompat
Disabled By: Default
Priority: 6 / 10
Category: Bi-directional Text
Severity: Error
Explanation: Looks for compatibility issues with RTL support.
API 17 adds a textAlignment attribute to specify text alignment. However, if you are supporting older versions than API 17, you must also specify a gravity or layout_gravity attribute, since older platforms will ignore the textAlignment attribute.
Disabled By: Default
Priority: 3 / 10
Category: Bi-directional Text
Severity: Warning
Explanation: Looks for usages of right-to-left text constants without enabling RTL support.
To enable right-to-left support, when running on API 17 and higher, you must set the android:supportsRtl attribute in the manifest <application> element.
If you have started adding RTL attributes, but have not yet finished the migration, you can set the attribute to false to satisfy this lint check.
Disabled By: Default
Priority: 5 / 10
Category: Bi-directional Text
Severity: Warning
Explanation: Looks for hardcoded left/right constants which could be start/end for bidirectional text.
Using Gravity#LEFT and Gravity#RIGHT can lead to problems when a layout is rendered in locales where text flows from right to left. Use Gravity#START and Gravity#END instead. Similarly, in XML gravity and layout_gravity attributes, use start rather than left.
For XML attributes such as paddingLeft and layout_marginLeft, use paddingStart and layout_marginStart. NOTE: If your minSdkVersion is less than 17, you should add both the older left/right attributes as well as the new start/right attributes. On older platforms, where RTL is not supported and the start/right attributes are unknown and therefore ignored, you need the older left/right attributes. There is a separate lint check which catches that type of error.
(Note: For Gravity#LEFT and Gravity#START, you can use these constants even when targeting older platforms, because the start bitmask is a superset of the left bitmask. Therefore, you can use gravity="start" rather than gravity="left|start".)
Disabled By: Default
Priority: 6 / 10
Category: Bi-directional Text
Severity: Error
Explanation: Ensures that specifying padding on one side is matched by padding on the other.
If you specify padding or margin on the left side of a layout, you should probably also specify padding on the right side (and vice versa) for right-to-left layout symmetry.
Explanation: Looks for TextViews which should probably allow their text to be selected.
If a <TextView> is used to display data, the user might want to copy that data and paste it elsewhere. To allow this, the <TextView> should specify android:textIsSelectable="true".
This lint check looks for TextViews which are likely to be displaying data: views whose text is set dynamically. This value will be ignored on platforms older than API 11, so it is okay to set it regardless of your minSdkVersion.
Explanation: Looks for comment markers of the form //STOPSHIP which indicates that code should not be released yet.
Using the comment // STOPSHIP can be used to flag code that is incomplete but checked in. This comment marker can be used to indicate that the code should not be shipped until the issue is addressed, and lint will look for these.
Note: This issue has an associated quickfix operation in Eclipse/ADT
Disabled By: Default
Priority: 5 / 10
Category: Usability:Typography
Severity: Warning
Explanation: Looks for straight quotes which can be replaced by curvy quotes.
Straight single quotes and double quotes, when used as a pair, can be replaced by "curvy quotes" (or directional quotes). This can make the text more readable.
Note that you should never use grave accents and apostrophes to quote, `like this'.
(Also note that you should not use curvy quotes for code fragments.)
This resource id definition appears not to be needed since it is not referenced from anywhere. Having id definitions, even if unused, is not necessarily a bad idea since they make working on layouts and menus easier, so there is not a strong reason to delete these.
Lint errors can be suppressed in a variety of ways:
1. With a @SuppressLint annotation in the Java code
2. With a tools:ignore attribute in the XML file
3. With a lint.xml configuration file in the project
4. With a lint.xml configuration file passed to lint via the --config flag
5. With the --ignore flag passed to lint.
To suppress a lint warning with an annotation, add a @SuppressLint("id") annotation on the class, method or variable declaration closest to the warning instance you want to disable. The id can be one or more issue id's, such as "UnusedResources" or {"UnusedResources","UnusedIds"}, or it can be "all" to suppress all lint warnings in the given scope.
To suppress a lint warning in an XML file, add a tools:ignore="id" attribute on the element containing the error, or one of its surrounding elements. You also need to define the namespace for the tools prefix on the root element in your document, next to the xmlns:android declaration:
* xmlns:tools="http://schemas.android.com/tools"
To suppress lint warnings with a configuration XML file, create a file named lint.xml and place it at the root directory of the project in which it applies. (If you use the Eclipse plugin's Lint view, you can suppress errors there via the toolbar and Eclipse will create the lint.xml file for you.).
The format of the lint.xml file is something like the following:
<?xml version="1.0" encoding="UTF-8"?>
<lint>
<!-- Disable this given check in this project -->
<issue id="IconMissingDensityFolder" severity="ignore" />
<!-- Ignore the ObsoleteLayoutParam issue in the given files -->
<issue id="ObsoleteLayoutParam">
<ignore path="res/layout/activation.xml" />
<ignore path="res/layout-xlarge/activation.xml" />
</issue>
<!-- Ignore the UselessLeaf issue in the given file -->
<issue id="UselessLeaf">
<ignore path="res/layout/main.xml" />
</issue>
<!-- Change the severity of hardcoded strings to "error" -->
<issue id="HardcodedText" severity="error" />
</lint>
To suppress lint checks from the command line, pass the --ignore flag with a comma separated list of ids to be suppressed, such as:
"lint --ignore UnusedResources,UselessLeaf /my/project/path"


Trying to install @rubinius 2.0 with rbenv? Here's my notes on what I ran into and how I got around it. http://nerd.jasonrclark.com/2013/10/running-rubinius-with-rbenv.html
10/8/2013, 8:21:54 AM
Favs: 0
Retweets: 0
link--- layout: tweet ---
Trying to install @rubinius 2.0 with rbenv? Here's my notes on what I ran into and how I got around it. http://nerd.jasonrclark.com/2013/10/running-rubinius-with-rbenv.html
10/8/2013, 8:21:54 AM
Favs: 0
Retweets: 0
link


|
ArkGameFrame
v0.1.0
ArkGameFraime is a lightweight, fast, scalable, distributed module and plugin framework to create a game server easily. Greatly inspired by OGRE and Bigworld.
|
#include <iostream>
#include "NFIModule.h"
#include "NFComm/NFCore/NFIPropertyManager.h"
#include "NFComm/NFCore/NFIRecordManager.h"
#include "NFComm/NFCore/NFIComponentManager.h"
Go to the source code of this file.
Classes | |
| class | NFIClass |
| class | NFIClassModule |


Solutions-oriented IT professional with over a decade of experience in the technical operations of high-end enterprise solutions. I have gained experience using a variety of programming languages and databases. This Web site is intended as a professional portfolio to showcase the skills, education, talent, and experience that I can bring to your organization.
An intensive 24-week bootcamp dedicated to designing and building web applications. Skills learned consisted of HTML5, CSS3, JavaScript, JQuery, Bootstrap, RESTful API, Firebase, Node JS, MySQL, MongoDB, Express JS, HandlebarsJS, Git, Heroku-deployment, React, and the MERN Stack.
Developed strengths in the analysis, applied design, development, and implementation of information technology systems. Concentration: Network Security
Speedy Railways Train Scheduler is an application that incorporates Firebase to host arrival and departure data. Moment.js is used to retrieve and manipulate the data. This app also provides up-to-date information about the trains arrival times.
View ProjectThe Premier Place to Plan Your Watch Parties with Friends! As easy as 1-Search for your favorite tv show! 2-Coordinate showtime with friends and family and 3-Tune in and enjoy!!
View ProjectHere you will find spiritual inspiration, prayer and guidance that will empower you in your every day life. The client has multiple social media platforms for her small ministry. As a solution, create a website to centralize all of her content in one central location so that she can be more effective in her ministry.
View ProjectA mobile friendly application that provides health tips, over-the-counter medicine information and prescription management. This app can be used in English or Spanish!
View Project


This section explains how to search PRIDE Archive, which offer a list of publicly available shortgun proteomics datasets.
PRIDE Archive is a proteomics data repository, which is part of the ProteomeXchange consortium that has been set up to provide
coordinated submisison of MS proteomics data to the main existing proteomics repositories, and to encourage optimal data dissemination.
The public databsets from PRIDE Archive are retrieved through its web service.
You can connect the pride inspector to the public database in 3 different ways:
- From the Welcome screen, clicking on the Search PRIDE Archive
icon
- From the option in the menu bar
- From the toolbar, clicking on the button
Once you are entered "Search PRIDE Archive", a search panel consists of three parts will be displayed:
Search Box: In this box, you can specify which metadata field you want to search
for. And the criteria for searching, as well as the search string. Once the search button is clicked,
the table below will show all the matching experiments.
Project Table: This table contains all the matching projects from the search, if no search
has been made, all the public projects are listed by default. The table also provides some key information
about the projects, such as: project title, species, tissue and etc. Users can choose to download all the files
belongs to the project by clicking on the download button.
Assay Table: You can choose a project of interest from the Project table. If the project is a complete submission,
which means it included the experimental results in standard file format. A list of assays will be shown in this table.
Users can download specific assay files by clicking on the download button in the relevant row.


Embed.
Watch videos or browse externals links everywhere!
Click the open button at the bottom left of your screen to start.
By
🐼Sanix darker


Welcome, on this page you can change the network settings for your alarm clock. Once you provide the clock with your network credentials it can then access the internet to change and sync its internal timekeeping.
Please input your network credentials in the inputs below, and press 'Change Settings' when done.


A Non-Technical Discussion of Programming Concepts
Analogy of HTML & CSS
If you were to design your dream home HTML would be the schematics. The structure, how many rooms, & where the windows are. It would also be an itemised list of the content in the house. 3 couches, 2 beds, Washing machine, and a pizza oven. CSS on the otherhand would be the choices you make around how things look in the house. What colour are the walls, where do you want to put the 3 couches, is the washing machine going in the bathroom or the middle of the lounge?
Control Flow & Loops
You can imagine control flow and loops like the road rules. When you pull out of the car park and about to enter the road you enter a loop.
While road isn't clear keep on checking both ways. Once road is clear turn left
(or right depending on your direction).
Once you've travelled for a while you then get to a stop light. Based on the colour of the stop light you will alter your behaviour.
If the light is red stop your car. Otherwise if the light is orange evaluate if you can stop in time or continue through if safer. In all other situations continue through the stop light.
In programming the stoplight would be like a conditional statement where you change your behaviour depending on different inputs. And there are multiple scenarios to account for.
What is the DOM and how you might interact with it
The Document Object Model (DOM) is a way for other programming languages to interact with your webpage. It provides a lot of features (or methods) for selecting parts of an HTML document and changing them based on certain criteria. The 'document' part of DOM refers to your webpage (the document).  It's through these properties specifically that you can interact with your webpage. Model refers to the fact the document 'object' 'models' all of the components that make up a web page. This model can be visualised through a tree diagram.
By Birger Eriksson - Own work, CC BY-SA 3.0, Link
Accessing Data From Arrays v Objects
The most helpful concept in distinguishing the two is that an array holds it contents in a numbered list. Now the order doesn't have to actually mean anything. But if you were to store "orange" it would be at location "x" say 3. An object on the other hand holds its content associated with a keyword. So the content of "orange" might be stored under the key "favourite_food". Which is great is you know what the keywords in an object are. But requries more work to extract content if you don't. Whereas an array is great if you don't care about what something is stored 'against' as long as it's stored.
What are Functions and Why are they Useful?
Functions are a set of instructions which have been given a name and can be accessed again and again without the programmer needing to repeat everything that goes into them each time. This is helpful as it lets you summarise 'functionality' into a name and helps to make code more readable. Not to mention save space. They can contain pretty much anything which has been discussed in this blog post to this point. And they can even contain other functions! If you've ever worked in a job with a set of operating instructions for different tasks you can think of a function as a particular task's instructions.


Documentation Authors: Marcin Grzejszczak
Spring, Spring Boot and Spring Cloud are tools that allow developers speed up the time of creating new business features. It’s common knowledge however that the feature is only valuable if it’s in production. That’s why companies spend a lot of time and resources on building their own deployment pipelines.
This project tries to solve the following problems:
-
Creation of a common deployment pipeline
-
Propagation of good testing & deployment practices
-
Speed up the time required to deploy a feature to production
A common way of running, configuring and deploying applications lowers support costs and time needed by new developers to blend in when they change projects.
The opinionated pipeline
This repo contains an opinionated pipeline to deploy a Spring Cloud based microservice. We’ve taken the following opinionated decisions:
-
usage of Spring Cloud, Spring Cloud Contract Stub Runner and Spring Cloud Eureka
-
application deployment to Cloud Foundry
-
For Maven:
-
usage of Maven Wrapper
-
artifacts deployment by
./mvnw clean deploy
-
stubrunner.ids
property to retrieve list of collaborators for which stubs should be downloaded -
running smoke tests on a deployed app via the
smoke
Maven profile -
running end to end tests on a deployed app via the
e2e
Maven profile
-
-
For Gradle (in the
github-analytics
application check thegradle/pipeline.gradle
file):-
usage of Gradlew Wrapper
-
deploy
task for artifacts deployment -
running smoke tests on a deployed app via the
smoke
task -
running end to end tests on a deployed app via the
e2e
task -
groupId
task to retrieve group id -
artifactId
task to retrieve artifact id -
currentVersion
task to retrieve the current version -
stubIds
task to retrieve list of collaborators for which stubs should be downloaded
-
This is the initial approach that can be easily changed since all the core deployment logic is done in a form of Bash scripts.
You can go through the setup of the demo environment for
Each of these setups are available under the folders jenkins
and
concourse
respectively.
Introduction
In the following section we will describe in more depth the rationale behind the presented opinionated pipeline. We will go through each deployment step and describe it in details.
Project setup
.
├── common
├── concourse
├── docs
└── jenkins
In the common
folder you can find all the Bash scripts containing the pipeline logic. These
scripts are reused by both Concourse and Jenkins pipelines.
In the concourse
folder you can find all the necessary scripts and setup to run Concourse demo.
In the docs
section you have the whole documentation of the project.
In the jenkins
folder you can find all the necessary scripts and setup to run Jenkins demo.
How to use it?
This repository can be treated as a template for your pipeline. We provide some opinionated implementation that you can alter to suit your needs. The best approach to use it to build your production projects would be to download the Spring Cloud Pipelines repository as ZIP, then init a Git project there and modify it as you wish.
Example for using the code from master
branch.
curl -LOk https://github.com/spring-cloud/spring-cloud-pipelines/archive/master.zip
unzip master.zip
cd spring-cloud-pipelines-master
git init
# modify the pipelines to suit your needs
git add .
git commit -m "Initial commit"
git remote add origin ${YOUR_REPOSITORY_URL}
git push origin master
|
Note
|
Why aren’t you simply cloning the repo? This is meant to be a seed for building new, versioned pipelines for you. You don’t want to have all of our history dragged along with you, don’t you? |
The flow
Let’s take a look at the flow of the opinionated pipeline
We’ll first describe the overall concept behind the flow and then we’ll split it into pieces and describe every piece independently.
Environments
So we’re on the same page let’s define some common vocabulary. We discern 4 typical environments in terms of running the pipeline.
-
build
-
test
-
stage
-
prod
Build environment is a machine where the building of the application takes place. It’s a CI / CD tool worker.
Test is an environment where you can deploy an application to test it. It doesn’t resemble production, we can’t be sure of it’s state (which application is deployed there and in which version). It can be used by multiple teams at the same time.
Stage is an environment that does resemble production. Most likely applications are deployed there in versions that correspond to those deployed to production. Typically databases there are filled up with (obfuscated) production data. Most often this environment is a single, shared one between many teams. In other words in order to run some performance, user acceptance tests you have to block and wait until the environment is free.
Prod is a production environment where we want our tested applications to be deployed for our customers.
Tests
Unit tests - tests that are executed on the application during the build phase. No integrations with databases / HTTP server stubs etc. take place. Generally speaking your application should have plenty of these to have fast feedback if your features are working fine.
Integration tests - tests that are executed on the built application during the build phase. Integrations with in memory databases / HTTP server stubs take place. According to the test pyramid, in most cases you should have not too many of these kind of tests.
Smoke tests - tests that are executed on a deployed application. The concept of these tests is to check the crucial parts of your application are working properly. If you have 100 features in your application but you gain most money from e.g. 5 features then you could write smoke tests for those 5 features. As you can see we’re talking about smoke tests of an application, not of the whole system. In our understanding inside the opinionated pipeline, these tests are executed against an application that is surrounded with stubs.
End to end tests - tests that are executed on a system composing of multiple applications. The idea of these tests is to check if the tested feature works when the whole system is set up. Due to the fact that it takes a lot of time, effort, resources to maintain such an environment and that often those tests are unreliable (due to many different moving pieces like network database etc.) you should have a handful of those tests. Only for critical parts of your business. Since only production is the key verifier of whether your feature works, some companies don’t even want to do those and move directly to deployment to production. When your system contains KPI monitoring and alerting you can quickly react when your deployed application is not behaving properly.
Performance testing - tests executed on an application or set of applications to check if your system can handle big load of input. In case of our opinionated pipeline these tests could be executed either on test (against stubbed environment) or stage (against the whole system)
Testing against stubs
Before we go into details of the flow let’s take a look at the following example.
When having only a handful of applications, performing end to end testing is beneficial. From the operations perspective it’s maintainable for a finite number of deployed instances. From the developers perspective it’s nice to verify the whole flow in the system for a feature.
In case of microservices the scale starts to be a problem:
The questions arise:
-
Should I queue deployments of microservices on one testing environment or should I have an environment per microservice?
-
If I queue deployments people will have to wait for hours to have their tests ran - that can be a problem
-
-
To remove that issue I can have an environment per microservice
-
Who will pay the bills (imagine 100 microservices - each having each own environment).
-
Who will support each of those environments?
-
Should we spawn a new environment each time we execute a new pipeline and then wrap it up or should we have them up and running for the whole day?
-
-
In which versions should I deploy the dependent microservices - development or production versions?
-
If I have development versions then I can test my application against a feature that is not yet on production. That can lead to exceptions on production
-
If I test against production versions then I’ll never be able to test against a feature under development anytime before deployment to production.
-
One of the possibilities of tackling these problems is to… not do end to end tests.
If we stub out all the dependencies of our application then most of the problems presented above disappear. There is no need to start and setup infrastructure required by the dependant microservices. That way the testing setup looks like this:
Such an approach to testing and deployment gives the following benefits (thanks to the usage of Spring Cloud Contract):
-
No need to deploy dependant services
-
The stubs used for the tests ran on a deployed microservice are the same as those used during integration tests
-
Those stubs have been tested against the application that produces them (check Spring Cloud Contract for more information)
-
We don’t have many slow tests running on a deployed application - thus the pipeline gets executed much faster
-
We don’t have to queue deployments - we’re testing in isolation thus pipelines don’t interfere with each other
-
We don’t have to spawn virtual machines each time for deployment purposes
It brings however the following challenges:
-
No end to end tests before production - you don’t have the full certainty that a feature is working
-
First time the applications will talk in a real way will be on production
Like every solution it has its benefits and drawbacks. The opinionated pipeline allows you to configure whether you want to follow this flow or not.
General view
The general view behind this deployment pipeline is to:
-
test the application in isolation
-
test the backwards compatibility of the application in order to roll it back if necessary
-
allow testing of the packaged app in a deployed environment
-
allow user acceptance tests / performance tests in a deployed environment
-
allow deployment to production
Obviously the pipeline could have been split to more steps but it seems that all of the aforementioned actions comprise nicely in our opinionated proposal.
Opinionated implementation
For the demo purposes we’re providing Docker Compose setup with Artifactory and Concourse / Jenkins tools.
Regardless of the picked CD application for the pipeline to pass one needs a Cloud Foundry instance (for example
Pivotal Web Services or PCF Dev) and the
infrastructure applications deployed to the JAR hosting application (for the demo we’re providing Artifactory).
The infrastructure applications are Eureka
for Service Discovery and Stub Runner Boot
for running
Spring Cloud Contract stubs.
|
Tip
|
In the demos we’re showing you how to first build the github-webhook project. That’s because
the github-analytics needs the stubs of github-webhook to pass the tests. Below you’ll find
references to github-analytics project since it contains more interesting pieces as far as testing
is concerned.
|
Build
In this step we’re generating a version of the pipeline and then we’re publishing 2 artifacts to Artifactory / Nexus:
-
a fat jar of the application
-
a Spring Cloud Contract jar containing stubs of the application
During this phase we’re executing a Maven
build using Maven Wrapper or a Gradle
build using Gradle Wrapper
, with unit and integration tests. We’re also tagging the repository with dev/${version}
format. That way in each
subsequent step of the pipeline we’re able to retrieve the tagged version. Also we know
exactly which version of the pipeline corresponds to which Git hash.
Test
Here we’re
-
starting a RabbitMQ service in Cloud Foundry
-
deploying
Eureka
infrastructure application to Cloud Foundry -
downloading the fat jar from Nexus and we’re uploading it to Cloud Foundry. We want the application to run in isolation (be surrounded by stubs). Currently due to port constraints in Cloud Foundry we cannot run multiple stubbed HTTP services in the cloud so to fix this issue we’re running the application with
smoke
Spring profile on which you can stub out all HTTP calls to return a mocked response -
if the application is using a database then it gets upgraded at this point via Flyway, Liquibase or any other tool once the application gets started
-
from the project’s Maven or Gradle build we’re extracting
stubrunner.ids
property that contains all thegroupId:artifactId:version:classifier
notation of dependant projects for which the stubs should be downloaded. -
then we’re uploading
Stub Runner Boot
and pass the extractedstubrunner.ids
to it. That way we’ll have a running application in Cloud Foundry that will download all the necessary stubs of our application -
from the checked out code we’re running the tests available under the
smoke
profile. In the case of GitHub Analytics application we’re triggering a message from the GitHub Webhook application’s stub, that is sent via RabbitMQ to GitHub Analytics. Then we’re checking if message count has increased. You can check those tests here. -
once the tests pass we’re searching for the last production release. Once the application is deployed to production we’re tagging it with
prod/${version}
tag. If there is no such tag (there was no production release) there will be no rollback tests executed. If there was a production release the tests will get executed. -
assuming that there was a production release we’re checking out the code corresponding to that release (we’re checking out the tag), we’re downloading the appropriate fat jar and we’re uploading it to Cloud Foundry. IMPORTANT the old jar is running against the NEW version of the database.
-
we’re running the old
smoke
tests against the freshly deployed application surrounded by stubs. If those tests pass then we have a high probability that the application is backwards compatible -
the default behaviour is that after all of those steps the user can manually click to deploy the application to a stage environment
Stage
Here we’re
-
starting a RabbitMQ service in Cloud Foundry
-
deploying
Eureka
infrastructure application to Cloud Foundry -
downloading the fat jar from Nexus and we’re uploading it to Cloud Foundry.
Next we have a manual step in which:
-
from the checked out code we’re running the tests available under the
e2e
profile. In the case of GitHub Analytics application we’re sending a HTTP message to GitHub Analytic’s endpoint. Then we’re checking if the received message count has increased. You can check those tests here.
The step is manual by default due to the fact that stage environment is often shared between teams and some preparations on databases / infrastructure have to take place before running the tests. Ideally these step should be fully automatic.
Prod
The step to deploy to production is manual but ideally it should be automatic.
Here we’re
-
starting a RabbitMQ service in Cloud Foundry (only for the demo to pass - you should provision the prod environment in a different way)
-
deploying
Eureka
infrastructure application to Cloud Foundry (only for the demo to pass - you should provision the prod environment in a different way) -
downloading the fat jar from Nexus and we’re uploading it to Cloud Foundry
-
tagging the Git repo with
prod/${version}
tag -
in the
Complete switch over
we’re currently not doing anything but you could perform some tests on production or when doing blue / green deployment you could switch of one of the instances. This step is manual.
Concourse Pipeline
The repository contains an opinionated pipeline that will build and deploy - Github Webhook application.
All in all there are the following projects taking part in the whole microservice setup
for this demo.
-
Github-Analytics - the app that has a REST endpoint and uses messaging. Our business application.
-
Github Webhook - project that emits messages that are used by Github Analytics. Our business application.
-
Eureka - simple Eureka Server. This is an infrastructure application.
-
Github Analytics Stub Runner Boot - Stub Runner Boot server to be used for tests with Github Analytics. Uses Eureka and Messaging. This is an infrastructure application.
Step by step
If you want to just run the demo as far as possible using PCF Dev and Docker Compose
Below you can find optional steps needed to be taken when you want to customize the pipeline
Fork repos
You need to fork only these. That’s because only then will your user be able to tag and push the tag to repo.
Set up your local Maven to work with Artifactory
First, you have to ensure that this section is present under your ~/.m2/settings.xml
<server>
<id>artifactory-local</id>
<username>admin</username>
<password>password</password>
</server>
If you don’t have this file just copy the one under seed/settings.xml
or copy paste it from below
<?xml version="1.0" encoding="UTF-8"?>
<settings>
<servers>
<server>
<id>artifactory-local</id>
<username>admin</username>
<password>password</password>
</server>
</servers>
</settings>
Start Jenkins and Artifactory
Concourse + Artifactory can be ran locally. To do that just execute the
start.sh
script from this repo.
git clone https://github.com/spring-cloud/spring-cloud-pipelines
cd spring-cloud-pipelines/concourse
./setup-docker-compose.sh
./start.sh <IP_ADDRESS>
The setup-docker-compose.sh
script should be executed once only to allow
generation of keys.
The <IP_ADDRESS>
param is an example of an external URL of Concourse
(equal to Docker-Machine ip in this example).
Then Concourse will be running on port 8080
and Artifactory 8081
.
Deploy the infra JARs to Artifactory
git clone https://github.com/spring-cloud/spring-cloud-pipelines
cd spring-cloud-pipelines/concourse
./deploy_infra.sh
As a result both eureka
and stub runner
repos will be cloned, built
and uploaded to Artifactory.
Start PCF Dev
TIP: You can skip this step if you have CF installed and don’t want to use PCF Dev The only thing you have to do is to set up spaces.
|
Warning
|
It’s more than likely that you’ll run out of resources when you reach stage step. Don’t worry! Keep calm and clear some apps from PCF Dev and continue. |
You have to download and start PCF Dev. A link how to do it is available here.
The default credentials when using PCF Dev are:
username: user
password: pass
email: user
org: pcfdev-org
space: pcfdev-space
api: api.local.pcfdev.io
You can start the PCF dev like this:
cf dev start
You’ll have to create 3 separate spaces (email admin, pass admin)
cf login -a https://api.local.pcfdev.io --skip-ssl-validation -u admin -p admin -o pcfdev-org
cf create-space pcfdev-test
cf set-space-role user pcfdev-org pcfdev-test SpaceDeveloper
cf create-space pcfdev-stage
cf set-space-role user pcfdev-org pcfdev-stage SpaceDeveloper
cf create-space pcfdev-prod
cf set-space-role user pcfdev-org pcfdev-prod SpaceDeveloper
You can also execute the ./setup_spaces.sh
script to do this.
Setup the fly
CLI
You can click one of the icons (depending on your OS) to download fly
, which is the Concourse CLI. Once you’ve downloaded that (and maybe added to your PATH) you can run:
fly --version
If fly
is properly installed then it should print out the version.
Setup your credentials.yml
The repo comes with credentials-sample.yml
which is set up with sample data (most credentials) are set to be applicable for PCF Dev. Copy this file to a new file credentials.yml
(the file is added to .gitignore so don’t worry that you’ll push it with your passwords) and edit it as you wish. For our demo jus setup:
-
app-url
- url pointing to your forkedgithub-webhook
repo -
github-private-key
- your private key to clone / tag GitHub repos -
repo-with-jars
- the IP is set to the defaults for Docker Machine. You should update it to point to your setup
If you don’t have a Docker Machine just execute ./whats_my_ip.sh
script to
get an external IP that you can pass to your repo-with-jars
instead of the default
Docker Machine IP.
Below you can see what environment variables are required by the scripts. To the right hand side you can see the default values for PCF Dev that we set in the credentials-sample.yml
.
| Property Name | Property Description | Default value |
|---|---|---|
M2_SETTINGS_REPO_ID |
The id of server from Maven settings.xml |
artifactory-local |
CF_TEST_API_URL |
The URL to the CF Api for TEST env |
api.local.pcfdev.io |
CF_STAGE_API_URL |
The URL to the CF Api for STAGE env |
api.local.pcfdev.io |
CF_PROD_API_URL |
The URL to the CF Api for PROD env |
api.local.pcfdev.io |
CF_TEST_ORG |
Name of the org for the test env |
pcfdev-org |
CF_TEST_SPACE |
Name of the space for the test env |
pcfdev-space |
CF_STAGE_ORG |
Name of the org for the stage env |
pcfdev-org |
CF_STAGE_SPACE |
Name of the space for the stage env |
pcfdev-space |
CF_PROD_ORG |
Name of the org for the prod env |
pcfdev-org |
CF_PROD_SPACE |
Name of the space for the prod env |
pcfdev-space |
REPO_WITH_JARS |
URL to repo with the deployed jars |
Build the pipeline
Log in (e.g. for Concourse running at <IP_ADDRESS>
- if you don’t provide any value then localhos
is assumed). If you execute this script (it assumes that either fly
is on your PATH
or it’s in the same folder as the script is):
./login.sh <IP_ADDRESS>
Next run the command to create the pipeline.
./set-pipeline.sh
Then you’ll create a github-webhook
pipeline under the docker
alias, using the provided credentials.yml
file.
You can override these values in exactly that order (e.g. ./set-pipeline.sh some-project another-target some-other-credentials.yml
)
Run the github-webhook
pipeline
Login
main
team
concourse
user and changeme
password
play
button
+
sign to start a new build
FAQ
Can I use the pipeline for some other repos?
Sure! Just change the app-url
in credentials.yml
!
Will this work for ANY project out of the box?
Not really. This is an opinionated pipeline
that’s why we took some
opinionated decisions like:
-
usage of Spring Cloud, Spring Cloud Contract Stub Runner and Spring Cloud Eureka
-
application deployment to Cloud Foundry
-
For Maven:
-
usage of Maven Wrapper
-
artifacts deployment by
./mvnw clean deploy
-
stubrunner.ids
property to retrieve list of collaborators for which stubs should be downloaded -
running smoke tests on a deployed app via the
smoke
Maven profile -
running end to end tests on a deployed app via the
e2e
Maven profile
-
-
For Gradle (in the
github-analytics
application check thegradle/pipeline.gradle
file):-
usage of Gradlew Wrapper
-
deploy
task for artifacts deployment -
running smoke tests on a deployed app via the
smoke
task -
running end to end tests on a deployed app via the
e2e
task -
groupId
task to retrieve group id -
artifactId
task to retrieve artifact id -
currentVersion
task to retrieve the current version -
stubIds
task to retrieve list of collaborators for which stubs should be downloaded
-
This is the initial approach that can be easily changed in the future.
Can I modify this to reuse in my project?
Sure! It’s open-source! The important thing is that the core part of the logic is written in Bash scripts. That way, in the majority of cases, you could change only the bash scripts without changing the whole pipeline. You can check out the scripts here.
I ran out of resources!!
When deploying the app to stage or prod you can get an exception Insufficient resources
. The way to
solve it is to kill some apps from test / stage env. To achieve that just call
cf target -o pcfdev-org -s pcfdev-test
cf stop github-webhook
cf stop github-eureka
cf stop stubrunner
You can also execute kill_all_pcfdev_apps.sh
that will remove all demo-related apps
deployed to PCF dev.
The rollback step fails due to missing JAR ?!
You must have pushed some tags and have removed the Artifactory volume that contained them. To fix this, just remove the tags
git tag -l | xargs -n 1 git push --delete origin
Can I see the output of a job from the terminal?
Yes! Assuming that pieline name is github-webhook
and job name is build-and-upload
you can running
fly watch --job github-webhook/build-and-upload -t docker
I clicked the job and it’s constantly pending…
Don’t worry… most likely you’ve just forgotten to click the play
button to
unpause the pipeline. Click to the top left, expand the list of pipelines and click
the play
button next to github-webhook
.
Another problem that might occur is that you need to have the version
branch.
Concourse will wait for the version
branch to appear in your repo. So in order for
the pipeline to start ensure that when doing some git operations you haven’t
forgotten to create / copy the version
branch too.
The route is already in use
If you play around with Jenkins / Concourse you might end up with the routes occupied
Using route github-webhook-test.local.pcfdev.io
Binding github-webhook-test.local.pcfdev.io to github-webhook...
FAILED
The route github-webhook-test.local.pcfdev.io is already in use.
Just delete the routes
yes | cf delete-route local.pcfdev.io -n github-webhook-test
yes | cf delete-route local.pcfdev.io -n github-eureka-test
yes | cf delete-route local.pcfdev.io -n stubrunner-test
yes | cf delete-route local.pcfdev.io -n github-webhook-stage
yes | cf delete-route local.pcfdev.io -n github-eureka-stage
yes | cf delete-route local.pcfdev.io -n github-webhook-prod
yes | cf delete-route local.pcfdev.io -n github-eureka-prod
You can also execute the ./remove_routes.sh
script
I’m unauthorized to deploy infrastructure jars
Most likely you’ve forgotten to update your local settings.xml
with the Artifactory’s
setup. Check out this section of the docs and update your settings.xml
.
Jenkins DSL Pipeline
The repository contains job definitions and the opinionated setup pipeline using Jenkins Job Dsl plugin. Those jobs will form an empty pipeline and a sample, opinionated one that you can use in your company.
All in all there are the following projects taking part in the whole microservice setup
for this demo.
-
Github-Analytics - the app that has a REST endpoint and uses messaging. Our business application.
-
Github Webhook - project that emits messages that are used by Github Analytics. Our business application.
-
Eureka - simple Eureka Server. This is an infrastructure application.
-
Github Analytics Stub Runner Boot - Stub Runner Boot server to be used for tests with Github Analytics. Uses Eureka and Messaging. This is an infrastructure application.
Project setup
.
├── jobs
│ ├── jenkins_pipeline_empty.groovy
│ ├── jenkins_pipeline_jenkinsfile_empty.groovy
│ ├── jenkins_pipeline_sample.groovy
│ └── jenkins_pipeline_sample_view.groovy
├── seed
│ ├── gradle.properties
│ ├── init.groovy
│ ├── jenkins_pipeline.groovy
│ └── settings.xml
└── src
├── main
└── test
In the jobs
folder you have all the seed jobs that will generate pipelines.
-
jenkins_pipeline_empty.groovy
- is a template of a pipeline with empty steps using the Jenkins Job DSL plugin -
jenkins_pipeline_jenkinsfile_empty.groovy
- is a template of a pipeline with empty steps using the Pipeline plugin -
jenkins_pipeline_sample.groovy
- is an opinionated implementation using the Jenkins Job DSL plugin -
jenkins_pipeline_sample_view.groovy
- builds the views for the pipelines
In the seed
folder you have the init.groovy
file which is executed when Jenkins starts.

In the src
folder you have production and test classes needed for you to build your own pipeline.
Currently we have tests only cause the whole logic resides in the jenkins_pipeline_sample
file.
Step by step
If you want to just run the demo as far as possible using PCF Dev and Docker Compose
Below you can find optional steps needed to be taken when you want to customize the pipeline
Fork repos
You need to fork only these. That’s because only then will your user be able to tag and push the tag to repo.
Set up your local Maven to work with Artifactory
First, you have to ensure that this section is present under your ~/.m2/settings.xml
<server>
<id>artifactory-local</id>
<username>admin</username>
<password>password</password>
</server>
If you don’t have this file just copy the one under seed/settings.xml
or copy paste it from below
<?xml version="1.0" encoding="UTF-8"?>
<settings>
<servers>
<server>
<id>artifactory-local</id>
<username>admin</username>
<password>password</password>
</server>
</servers>
</settings>
Start Jenkins and Artifactory
Jenkins + Artifactory can be ran locally. To do that just execute the
start.sh
script from this repo.
git clone https://github.com/spring-cloud/spring-cloud-pipelines
cd spring-cloud-pipelines/jenkins
./start.sh yourGitUsername yourGitPassword yourForkedGithubOrg
Then Jenkins will be running on port 8080
and Artifactory 8081
.
The provided parameters will be passed as env variables to Jenkins VM
and credentials will be set in your set. That way you don’t have to do
any manual work on the Jenkins side. Also the REPOS
env variable will
contain your GitHub org in which you have the forked repos.
Deploy the infra JARs to Artifactory
git clone https://github.com/spring-cloud/spring-cloud-pipelines
cd spring-cloud-pipelines/jenkins
./deploy_infra.sh
As a result both eureka
and stub runner
repos will be cloned, built
and uploaded to Artifactory.
Start PCF Dev
|
Tip
|
You can skip this step if you have CF installed and don’t want to use PCF Dev The only thing you have to do is to set up spaces. |
|
Warning
|
It’s more than likely that you’ll run out of resources when you reach stage step. Don’t worry! Keep calm and clear some apps from PCF Dev and continue. |
You have to download and start PCF Dev. A link how to do it is available here.
The default credentials when using PCF Dev are:
username: user
password: pass
email: user
org: pcfdev-org
space: pcfdev-space
api: api.local.pcfdev.io
You can start the PCF dev like this:
cf dev start
You’ll have to create 3 separate spaces (email admin, pass admin)
cf login -a https://api.local.pcfdev.io --skip-ssl-validation -u admin -p admin -o pcfdev-org
cf create-space pcfdev-test
cf set-space-role user pcfdev-org pcfdev-test SpaceDeveloper
cf create-space pcfdev-stage
cf set-space-role user pcfdev-org pcfdev-stage SpaceDeveloper
cf create-space pcfdev-prod
cf set-space-role user pcfdev-org pcfdev-prod SpaceDeveloper
You can also execute the ./setup_spaces.sh
script to do this.
Run the seed job
We already create the seed job for you but you’ll have to run it. When you do run it you have to provide some properties. By default we create a seed that has all the properties options, but you can delete most of it. If you set the properties as global env variables you have to remove them from the seed.
Anyways, to run the demo just provide in the REPOS
var the comma separated
list of URLs of the 2 aforementioned forks of github-webhook
and `github-analytics'.
REPOS
parameter with URLs of your forks (you’ll have more properties than the ones in the screenshot)
Run the github-webhook
pipeline
We already create the seed job for you but you’ll have to run it. When you do run it you have to provide some properties. By default we create a seed that has all the properties options, but you can delete most of it. If you set the properties as global env variables you have to remove them from the seed.
Anyways, to run the demo just provide in the REPOS
var the comma separated
list of URLs of the 2 aforementioned forks of github-webhook
and github-analytics
.
|
Important
|
Most likely your 1st build will suddenly hang for 10 minutes. If you rerun it again it should work after 2-3 minutes. My guess is that it’s related to Docker Compose so sorry for this unfortunate situation. |
|
Important
|
If your build fails on the deploy previous version to stage due to missing jar, that means that you’ve forgotten to clear the tags in your repo. Typically that’s due to the fact that you’ve removed the Artifactory volume with deployed JAR whereas a tag in the repo is still pointing there. Check out this section on how to remove the tag. |
|
Important
|
Most likely you will run out of memory so when reaching the stage environment it’s good to kill all apps on test. Check out the FAQ section for more details! |
Optional steps
All the steps below are not necessary to run the demo. They are needed only when you want to do some custom changes.
Deploying infra jars to a different location
It’s enough to provide the distribution.management.release.url
system prop to Maven.
Example for deploying to Artifactory at IP <IP_ADDRESS>
Github Eureka:
git clone https://github.com/spring-cloud-samples/github-eureka
cd github-eureka
./mvnw clean deploy -Ddistribution.management.release.url=http://<IP_ADDRESS>:8081/artifactory/libs-release-local
Github Stub Runner:
git clone https://github.com/spring-cloud-samples/github-analytics-stub-runner-boot
cd github-analytics-stub-runner-boot
./mvnw clean deploy -Ddistribution.management.release.url=http://<IP_ADDRESS>:8081/artifactory/libs-release-local
Setup settings.xml for Maven deployment
|
Tip
|
If you want to use the default connection to the Docker version of Artifactory you can skip this step |
So that ./mvnw deploy
works with Artifactory from Docker we’re
already copying the missing settings.xml
file for you. It looks like this:
<server>
<id>artifactory-local</id>
<username>admin</username>
<password>password</password>
</server>
If you want to use your own version of Artifactory / Nexus you have to update
the file (it’s in seed/settings.xml
).
Setup Jenkins env vars
If you want to only play around with the demo that we’ve prepared you have to set ONE variable which is the REPOS
variable.
That variable needs to consists of comma separated list of URLs to repositories containing business apps. So you should pass your forked repos URLs.
You can do it in the following ways:
-
globally via Jenkins global env vars (then when you run the seed that variable will be taken into consideration and proper pipelines will get built)
-
modify the seed job parameters (you’ll have to modify the seed job configuration and change the
REPOS
property) -
provide the repos parameter when running the seed job
For the sake of simplicity let’s go with the last option.
|
Important
|
If you’re choosing the global envs, you HAVE to remove the other approach
(e.g. if you set the global env for REPOS , please remove that property in the
seed job
|
Seed properties
Click on the seed job and pick Build with parameters
. Then as presented in the screen below (you’ll have far more properties to set) just modify the REPOS
property by providing the comma separated list of URLs to your forks. Whatever you set will be parsed by the seed job and passed to the generated Jenkins jobs.
|
Tip
|
This is very useful when the repos you want to build differ. E.g. use
different JDK. Then some seeds can set the JDK_VERSION param to one version
of Java installation and the others to another one.
|
Example screen:
In the screenshot we could parametrize the REPOS
and REPO_WITH_JARS
params.
Global envs
|
Important
|
This section is presented only for informational purposes - for the sake of demo you can skip it |
You can add env vars (go to configure Jenkins → Global Properties) for the following properties (the defaults are for PCF Dev):
Example screen:
All env vars
The env vars that are used in all of the jobs are as follows:
| Property Name | Property Description | Default value |
|---|---|---|
GIT_NAME |
The name used by Git to tag repo |
Pivo Tal |
CF_TEST_API_URL |
The URL to the CF Api for TEST env |
api.local.pcfdev.io |
CF_STAGE_API_URL |
The URL to the CF Api for STAGE env |
api.local.pcfdev.io |
CF_PROD_API_URL |
The URL to the CF Api for PROD env |
api.local.pcfdev.io |
CF_TEST_ORG |
Name of the org for the test env |
pcfdev-org |
CF_TEST_SPACE |
Name of the space for the test env |
pcfdev-space |
CF_STAGE_ORG |
Name of the org for the stage env |
pcfdev-org |
CF_STAGE_SPACE |
Name of the space for the stage env |
pcfdev-space |
CF_PROD_ORG |
Name of the org for the prod env |
pcfdev-org |
CF_PROD_SPACE |
Name of the space for the prod env |
pcfdev-space |
REPO_WITH_JARS |
URL to repo with the deployed jars |
|
M2_SETTINGS_REPO_ID |
The id of server from Maven settings.xml |
artifactory-local |
JDK_VERSION |
The name of the JDK installation |
jdk8 |
PIPELINE_VERSION |
What should be the version of the pipeline (ultimately also version of the jar) |
1.0.0.M1-${GROOVY,script ="new Date().format('yyMMdd_HHmmss')"}-VERSION |
GIT_EMAIL |
The email used by Git to tag repo |
Set Git email / user
Since our pipeline is setting the git user / name explicitly for the build step
you’d have to go to Configure
of the build step and modify the Git name / email.
If you want to set it globally you’ll have to remove the section from the build
step and follow these steps to set it globally.
You can set Git email / user globally like this:
Jenkins Credentials
In your scripts we reference the credentials via IDs. These are the defaults for credentials
| Property Name | Property Description | Default value |
|---|---|---|
CF_PROD_CREDENTIAL_ID |
Credential ID for CF Prod env access |
cf-prod |
GIT_CREDENTIAL_ID |
Credential ID used to tag a git repo |
git |
CF_TEST_CREDENTIAL_ID |
Credential ID for CF Test env access |
cf-test |
CF_STAGE_CREDENTIAL_ID |
Credential ID for CF Stage env access |
cf-stage |
If you already have in your system a credential to for example tag a repo
you can use it by passing the value of the property GIT_CREDENTIAL_ID
Add Jenkins credentials for GitHub
You have to set credentials with id: git
.
Below you can find instructions on how to set a credential (e.g. for cf-test
credential but
remember to provide the one with id git
).
git
credential ID (in this example cf-test
)
Enable Groovy Token Macro Processing
With scripted that but if you needed to this manually then this is how to do it:
FAQ
Pipeline version contains ${PIPELINE_VERSION}
You can check the Jenkins logs and you’ll see
WARNING: Skipped parameter `PIPELINE_VERSION` as it is undefined on `jenkins-pipeline-sample-build`.
Set `-Dhudson.model.ParametersAction.keepUndefinedParameters`=true to allow undefined parameters
to be injected as environment variables or
`-Dhudson.model.ParametersAction.safeParameters=[comma-separated list]`
to whitelist specific parameter names, even though it represents a security breach
To fix it you have to do exactly what the warning suggests… Also ensure that the Groovy token macro processing
checkbox is set.
Pipeline version is not passed to the build
You can see that the Jenkins version is properly set but in the build version is still snapshot and
the echo "${PIPELINE_VERSION}"
doesn’t print anything.
You can check the Jenkins logs and you’ll see
WARNING: Skipped parameter `PIPELINE_VERSION` as it is undefined on `jenkins-pipeline-sample-build`.
Set `-Dhudson.model.ParametersAction.keepUndefinedParameters`=true to allow undefined parameters
to be injected as environment variables or
`-Dhudson.model.ParametersAction.safeParameters=[comma-separated list]`
to whitelist specific parameter names, even though it represents a security breach
To fix it you have to do exactly what the warning suggests…
The build times out with pipeline.sh
info
Docker compose, docker compose, docker compose… The problem is that for some reason, only in Docker, the execution of Java hangs. But it hangs randomly and only the first time you try to execute the pipeline.
The solution to this is to run the pipeline again. If once it suddenly, magically passes then it will pass for any subsequent build.
Another thing that you can try is to run it with plain Docker. Maybe that will help.
Can I use the pipeline for some other repos?
Sure! you can pass REPOS
variable with comma separated list of
project_name$project_url
format. If you don’t provide the PROJECT_NAME the
repo name will be extracted and used as the name of the project.
E.g. for REPOS
equal to:
will result in the creation of pipelines with root names github-analytics
and github-webhook
.
E.g. for REPOS
equal to:
foo$https://github.com/spring-cloud-samples/github-analytics,bar$https://github.com/spring-cloud-samples/atom-feed
will result in the creation of pipelines with root names foo
for github-analytics
and bar
for github-webhook
.
Will this work for ANY project out of the box?
Not really. This is an opinionated pipeline
that’s why we took some
opinionated decisions like:
-
usage of Spring Cloud, Spring Cloud Contract Stub Runner and Spring Cloud Eureka
-
application deployment to Cloud Foundry
-
For Maven:
-
usage of Maven Wrapper
-
artifacts deployment by
./mvnw clean deploy
-
stubrunner.ids
property to retrieve list of collaborators for which stubs should be downloaded -
running smoke tests on a deployed app via the
smoke
Maven profile -
running end to end tests on a deployed app via the
e2e
Maven profile
-
-
For Gradle (in the
github-analytics
application check thegradle/pipeline.gradle
file):-
usage of Gradlew Wrapper
-
deploy
task for artifacts deployment -
running smoke tests on a deployed app via the
smoke
task -
running end to end tests on a deployed app via the
e2e
task -
groupId
task to retrieve group id -
artifactId
task to retrieve artifact id -
currentVersion
task to retrieve the current version -
stubIds
task to retrieve list of collaborators for which stubs should be downloaded
-
This is the initial approach that can be easily changed in the future.
Can I modify this to reuse in my project?
Sure! It’s open-source! The important thing is that the core part of the logic is written in Bash scripts. That way, in the majority of cases, you could change only the bash scripts without changing the whole pipeline.
I ran out of resources!!
[jenkins_resources]] When deploying the app to stage or prod you can get an exception Insufficient resources
. The way to
solve it is to kill some apps from test / stage env. To achieve that just call
cf target -o pcfdev-org -s pcfdev-test
cf stop github-webhook
cf stop github-eureka
cf stop stubrunner
You can also execute kill_all_pcfdev_apps.sh
that will remove all demo-related apps
deployed to PCF dev.
The rollback step fails due to missing JAR ?!
You must have pushed some tags and have removed the Artifactory volume that contained them. To fix this, just remove the tags
git tag -l | xargs -n 1 git push --delete origin
I want to provide a different JDK version
-
by default we assume that you have jdk with id
jdk8
configured -
if you want a different one just override
JDK_VERSION
env var and point to the proper one
|
Tip
|
The docker image comes in with Java installed at /usr/lib/jvm/java-8-openjdk-amd64 .
You can go to Global Tools and create a JDK with jdk8 id and JAVA_HOME
pointing to /usr/lib/jvm/java-8-openjdk-amd64
|
To change the default one just follow these steps:
And that’s it!
I want deployment to stage and prod be automatic
No problem, just set the property / env var to true
-
AUTO_DEPLOY_TO_STAGE
to automatically deploy to stage -
AUTO_DEPLOY_TO_PROD
to automatically deploy to prod
I can’t tag the repo!
When you get sth like this:
19:01:44 stderr: remote: Invalid username or password.
19:01:44 fatal: Authentication failed for 'https://github.com/marcingrzejszczak/github-webhook/'
19:01:44
19:01:44 at org.jenkinsci.plugins.gitclient.CliGitAPIImpl.launchCommandIn(CliGitAPIImpl.java:1740)
19:01:44 at org.jenkinsci.plugins.gitclient.CliGitAPIImpl.launchCommandWithCredentials(CliGitAPIImpl.java:1476)
19:01:44 at org.jenkinsci.plugins.gitclient.CliGitAPIImpl.access$300(CliGitAPIImpl.java:63)
19:01:44 at org.jenkinsci.plugins.gitclient.CliGitAPIImpl$8.execute(CliGitAPIImpl.java:1816)
19:01:44 at hudson.plugins.git.GitPublisher.perform(GitPublisher.java:295)
19:01:44 at hudson.tasks.BuildStepMonitor$3.perform(BuildStepMonitor.java:45)
19:01:44 at hudson.model.AbstractBuild$AbstractBuildExecution.perform(AbstractBuild.java:779)
19:01:44 at hudson.model.AbstractBuild$AbstractBuildExecution.performAllBuildSteps(AbstractBuild.java:720)
19:01:44 at hudson.model.Build$BuildExecution.post2(Build.java:185)
19:01:44 at hudson.model.AbstractBuild$AbstractBuildExecution.post(AbstractBuild.java:665)
19:01:44 at hudson.model.Run.execute(Run.java:1745)
19:01:44 at hudson.model.FreeStyleBuild.run(FreeStyleBuild.java:43)
19:01:44 at hudson.model.ResourceController.execute(ResourceController.java:98)
19:01:44 at hudson.model.Executor.run(Executor.java:404)
most likely you’ve passed a wrong password. Check the credentials section on how to update your credentials.
Deploying to test / stage / prod fails - error finding space
If you receive a similar exception:
20:26:18 API endpoint: https://api.local.pcfdev.io (API version: 2.58.0)
20:26:18 User: user
20:26:18 Org: pcfdev-org
20:26:18 Space: No space targeted, use 'cf target -s SPACE'
20:26:18 FAILED
20:26:18 Error finding space pcfdev-test
20:26:18 Space pcfdev-test not found
It means that you’ve forgotten to create the spaces in your PCF Dev installation.
The route is already in use
If you play around with Jenkins / Concourse you might end up with the routes occupied
Using route github-webhook-test.local.pcfdev.io
Binding github-webhook-test.local.pcfdev.io to github-webhook...
FAILED
The route github-webhook-test.local.pcfdev.io is already in use.
Just delete the routes
yes | cf delete-route local.pcfdev.io -n github-webhook-test
yes | cf delete-route local.pcfdev.io -n github-eureka-test
yes | cf delete-route local.pcfdev.io -n stubrunner-test
yes | cf delete-route local.pcfdev.io -n github-webhook-stage
yes | cf delete-route local.pcfdev.io -n github-eureka-stage
yes | cf delete-route local.pcfdev.io -n github-webhook-prod
yes | cf delete-route local.pcfdev.io -n github-eureka-prod
You can also execute the ./remove_routes.sh
script
I’m unauthorized to deploy infrastructure jars
Most likely you’ve forgotten to update your local settings.xml
with the Artifactory’s
setup. Check out this section of the docs and update your settings.xml
.
How to build it
./gradlew clean build
|
Warning
|
The ran test only checks if your scripts compile. |
How to work with Jenkins Job DSL plugin
Check out the tutorial. Provide the link to this repository in your Jenkins installation.
|
Warning
|
Remember that views can be overridden that’s why the suggestion is to contain in one script all the logic needed to build a view
for a single project (check out that spring_cloud_views.groovy is building all the spring-cloud views).
|
How to build it
Build and test
You can execute
./gradlew clean build
to build and test the project.
Generate readme
To generate readme just run
./gradlew generateReadme


Technical blog from Craig Russell.
This article describes how to use Kotlin’s data classes to represent the view state of an Android Architectures Component ViewModel
Using a ViewModel
, we can represent the current state of the UI and pass this to an Activity which can render it. Using this architecture, an Activity will react to changes in the view state as they happen.
Since this view state is typically only changed by the ViewModel
, we can make it immutable as far as the Activity is concerned.
We can define the UI state as a Kotlin data class within our ViewModel
; we take this as a convenient place to add default values for each of the fields.
data class ViewState(
val isLoading: Boolean = false,
val progress: Int = 0,
val url: String? = null,
val isEditing: Boolean = false,
val browserShowing: Boolean = false,
val showClearButton: Boolean = false
)
Once defined like this, we can expose a LiveData
val viewState: MutableLiveData<ViewState> = MutableLiveData()
init {
viewState.value = ViewState()
}
private fun currentViewState(): ViewState = viewState.value!!
Above, we define the viewState
value which is observable, and we push a default value to it using the init
block. For convenience, we also define a private function that can be used in the ViewModel
to obtain the current view state at any time.
Technically viewState.value
is nullable, even though we know it won’t be since we’ve provided a default value upon creating, so this function saves the rest of the class from thinking about viewState.value
from ever being null. We need to use the ugly !!
syntax here, but it’s isolated to this one function and saves the rest of the view model from needing to handle nulls.
In the Activity we can subscribe to observing any changes to this view state.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_browser)
viewModel.viewState.observe(this, Observer<BrowserViewModel.ViewState> {
it?.let { render(it) }
})
}
private fun render(viewState: BrowserViewModel.ViewState) {
when (viewState.browserShowing) {
true -> webView.show()
false -> webView.hide()
}
when (viewState.isLoading) {
true -> pageLoadingIndicator.show()
false -> pageLoadingIndicator.hide()
}
when (viewState.showClearButton) {
true -> showClearButton()
false -> hideClearButton()
}
pageLoadingIndicator.progress = viewState.progress
}
Every time a change is pushed from the ViewModel
, our Activity immediately gets notified, and renders the UI accordingly.
So how do changes to the view state happen? Since we’ve defined the view state as being immutable, how do we change anything?
When the ViewModel
wants to make a change that the Activity will render, it copies the existing view state and changes only the values it needs to, preserving the existing values for the other fields.
override fun progressChanged(newProgress: Int) {
viewState.value = currentViewState().copy(progress = newProgress)
}
override fun loadingStarted() {
viewState.value = currentViewState().copy(isLoading = true)
}
override fun loadingFinished() {
viewState.value = currentViewState().copy(isLoading = false)
}
To update one or more view state properties, the ViewModel
grabs the current view state, as returned by currentViewState()
, and uses the copy method to set a new value on one or more fields.
The copy method is provided as part of the Kotlin data class
. When we use copy, all fields in the object remain as their original value unless you provide a new value.
It’s perfectly fine to define multiple fields that have changed in your view state as part of that copy method too, making it a convenient way of capturing changes. For example:
viewState.value = currentViewState().copy(isEditing = hasFocus, showClearButton = false)
Because viewState
is LiveData
, any time a new value is set using viewState.value
the Activity will immediately be notified that the UI state has changed and it will render the new UI.


Web Page HTML
This is web page stuff
Find a link to useful javascript web pages
JAVASCRIPT BASICS
W3Schools JAVASCRIPT
Javascript first steps
Modern Javascript
Speaking Javascript
A helpful javascript video
Javascript Tutorial: The very basics
| White | Orange |
| Black | Blue |
list of colours
- Orange
- White
- Black
- Blue
Fancy ones next:


--- layout: page title: About HMC Docs ---
We started this project to make sure that HMC has up-to-date documentation for all of its products. The product documentation revolves around 3 main categories:
In addition there will be a how-to section organized as posts or articles to produce something close to a knowledge base base.
This asset lives as a collection of documentation repositories in GitHub under an organization called HMCDOCS. This site is the public face for this organization and it has four sections: