Compare commits

..

22 Commits

Author SHA1 Message Date
e4b9e91688 content: update achievements list
All checks were successful
ci/woodpecker/manual/build Pipeline was successful
2025-04-10 09:43:23 +06:00
fa63ef58d2 update content 2025-04-10 09:29:30 +06:00
8c2ed8ba7b add CKA cert 2025-03-11 19:01:19 +06:00
414a53bd5d update readme 2025-02-20 20:40:19 +06:00
c964df3fbe update build pipeline 2025-02-20 19:18:50 +06:00
c75c73995c remove hardcoded values 2025-02-20 18:35:10 +06:00
56bdb7d6de fix a missing link after file rename 2025-02-20 18:33:00 +06:00
725af11403 reduce repetion in package.json 2025-02-20 18:32:44 +06:00
459f1588e0 update history & achievements 2025-02-20 18:32:17 +06:00
f2afe60c6c swap order of specializations 2025-02-20 18:04:13 +06:00
324ee0d938 format webmanifest 2025-02-20 18:00:38 +06:00
b7cd26ec27 update name pronounc script 2025-02-20 17:59:58 +06:00
325b62634a ci: reduce cache duplication 2024-06-01 04:33:08 +06:00
5c72daf88c ci: refactor 2024-06-01 04:31:34 +06:00
f8a3cb48dd update nodejs & package versions 2024-06-01 02:51:40 +06:00
4cf6bf1c9b packages: define deps instead of devDeps 2024-06-01 02:38:54 +06:00
c921a9cf9f ci: use variable for cache path style 2024-05-31 05:55:39 +06:00
54ebd69e0b remove iac config
iac config has been extracted into this repo:
https://git.bdeshi.space/bdeshi/resume-manpage-iac
2024-05-31 05:37:12 +06:00
5ba3d36f0d iac: fix a ternary 2024-05-21 17:28:13 +06:00
322830ab73 footer: link to repo instead of commit
try to get repo & commit sha from env first.

supports github, gitlab, woodpecker, and
other ci systems that provide these vars:
  - CI_COMMIT_SHA / GITHUB_SHA
  - CI_REPO_URL / CI_PROJECT_URL / GITHUB_SERVER_URL+GITHUB_REPOSITORY
2024-05-20 23:23:37 +06:00
d4455cdd2a ci: DRY 2024-05-20 22:14:21 +06:00
d2a062c1bd ci: test zstd cache perf 2024-05-20 21:03:37 +06:00
33 changed files with 1354 additions and 1605 deletions

2
.nvmrc
View File

@ -1 +1 @@
v16.13.2 v18.16.0

86
.woodpecker/build.yml Normal file
View File

@ -0,0 +1,86 @@
---
# https://woodpecker-ci.org/docs/intro
when:
event: [push, manual]
variables:
images:
- &image_node node:18.16.0
- &image_aws_cli amazon/aws-cli:2.15.50
- &image_drone_cache meltwater/drone-cache:v1.4.0
deploy_envs: &deploy_envs
S3_BUCKET:
from_secret: S3_BUCKET
CLOUDFRONT_DISTRIBUTION:
from_secret: CLOUDFRONT_DISTRIBUTION
AWS_ACCESS_KEY_ID:
from_secret: AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY:
from_secret: AWS_SECRET_ACCESS_KEY
AWS_REGION:
from_secret: AWS_REGION
cache_settings: &cache_settings
access-key:
from_secret: CACHE_S3_ACCESS_KEY_ID
secret-key:
from_secret: CACHE_S3_SECRET_ACCESS_KEY
endpoint:
from_secret: CACHE_S3_ENDPOINT
region:
from_secret: CACHE_S3_REGION
bucket:
from_secret: CACHE_S3_BUCKET
path_style:
from_secret: CACHE_S3_USE_PATH_STYLE
cache_key: '{{ checksum "yarn.lock" }}'
archive_format: zstd
mount:
- 'node_modules'
steps:
- name: cache/restore
image: *image_drone_cache
settings:
<<: *cache_settings
restore: true
- name: build/nodejs
depends_on: [cache/restore]
image: *image_node
commands:
- corepack enable yarn
- yarn install --prefer-offline
- yarn run build
- name: cache/rebuild
depends_on: [build/nodejs]
image: *image_drone_cache
settings:
<<: *cache_settings
rebuild: true
- name: publish/s3
depends_on: [build/nodejs]
when:
- branch: main
image: *image_aws_cli
environment:
<<: *deploy_envs
commands:
- aws s3 sync --delete ./dist "s3://$${S3_BUCKET}/"
- name: publish/cloudfront
depends_on: [publish/s3]
when:
- branch: main
image: *image_aws_cli
environment:
<<: *deploy_envs
commands:
- aws cloudfront create-invalidation --distribution-id
"$${CLOUDFRONT_DISTRIBUTION}" --paths '/*'

View File

