Azure DevOps: CI/CD IaC with YAML Pipeline

Sign in to your organisation (https://dev.azure.com/{yourorganization})

Azure DevOps looks like the following screenshot.

Find more details about key consepts in Azure Pipelines Key Concepts

Find more details about extending Azure Pipelines Templates in Azure Pipelines Templates

Find more details about Azure template parameters in Azure Pipeline Template Parameters

Find more details about Azure template predefined variables in Azure Pipeline Template Predefined Variables

Find more details about Azure template script variables in Azure Pipeline Template Script Variables

Find more details about usage of expressions in Azure Pipelines Expressions

In a pipeline, template expression variables (${{ variables.var }}) get processed at compile time, before runtime starts. Macro syntax variables ($(var)) get processed during runtime before a task runs. Runtime expressions ($[variables.var]) also get processed during runtime but are intended to be used with conditionsand expressions

Find more details about usage of Azure template variables in Azure Pipeline Template Variable Usage

Azure DevOps Organizations Page

Continue reading

Azure DevOps REST API

When we need to create, retrieve, update or delete access to the Azure DevOps services's resources, we can use Azure DevOps REST API.

Find more Azure DevOps REST services in https://docs.microsoft.com/en-us/rest/api/azure/devops/?view=azure-devops-rest-7.1

Process REST API

Get Process Id in your organization

Find more details in https://docs.microsoft.com/en-us/rest/api/azure/devops/core/processes/list?view=azure-devops-rest-7.1

ORGANIZATION=$1

PROCESS_NAME=$2

PAT=$3

curl --silent --user :$PAT \
--request GET "https://dev.azure.com/$ORGANIZATION/_apis/process/processes?api-version=6.0" | jq -r '.value[] | select(.name=="'$PROCESS_NAME'") | .id'
$ . ./getProcessId.sh kenanhancer Agile blablabla

adcc42ab-9882-485e-a3ed-7678f01f66bc

Get Process in your organization

Find more details in https://docs.microsoft.com/en-us/rest/api/azure/devops/core/processes/get?view=azure-devops-rest-7.1

echo -n "Organization: " && read ORGANIZATION

echo -n "Process Name: " && read PROCESS_NAME

echo -n "PAT: " && read PAT

PROCESS_ID=$(. ./getProcessId.sh $ORGANIZATION $PROCESS_NAME $PAT)

curl --silent --user :$PAT \
--request GET "https://dev.azure.com/$ORGANIZATION/_apis/process/processes/$PROCESS_ID?api-version=6.0" | jq -r .
$ . ./getProcess.sh
Organization: kenanhancer
Process Name: Agile
PAT: blablabla

{
  "id": "adcc42ab-9882-485e-a3ed-7678f01f66bc",
  "description": "This template is flexible and will work great for most teams using Agile planning methods, including those practicing Scrum.",
  "isDefault": true,
  "_links": {
    "self": {
      "href": "https://dev.azure.com/kenanhancer/_apis/process/processes/adcc42ab-9882-485e-a3ed-7678f01f66bc"
    }
  },
  "type": "system",
  "url": "https://dev.azure.com/kenanhancer/_apis/process/processes/adcc42ab-9882-485e-a3ed-7678f01f66bc",
  "name": "Agile"
}
Continue reading

Azure DevOps: Creating Personal Access Token (PAT)

Sign in to your organisation (https://dev.azure.com/{yourorganization})

Treat and use a PAT like your password and keep it a secret.

Use your PAT anywhere your user credentials are required for authentication in Azure DevOps.

You can use a personal access token (PAT) as an alternate password to authenticate into Azure DevOps.

A personal access token contains your security credentials for Azure DevOps. A PAT identifies you, your accessible organizations, and scopes of access. As such, they're as critical as passwords, so you should treat them the same way.

If you're working within Microsoft tools, then your Microsoft account (MSA) or Azure Active Directory (Azure AD) is an acceptable and well-supported approach. But, if you're working with third-party tools that don't support Microsoft or Azure AD accounts – or you don't want to provide your primary credentials to the tool – use PATs to limit your risk.

find more details about creating PAT in Azure DevOps

Continue reading

Linux Bash: Language Basics

I will not write all story here but people were using Teleprinter (Teletypewriter, Teletype, TTY) from 1830s and 1840s. As seen in the following pictures, it was an electromechanical device used for communicating text over telegraph lines etc. There wasn't any monitor, output was written in a paper. Some models were creating punched tape for data storage (either from typed input or from data received from a remote source) and read back such tape for local printing or transmission.

Nowadays, we use computers with monitor and operating system but Linux still uses TTY concept under the hood 🙂

You can find some diagrams below relation with Terminal Emulator and TTY

Teletypewriter(Teletype, Teleprinter or TTY)
A restored 1930s Teletype is now a Linux TTY
A Teletype Model 32 ASR used for Telex service
Video terminals like the DEC VT-100 (1978) made teletypes obsolete as computer I/O devices
Terminal Emulator (Pseudo type writer or PTY)
Each Terminal Emulator window attached to separate TTY as shown in the above screenshot.
Continue reading

TypeScript Recursive Type

Below two code blocks are doing same job and the only difference is below second code block uses variadic tuple. Check the below links for more details.

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#more-recursive-type-aliases

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-1.html#recursive-conditional-types

type CompareLength<Left extends any[], Right extends any[]> =
    Left['length'] extends Right['length'] ? 'equal' :
    Left extends [] ? 'shorterLeft' :
    Right extends [] ? 'shorterRight' :
    ((..._: Left) => any) extends ((_: any, ..._1: infer LeftRest) => any) ?
    ((..._: Right) => any) extends ((_: any, ..._1: infer RightRest) => any) ?
    CompareLength<LeftRest, RightRest> :
    never :
    never;

type T1 = CompareLength<[firstName: string], [lastName: string]>;

type T2 = CompareLength<[firstName: string], [lastName: string, age: number]>;

type T3 = CompareLength<[firstName: string, age: number], [lastName: string]>;
type CompareLength<Left extends any[], Right extends any[]> =
    Left['length'] extends Right['length'] ? 'equal' :
    Left extends [] ? 'shorterLeft' :
    Right extends [] ? 'shorterRight' :
    Left extends [any, ...infer L] ? 
    Right extends [any, ...infer R] ? 
    CompareLength<L, R> :
    never :
    never;

type T1 = CompareLength<[firstName: string], [lastName: string]>;

type T2 = CompareLength<[firstName: string], [lastName: string, age: number]>;

type T3 = CompareLength<[firstName: string, age: number], [lastName: string]>;

TypeScript Exhaustiveness Checking Part 2

type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";

const sendRequest = (url: string, method: HttpMethod) => {
    switch (method) {
        case 'DELETE':

            break;
        case 'GET':

            break;
        case 'POST':

            break;
        case 'PUT':

            break;
        default:
            const exhaustiveCheck: never = method; // ✅ no error
            throw new Error(`Unhandled case: ${exhaustiveCheck}`);
    }
};
type Fruit = 'banana' | 'orange' | 'mango';

function exhaustiveCheck(param: never): never {
    throw new Error('should not reach here')
}

function makeDessert(fruit: Fruit) {
    switch (fruit) {
        case 'banana': return 'Banana Shake'
        case 'orange': return 'Orange Juice'
    }
    exhaustiveCheck(fruit) // ? ERROR! `mango` is not assignable
}
Continue reading

TypeScript Exhaustiveness Checking

Exhaustiveness checking is a good feature when you use switch block. Assume that you need to check a value of variable which data type is union type as shown below screenshot.

Shape is a discriminated union which consists of three types named Circle, Square and Triangle.

kind field is shared in Circle, Square and Triangle types so that if developer forgets to use any of kind field value in switch block, TypeScript will error in coding-time.

Notice that there is a red line in line 347, it is due to missing triangle case in switch block.

This is the error shown in the code.

After adding triangle case in line 346, the error disappeared.

Continue reading