tag:blogger.com,1999:blog-20948842596898030842024-03-05T20:39:22.317+08:00CWLAU's Dev BlogCode everything. Relax and simple.Unknownnoreply@blogger.comBlogger5125tag:blogger.com,1999:blog-2094884259689803084.post-6397008312949280742016-08-21T15:58:00.001+08:002016-08-21T16:54:33.424+08:00Google App Engine Continuous Integration with GitHub and CircleCIIn this blog post, I will share how to implement continuous integration with your GitHub repository for your Google App Engine application.<br />
<br />
<span class="section">First of all, what is Continuous Integration (CI)?</span>
In a normal process of a development cycle, developers will go through several steps, especially for GitHub as stated in <a href="https://guides.github.com/introduction/flow/" target="_blank">GitHub Flow</a>:<br />
<br />
Without CI yet:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiN_Xr-X3yyxuEjmSD8gFsckoAFQJJNcHyJcyRN67wkXRsSxFdv6od2w5osVorz7PsdSUtpPoi8DivsJAUCo7Dj5gigtriKXucGOEm3Mh9jCbPbc1B6KvtOUFbMJKIDgx0gEL8IQm2hJeOG/s1600/before_ci.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="109" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiN_Xr-X3yyxuEjmSD8gFsckoAFQJJNcHyJcyRN67wkXRsSxFdv6od2w5osVorz7PsdSUtpPoi8DivsJAUCo7Dj5gigtriKXucGOEm3Mh9jCbPbc1B6KvtOUFbMJKIDgx0gEL8IQm2hJeOG/s640/before_ci.png" width="640" /></a></div>
<br />
That sounds reasonable, right? However, it can be more perfect. With CI, developers can define test cases and run it automatically before deploying to production server. Also, CI also helps streamline the whole deployment process by triggering it automatically after code merge, instead of deploying by humans.<br />
<br />
With CI, you can do more as follows:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKghQw1-79O_BSz1701TZDkaaaeAu9G9xnv7LER_kwnzzDnQmQTL1NSMwQaGZS9QfC-VEJAQkUSxcqS-13ux9x0fvGoC4WpFgVAz-51pLuWfq0Mkrx-DTgaRn_GxCcLRzNQ6Rx6gDRvLrs/s1600/after_ci.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="89" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKghQw1-79O_BSz1701TZDkaaaeAu9G9xnv7LER_kwnzzDnQmQTL1NSMwQaGZS9QfC-VEJAQkUSxcqS-13ux9x0fvGoC4WpFgVAz-51pLuWfq0Mkrx-DTgaRn_GxCcLRzNQ6Rx6gDRvLrs/s640/after_ci.png" width="640" /></a></div>
<br />
<span class="section">Continuous Integration service providers</span>
There are several service providers of Continuous Integration, such as <a href="https://circleci.com/" target="_blank">CircleCI</a>, <a href="https://travis-ci.org/" target="_blank">Travis CI</a>, etc. Some of them offers free package for open source projects. If you have an open source projects, it is worth a try.<br />
<br />
In this blog post, the main focus is on CI with CircleCI.<br />
<br />
<span class="section">CI for Google App Engine</span>
<i>I have created <a href="https://github.com/cwlau/gae-circleci-integration" target="_blank">this GitHub repository</a> as an working example to demonstrate how to setup CI with Google App Engine from a GitHub repo. The detailed steps are listed in the GitHub repo. Fork it to have a try!</i><br />
<br />
Here are some points to note:<br />
<ul>
<li>You will need to create an CircleCI account by granting access for it to retrieve all of your repos. You may wish to create a separate GitHub account to manage your repos under different organizations.</li>
<li>The example only compiles a <pre class="code inline">webapp2</pre>
application in GAE. If your application needs more packages installed for a test, you will need to edit the content of file circle.yml (<pre class="code inline">dependencies</pre>
> <pre class="code inline">pre</pre>
)
</li>
</ul>
<br />
<span class="section">CircleCI Badge for your GitHub repo</span>
You can add this in the README.md of your GitHub repo:
<br />
<pre class="code html inline" style="white-space: normal;">![](https://circleci.com/gh/<owner>/<repo>.png?&style=shield&circle-token=<YOUR TOKEN HERE>)</pre>
<br />
Find more about the badges in the <a href="https://circleci.com/docs/status-badges/" target="_blank">CircleCI documentation</a>.
<br />
<span class="section">Summary</span>
After reading this blog post, you should understand the basic idea of how to setup continuous integration for your GAE application with CircleCI and your GitHub repo.
<br />
<br />
The demo repo is a very simple application without any functionality. In reality, you may need to take care of your application by defining more complex test cases to ensure it works.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2094884259689803084.post-27257309947688827852015-12-08T00:07:00.000+08:002016-08-21T16:58:49.601+08:00More details on Google App Engine os.environ attributesWe can use python <pre class="code python inline">os</pre>
package in Google App Engine to obtain some useful information for the request. <a href="http://blog.cwlau.com/2015/09/how-to-obtain-user-geolocation-with.html" target="_blank">As mentioned, we can obtain user geolocation of a user.</a> Actually, there is a lot more we can do with it.
<br />
<br />
<a href="http://code.cwlau.com/demo/os_environ" target="_blank">A LIVE DEMO is available</a>. The demo contains a full list of <pre class="code python inline">os.environ</pre> keys and their corresponding values. Some values are not publicly disclosed, but you can try it in your own application.
<br />
<br />
The values are accessed with <pre class="code python inline">os.environ[key]</pre>
with <pre class="code python inline">key</pre> value available, such as <pre class="code python inline">HTTP_USER_AGENT</pre> and <pre class="code python inline">REMOTE_ADDR</pre>
. However, some of the App Engine-specific keys such as <pre class="code python inline">USER_EMAIL</pre>
and <pre class="code python inline">HTTP_X_APPENGINE_COUNTRY</pre>
, only exist in the GAE environment.
<br />
<br />
The following section comes with the complete source code.
<br />
<br />
<script src="https://gist.github.com/cwlau/7523aa06f6ffbbc7f8dc.js"></script>
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2094884259689803084.post-85106937707341556252015-11-16T12:49:00.000+08:002018-08-31T15:36:34.676+08:0010 Essential Atom Packages for Sublime Text users<a href="https://atom.io/" target="_blank">Atom</a> is a Text Editor published by <a href="https://github.com/" target="_blank">GitHub</a>. If you are new to development, or would like to give another editor a try, Atom is a good choice for you.<br/><br/>
The benefits of using Atom:<br/>
- It is free,<br/>
- Atom allows customization by installing packages/ themes,<br/>
- Atom is available on Windows, Mac and Linux,<br/>
<br/>
I was used to <a href="https://www.sublimetext.com/" target="_blank">Sublime Text</a> for my development work. In order to make Atom my favourite one, I conducted a short research about some useful packages in Atom and somehow made it more similar to Sublime Text.
<br/><br/>
The followings are 10 essential Atom packages available at <a href="https://atom.io/packages" target="_blank">Atom Package List</a>.
<br/>
<span class="section">1. pigments</span>
Supports color highlighting.<br/><br/>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiIFatHabjpySun3fCO1y41tG8RX9ewm89Vrw26fx6mAP3ulDKz8QHF0z1s1md_L8jOoB3a5v524nDzanVXk4cZwsgg9qtf-J3BK_I-ASrlEMxGTbwVbZPhLsp9cGqWY-zQzDSkf6RxNQl/s1600/atom_pigment_img.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiIFatHabjpySun3fCO1y41tG8RX9ewm89Vrw26fx6mAP3ulDKz8QHF0z1s1md_L8jOoB3a5v524nDzanVXk4cZwsgg9qtf-J3BK_I-ASrlEMxGTbwVbZPhLsp9cGqWY-zQzDSkf6RxNQl/s640/atom_pigment_img.png" /></a>
<a href="https://atom.io/packages/pigments" target="_blank">https://atom.io/packages/pigments</a>
<br/>
<span class="section">2. color-picker</span>
Pick a color in the editor with a right-click.<br/><br/>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixSwkC7z3Y_kR6p1Qui2bmm2LEM7yuRU3fOBJOqv9IamTR43gSdfT_MWwMmGoqiZTeEDRTIB-LYZbPZy3z2VpEpD6RFmwuKR0e3pHJVXuSReeRMXRXSTqAKwkXKgI3XjJf1YmwMkG8aIAi/s1600/atom_colorpicker_img.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixSwkC7z3Y_kR6p1Qui2bmm2LEM7yuRU3fOBJOqv9IamTR43gSdfT_MWwMmGoqiZTeEDRTIB-LYZbPZy3z2VpEpD6RFmwuKR0e3pHJVXuSReeRMXRXSTqAKwkXKgI3XjJf1YmwMkG8aIAi/s640/atom_colorpicker_img.png" /></a>
<a href="https://atom.io/packages/color-picker" target="_blank">https://atom.io/packages/color-picker</a>
<br/>
<span class="section">3. minimap</span>
While Sublime Text supports minimap by default, we need to manually install this package in Atom to have minimap.<br/><br/>
<a href="https://atom.io/packages/minimap" target="_blank">https://atom.io/packages/minimap</a>
<br/>
<span class="section">4. highlight-selected</span>
This package helps to highlight repeated words. Use Ctrd+D to select the next occurance of the word.<br/><br/>
<a href="https://atom.io/packages/highlight-selected" target="_blank">https://atom.io/packages/highlight-selected</a><br/>
<a href="https://atom.io/packages/minimap-highlight-selected" target="_blank">https://atom.io/packages/minimap-highlight-selected</a>
<br/>
<span class="section">5. markdown-preview-plus</span>
This package provides a real-time preview of markdown documents.<br/><br/>
<a href="https://atom.io/packages/markdown-preview-plus" target="_blank">https://atom.io/packages/markdown-preview-plus</a>
<br/>
<span class="section">6. autoclose-html</span>
This package enables auto-closing html tags in HTML documents.<br/><br/>
<a href="https://atom.io/packages/autoclose-html" target="_blank">https://atom.io/packages/autoclose-html</a>
<br/>
<span class="section">7. file-icons</span>
Adds colourful file specific icons for improved visual grepping in Tree View, Fuzzy Finder and Tabs<br/><br/>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9pxgQpphW_BG-z2lLLLVKdjV0VfPka7QWDPgXb6nAps0FTHExInvwwFJR17eP4uCXphlV5Ft65JtRKHn9QNUeDUnsTWVzUMFfrUybc1-yuAG-zilZwIrdUGTmKseehrUKVBGftC4tHOZc/s1600/atom_fileicons.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9pxgQpphW_BG-z2lLLLVKdjV0VfPka7QWDPgXb6nAps0FTHExInvwwFJR17eP4uCXphlV5Ft65JtRKHn9QNUeDUnsTWVzUMFfrUybc1-yuAG-zilZwIrdUGTmKseehrUKVBGftC4tHOZc/s640/atom_fileicons.png" /></a>
<a href="https://atom.io/packages/file-icons" target="_blank">https://atom.io/packages/file-icons</a>
<br/>
<span class="section">8. merge-conflicts</span>
Lets you resolve your git merge conflicts in Atom.<br/><br/>
<a href="https://atom.io/packages/merge-conflicts" target="_blank">https://atom.io/packages/merge-conflicts</a>
<br/>
<span class="section">9. sublime-style-column-selection</span>
This package adds back one of my favourite functions in Sublime Text -- Column select. With this package, we can hold Alt key and mouse select columns of text.<br/><br/>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSrN3ko1c2lOke9l3W_OuLVPF_GAXA22J2u6paFBOqQmCvRG_VQtb-AhoNR6t1uT4ovpryGfOMYkMY37Srevj2qhEY92HcG2-0RDTDjY6nLVSuxjswjBwa2laeX8OQ_f9DFq3N1LHyIWID/s1600/atom_column_select_img.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSrN3ko1c2lOke9l3W_OuLVPF_GAXA22J2u6paFBOqQmCvRG_VQtb-AhoNR6t1uT4ovpryGfOMYkMY37Srevj2qhEY92HcG2-0RDTDjY6nLVSuxjswjBwa2laeX8OQ_f9DFq3N1LHyIWID/s640/atom_column_select_img.png" /></a>
<a href="https://atom.io/packages/sublime-style-column-selection" target="_blank">https://atom.io/packages/sublime-style-column-selection</a>
<br/>
<span class="section">10. slush-poppies</span>
This is my favourite theme used in Sublime Text. Together with this theme I also changed my UI Theme settings to "One Light".<br/><br/>
<a href="https://atom.io/packages/slush-poppies" target="_blank">https://atom.io/packages/slush-poppies</a>
<br/>
<br/>
<br/>
What is your favourite Package in Atom? Leave me a comment below!
<br/>
<br/>
Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-2094884259689803084.post-8273773681192258952015-10-14T14:56:00.001+08:002018-08-31T15:48:16.150+08:00How to center a HTML Popup dialog with CSSIn order to create a CSS-only auto-centered dialog, a few steps have to be done.<br />
<br />
The first step is to add CSS <pre class="code css inline">position: fixed;</pre> to the target element with its <pre class="code css inline">top</pre> and <pre class="code css inline">left</pre> attributes both equal to <pre class="code css inline">50%</pre>.
<br /><br />
The target element now appears like this:
<br/><br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmHUkY4EJLfsiYd1ihiSYuxPwIqx7LcB5xpCCTFsVM7Jnd7aVYOrnVYEQYkoE49jkZOPb9CxehER_vEKed-uqIiEDXtgWPse09Sb0zvTQS3EXoPhyy43wxx6Pak6kiiHfmizGeM9I8YtB3/s1600/layout_1.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmHUkY4EJLfsiYd1ihiSYuxPwIqx7LcB5xpCCTFsVM7Jnd7aVYOrnVYEQYkoE49jkZOPb9CxehER_vEKed-uqIiEDXtgWPse09Sb0zvTQS3EXoPhyy43wxx6Pak6kiiHfmizGeM9I8YtB3/s640/layout_1.png" /></a>
<br /><br />
There is a problem -- setting left and top to 50% does not make it centered. Instead, the element shifted a bit from the center. To solve this, finish step 2 below.
<br /><br />
The next step is to adjust the extra pixels shifted from the center. We can set its <pre class="code css inline">margin-left</pre> and <pre class="code css inline">margin-top</pre> to -1*(its width) and -1*(its height) respectively. For instance, a <pre class="code html inline">div</pre> with width:400px should set <pre class="code css inline">margin-left: -200px</pre>. With this approach, the element shifts back to center and keeps centered all the time.
<br /><br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhaLj6fyy5-IilyoLXbcD9WNEyo4-aR8fHC1hi5GxSEXcLDpnC92wqEVIcWJsEr2ACqUq67WtzHiUzVcKkKWQUmZVXu1mMaGakWQe0VPvAnyer9qP_1OVbGCfoOFLmzTIYBmd6MoJmdDXv/s1600/layout_2.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhaLj6fyy5-IilyoLXbcD9WNEyo4-aR8fHC1hi5GxSEXcLDpnC92wqEVIcWJsEr2ACqUq67WtzHiUzVcKkKWQUmZVXu1mMaGakWQe0VPvAnyer9qP_1OVbGCfoOFLmzTIYBmd6MoJmdDXv/s640/layout_2.png" /></a>
<br /><br />
<span class="tips">Note: The element width and height should be a fixed value.</span>
<br /><br />
The following code summarizes the demo:<br />
<br />
<script src="https://gist.github.com/cwlau/7eed31d8dc3090ebb198.js"></script>
<br />
Here is a <a href="https://code.cwlau.com/demo/html/fixed_dialog.html" target="_blank">Live Demo</a> of this example.
<br /><br />
<i>Update 7 Nov 2015: Updated source code section to GitHub version</i>
<br/>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2094884259689803084.post-10780500724934072602015-09-09T00:57:00.000+08:002016-08-21T16:57:17.501+08:00How to obtain user geolocation with Google App EngineSometimes it is good to provide a better user experience by obtaining geolocation of a user. In Google App Engine, we can use the information in python <pre class="code python inline">os</pre> package to achieve this:<br />
<br />
Get the current city of a user:
<br />
<br />
<script src="https://gist.github.com/cwlau/02e511cb3f23a2dc9c44.js?file=city.py"></script>
Get the current country of a user (Will return a <a href="https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2" target="_blank">ISO 3166-1 alpha-2</a> country code):
<br />
<br />
<script src="https://gist.github.com/cwlau/02e511cb3f23a2dc9c44.js?file=country.py"></script>
Note: If App Engine fails to supply a city name or country code, the output will be the second argument supplied to the <pre class="code python inline">os.environ.get()</pre>function call.
<br />
<br />
Update 13 Oct 2015: Added a <a href="http://code.cwlau.com/demo/geolocation" target="_blank">Demo link</a>
<br />
<br />
<i>Update 7 Nov 2015: Added complete source code.</i>
<br />
<script src="https://gist.github.com/cwlau/02e511cb3f23a2dc9c44.js?file=geolocation.py"></script>
Unknownnoreply@blogger.com1