@ -1,84 +0,0 @@
# https://woodpecker-ci.org/docs/intro
when:
event: [push, manual]
variables:
secrets: &secrets
- S3_BUCKET
- CLOUDFRONT_DISTRIBUTION
- AWS_ACCESS_KEY_ID
- AWS_SECRET_ACCESS_KEY
- AWS_REGION
steps:
- name: cache/restore
image: meltwater/drone-cache:v1.4.0
environment:
AWS_ACCESS_KEY_ID:
from_secret: CACHE_S3_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY:
from_secret: CACHE_S3_SECRET_ACCESS_KEY
settings:
restore: true
path_style: true
cache_key: '{{ .Commit.Branch }}-{{ checksum "yarn.lock" }}'
archive_format: gzip
bucket:
from_secret: CACHE_S3_BUCKET
endpoint:
from_secret: CACHE_S3_ENDPOINT
region:
from_secret: CACHE_S3_REGION
mount:
- 'node_modules'
- name: build/yarn
depends_on: [ cache/restore ]
image: node:18
commands:
- yarn install
- yarn build
- name: cache/rebuild
depends_on: [ build/yarn ]
image: meltwater/drone-cache:v1.4.0
environment:
AWS_ACCESS_KEY_ID:
from_secret: CACHE_S3_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY:
from_secret: CACHE_S3_SECRET_ACCESS_KEY
settings:
rebuild: true
path_style: true
cache_key: '{{ .Commit.Branch }}-{{ checksum "yarn.lock" }}'
archive_format: gzip
bucket:
from_secret: CACHE_S3_BUCKET
endpoint:
from_secret: CACHE_S3_ENDPOINT
region:
from_secret: CACHE_S3_REGION
mount:
- 'node_modules'
- name: publish/s3
depends_on: [ build/yarn ]
when:
- branch: main
image: amazon/aws-cli:2.15.50
commands:
- aws s3 sync --delete ./dist s3://$${S3_BUCKET}/
secrets:
- <<: *secrets
- name: publish/cloudfront
depends_on: [ publish/s3 ]
when:
- branch: main
image: amazon/aws-cli:2.15.50
commands:
- aws cloudfront create-invalidation --distribution-id $${CLOUDFRONT_DISTRIBUTION} --paths '/*'
secrets:
- <<: *secrets

View File

