From 3de059de8d8005e9b4bed1defb8a6cf1e9e2051f Mon Sep 17 00:00:00 2001 From: Anupam Date: Thu, 5 Mar 2026 09:29:32 +0530 Subject: [PATCH 1/5] refactor: kzb-01 fldr restructure --- python/gcp-compute/get_compute_engine_list.py | 27 +++++++ python/gcp-compute/get_gce_metadata.py | 34 +++++++++ python/gcp-compute/get_gce_properties.py | 34 +++++++++ python/gcp-compute/get_instances_with_eips.py | 25 +++++++ .../gcp-compute/get_unused_compute_disks.py | 20 +++++ .../gcp-compute/get_unused_external_ips_1.py | 26 +++++++ .../gcp-compute/get_unused_external_ips_2.py | 74 +++++++++++++++++++ python/gcp-compute/requirements.txt | 3 + python/gcp-compute/stop_compute_instance.py | 44 +++++++++++ .../gcp-resource-manager/get_all_projects.py | 40 ++++++++++ python/gcp-resource-manager/requirements.txt | 1 + python/gcp-security/get_key_details.py | 22 ++++++ python/gcp-security/requirements.txt | 2 + 13 files changed, 352 insertions(+) create mode 100644 python/gcp-compute/get_compute_engine_list.py create mode 100644 python/gcp-compute/get_gce_metadata.py create mode 100644 python/gcp-compute/get_gce_properties.py create mode 100644 python/gcp-compute/get_instances_with_eips.py create mode 100644 python/gcp-compute/get_unused_compute_disks.py create mode 100644 python/gcp-compute/get_unused_external_ips_1.py create mode 100644 python/gcp-compute/get_unused_external_ips_2.py create mode 100644 python/gcp-compute/requirements.txt create mode 100644 python/gcp-compute/stop_compute_instance.py create mode 100644 python/gcp-resource-manager/get_all_projects.py create mode 100644 python/gcp-resource-manager/requirements.txt create mode 100644 python/gcp-security/get_key_details.py create mode 100644 python/gcp-security/requirements.txt diff --git a/python/gcp-compute/get_compute_engine_list.py b/python/gcp-compute/get_compute_engine_list.py new file mode 100644 index 0000000..ba35602 --- /dev/null +++ b/python/gcp-compute/get_compute_engine_list.py @@ -0,0 +1,27 @@ +import argparse +from google.cloud import compute_v1 + +def get_compute_instances(project_id): + """ Prints all the google compute instances of a project """ + + instance_client = compute_v1.InstancesClient() + + request = compute_v1.AggregatedListInstancesRequest() + request.project = project_id + request.max_results = 50 + + agg_list = instance_client.aggregated_list(request=request) + + for zone, response in agg_list: + if response.instances: + for instance in response.instances: + print(f"Instance Name: {instance.name}, Instance ID: {instance.id}, Instance Zone: {zone}") + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("project_id", help="Your Google Cloud project ID.") + args = parser.parse_args() + get_compute_instances(args.project_id) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/python/gcp-compute/get_gce_metadata.py b/python/gcp-compute/get_gce_metadata.py new file mode 100644 index 0000000..6986cdf --- /dev/null +++ b/python/gcp-compute/get_gce_metadata.py @@ -0,0 +1,34 @@ +# Import the required python libraries +import requests + +def get_instance_metadata(root_url, request_header, metadata_list): + """ + This function returns the google compute instance metadata. + + Note: You can query the contents of the metadata server by making a request to the root URLs from within + a virtual machine instance. + Use the http://metadata.google.internal/computeMetadata/v1/ root URL to make requests to metadata server. + + Ref: https://cloud.google.com/compute/docs/metadata/overview#querying + """ + + for metadata in metadata_list: + try: + response = requests.get(root_url + metadata, headers=request_header) + print(response.text) + except Exception as error: + print(f'Error occurred: {error}') + +def main(): + """ + This main function calls the `get_instance_metadata` function to get google compute instance metadata. + """ + + root_url = "http://metadata.google.internal/computeMetadata/v1/" + request_header = {"Metadata-Flavor": "Google"} + metadata_list = ["instance/hostname", "instance/network-interfaces/0/ip"] + + get_instance_metadata(root_url, request_header, metadata_list) + +if __name__ == "__main__": + main() diff --git a/python/gcp-compute/get_gce_properties.py b/python/gcp-compute/get_gce_properties.py new file mode 100644 index 0000000..1582f0f --- /dev/null +++ b/python/gcp-compute/get_gce_properties.py @@ -0,0 +1,34 @@ +# Import the required python libraries +from google.cloud import compute_v1 + +def get_instance_properties(project_id, zone, instance_name): + """ + This function returns the google compute instance properties. + """ + + instances_client = compute_v1.InstancesClient() + + try: + instance_properties = instances_client.get(project=project_id, zone=zone, instance=instance_name) + if instance_properties: + print(f"Instance Name: {instance_properties.name}") + print(f"Instance ID: {instance_properties.id}") + print(f"Instance Status: {instance_properties.status}") + print(f"Instance Machine Type: {instance_properties.machine_type}") + print(f"Instance Creation Time: {instance_properties.creation_timestamp}") + except Exception as error: + print(f"Error retrieving instance properties: {error}") + +def main(): + """ + This main function calls the `get_instance_properties` function to get google compute instance properties. + """ + + project_id = "UPDATE_ME" + zone = "UPDATE_ME" + instance_name = "UPDATE_ME" + + get_instance_properties(project_id, zone, instance_name) + +if __name__ == "__main__": + main() diff --git a/python/gcp-compute/get_instances_with_eips.py b/python/gcp-compute/get_instances_with_eips.py new file mode 100644 index 0000000..bdba7bf --- /dev/null +++ b/python/gcp-compute/get_instances_with_eips.py @@ -0,0 +1,25 @@ +import argparse +from google.cloud import compute_v1 + +def get_gce_with_eips(project_id): + """ Prints all the instances with external IP in any of its network interface """ + + instance_client = compute_v1.InstancesClient() + agg_list = instance_client.aggregated_list(project=project_id) + + for zone, response in agg_list: + if response.instances: + for instance in response.instances: + for interface in instance.network_interfaces: + if interface.access_configs: + print(f"Instance Name: {instance.name}, Instance ID: {instance.id}, Instance Zone: {zone}") + break + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("project_id", help="Your Google Cloud project ID.") + args = parser.parse_args() + get_gce_with_eips(args.project_id) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/python/gcp-compute/get_unused_compute_disks.py b/python/gcp-compute/get_unused_compute_disks.py new file mode 100644 index 0000000..57e8a9f --- /dev/null +++ b/python/gcp-compute/get_unused_compute_disks.py @@ -0,0 +1,20 @@ +from google.cloud import compute_v1 + +def get_unused_compute_disks(project_id): + """ + Prints the unused regional/zonal compute disks of a project. + """ + + addresses_client = compute_v1.DisksClient() + for zone, response in addresses_client.aggregated_list(project=project_id): + if response.disks: + for disk in response.disks: + if len(disk.users) == 0: + print(f"Disk Name: {disk.name}, Disk Size: {disk.size_gb}, Disk Location: {zone}") + +def main(project_id): + get_unused_compute_disks(project_id) + +if __name__ == "__main__": + project_id = "UPDATE_ME" + main(project_id) \ No newline at end of file diff --git a/python/gcp-compute/get_unused_external_ips_1.py b/python/gcp-compute/get_unused_external_ips_1.py new file mode 100644 index 0000000..91cbdcd --- /dev/null +++ b/python/gcp-compute/get_unused_external_ips_1.py @@ -0,0 +1,26 @@ +# from google.oauth2 import service_account +from google.cloud import compute_v1 + +# Use this, if authentication to be done via service account +# credentials = service_account.Credentials.from_service_account_file('sa-key.json') +# addresses_client = compute_v1.AddressesClient(credentials=credentials) + +def get_reserved_ips(project_ids): + addresses_client = compute_v1.AddressesClient() + + for project_id in project_ids: + request = compute_v1.AggregatedListAddressesRequest() + request.project = project_id + + for region, response in addresses_client.aggregated_list(request=request): + if response.addresses: + for address in response.addresses: + if(address.address_type == "EXTERNAL" and address.status == "RESERVED"): + print("External IP:", address.name, "Region:", region) + +def main(): + project_ids = ["UPDATE_ME"] + get_reserved_ips(project_ids) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/python/gcp-compute/get_unused_external_ips_2.py b/python/gcp-compute/get_unused_external_ips_2.py new file mode 100644 index 0000000..9b81732 --- /dev/null +++ b/python/gcp-compute/get_unused_external_ips_2.py @@ -0,0 +1,74 @@ +"""Get Unsed External IP Addresses + +This script prints all the unused external IP addresses of all the projects +present under a parent(folder/organization) along with details like (region, +external IP name, project ID) + +This script requires that Cloud Client Libraries of gcp services +`google-cloud-compute` and `google-cloud-resource-manager` be installed +within the Python environment you are running this script in. + +This file can also be imported as a module and contains the following +functions: + + * get_gcp_projects - returns the list of projects under a parent + * get_reserved_ips - prints the unused eips along with details + * main - the main function of the script +""" + +from google.cloud import compute_v1, resourcemanager_v3 + +def get_gcp_projects(parent): + """Returns the list of projects under a parent (folder/org) + + Args: + parent (str): the id of the parent whose projects to be returned + + Returns: + list: a list of strings representing the projects under a parent + """ + + project_ids = [] + + # Create a client + client = resourcemanager_v3.ProjectsClient() + # Initialize request argument(s) + request = resourcemanager_v3.ListProjectsRequest(parent=parent) + # Make the request + page_result = client.list_projects(request=request) + # Handle the response + for response in page_result: + project_ids.append(response.project_id) + return project_ids + +def get_reserved_ips(project_ids): + """Prints the list of unused external IPs of a GCP Project + + Args: + project_ids (list): the list of the projects whose unused external + IP addresses to be printed + + Returns: + it returns None as the function doesn't have any return statement + but it prints the list of unused external IPs of a GCP Project + """ + + addresses_client = compute_v1.AddressesClient() + + for project_id in project_ids: + request = compute_v1.AggregatedListAddressesRequest() + request.project = project_id + + for region, response in addresses_client.aggregated_list(request=request): + if response.addresses: + for address in response.addresses: + if(address.address_type == "EXTERNAL" and address.status == "RESERVED"): + print(f"Project ID: {project_id} External IP: {address.name} Region: {region}") + +def main(): + parent="organizations/UPDATE_ME" # For folder, use "folders/UPDATE_ME" + project_ids = get_gcp_projects(parent) + get_reserved_ips(project_ids) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/python/gcp-compute/requirements.txt b/python/gcp-compute/requirements.txt new file mode 100644 index 0000000..3fb67a8 --- /dev/null +++ b/python/gcp-compute/requirements.txt @@ -0,0 +1,3 @@ +requests +google-cloud-compute==1.11.0 +google-cloud-resource-manager==1.10.1 \ No newline at end of file diff --git a/python/gcp-compute/stop_compute_instance.py b/python/gcp-compute/stop_compute_instance.py new file mode 100644 index 0000000..682fc83 --- /dev/null +++ b/python/gcp-compute/stop_compute_instance.py @@ -0,0 +1,44 @@ +from google.cloud import compute_v1 + +def get_compute_instances(project_id): + """ + Gets the details list of targetted Google Compute Engine instances. + """ + + instance_list = [] # Initialize an empty list to store instance details + + instance_client = compute_v1.InstancesClient() + agg_list = instance_client.aggregated_list(project=project_id) + + for zone, response in agg_list: + if response.instances: + for instance in response.instances: + if ("purpose", "test") in instance.labels.items(): + temp_instance_dict = {} # Initialize a dictionary to temporary hold and dump values in a dict + temp_instance_dict.update({"instance_name" : instance.name}) + temp_instance_dict.update({"instance_zone" : zone.split("/")[1]}) + temp_instance_dict.update({"instance_project" : project_id}) + instance_list.append(temp_instance_dict) + return instance_list + +def stop_compute_instances(instance_list): + """ + Stops running Google Compute Engine instances. + """ + instance_client = compute_v1.InstancesClient() + + for instance in instance_list: + operation = instance_client.stop( + project=instance["instance_project"], zone=instance["instance_zone"], instance=instance["instance_name"] + ) + result = operation.result(timeout=300) + + print("Stop operation completed for targetted compute instances.") + +def main(project_id): + instance_list = get_compute_instances(project_id) + stop_compute_instances(instance_list) + +if __name__ == "__main__": + project_id = "UPDATE_ME" + main(project_id) \ No newline at end of file diff --git a/python/gcp-resource-manager/get_all_projects.py b/python/gcp-resource-manager/get_all_projects.py new file mode 100644 index 0000000..369f00a --- /dev/null +++ b/python/gcp-resource-manager/get_all_projects.py @@ -0,0 +1,40 @@ +from google.cloud import resourcemanager_v3 + +def list_containers(parent): + all_project_ids = [] + all_folder_ids = [] + folder_ids = [] + + prj_client = resourcemanager_v3.ProjectsClient() + prj_result = prj_client.list_projects(parent=parent) + if prj_result: + for prj_response in prj_result: + all_project_ids.append(prj_response.project_id) + + fldr_client = resourcemanager_v3.FoldersClient() + fldr_result = fldr_client.list_folders(parent=parent) + if fldr_result: + for fldr_response in fldr_result: + all_folder_ids.append(fldr_response.name) + folder_ids.append(fldr_response.name) + + while all_folder_ids: + folder_id = all_folder_ids.pop() + subfldr_result = fldr_client.list_folders(parent=folder_id) + if subfldr_result: + for subfldr_response in subfldr_result: + all_folder_ids.append(subfldr_response.name) + folder_ids.append(subfldr_response.name) + + project_under_folder_result = prj_client.list_projects(parent=folder_id) + if project_under_folder_result: + for prj_under_fldr_response in project_under_folder_result: + all_project_ids.append(prj_under_fldr_response.project_id) + return(f"Project IDs:{all_project_ids}, Folder IDs:{folder_ids}") + +def main(): + parent="organizations/UPDATE_ME" + print(list_containers(parent)) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/python/gcp-resource-manager/requirements.txt b/python/gcp-resource-manager/requirements.txt new file mode 100644 index 0000000..0814a65 --- /dev/null +++ b/python/gcp-resource-manager/requirements.txt @@ -0,0 +1 @@ +google-cloud-resource-manager==1.10.1 \ No newline at end of file diff --git a/python/gcp-security/get_key_details.py b/python/gcp-security/get_key_details.py new file mode 100644 index 0000000..ac95f0e --- /dev/null +++ b/python/gcp-security/get_key_details.py @@ -0,0 +1,22 @@ +from google.cloud import kms_v1 + +def get_crypto_key(crypto_key_name): + client = kms_v1.KeyManagementServiceClient() + + # request = kms_v1.GetCryptoKeyRequest( + # name=crypto_key_name, + # ) + # response = client.get_crypto_key(request=request) + + response = client.get_crypto_key(name=crypto_key_name) + if response: + if(response.rotation_period.days >= 90): + print("Key rotation period is good.") + +def main(): + crypto_key_name = "projects/UPDATE_ME/locations/UPDATE_ME/keyRings/UPDATE_ME/cryptoKeys/UPDATE_ME" + get_crypto_key(crypto_key_name) + +# Executing as standalone script +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/python/gcp-security/requirements.txt b/python/gcp-security/requirements.txt new file mode 100644 index 0000000..d330145 --- /dev/null +++ b/python/gcp-security/requirements.txt @@ -0,0 +1,2 @@ +google-cloud-resource-manager==1.10.1 +google-cloud-kms==2.17.0 \ No newline at end of file From 42cb382c2420e550a8c27218890939ccabd7e945 Mon Sep 17 00:00:00 2001 From: Anupam Date: Thu, 5 Mar 2026 09:31:26 +0530 Subject: [PATCH 2/5] feat: kzb-01 add common workflows --- .github/CODEOWNERS | 5 ++++ .github/conventional-commit-lint.yaml | 5 ++++ .github/pull-request_template.md | 15 ++++++++++ .github/workflows/pull-request.yml | 40 +++++++++++++++++++++++++++ 4 files changed, 65 insertions(+) create mode 100644 .github/CODEOWNERS create mode 100644 .github/conventional-commit-lint.yaml create mode 100644 .github/pull-request_template.md create mode 100644 .github/workflows/pull-request.yml diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..5392490 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,5 @@ +# This is a comment. Each line is a file pattern followed by one or more owners. + +# These owners will be the default owners for everything in the repo. @oneanupam will be requested for review when someone opens a pull request. + +- @oneanupam diff --git a/.github/conventional-commit-lint.yaml b/.github/conventional-commit-lint.yaml new file mode 100644 index 0000000..ad67fc6 --- /dev/null +++ b/.github/conventional-commit-lint.yaml @@ -0,0 +1,5 @@ +# Config for GitHub App that ensures that commit messages and pull requests are based on conventionalcommits.org +# https://github.com/googleapis/repo-automation-bots/tree/main/packages/conventional-commit-lint + +enabled: true +always_check_pr_title: true \ No newline at end of file diff --git a/.github/pull-request_template.md b/.github/pull-request_template.md new file mode 100644 index 0000000..4bdd312 --- /dev/null +++ b/.github/pull-request_template.md @@ -0,0 +1,15 @@ +# Description +Please include a short summary of the update made along with the context. + +## Checklist +- [ ] Self-review of the code is performed. +- [ ] Code has been fully tested and completely functional. + +## Type of Change +- [ ] break: Resolved a breaking change. This will increment the major version. +- [ ] feat: A new feature or enhancement added to the codebase. This will increment the minor version. +- [ ] fix: A bug fix or correction to resolve an issue. This will increment the patch version. +- [ ] chore: Other changes not directly affecting the code (e.g., documentation update). No version increment. + +## Reference +https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/creating-a-pull-request-template-for-your-repository \ No newline at end of file diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml new file mode 100644 index 0000000..6ee7457 --- /dev/null +++ b/.github/workflows/pull-request.yml @@ -0,0 +1,40 @@ +name: Pull Request Checks + +on: + pull_request: + branches: + - master + types: + - opened + - synchronize + - reopened + +jobs: + pull-request-check: + runs-on: ubuntu-latest + steps: + # Checkout the repository code + - name: Code checkout + id: code_checkout + uses: actions/checkout@v4 + + # Check PR title prefix to ensure it follows the convention + - name: Check PR title prefix + run: | + echo "PR Title: '${{ github.event.pull_request.title }}'" + + if [[ ! "${{ github.event.pull_request.title }}" =~ ^(ci|feat|fix|chore|docs|refactor): ]]; then + echo "❌ PR title must start with one of: ci:, feat:, fix:, chore:, docs:, refactor:" + exit 1 + else + echo "✅ PR title is valid." + fi + + # Scan the repo for any sensitive information like secrets etc + - name: Secret Scanning + uses: trufflesecurity/trufflehog@main + with: + path: ./ # Code repository path + base: "" # Start scanning from here + head: ${{ github.head_ref || github.ref_name }} # Scan commits until here + extra_args: --only-verified From c6c8f7b8b8b4482f865f689b313e54eeb0cad4a0 Mon Sep 17 00:00:00 2001 From: Anupam Date: Thu, 5 Mar 2026 09:32:36 +0530 Subject: [PATCH 3/5] chore: kzb-01 add configs --- .editorconfig | 50 +++++++++++++++++++++++++++++++++++++++++ .pre-commit-config.yaml | 17 ++++++++++++++ .vscode/extensions.json | 5 +++++ .vscode/settings.json | 5 +++++ 4 files changed, 77 insertions(+) create mode 100644 .editorconfig create mode 100644 .pre-commit-config.yaml create mode 100644 .vscode/extensions.json create mode 100644 .vscode/settings.json diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..b097c31 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,50 @@ +# EditorConfig is awesome: http://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +# Unix-style newlines at the bottom of every file +end_of_line = lf +charset = utf-8 + +# indentation style and size +indent_style = space +indent_size = 2 + +# Make sure every file has a blank line at the end +insert_final_newline = true + +# Remove any whitespace characters preceding newline characters +trim_trailing_whitespace = true + +# Give operators breathing room, but not brackets +spaces_around_operators = true +spaces_around_brackets = false + +# 4 space indentation +[*.{py,java}] +indent_size = 4 + +[*.json] +indent_size = 4 + +# 2 space indentation +[*.{js,html}] +indent_size = 2 + +[*.{tf}] +indent_size = 2 + +[*.rb] +indent_size = 2 + +[*.yml] +indent_size = 2 + +[*.yaml] +indent_size = 2 + +[*.{md}] +indent_size = unset +trim_trailing_whitespace = false diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..e3e1d37 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,17 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.6.0 + hooks: + - id: no-commit-to-branch + args: [--branch, main, --branch, master] + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-added-large-files + - id: detect-private-key + - repo: https://github.com/gitleaks/gitleaks + rev: v8.18.4 + hooks: + - id: gitleaks diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..ae7c2f6 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "EditorConfig.EditorConfig" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7b6db2d --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.insertFinalNewline": true, + "files.trimTrailingWhitespace": true, + "files.trimFinalNewlines": true +} From fbc607417d1a835557260a539db034dbe06d46f5 Mon Sep 17 00:00:00 2001 From: Anupam Date: Thu, 5 Mar 2026 09:33:49 +0530 Subject: [PATCH 4/5] docs: kzb-01 add docs --- docs/index.md | 0 docs/usecases.md | 9 +++++++++ 2 files changed, 9 insertions(+) create mode 100644 docs/index.md create mode 100644 docs/usecases.md diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/usecases.md b/docs/usecases.md new file mode 100644 index 0000000..25726ed --- /dev/null +++ b/docs/usecases.md @@ -0,0 +1,9 @@ +# GCP Common UseCases +This document lists the most of the common use cases for which python scripts are written. + +1. Get all the unused external IP addresses reserved in a GCP project to save operational cost. +2. [WIP] Get all the service account in a GCP project having service account keys. +3. Get all the compute engines in a google cloud project having external IP address. +4. Get all the unused compute disks in a google cloud project to save operational cost. +5. Get all the projects in a GCP organization. +6. Stop all the google compute engine instances based on a label association. \ No newline at end of file From 0b004fe22639e0e20fe7998295b29c611d6c0fa7 Mon Sep 17 00:00:00 2001 From: Anupam Date: Thu, 5 Mar 2026 09:34:46 +0530 Subject: [PATCH 5/5] docs: kzb-01 add contributing guidelines --- CONTRIBUTING.md | 59 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..441594c --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,59 @@ +# Contribution + +This document provides guidelines for contributing to the project. + +## Pull Request + +Pull requests are the best way to propose changes to the codebase (we use ["fork-and-pull" Git workflow](https://github.com/susam/gitpr)). We actively welcome your pull requests: + +1. Fork the repository to your own Github account. +2. Clone the project to your machine. +3. Create a branch locally with a succinct but descriptive name. +4. Commit changes to the branch following any formatting and testing guidelines specific to this repo. +5. Push changes to your forked repository. +6. Open a Pull Request in our repository. + +## Guidelines + +### Commit Message Guidelines + +Use the combination of "Commit Type" and "Commit Summary" with an optional "Commit description". + +- Commit Type: Use the proper commit type for the changes as per [conventional commit](https://www.conventionalcommits.org/en/v1.0.0/) types. +- Commit Summary: Always use the imperative present tense (Write your commit messages as if you're giving a command or describing what the commit does, not what you did). Don’t capitalize the first letter of the commit message. Don’t use a period at the end of your text. + +``` +Ex: Suppose, You updated a file. So, the commit message could be - + docs: update readme file + feat: add application dockerfile +``` + +### PR Guidelines + +Format: [Commit Type] Short Summary + +``` +Ex: Suppose, You added some functionality. So, the title could be - + [feat] added function to read input from user +``` + +### Coding Guidelines + +- Try to put comments in your code, where required. +- Try to follow DRY (Don't Repeat Yourself) principle. +- Follow the style guide to write terraform code recommended by terraform. + +## Report Bugs + +We use GitHub issues to track bugs. Report a bug by opening a new issue. + +## Linting and Formatting + +All of the bash scripts in the repository must be linted or formatted using `shellcheck` to maintain a standard of quality. + +- On the web, Paste a shell script on https://www.shellcheck.net for instant feedback. ShellCheck.net is always synchronized to the latest git commit, and is the easiest way to give ShellCheck a go. +- From your terminal, Run shellcheck yourscript in your terminal for instant output, + +## License + +By contributing, you agree that your contributions will be licensed under its [MIT License](LICENSE).