File size: 8,909 Bytes
04785dd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8647366
 
 
 
04785dd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8647366
04785dd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# =============================
# Variable Documentation
# =============================

# PYPI_TOKEN: Authentication token for PyPI publishing
# Usage: make publish PYPI_TOKEN=your_pypi_token

# PACKAGE_NAME: Name of the Python package for dependency tree
# Usage: make print-dependency-tree PACKAGE_NAME=your_package_name


# =============================
# Project Configuration
# =============================
PROJECT_NAME = jio-savan-music-downloader
GITHUB_USERNAME = DeepakPant93
GITHUB_REPO = $(PROJECT_NAME)
PROJECT_SLUG = jio_savan_music_downloader
CLOUD_REGION = eastus
TAG = latest
IMAGE_NAME = deepak93p/$(PROJECT_SLUG)
RESOURCE_GROUP = $(PROJECT_NAME)-rg
APP_NAME = $(PROJECT_NAME)-app
APP_ENV_NAME = $(APP_NAME)-env
BUMP_TYPE = patch

# =============================
# Help (Default Target)
# =============================
.PHONY: help
help: ## Display this help message
	@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-25s\033[0m %s\n", $$1, $$2}'

.DEFAULT_GOAL := help

# =============================
# Installation and Setup
# =============================
.PHONY: bake-env
bake-env: clean-env ## Install the poetry environment and set up pre-commit hooks
	@echo "πŸš€ Creating virtual environment using pyenv and poetry"
	@poetry install
	@poetry run pre-commit install || true
	@max_retries=3; count=0; \
	while ! make lint; do \
		count=$$((count + 1)); \
		if [ $$count -ge $$max_retries ]; then \
			echo "Max retries reached. Exiting."; \
			exit 1; \
		fi; \
		echo "Retrying make lint ($$count/$$max_retries)..."; \
	done
	@poetry shell

.PHONY: clean-env
clean-env: ## Remove the poetry environment
	@echo "πŸš€ Removing virtual environment"
	@rm -rf .venv

.PHONY: reset-env
reset-env: clean-env bake-env ## Install the poetry environment and set up pre-commit hooks

.PHONY: init-repo
init-repo: ## Initialize git repository
	@echo "πŸš€ Initializing git repository"
	@git init
	@echo "πŸš€ Creating initial commit"
	@git add .
	@git commit -m "Initial commit"
	@echo "πŸš€ Adding remote repository"
	@git branch -M main
	@git remote add origin git@github.com:$(GITHUB_USERNAME)/$(GITHUB_REPO).git
	@echo "πŸš€ Pushing initial commit"
	@git push -u origin main

.PHONY: setup-cloud-env
setup-cloud-env: ## Create resource group, container app environment, and service principal
	@echo "πŸš€ Creating resource group: $(RESOURCE_GROUP)"
	@az group create --name $(RESOURCE_GROUP) --location $(CLOUD_REGION)

	@echo "πŸš€ Creating container app environment: $(APP_ENV_NAME)"
	@az containerapp env create --name $(APP_ENV_NAME) --resource-group $(RESOURCE_GROUP) --location $(CLOUD_REGION)

	@echo "πŸš€ Fetching subscription ID"
	@subscription_id=$$(az account show --query "id" -o tsv) && \
	echo "Subscription ID: $$subscription_id" && \
	echo "πŸš€ Creating service principal for: $(APP_NAME)" && \
	az ad sp create-for-rbac --name "$(APP_NAME)-service-principal" --role contributor --scopes /subscriptions/$$subscription_id --sdk-auth

	@echo "πŸš€ Creating container app: $(APP_NAME)"
	@az containerapp create --name $(APP_NAME) --resource-group $(RESOURCE_GROUP) --environment $(APP_ENV_NAME) --image 'nginx:latest' --target-port 80 --ingress 'external' --query "properties.configuration.ingress.fqdn"

.PHONY: clean-cloud-env
clean-cloud-env: ## Delete resource group, container app environment, and service principal
	@echo "πŸš€ Deleting service principal for: $(APP_NAME)-service-principal"
	@sp_object_id=$$(az ad sp list --display-name "$(APP_NAME)-service-principal" --query "[0].id" -o tsv) && \
	if [ -n "$$sp_object_id" ]; then \
		az ad sp delete --id $$sp_object_id; \
		echo "Service principal deleted"; \
	else \
		echo "Service principal not found, skipping deletion"; \
	fi

	@echo "πŸš€ Deleting container app: $(APP_NAME)"
	@az containerapp delete --name $(APP_NAME) --resource-group $(RESOURCE_GROUP) --yes --no-wait || echo "Container app not found, skipping deletion"

	@echo "πŸš€ Deleting container app environment: $(APP_ENV_NAME)"
	@az containerapp env delete --name $(APP_ENV_NAME) --resource-group $(RESOURCE_GROUP) --yes --no-wait || echo "Container app environment not found, skipping deletion"

	@echo "πŸš€ Deleting resource group: $(RESOURCE_GROUP)"
	@az group delete --name $(RESOURCE_GROUP) --yes --no-wait || echo "Resource group not found, skipping deletion"


# =============================
# Code Quality and Testing
# =============================
.PHONY: lint
lint: ## Run code quality tools
	@echo "πŸš€ Checking Poetry lock file consistency with 'pyproject.toml'"
	@poetry check --lock
	@echo "πŸš€ Linting code with pre-commit"
	@poetry run pre-commit run -a
	@echo "πŸš€ Static type checking with mypy"
	# @echo "πŸš€ Sorting imports with isort"
	# @poetry run isort jio_savan_music_downloader/
	# @echo "πŸš€ Linting code with Ruff"
	# @poetry run ruff format jio_savan_music_downloader/
	@poetry run mypy
	@echo "πŸš€ Checking for obsolete dependencies with deptry"
	@poetry run deptry .
	@echo "πŸš€ Checking for security vulnerabilities with bandit"
	@poetry run bandit -c pyproject.toml -r jio_savan_music_downloader/ -ll


.PHONY: test
test: ## Run tests with pytest
	@echo "πŸš€ Running tests with pytest"
	@poetry run pytest --cov --cov-config=pyproject.toml --cov-report=term-missing


# =============================
# Build and Release
# =============================
.PHONY: bake
bake: clean-bake ## Build wheel file using poetry
	@echo "πŸš€ Creating wheel file"
	@poetry build

.PHONY: clean-bake
clean-bake: ## Clean build artifacts
	@rm -rf dist

.PHONY: bump
bump: ## Bump project version
	@echo "πŸš€ Bumping version"
	@poetry run bump-my-version bump $(BUMP_TYPE)

.PHONY: publish
publish: ## Publish a release to PyPI
	@echo "πŸš€ Publishing: Dry run"
	@poetry config pypi-token.pypi $(PYPI_TOKEN)
	@poetry publish --dry-run
	@echo "πŸš€ Publishing"
	@poetry publish

.PHONY: bake-and-publish
bake-and-publish: bake publish ## Build and publish to PyPI

.PHONY: update
update: ## Update project dependencies
	@echo "πŸš€ Updating project dependencies"
	@poetry update
	@poetry run pre-commit install --overwrite
	@echo "Dependencies updated successfully"

# =============================
# Run and Documentation
# =============================
.PHONY: run
run: ## Run the project's main application
	@echo "πŸš€ Running the project"
	@poetry run streamlit run $(PROJECT_SLUG)/app.py

.PHONY: docs-test
docs-test: ## Test if documentation can be built without warnings or errors
	@poetry run mkdocs build -s

.PHONY: docs
docs: ## Build and serve the documentation
	@poetry run mkdocs serve

# =============================
# Docker
# =============================
.PHONY: bake-container
bake-container: ## Build Docker image
	@echo "πŸš€ Building Docker image"
	docker build -t $(IMAGE_NAME):$(TAG) -f Dockerfile .

.PHONY: container-push
container-push: ## Push Docker image to Docker Hub
	@echo "πŸš€ Pushing Docker image to Docker Hub"
	docker push $(IMAGE_NAME):$(TAG)

.PHONY: bake-container-and-push
bake-container-and-push: bake-container container-push ## Build and push Docker image to Docker Hub

.PHONY: clean-container
clean-container: ## Clean up Docker resources related to the app
	@echo "πŸš€ Deleting Docker image for app: $(IMAGE_NAME)"
	@docker images $(IMAGE_NAME) --format "{{.Repository}}:{{.Tag}}" | xargs -r docker rmi -f || echo "No image to delete"

	@echo "πŸš€ Deleting unused Docker volumes"
	@docker volume ls -qf dangling=true | xargs -r docker volume rm || echo "No unused volumes to delete"

	@echo "πŸš€ Deleting unused Docker networks"
	@docker network ls -q --filter "dangling=true" | xargs -r docker network rm || echo "No unused networks to delete"

	@echo "πŸš€ Cleaning up stopped containers"
	@docker ps -aq --filter "status=exited" | xargs -r docker rm || echo "No stopped containers to clean up"


# =============================
# Debug
# =============================

.PHONY: print-dependency-tree
print-dependency-tree: ## Print dependency tree
	@echo "Printing dependency tree..."
	@poetry run pipdeptree -p $(PACKAGE_NAME)


# =============================
# Cleanup
# =============================
.PHONY: teardown
teardown: clean-bake clean-container ## Clean up temporary files and directories and destroy the virtual environment, Docker image from your local machine
	@echo "πŸš€ Cleaning up temporary files and directories"
	@rm -rf .pytest_cache || true
	@rm -rf dist || true
	@rm -rf build || true
	@rm -rf htmlcov || true
	@rm -rf .venv || true
	@rm -rf .mypy_cache || true
	@rm -rf site || true
	@find . -type d -name "__pycache__" -exec rm -rf {} + || true
	@rm -rf .ruff_cache || true
	@echo "πŸš€ Clean up completed."

.PHONY: teardown-all
teardown-all: teardown clean-cloud-env ## Clean up temporary files and directories and destroy the virtual environment, Docker image, and Cloud resources