Port to hugo.

This commit is contained in:
2020-04-11 12:52:15 +05:30
parent 020a5dbc5f
commit 8c86399952
23 changed files with 105 additions and 823 deletions

View File

@@ -0,0 +1,172 @@
+++
title = "React Native with Gitlab CI/CD"
date = "2020-04-06"
author = "Ceda EI"
authorTwitter = "" #do not include @
cover = ""
tags = ["react-native", "javascript", "gitlab"]
keywords = ["react-native", "javascript", "gitlab", "ci", "cd"]
description = "Recently, I decided to set up automated builds for [Sonzai](https://gitlab.com/ceda_ei/sonzai.git)."
showFullContent = false
+++
## Introduction
The aim of setting up CI/CD is to automatically build the app on every commit
and send the APK. I looked into Gitlab CI/CD for this purpose since my [project
repository](https://gitlab.com/ceda_ei/sonzai/) is already hosted on Gitlab.
## Build Stage
To get started, I needed to choose a docker image in which the repo would be
built. After looking around a bit, I found that the
[react-native-community](https://github.com/react-native-community/) has an
official [Docker
image](https://hub.docker.com/r/reactnativecommunity/react-native-android), the
source of which can be found on
[GitHub](https://github.com/react-native-community/docker-android).
Gitlab CI/CD is controlled by a versioned file in the repo: `.gitlab-ci.yml`.
To start off, I added the `build` job in the file and set image to the docker
image above.
```yml
stages:
- build
build:
image: reactnativecommunity/react-native-android
stage: build
```
I needed to add the commands to be executed in order to build the app. Those
commands are added under the `script` key as an array. In my case, I need to
run `yarn install` to install all dependencies followed by `./gradlew
assembleRelease` in the `android` directory. The file now looks like.
```yml
stages:
- build
build:
image: reactnativecommunity/react-native-android
stage: build
script:
- yarn install
- cd android && chmod +x gradlew
- ./gradlew assembleRelease
```
Next, once the build is done, I need to export the `outputs` generated in the
build to be consumed by the deploy stage. This is done by adding an `artifacts`
object which contains a `path` array for all the paths that need to be included
in the artifacts. In this case, the outputs are in
`android/app/build/outputs/`. The file now looks like:
```yml
stages:
- build
- deploy
build:
image: reactnativecommunity/react-native-android
stage: build
script:
- yarn install
- cd android && chmod +x gradlew
- ./gradlew assembleRelease
artifacts:
paths:
- android/app/build/outputs/
```
The build stage is now done.
## Deploy Stage
Although I could use the same image, the image is fairly large and takes time
to initialize. So, I used
[curlimages/curl](https://hub.docker.com/r/curlimages/curl) which is an alpine
image with curl added and thus is really light. I will be using `curl` to
upload the file to Telegram. Check out the
[documentation](core.telegram.org/bots/api) for bots API. Adding the deploy
stage, the file looks as:
```yml
stages:
- build
- deploy
build:
image: reactnativecommunity/react-native-android
stage: build
script:
- yarn install
- cd android && chmod +x gradlew
- ./gradlew assembleRelease
artifacts:
paths:
- android/app/build/outputs/
deploy_tg:
image: curlimages/curl
stage: deploy
```
I created a bot via [@BotFather](https://t.me/BotFather) and added it to a
[channel](https://t.me/sonzai_builds). Next, I got the channel's chat ID. I
stored the Bot Token and the channel's chat ID as variables in Gitlab's UI
under Repository > Settings > CI / CD > Variables as `TG_BOT_TOKEN` and
`TG_CHAT_ID` respectively.
![Gitlab's UI screenshot](/gitlab-ci.jpg)
Next, I added a curl request in the script array to make the actual request to
Telegram Bot API which utilizes these variables. It also utilizes some
predefined variables in [Gitlab's default
environment](https://gitlab.com/help/ci/variables/predefined_variables.md).
Here is the final `.gitlab-ci.yml`
```yml
stages:
- build
- deploy
build:
image: reactnativecommunity/react-native-android
stage: build
script:
- yarn install
- cd android && chmod +x gradlew
- ./gradlew assembleRelease
artifacts:
paths:
- android/app/build/outputs/
deploy_tg:
image: curlimages/curl
stage: deploy
script:
- >-
curl
-F chat_id=$TG_CHAT_ID
-F document=@android/app/build/outputs/apk/release/app-release.apk
-F caption=" <b>Branch</b>: <code>$CI_COMMIT_BRANCH</code>
<b>Commit</b>: <code>$CI_COMMIT_SHORT_SHA</code>
<b>Tag(if any)</b>: <code>$CI_COMMIT_TAG</code>
<code>$CI_COMMIT_MESSAGE</code>"
-F parse_mode=html
https://api.telegram.org/bot${TG_BOT_TOKEN}/sendDocument
```
Here is the first build using this.
{{< rawhtml >}}
<script async src="https://telegram.org/js/telegram-widget.js?7" data-telegram-post="sonzai_builds/8" data-width="100%"></script>
{{< /rawhtml >}}

214
content/posts/vim-folds.md Normal file
View File

@@ -0,0 +1,214 @@
+++
title = "Sorting VCF files with Vim folds"
date = "2019-07-23"
author = "Ceda EI"
authorTwitter = "" #do not include @
cover = ""
tags = ["vim", "neovim"]
keywords = ["vim", "neovim", "folds"]
description = "A while ago I wanted to sort my contacts which had become a mess. I wanted to use this opportunity to do something nice with Vim too. Enter Vim-folds."
showFullContent = false
+++
## Getting Started
I initiated a repository for the plugin.
```sh
cd ~/repos/
git init vcf.Vim
```
I use [Vim-plug](https://github.com/junegunn/Vim-plug) for package management
in Vim and added that to `Vim-plug`
```Vim
Plug '~/repos/vcf.Vim/'
```
Next, I exported all my contacts into a Virtual Contact File.
## Filetype Detection
To get started I needed Vim to assign a filetype to VCFs. A small `autocmd` is
enough to take care of that. By convention, filetype detection files go in
`ftdetect` directory.
`ftdetect/vcf.Vim`
```Vim
au BufNewFile,BufRead *.vcf set filetype=vcf
```
This sets the filetype of all files with filenames ending with `.vcf` to `vcf`
## Folding
Plugins for specific filetypes are stored in the `ftplugin` directory. Vim
sources the file if the filetype matches the filename without the `.vim`
extension e.g. if the filetype is set to `javascript`, `javascript.vim` in
`ftplugin` directory will be sourced.
Each contact in a VCF looks like this:
```vcf
BEGIN:VCARD
VERSION:2.1
N:Lname;Fname;;;
FN:Fname Lname
TEL;VOICE:+911234567890
END:VCARD
```
I want my folds to look like
```vcf
Fname Lname····································
```
I am going to use `expr` foldmethod. This can simply be done using `set
foldmethod=expr`. What this tells vim is to run a function on every line and
set the fold level based on that. To set the expression to run, we use `set
foldexpr=OurFunction()`.
Let's write a function first and set `foldexpr` to it. Define the function by
the usual syntax.
```vim
function! VCFFold()
endfunction
set foldmethod=expr
set foldexpr=VCFFold()
```
When the function is run, vim sets a special variable `v:num` that tells us
which line the function is being run on. To get the current line, we use the
`getline` function.
```vim
let thisline = getline(v:lnum)
```
We want to start a new level fold at every line which starts with `BEGIN`. For
all the other lines, we want to keep the same fold level as previous line since
we don't have nested folds in VCF. Vim folds with expr work by running the
function on each line and determining the fold level of that line based on the
return value of that function. Some of the return values are:
+ `>n` - This tells vim to start a new `n`th level fold there
+ `=` - This tells vim that the fold level is same as previous line.
+ `n` - This tells vim that the fold level is `n`
There are more return values. Check `:help fold-expr`
We can simply set the fold level to `>1` at every `BEGIN` and set it to `=` on
every other line. This way, every contact will end up in a fold starting at the
`BEGIN` of every contact. We can simply use `match` function to check if the
line begins with `BEGIN` and return `>1` in that case, else we will return `=`.
```vim
if match(thisline, '^BEGIN') >= 0
return ">1"
endif
return "="
```
Putting it all together, we get.
```vim
function! VCFFold()
let thisline = getline(v:lnum)
if match(thisline, '^BEGIN') >= 0
return ">1"
endif
return "="
endfunction
set foldmethod=expr
set foldexpr=VCFFold()
```
## Fold Text
To set the fold text, we have to set the `foldtext` to a function. Let's create
a funtion named `VCFFoldText` for this purpose and set `foldtext` to it.
```vim
function! VCFFoldText()
endfunction
set foldtext=VCFFoldText()
```
The name is stored as a line `N:Lname;Fname;;;`. Two special variables set for
foldtext function are `v:foldstart` and `v:foldend` which are the line numbers
where the current fold starts and ends. We can iterate from `v:foldstart` to
`v:foldend` using the range function. While iterating, we can simply look for a
line that begins with `N:` and return the name from it. If we don't find any
such line, we can return `No Name`.
```vim
function! VCFFoldText()
for i in range(v:foldstart, v:foldend)
let l:thisline = getline(i)
if match(l:thisline, '^N:') >= 0
" Return the string here
endif
endfor
return "No Name"
endfunction
```
All we need to do is split the parts on semi-colons and join that array back
depending on our preferences of whether we want first name first or last name
first. In my case I want first name first.
```vim
let l:parts = split(l:thisline, ';')
return substitute(join(l:parts[1:], " ") . l:parts[0][2:], '\s\+', ' ', 'g')
```
`split` splits the string into an array with the second parameter (`;` in this
case) as delimiter. I then join all the elements from first element (skipping
the zeroth element which is the last name) and then append the zeroth element
without the first two characters (since those are `N:`). Finally, I replace
multiple spaces with one space.
## Complete Program
```vim
function! VCFFold()
let thisline = getline(v:lnum)
if match(thisline, '^BEGIN') >= 0
return ">1"
endif
return "="
endfunction
set foldmethod=expr
set foldexpr=VCFFold()
function! VCFFoldText()
for i in range(v:foldstart, v:foldend)
let l:thisline = getline(i)
if match(l:thisline, '^N:') >= 0
let l:parts = split(l:thisline, ';')
return substitute(join(l:parts[1:], " ") . l:parts[0][2:], '\s\+', ' ', 'g')
endif
endfor
return "No Name"
endfunction
set foldtext=VCFFoldText()
```
## Installation
If you just want the above program, it is available as
[vcf.vim](https://gitlab.com/ceda_ei/vcf.vim). You can install it with
[Vim-plug](https://github.com/junegunn/Vim-plug) via:
```vim
Plug 'https://gitlab.com/ceda_ei/vcf.vim.git'
```