@ -44,6 +44,12 @@ $ ls dist
- `/meta/iac`: terraform iac config for the backend services hosting the rendered site. - `/meta/iac`: terraform iac config for the backend services hosting the rendered site.
## deployment
this project deploys to s3+cloudfront with woodpecker ci.
backend infrastructure for the deployment is defined here: [resume-manpage-iac](https://git.bdeshi.space/bdeshi/resume-manpage-iac)
--- ---
[pug]: https://pugjs.org [pug]: https://pugjs.org

View File

@ -1,15 +0,0 @@
export TF_WORKSPACE=production
export TF_TOKEN_app_terraform_io=***
export TF_CLOUD_ORGANIZATION=***
export TF_CLOUD_PROJECT=***
export AWS_PROFILE=***
export AWS_ACCESS_KEY_ID=***
export AWS_SECRET_ACCESS_KEY=***
export WOODPECKER_SERVER=***
export WOODPECKER_TOKEN=***
export GITEA_BASE_URL=***
export GITEA_TOKEN=***

34
_meta/iac/.gitignore vendored
View File

@ -1,34 +0,0 @@
# Local .terraform directories
**/.terraform/*
# .tfstate files
*.tfstate
*.tfstate.*
# Crash log files
crash.log
crash.*.log
# Exclude all .tfvars files, which are likely to contain sensitive data, such as
# password, private keys, and other secrets. These should not be part of version
# control as they are data points which are potentially sensitive and subject
# to change depending on the environment.
*.tfvars
*.tfvars.json
# Ignore override files as they are usually used to override resources locally and so
# are not checked in
override.tf
override.tf.json
*_override.tf
*_override.tf.json
# Include override files you do wish to add to version control using negated pattern
# !example_override.tf
# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
# example: *tfplan*
# Ignore CLI configuration files
.terraformrc
terraform.rc

View File

@ -1 +0,0 @@
1.8.3

View File

@ -1,71 +0,0 @@
# This file is maintained automatically by "terraform init".
# Manual edits may be lost in future updates.
provider "registry.terraform.io/go-gitea/gitea" {
version = "0.3.0"
constraints = "~> 0.3.0"
hashes = [
"h1:9kI/rtwDrBt0Km055WJswN+PeGegoEov+1ZmyQ3QxAA=",
"zh:37e9c35f76a5fa71b7864aa6af45c380463b5ea2afd162109f9960bf33f7b93e",
"zh:4496717687dea48de96db815def8b2144b46c5c8a885c139dd45d5ddc6d13f4e",
"zh:4875b3e9092d4f15678f7a605469c144bf298b05c8f8527bb27b1fdf6cb6fba0",
"zh:51f15e0ef905619eb7236bbbdebd81f70f5e024c025a347b0224ed95c5103668",
"zh:5779e9276a20c294710ec57397c06fb3afd9bffd28a5de8189fd7af1ed925ea9",
"zh:63c2ec086260a2e15c9e77ca49344a56e4b86d52b3f502941c9562aa12345887",
"zh:728fd15b2f3ec1c60ad45a996bac98022198078d0368507516f3a0526fd6c503",
"zh:7951a3bf904f836c73b00263d2f057f5ffc123c2946508a57ca2d2a1dc3874ab",
"zh:8495b9e6f6ae9f49b8e80fe3ccf47f1f942745c21fa30648e98aa6fe41a647d9",
"zh:862888963677516379a34c4dbb2396810e1a0ac2e644704d692e4f847d487f55",
"zh:8b1e1badf2ea6c4fcfdf71d98a68a8ba8f0850a4c5ec5f5a451a81cfd2c2b9e2",
"zh:936671c9700a8549b9a4540ecec167415db704e97744ca1fd5e3ad9d48020693",
"zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425",
"zh:c134d5445ce56de7115ceb16d65ed2082b7987273a9d17626e9f6a4e6e8d4ce9",
"zh:fb6fc4d41737bf2e0bd4a2e40ae2d7bddcda7361968f6b74fad00b4fd55e9506",
]
}
provider "registry.terraform.io/hashicorp/aws" {
version = "5.49.0"
constraints = "~> 5.49.0"
hashes = [
"h1:Y3xvYjzBIwYSbcnZDcs6moiy30uxRoY5oT2ExQHKG5A=",
"zh:0979b07cdeffb868ea605e4bbc008adc7cccb5f3ba1d3a0b794ea3e8fff20932",
"zh:2121a0a048a1d9419df69f3561e524b7e8a6b74ba0f57bd8948799f12b6ad3a1",
"zh:573362042ba0bd18e98567a4f45d91b09eb0d223513518ba04f16a646a906403",
"zh:57be7a4d6c362be2fa586d270203f4eac1ee239816239a9503b86ebc8fa1fef0",
"zh:5c72ed211d9234edd70eac9d77c3cafc7bbf819d1c28332a6d77acf227c9a23c",
"zh:7786d1a9781f8e8c0079bf58f4ed4aeddec0caf54ad7ddcf43c47936d545a04f",
"zh:82133e7d39787ee91ed41988da71beecc2ecb900b5da94b3f3d77fbc4d4dc722",
"zh:8cdb1c154dead85be8352afd30eaf41c59249de9e7e0a8eb4ab8e625b90a4922",
"zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425",
"zh:ac215fd1c3bd647ae38868940651b97a53197688daefcd70b3595c84560e5267",
"zh:c45db22356d20e431639061a72e07da5201f4937c1df6b9f03f32019facf3905",
"zh:c9ba90e62db9a4708ed1a4e094849f88ce9d44c52b49f613b30bb3f7523b8d97",
"zh:d2be3607be2209995c80dc1d66086d527de5d470f73509e813254067e8287106",
"zh:e3fa20090f3cebf3911fc7ef122bd8c0505e3330ab7d541fa945fea861205007",
"zh:ef1b9d5c0b6279323f2ecfc322db8083e141984cfe1bb2f33c0f4934fccb69e3",
]
}
provider "registry.terraform.io/kichiyaki/woodpecker" {
version = "0.3.0"
constraints = "~> 0.3.0"
hashes = [
"h1:MWilItwMvIsQN88cyU8Yht23OmNv2BFlVNmh0ui8NNQ=",
"zh:0cf8e4475f78397235bc2dda4efaccd10836b141a06413457f9aaa869638d5fb",
"zh:280345c4d6f632559458021b9cd6ef91f66a7174e72f144d82bffe08771ec742",
"zh:52288022d7b1e9e8f1567e17d2af7309546aff0275bcd89d474f9798fe851fea",
"zh:72d190ae69863dc7f6474fa21f524820ae8a01be15d9373cadb2b228a54599f8",
"zh:7901fa0ceee94026c56a786b0357f4d542304f5947b760766158e096c7361ed0",
"zh:a41d5c895568da74325d6f8e4bd11aca7f878d8e5090967a003f8b959797fbdb",
"zh:b7d3e9d5cfd4ed5fc2608234bcaade05b80425877b8922a7095689f1b9ebda4f",
"zh:c45017d5fb293e71794bb7f9645aa33fe5e2b85038cf0d45ac9876a7320b95fd",
"zh:c8955aadde1f4142b1e79505ecd79258354f73690b581f552662941f97a3795d",
"zh:e2408e5ffb2236a4335a4d0945e3dd54cabb96afbc4c42c4489fbbd2065e157c",
"zh:f0589fc29eb6c66640de50e07fd3ce0fac7759f7563230620ea7dcbb4de4f589",
"zh:f28c493ae8eefc87d7ca577385a2c5bd10949d1d8aa54b04d2c82409fa654c9b",
"zh:f56f23a13c6f1999409ea292e99b891f80e3727630222ed8ffa94b3c43725683",
"zh:f809ab383cca0a5f83072981c64208cbd7fa67e986a86ee02dd2c82333221e32",
"zh:f8f2a4cb994246d1270c805630ddf285156d3e9a6493ed6260b5ee2b1ad121f4",
]
}

View File

@ -1,34 +0,0 @@
resource "aws_acm_certificate" "created" {
domain_name = var.domain_name
validation_method = "DNS"
subject_alternative_names = []
}
resource "aws_acm_certificate_validation" "created" {
certificate_arn = aws_acm_certificate.created.arn
depends_on = [terraform_data.print_acm_validation_records]
}
# HACK: im sorry
resource "terraform_data" "print_acm_validation_records" {
provisioner "local-exec" {
command = <<-EOT
echo -en '\n\n\n\n\n\n
add the following records to associated DNS server:\n\n
${local.acm_validation_records_provisioner_string}
\n\n\n\n\n\n'
EOT
}
}
locals {
acm_validation_records_provisioner_string = join("\n", [
for map in aws_acm_certificate.created.domain_validation_options :
join("\n", [
join(" | ", keys(map)),
join(" | ", values(map))
])
])
}

View File

@ -1,50 +0,0 @@
data "aws_cloudfront_cache_policy" "caching_optimized" {
name = "Managed-CachingOptimized"
}
locals {
cloudfront_s3_origin_id = "S3-${aws_s3_bucket.created.id}"
}
resource "aws_cloudfront_distribution" "created" {
enabled = true
is_ipv6_enabled = true
aliases = [var.domain_name]
default_root_object = var.aws_cloudfront_default_root_object
price_class = var.aws_cloudfront_price_class
http_version = "http2and3"
origin {
domain_name = aws_s3_bucket.created.bucket_regional_domain_name
origin_id = local.cloudfront_s3_origin_id
origin_access_control_id = aws_cloudfront_origin_access_control.s3_access.id
}
default_cache_behavior {
allowed_methods = ["GET", "HEAD", "OPTIONS"]
cached_methods = ["GET", "HEAD"]
cache_policy_id = data.aws_cloudfront_cache_policy.caching_optimized.id
target_origin_id = local.cloudfront_s3_origin_id
viewer_protocol_policy = "redirect-to-https"
compress = true
}
restrictions {
geo_restriction {
restriction_type = "none"
locations = []
}
}
viewer_certificate {
acm_certificate_arn = aws_acm_certificate.created.arn
minimum_protocol_version = var.aws_cloudfront_minimum_protocol_version
ssl_support_method = "sni-only"
}
depends_on = [aws_acm_certificate_validation.created]
}
resource "aws_cloudfront_origin_access_control" "s3_access" {
name = "S3_${aws_s3_bucket.created.id}"
description = "S3:${aws_s3_bucket.created.id}"
origin_access_control_origin_type = "s3"
signing_behavior = "always"
signing_protocol = "sigv4"
}

View File

@ -1,41 +0,0 @@
data "aws_caller_identity" "current" {}
data "aws_kms_alias" "aws_s3" {
name = "alias/aws/s3"
}
data "aws_iam_policy_document" "s3_cloudfront_access" {
statement {
principals {
type = "Service"
identifiers = ["cloudfront.amazonaws.com"]
}
actions = [
"s3:GetObject",
"s3:ListBucket"
]
resources = [
aws_s3_bucket.created.arn,
"${aws_s3_bucket.created.arn}/*"
]
condition {
test = "StringEquals"
variable = "AWS:SourceArn"
values = [aws_cloudfront_distribution.created.arn]
}
}
}
data "aws_iam_policy_document" "pubilsher" {
statement {
actions = [
"s3:*",
"cloudfront:*"
]
resources = [
aws_s3_bucket.created.arn,
"${aws_s3_bucket.created.arn}/*",
aws_cloudfront_distribution.created.arn
]
}
}

View File

@ -1,19 +0,0 @@
resource "aws_iam_user" "publisher" {
name = "${var.domain_name}_publisher"
path = "/${var.aws_tag_iac_identifier}/${local.workspace_env}/"
force_destroy = true
}
resource "aws_iam_access_key" "publisher" {
user = aws_iam_user.publisher.name
}
resource "aws_iam_policy" "publisher" {
name_prefix = "${var.domain_name}_publisher"
policy = data.aws_iam_policy_document.pubilsher.json
}
resource "aws_iam_user_policy_attachment" "publisher" {
policy_arn = aws_iam_policy.publisher.arn
user = aws_iam_user.publisher.name
}

View File

@ -1,28 +0,0 @@
resource "aws_s3_bucket" "created" {
bucket_prefix = var.aws_s3_use_domain_prefix ? var.domain_name : var.aws_s3_bucket_prefix
force_destroy = var.aws_s3_force_destroy
}
resource "aws_s3_bucket_public_access_block" "created" {
bucket = aws_s3_bucket.created.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
resource "aws_s3_bucket_server_side_encryption_configuration" "created" {
bucket = aws_s3_bucket.created.id
rule {
bucket_key_enabled = true
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
# kms_master_key_id = data.aws_kms_alias.aws_s3.arn
}
}
}
resource "aws_s3_bucket_policy" "created" {
bucket = aws_s3_bucket.created.id
policy = data.aws_iam_policy_document.s3_cloudfront_access.json
}

View File

@ -1,6 +0,0 @@
data "gitea_user" "current" {}
data "gitea_repo" "source" {
name = var.gitea_repo
username = coalesce(var.gitea_user, data.gitea_user.current.username)
}

View File

@ -1,61 +0,0 @@
locals {
secrets_map = {
aws_region = { value = var.aws_region }
aws_access_key_id = { value = aws_iam_access_key.publisher.id }
aws_secret_access_key = { value = aws_iam_access_key.publisher.secret }
cloudfront_distribution = { value = aws_cloudfront_distribution.created.id }
s3_bucket = { value = aws_s3_bucket.created.id }
}
}
################################
#### for adduc/woodpecker ####
################################
# adduc/woodpecker@v0.4.0 is incompatible with latest woodpecker (eg, v2.41)
# data "woodpecker_self" "current" { }
#
# resource "woodpecker_repository" "created" {
# name = data.gitea_repo.source.name
# # woodpecker username can come from associated gitea username
# owner = coalesce(var.woodpecker_user, var.gitea_user, data.woodpecker_self.current.login)
# visibility = data.gitea_repo.source.private ? "Public" : "Private"
# }
# resource "woodpecker_repository_secret" "secrets" {
# count = length(keys(local.secrets_map))
#
# repo_owner = woodpecker_repository.created.owner
# repo_name = woodpecker_repository.created.name
# name = upper(keys(local.secrets_map)[count.index])
# value = values(local.secrets_map)[count.index].value
# events = try(values(local.secrets_map)[count.index].events, var.woodpecker_secrets_events, [])
# }
####################################
#### for Kichiyaki/woodpecker ####
####################################
data "woodpecker_user" "current" {
login = ""
}
resource "woodpecker_repository" "created" {
full_name = join("/", [
coalesce(var.woodpecker_user, var.gitea_user, data.woodpecker_user.current.login),
data.gitea_repo.source.name
])
visibility = data.gitea_repo.source.private ? "public" : "private"
}
resource "woodpecker_repository_secret" "secrets" {
count = length(keys(local.secrets_map))
repository_id = woodpecker_repository.created.id
name = upper(keys(local.secrets_map)[count.index])
value = values(local.secrets_map)[count.index].value
events = try(values(local.secrets_map)[count.index].events, var.woodpecker_secrets_events, [])
}

View File

@ -1,2 +0,0 @@
organization = "bdeshi-space"
workspaces { prefix = "resume-manpage-" }

View File

@ -1,40 +0,0 @@
output "aws_account_id" {
value = data.aws_caller_identity.current.account_id
description = "ID of the AWS account."
}
output "s3_bucket" {
value = aws_s3_bucket.created.id
description = "name of the created S3 bucket."
}
output "cloudfront_distribution" {
value = aws_cloudfront_distribution.created.id
description = "ID of the created CloudFront distribution."
}
output "cloudfront_domain" {
value = aws_cloudfront_distribution.created.domain_name
description = "domain name of the created CloudFront distribution."
}
output "acm_certificate_arn" {
value = aws_acm_certificate.created.arn
description = "ARN of the created ACM certificate."
}
output "iam_access_key_id" {
value = aws_iam_access_key.publisher.id
description = "access key ID of the publisher IAM user."
}
output "iam_secret_access_key" {
value = aws_iam_access_key.publisher.secret
sensitive = true
description = "secret access key of the publisher IAM user."
}
output "domain_name" {
value = var.domain_name
description = "target publishing domain name."
}

View File

@ -1,55 +0,0 @@
terraform {
required_version = "~> 1.8.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~>5.49.0"
}
# woodpecker = {
# source = "adduc/woodpecker"
# version = "~> 0.4.0"
# }
woodpecker = {
source = "Kichiyaki/woodpecker"
version = "~> 0.3.0"
}
gitea = {
source = "go-gitea/gitea"
version = "~>0.3.0"
}
}
backend "remote" {}
# cloud {
# organization = collected from TF_CLOUD_ORGANIZATION env
# workspaces {
# project = collected from TF_CLOUD_PROJECT env
# }
# }
}
provider "aws" {
# profile = collected from AWS_PROFILE env
region = var.aws_region
default_tags {
tags = {
"ManagedBy" = var.aws_tag_iac_identifier
"iac/project" = var.aws_tag_iac_project_name
"iac/source" = "${data.gitea_repo.source.ssh_url}/${var.aws_tag_iac_project_subpath}"
"iac/environment" = local.workspace_env
}
}
}
provider "woodpecker" {
# server = collected from WOODPECKER_SERVER env
# token = collected from WOODPECKER_TOKEN env
}
provider "gitea" {
# base_url = collected from GITEA_BASE_URL env
# token = collected from GITEA_TOKEN env
}

View File

@ -1,5 +0,0 @@
domain_name = "sammay.sarkar.website"
aws_tag_iac_project_name = "resume-manpage"
aws_tag_iac_project_subpath = "/iac"
gitea_repo = "resume-manpage"
woodpecker_secrets_events = ["push", "deployment", "manual"]

View File

@ -1,103 +0,0 @@
####################
#### commons ####
####################
variable "domain_name" {
type = string
description = "domain name where the built site is published."
}
################
#### aws ####
################
variable "aws_tag_iac_identifier" {
type = string
default = "iac/terraform"
description = "IaC tool name added as a tag to AWS resources, also used in iam user path."
}
variable "aws_tag_iac_project_name" {
type = string
description = "IaC project name added as a tag to AWS resources."
}
variable "aws_tag_iac_project_subpath" {
type = string
description = "IaC project source path added as a tag to AWS resources."
}
variable "aws_region" {
type = string
default = "us-east-1"
description = "AWS region passed to AWS provider."
}
variable "aws_s3_bucket_prefix" {
type = string
default = null
description = "AWS S3 bucket name prefix."
}
variable "aws_s3_use_domain_prefix" {
type = bool
default = true
description = "use var.domain_name as AWS S3 bucket name prefix."
}
variable "aws_s3_force_destroy" {
type = bool
default = true
description = "delete all bucket objects to allow clean bucket destroy operation."
}
variable "aws_cloudfront_default_root_object" {
type = string
default = "index.html"
description = "default root object name for the CloudFront distribution."
}
variable "aws_cloudfront_price_class" {
type = string
default = "PriceClass_200"
description = "price class for the CloudFront distribution: PriceClass_All|PriceClass_200|PriceClass_100."
}
variable "aws_cloudfront_minimum_protocol_version" {
type = string
default = "TLSv1.2_2021"
description = "name of the minimum SSL protocol version used by CloudFront for HTTPS requests."
}
################
#### gitea ####
################
variable "gitea_repo" {
type = string
description = "name of source Gitea repository."
}
variable "gitea_user" {
type = string
default = null
description = "username of Gitea repo owner."
}
################
# woodpecker #
################
variable "woodpecker_user" {
type = string
default = null
description = "username of Woodpecker server."
}
variable "woodpecker_secrets_events" {
type = list(string)
default = ["push"]
description = "default list of allowed events for Woodpecker secrets created."
}

View File

@ -1,9 +0,0 @@
locals {
# terraform remote backend prefix key means local and remote
# wokspace names can differ.
# assuming workspace are named as `prefix+env`, this section
# extracts the env from both local or remote workspace names.
_workspace_name_segments = split("-", terraform.workspace)
_workspace_name_segments_count = length(local._workspace_name_segments)
workspace_env = local._workspace_name_segments[local._workspace_name_segments_count - 1]
}

View File

@ -1 +1,19 @@
{"name":"","short_name":"","icons":[{"src":"./images/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"./images/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} {
"name": "",
"short_name": "",
"icons": [
{
"src": "./images/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "./images/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
}

View File

@ -18,7 +18,7 @@ div.container
include ./sections/description include ./sections/description
include ./sections/options include ./sections/options
include ./sections/history include ./sections/history
include ./sections/recognition include ./sections/achievement
include ./sections/contact include ./sections/contact
include ./sections/seealso include ./sections/seealso
include ./sections/copyright include ./sections/copyright

View File

@ -4,18 +4,24 @@ section.achievements
h1.target#achievements: a(href="#achievements") achievements h1.target#achievements: a(href="#achievements") achievements
.desc .desc
ul ul
li
b: +ext_a("https://www.credly.com/badges/40f2170e-692d-4aaa-a18e-a51d40a9d41b/public_url", "Certified Kubernetes Administrator")
|, CNCF / Linux Foundation
li
b: +ext_a("https://www.credly.com/badges/231c502b-2d41-4d9f-8233-4f4e63e38caa/public_url", "Certified Kubernetes Application Developer")
|, CNCF / Linux Foundation
li li
b: +ext_a("https://www.credly.com/badges/07c275c9-019c-47dc-be22-98f932094362/public_url", "Terraform Associate") b: +ext_a("https://www.credly.com/badges/07c275c9-019c-47dc-be22-98f932094362/public_url", "Terraform Associate")
|, HashiCorp |, HashiCorp
li
b: +ext_a("https://coursera.org/share/90a24b5165900b3e22011c322b4013f8", "Google IT Support Professional")
|, Google
li li
b: +ext_a("https://coursera.org/share/53e0dc7863382d6253086b8dcac2518d", "AWS DevOps Specialization") b: +ext_a("https://coursera.org/share/53e0dc7863382d6253086b8dcac2518d", "AWS DevOps Specialization")
|, AWS |, AWS
li li
b: +ext_a("https://coursera.org/share/5b48cc6ac827b619d69056d0d6705b5b", "Google Cloud Digital Leader") b: +ext_a("https://coursera.org/share/5b48cc6ac827b619d69056d0d6705b5b", "Google Cloud Digital Leader")
|, Google |, Google
li
b: +ext_a("https://coursera.org/share/90a24b5165900b3e22011c322b4013f8", "Google IT Support Professional")
|, Google
li li
b: +ext_a("https://coursera.org/share/47e5a79207cec44a45fcf2cb0ca1f815", "Python IT Automation Certificate") b: +ext_a("https://coursera.org/share/47e5a79207cec44a45fcf2cb0ca1f815", "Python IT Automation Certificate")
|, Google |, Google
@ -34,7 +40,8 @@ section.achievements
li li
b: +ext_a("https://www.hackerrank.com/certificates/dcdb6c3c4463", "Problem Solving Skill Certificate") b: +ext_a("https://www.hackerrank.com/certificates/dcdb6c3c4463", "Problem Solving Skill Certificate")
|, HackerRank |, HackerRank
li #[b Recognized Contributor], Wikipedia li #[b Top Performer], FieldNation
li #[b MVP], Pillar li #[b MVP], Pillar
li #[b Star Performer], Digital Healthcare Solutions li #[b Star Performer], Digital Healthcare Solutions
// li #[b Recognized Contributor], Wikipedia
span.darker i use arch btw span.darker i use arch btw

View File

@ -2,13 +2,13 @@ section.description
h1.target#description: a(href="#description") description h1.target#description: a(href="#description") description
.desc .desc
p. p.
Hello! I am a self-taught technology professional with a strong background in Hello! I am a self-taught technology professional with effective hands-on
#[em system administration] and #[em software programming], carrying effective hands-on experience in #[em modern dev-ops], #[em cloud-ops], and #[em IaC] skill areas,
experience in #[em modern dev-ops], #[em cloud-ops], and #[em IaC] work domains. from a strong background in #[em system administration] and #[em software programming].
p. p.
It's my passion to keep learning and building things that are useful, It's my passion to keep learning and building things that are useful,
sustainable, minimal, and easy to use. I put a lot of care to keep my work sustainable, minimal, and easy to use. I put a lot of care to keep my work
output #[em clean], #[em maintainable] and #[em well-documented]. output #[em resilient], #[em maintainable] and #[em well-documented].
p. p.
As an active supporter of the open-source culture, I'm always As an active supporter of the open-source culture, I'm always
looking for opportunities to contribute and to assist the community. looking for opportunities to contribute and to assist the community.

View File

@ -3,25 +3,40 @@ section.history
.desc .desc
// p My professional employment summary with notable duties is listed below. // p My professional employment summary with notable duties is listed below.
ul ul
li #[b.job DevOps Consultant] - #[em.org freelance] #[span.period 2022-....]
li #[b.job DevOps Consultant] - #[em.org freelance]
ul ul
li adapting classic workloads to serverless architecture li adapting classic workloads to serverless architecture
li implementing modern logging and tracing solutions li implementing modern logging and tracing solutions
li converting adhoc services to IaC/CaC projects li converting adhoc services to IaC/CaC projects
li providing support for cloud devops processes li providing support for cloud platform operations
li performing technical evaluation of bleeding-edge technologies
li #[b.job DevOps Engineer] - #[em.org Pillar] #[span.period 2022-....] li #[b.job Senior Platform Engineer] - #[em.org FieldNation] #[span.period 2024-....]
ul ul
li designing cost-effective k8s and AWS infrastructure li contributing to design and implementation of internal developer platforms
li implementing monitoring and alerting mechanism li ensuring best practices for infrastructure operations
li managing cloud-native ci/cd pipelines li serving as a mentor on cloud-native operational excellence
li leading regional platform team and guiding self-sufficiency
li #[b.job DevOps Engineer] - #[em.org Digital Healthcare Solutions] #[span.period 2021-....] li #[b.job Lead DevOps Engineer] - #[em.org Pillar] #[span.period 2023-2024]
ul ul
li supervising kubernetes and classic server workloads li provided operational expertise for critical strategic planning
li in charge of AWS infrastructure administration li performed extesnive RnD on technical solutions to guide purchase decisions
li maintaining total monitoring stack li planned and managed operations projects and targets
li managing ci/cd pipeline
li #[b.job DevOps Engineer] - #[em.org Pillar] #[span.period 2022-2023]
ul
li designed cost-effective k8s and AWS infrastructure
li implemented end-to-end monitoring and alerting mechanisms
li managed cloud-native ci/cd pipelines
li #[b.job DevOps Engineer] - #[em.org Digital Healthcare Solutions] #[span.period 2021-2022]
ul
li supervised kubernetes and classic server workloads
li performed AWS infrastructure administration
li maintained total monitoring stack
li managed ci/cd pipelines
li #[b.job TechOps Engineer] - #[em.org Telenor Health / Digital Healthcare Solutions] #[span.period 2020-2021] li #[b.job TechOps Engineer] - #[em.org Telenor Health / Digital Healthcare Solutions] #[span.period 2020-2021]
ul ul

View File

@ -4,11 +4,11 @@ audio#pronounce(controls=false preload="auto")
source(src="assets/media/spell.wav" type="audio/wav") source(src="assets/media/spell.wav" type="audio/wav")
script. script.
function pronounce() { window.pronounce = function() {
var audio = document.getElementById('pronounce') var audio = document.getElementById('pronounce');
audio.play() audio.play();
} };
section.name section.name
h1.target#name: a(href="#name") name h1.target#name: a(href="#name") name
.desc #[a(href='#' onclick="pronounce()") #{name} 🔉] - #{description} .desc #[a(href='#' onclick="pronounce()" title="tap for name pronunciation") #{name} 🔉] - #{description}

View File

@ -3,6 +3,23 @@ section.options
.desc .desc
ul ul
li
b.target#devops: a(href="#devops") --dev-ops
.opt_desc
p.
I am involved with both classic and modern DevOps practices, having current knowledge of
dev-ops orchestration and management tools such as #[em Docker], #[em Kubernetes], #[em Terraform].
My professional experience includes managing production k8s clusters on #[em AWS] cloud.
I have also worked on converting legacy workloads to #[em serverless] paradigm and maintaining them.
p.
I can set up a working dev-ops environment from scratch, with a working CI/CD pipeline —
doing this with both modern container-based tools such as #[em k8s], #[em Helm], #[em Argo],
#[em Gitlab/Github CI], or alternatively with legacy tools such as #[em Ansible] and #[em Jenkins].
p.
My expertise on #[em observability] comprises of managing monitoring and alerting stacks built
with #[em prometheus], #[em Grafana], #[em PagerDuty], as well as in-depth observability
toolkits such as #[em Graylog], #[em NewRelic], #[em DataDog], #[em Splunk] etc.
li li
b.target#sysadmin: a(href="#sysadmin") --sys-admin b.target#sysadmin: a(href="#sysadmin") --sys-admin
.opt_desc .opt_desc
@ -17,23 +34,6 @@ section.options
p. p.
My expertise on #[em Windows] systems is above-average, with working knowledge of #[em Mac OSX]. My expertise on #[em Windows] systems is above-average, with working knowledge of #[em Mac OSX].
li
b.target#devops: a(href="#devops") --dev-ops
.opt_desc
p.
I am involved in both classic and modern DevOps practices, having current knowledge of
dev-ops orchestration and management tools such as #[em Docker], #[em Kubernetes], #[em Terraform].
My professional experience includes managing production k8s clusters on #[em AWS] cloud.
I have also worked on converting legacy workloads to #[em serverless] paradigm and maintaining them.
p.
I can set up a working dev-ops environment from scratch, with a working CI/CD pipeline —
doing this with both modern container-based tools such as #[em k8s], #[em Helm], #[em Argo],
#[em Gitlab/Github CI], or alternatively with legacy tools such as #[em Ansible] and #[em Jenkins].
p.
My expertise on #[em observability] comprises of managing monitoring and alerting stacks built
with #[em prometheus], #[em Grafana], #[em PagerDuty], as well as in-depth observability
toolkits such as #[em Graylog], #[em NewRelic], #[em DataDog], #[em Splunk] etc.
li li
b.target#backend: a(href="#backend") --back-end b.target#backend: a(href="#backend") --back-end
.opt_desc .opt_desc
@ -83,7 +83,9 @@ section.options
DNS, VPN, code hosting, RSS, caldav and more. DNS, VPN, code hosting, RSS, caldav and more.
p. p.
My other interests are the #[em decentralized web] and the #[em indie] community. My other interests are the #[em decentralized web] and the #[em indie] community.
I closely follow the fediverse and indieweb movements. I closely follow the fediverse and indieweb movement. I also hang around niche cozy
communities like tilde club, 512kb club etc.
p. p.
I am a #[strike huge] mid-level nerd, which might be apparent from the design of this page. I am a #[strike huge] mid-level nerd, which might be apparent from the design of this page.
My field of work is complementary to my passion. I love to tinker with technology, My field of work is complementary to my passion. I love to tinker with technology,

View File

@ -2,11 +2,17 @@ section.seealso
h1.target#seealso: a(href="#seealso") see also h1.target#seealso: a(href="#seealso") see also
.desc .desc
p p
a(href="https://bdeshi.space" rel="external").print: b articles a(href=links.blog rel="external").print: b articles
|(7), |(7),
| |
a(href="https://github.com/bdeshi" rel="external nofollow noopener noreferrer").print: b github a(href=links.github rel="external nofollow noopener noreferrer").print: b github
|(4) |(4)
//-
|
a(href=links.showcase).print: b showcase
|(5)
//- //-
| |
| |

View File

@ -2,12 +2,12 @@ section.synopsis
h1.target#synopsis: a(href="#synopsis") synopsis h1.target#synopsis: a(href="#synopsis") synopsis
.desc .desc
p #[b #{name}] p #[b #{name}]
| --#[a(href="#sysadmin") sys-admin]
|
span.dimmer [#[em linux], #[em server] ...]
| --#[a(href='#devops') dev-ops] | --#[a(href='#devops') dev-ops]
| |
span.dimmer [#[em cloud], #[em k8s], #[em iac] ...] span.dimmer [#[em cloud], #[em k8s], #[em iac] ...]
| --#[a(href="#sysadmin") sys-admin]
|
span.dimmer [#[em linux], #[em server] ...]
p #[b #{name}] p #[b #{name}]
| --#[a(href='#backend') back-end] --#[a(href="#automation") automation] | --#[a(href='#backend') back-end] --#[a(href="#automation") automation]
| |

View File

@ -1,18 +1,22 @@
{ {
"name": "manpage-html", "name": "resume-manpage",
"version": "0.0.1", "version": "0.0.1",
"license": "CC-BY-4.0", "license": "CC-BY-4.0",
"source": "index.pug",
"dependencies": {
"@csstools/normalize.css": "^12.0.0"
},
"devDependencies": { "devDependencies": {
"@csstools/normalize.css": "^12.0.0", "@parcel/packager-raw-url": "^2.5.0",
"@parcel/packager-raw-url": "2.5.0", "@parcel/transformer-pug": "^2.5.0",
"@parcel/transformer-pug": "2.5.0", "@parcel/transformer-sass": "^2.5.0",
"@parcel/transformer-sass": "2.5.0", "@parcel/transformer-webmanifest": "^2.5.0",
"@parcel/transformer-webmanifest": "2.5.0",
"parcel": "^2.5.0" "parcel": "^2.5.0"
}, },
"scripts": { "scripts": {
"build": "parcel build index.pug", "prebuild": "rm -rf dist",
"serve": "parcel serve index.pug", "build": "parcel build",
"watch": "parcel watch index.pug" "serve": "parcel serve",
"watch": "parcel watch"
} }
} }

View File

@ -3,30 +3,45 @@
last_name = 'Sarkar', last_name = 'Sarkar',
name = first_name.toLowerCase() + '_' + last_name.toLowerCase(), name = first_name.toLowerCase() + '_' + last_name.toLowerCase(),
site_url = 'https://sammay.sarkar.website', site_url = 'https://sammay.sarkar.website',
description = 'server magician', description = 'cloud-native magician',
meta_description = "a self-taught tech professional with a strong background in system administration and general programming, with proven hands-on experience in modern DevOps, cloud, and IaC work areas." meta_description = "a self-taught tech professional with a strong background in system administration and general programming, with proven hands-on experience in modern DevOps, cloud, and IaC work areas."
var section = 8, var section = 8,
section_name = 'System Administration Manuals' section_name = 'System Administration Manuals'
var version = require('child_process').execSync('git rev-parse HEAD').toString().trim(),
short_version = version.substring(0, 7),
date = (new Date()).toDateString()
year = (new Date()).getFullYear()
var contacts = { var contacts = {
'location': 'Dhaka, Bangladesh (GMT+6)', 'location': 'Dhaka, Bangladesh (GMT+6)',
'email': '<a href="mailto:sammay@sarkar.website">sammay@sarkar.website</a>', 'email': '<a href="mailto:sammay@sarkar.website">sammay@sarkar.website</a>',
'pubkey': '<a href="assets/pubkey.asc">0x2F66DAA6F22F092C</a>', 'pubkey': '<a href="assets/pubkey.asc">0x2F66DAA6F22F092C</a>',
'linkedin': '<a href="https://www.linkedin.com/in/sammay-sarkar/">sammay-sarkar</a>', 'linkedin': '<a href="https://www.linkedin.com/in/sammay-sarkar/">sammay-sarkar</a>',
'cell': '<span id="phone"><a href="tel:+8801622085295">+8801622085295</a> <span id="phone-hint">/* please consider texting first? */</span></span>' 'cell': '<span id="phone"><a href="tel:+8801622085295">+8801622085295</a> <span id="phone-hint">/* please consider texting first? */</span></span>',
// 'telegram': '<a href="https://t.me/bdeshi">@bdeshi</a>',
// 'irc': 'bdeshi at libera.chat'
} }
var links = { var links = {
'blog': '<a href="https://bdeshi.space">bdeshi.space</a>', 'blog': 'https://bdeshi.space',
'showcase': '<a href="/portfolio">/portfolio</a>', 'showcase': '/portfolio.pug',
'github': '<a href="https://github.com/bdeshi">github.com/bdeshi</a>', 'github': 'https://github.com/bdeshi',
// 'fediverse': '<a href="https://mastodon.social/@bdeshi">@bdeshi</a>', // 'fediverse': 'https://mastodon.social/@bdeshi',
'telegram': '<a href="https://t.me/bdeshi">bdeshi</a>',
'irc': 'bdeshi at libera.chat'
} }
var monospace_font_css = "https://fonts.googleapis.com/css2?" var monospace_font_css = "https://fonts.googleapis.com/css2?"
+ "family=IBM+Plex+Mono:ital,wght@0,400;0,700;1,400;1,700" + "family=IBM+Plex+Mono:ital,wght@0,400;0,700;1,400;1,700"
+ "display=swap" + "display=swap"
var source_link = 'https://git.bdeshi.space/bdeshi/resume-manpage/commit/' + version
var source_link = (process.env.CI_REPO_URL ?
process.env.CI_REPO_URL : process.env.CI_PROJECT_URL ?
process.env.CI_PROJECT_URL : process.env.GITHUB_REPOSITORY ?
`${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}` :
require('child_process').execSync('git remote get-url origin').
toString().replace(":", "/").replace("git@", "https://")
),
version = (process.env.CI_COMMIT_SHA ?
process.env.CI_COMMIT_SHA : process.env.GITHUB_SHA ?
process.env.GITHUB_SHA :
require('child_process').execSync('git rev-parse HEAD').toString()
),
short_version = version.substring(0, 7),
date = (new Date()).toDateString(),
year = (new Date()).getFullYear()

1998
yarn.lock

File diff suppressed because it is too large Load Diff