From 0a1a7213370b2dfa4baadb2ecb619065127a29d3 Mon Sep 17 00:00:00 2001 From: Vianpyro Date: Sat, 7 Jun 2025 13:26:59 +0000 Subject: [PATCH 01/16] Enhance .gitattributes for SQL file detection --- .gitattributes | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitattributes b/.gitattributes index 176a458..8293c25 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,3 @@ * text=auto +*.sql linguist-language=sql +*.sql linguist-detectable=true From be29b6a408250cb7ffa9002866a1a2e1e737372a Mon Sep 17 00:00:00 2001 From: Vianpyro Date: Sat, 7 Jun 2025 13:31:43 +0000 Subject: [PATCH 02/16] Fix .gitattributes for SQL file detection and update test file handling --- .gitattributes | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitattributes b/.gitattributes index 8293c25..618a1d0 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,3 @@ * text=auto -*.sql linguist-language=sql -*.sql linguist-detectable=true +*.sql linguist-language=SQL linguist-detectable=true +*.test.sql -linguist-language From 26370f1bbeb1811aefbc8a448612f60359af40a2 Mon Sep 17 00:00:00 2001 From: Vianpyro Date: Sat, 7 Jun 2025 14:00:21 +0000 Subject: [PATCH 03/16] Add schema tests for database table existence verification --- database/tests/authentication.test.sql | 4 ++- database/tests/sample.test.sql | 6 ++-- database/tests/schema.test.sql | 44 ++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 database/tests/schema.test.sql diff --git a/database/tests/authentication.test.sql b/database/tests/authentication.test.sql index 1270361..7b9772c 100644 --- a/database/tests/authentication.test.sql +++ b/database/tests/authentication.test.sql @@ -1,5 +1,7 @@ CREATE EXTENSION IF NOT EXISTS pgtap; +BEGIN; + SELECT plan(2); -- Clean environment @@ -34,6 +36,6 @@ SELECT is( 1, 'A successful login attempt is logged' ); --- Finish the tests and clean up. SELECT finish(TRUE); + ROLLBACK; diff --git a/database/tests/sample.test.sql b/database/tests/sample.test.sql index edb07a9..5986409 100644 --- a/database/tests/sample.test.sql +++ b/database/tests/sample.test.sql @@ -1,13 +1,13 @@ CREATE EXTENSION IF NOT EXISTS pgtap; +BEGIN; + SELECT plan(2); -BEGIN; -- Basic tests to ensure pgtap is working SELECT ok(TRUE, 'True is ok'); SELECT is(1 + 1, 2, '1 + 1 equals 2'); - --- Finish the tests and clean up. SELECT finish(TRUE); + ROLLBACK; diff --git a/database/tests/schema.test.sql b/database/tests/schema.test.sql new file mode 100644 index 0000000..de0465b --- /dev/null +++ b/database/tests/schema.test.sql @@ -0,0 +1,44 @@ +CREATE EXTENSION IF NOT EXISTS pgtap; + +BEGIN; + +SELECT plan(34); + +SELECT has_table('users', 'Table exists'); +SELECT has_table('user_permissions', 'Table exists'); +SELECT has_table('user_sessions', 'Table exists'); +SELECT has_table('email_verifications', 'Table exists'); +SELECT has_table('password_resets', 'Table exists'); +SELECT has_table('user_authentication_methods', 'Table exists'); +SELECT has_table('login_attempts', 'Table exists'); +SELECT has_table('products', 'Table exists'); +SELECT has_table('product_categories', 'Table exists'); +SELECT has_table('product_variants', 'Table exists'); +SELECT has_table('product_images', 'Table exists'); +SELECT has_table('product_likes', 'Table exists'); +SELECT has_table('product_comments', 'Table exists'); +SELECT has_table('moderation_actions', 'Table exists'); +SELECT has_table('carts', 'Table exists'); +SELECT has_table('cart_items', 'Table exists'); +SELECT has_table('orders', 'Table exists'); +SELECT has_table('order_items', 'Table exists'); +SELECT has_table('order_status_histories', 'Table exists'); +SELECT has_table('order_delivery_infos', 'Table exists'); +SELECT has_table('order_timestamps', 'Table exists'); +SELECT has_table('discount_codes', 'Table exists'); +SELECT has_table('user_discounts', 'Table exists'); +SELECT has_table('loyalty_programs', 'Table exists'); +SELECT has_table('user_loyalty_progress', 'Table exists'); +SELECT has_table('languages', 'Table exists'); +SELECT has_table('translations', 'Table exists'); +SELECT has_table('product_translations', 'Table exists'); +SELECT has_table('category_translations', 'Table exists'); +SELECT has_table('metrics_events', 'Table exists'); +SELECT has_table('admin_accounts', 'Table exists'); +SELECT has_table('admin_actions', 'Table exists'); +SELECT has_table('contact_messages', 'Table exists'); +SELECT has_table('feedbacks', 'Table exists'); + +SELECT finish(TRUE); + +ROLLBACK; From 62a92912390e176568dd5c34f7ab45ff033a7f18 Mon Sep 17 00:00:00 2001 From: Vianpyro Date: Sat, 7 Jun 2025 14:07:13 +0000 Subject: [PATCH 04/16] Enhance schema tests to verify types, tables, and indexes --- database/tests/schema.test.sql | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/database/tests/schema.test.sql b/database/tests/schema.test.sql index de0465b..27fc190 100644 --- a/database/tests/schema.test.sql +++ b/database/tests/schema.test.sql @@ -2,7 +2,22 @@ CREATE EXTENSION IF NOT EXISTS pgtap; BEGIN; -SELECT plan(34); +SELECT plan(48); + +-- Verify that the schema has the expected types + +SELECT has_type('delivery_type', 'Type exists'); +SELECT has_type('order_status', 'Type exists'); +SELECT has_type('payment_status', 'Type exists'); +SELECT has_type('authentication_method', 'Type exists'); +SELECT has_type('moderation_action_type', 'Type exists'); +SELECT has_type('moderation_target_type', 'Type exists'); +SELECT has_type('discount_type', 'Type exists'); +SELECT has_type('promotion_type', 'Type exists'); +SELECT has_type('admin_account_role', 'Type exists'); +SELECT has_type('admin_action_target_type', 'Type exists'); + +-- Verify that the schema has the expected tables SELECT has_table('users', 'Table exists'); SELECT has_table('user_permissions', 'Table exists'); @@ -39,6 +54,13 @@ SELECT has_table('admin_actions', 'Table exists'); SELECT has_table('contact_messages', 'Table exists'); SELECT has_table('feedbacks', 'Table exists'); +-- Verify that the schema has the expected indexes + +SELECT has_index('users', 'idx_users_email_hash', 'Index exists'); +SELECT has_index('user_sessions', 'idx_user_sessions_token', 'Index exists'); +SELECT has_index('login_attempts', 'idx_login_attempts_user_id', 'Index exists'); +SELECT has_index('metrics_events', 'idx_metrics_events_event_type', 'Index exists'); + SELECT finish(TRUE); ROLLBACK; From 86b756a9477eaa70ccb50859a9f8bc44c30ba13a Mon Sep 17 00:00:00 2001 From: Vianpyro Date: Sat, 7 Jun 2025 14:12:38 +0000 Subject: [PATCH 05/16] Add seed data tests for language existence verification --- database/tests/seed_data.test.sql | 33 +++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 database/tests/seed_data.test.sql diff --git a/database/tests/seed_data.test.sql b/database/tests/seed_data.test.sql new file mode 100644 index 0000000..fce97e2 --- /dev/null +++ b/database/tests/seed_data.test.sql @@ -0,0 +1,33 @@ +CREATE EXTENSION IF NOT EXISTS pgtap; + +BEGIN; + +SELECT plan(3); + +SELECT is( + ( + SELECT count(*)::INT FROM languages + WHERE iso_code = 'fr' + ), + 1, 'Language with ISO code "fr" exists' +); + +SELECT is( + ( + SELECT count(*)::INT FROM languages + WHERE iso_code = 'en' + ), + 1, 'Language with ISO code "en" exists' +); + +SELECT is( + ( + SELECT count(*)::INT FROM languages + WHERE iso_code = 'es' + ), + 1, 'Language with ISO code "es" exists' +); + +SELECT finish(TRUE); + +ROLLBACK; From 8ff7849603e0cb3223b3315c140e5e19faa85a84 Mon Sep 17 00:00:00 2001 From: Vianpyro Date: Sat, 7 Jun 2025 14:39:02 +0000 Subject: [PATCH 06/16] Implement user authentication procedures and functions, including login attempt logging, 2FA checks, and user registration. --- database/functions/authenticate_user.sql | 27 ++++++ database/functions/disable_2fa.sql | 8 ++ database/functions/get_user_2fa_secret.sql | 9 ++ database/functions/is_2fa_enabled.sql | 12 +++ database/procedures/authentication.sql | 90 ------------------- .../procedures/handle_successful_login.sql | 16 ++++ database/procedures/log_login_attempt.sql | 13 +++ database/procedures/register_user.sql | 36 ++++++++ 8 files changed, 121 insertions(+), 90 deletions(-) create mode 100644 database/functions/authenticate_user.sql create mode 100644 database/functions/disable_2fa.sql create mode 100644 database/functions/get_user_2fa_secret.sql create mode 100644 database/functions/is_2fa_enabled.sql delete mode 100644 database/procedures/authentication.sql create mode 100644 database/procedures/handle_successful_login.sql create mode 100644 database/procedures/log_login_attempt.sql create mode 100644 database/procedures/register_user.sql diff --git a/database/functions/authenticate_user.sql b/database/functions/authenticate_user.sql new file mode 100644 index 0000000..af8534f --- /dev/null +++ b/database/functions/authenticate_user.sql @@ -0,0 +1,27 @@ +-- Authenticate a user and log the result +CREATE OR REPLACE FUNCTION authenticate_user( + p_username VARCHAR, + p_password_hash VARCHAR, + p_ip_address INET, + p_user_agent TEXT +) RETURNS BOOLEAN AS $$ +DECLARE + v_user_id INTEGER; +BEGIN + -- Attempt to find the user by username and hashed password + SELECT user_id INTO v_user_id + FROM users + WHERE username = p_username AND password_hash = p_password_hash + LIMIT 1; + + IF v_user_id IS NOT NULL THEN + -- Successful login: handle and log + CALL handle_successful_login(v_user_id, p_ip_address, p_user_agent); + RETURN TRUE; + ELSE + -- Failed login: log with NULL user_id + CALL log_login_attempt(NULL, p_ip_address, p_user_agent, FALSE); + RETURN FALSE; + END IF; +END; +$$ LANGUAGE plpgsql; diff --git a/database/functions/disable_2fa.sql b/database/functions/disable_2fa.sql new file mode 100644 index 0000000..0840da0 --- /dev/null +++ b/database/functions/disable_2fa.sql @@ -0,0 +1,8 @@ +-- Disable 2FA for a user +CREATE OR REPLACE FUNCTION disable_2fa(p_user_id INTEGER) RETURNS VOID AS $$ +BEGIN + UPDATE user_authentication_methods + SET is_enabled = FALSE, updated_at = NOW() + WHERE user_id = p_user_id; +END; +$$ LANGUAGE plpgsql; diff --git a/database/functions/get_user_2fa_secret.sql b/database/functions/get_user_2fa_secret.sql new file mode 100644 index 0000000..06d53b8 --- /dev/null +++ b/database/functions/get_user_2fa_secret.sql @@ -0,0 +1,9 @@ +-- Get the user's authentication methods secret +CREATE OR REPLACE FUNCTION get_user_authentication_method_secret(p_user_id INTEGER) RETURNS TABLE (method TEXT, secret TEXT) AS $$ +BEGIN + RETURN QUERY + SELECT authentication_method, user_authentication_method_secret + FROM user_authentication_methods + WHERE user_id = p_user_id AND is_enabled = TRUE; +END; +$$ LANGUAGE plpgsql; diff --git a/database/functions/is_2fa_enabled.sql b/database/functions/is_2fa_enabled.sql new file mode 100644 index 0000000..8188427 --- /dev/null +++ b/database/functions/is_2fa_enabled.sql @@ -0,0 +1,12 @@ +-- Check if the user has 2FA enabled +CREATE OR REPLACE FUNCTION is_2fa_enabled(p_user_id INTEGER) RETURNS BOOLEAN AS $$ +DECLARE + v_enabled BOOLEAN; +BEGIN + SELECT is_enabled INTO v_enabled + FROM user_authentication_methods + WHERE user_id = p_user_id; + + RETURN COALESCE(v_enabled, FALSE); +END; +$$ LANGUAGE plpgsql; diff --git a/database/procedures/authentication.sql b/database/procedures/authentication.sql deleted file mode 100644 index c228fa3..0000000 --- a/database/procedures/authentication.sql +++ /dev/null @@ -1,90 +0,0 @@ --- Log a login attempt (used in both success and failure cases) -CREATE OR REPLACE PROCEDURE log_login_attempt( - p_user_id INTEGER, - p_ip_address INET, - p_user_agent TEXT, - p_success BOOLEAN -) -LANGUAGE plpgsql AS $$ -BEGIN - INSERT INTO login_attempts (user_id, ip_address, user_agent, success) - VALUES (p_user_id, p_ip_address, p_user_agent, p_success); -END; -$$; - --- Update last_login and log successful attempt -CREATE OR REPLACE PROCEDURE handle_successful_login( - p_user_id INTEGER, - p_ip_address INET, - p_user_agent TEXT -) -AS $$ -BEGIN - -- Update login timestamp - UPDATE users SET last_login_at = NOW(), updated_at = NOW() - WHERE user_id = p_user_id; - - -- Log success - CALL log_login_attempt(p_user_id, p_ip_address, p_user_agent, TRUE); -END; -$$ LANGUAGE plpgsql; - --- Check if the user has 2FA enabled -CREATE OR REPLACE FUNCTION is_2fa_enabled(p_user_id INTEGER) RETURNS BOOLEAN AS $$ -DECLARE - v_enabled BOOLEAN; -BEGIN - SELECT is_enabled INTO v_enabled - FROM user_authentication_methods - WHERE user_id = p_user_id; - - RETURN COALESCE(v_enabled, FALSE); -END; -$$ LANGUAGE plpgsql; - --- Get the user's authentication methods secret -CREATE OR REPLACE FUNCTION get_user_authentication_method_secret(p_user_id INTEGER) RETURNS TABLE (method TEXT, secret TEXT) AS $$ -BEGIN - RETURN QUERY - SELECT authentication_method, user_authentication_method_secret - FROM user_authentication_methods - WHERE user_id = p_user_id AND is_enabled = TRUE; -END; -$$ LANGUAGE plpgsql; - --- Disable 2FA for a user -CREATE OR REPLACE FUNCTION disable_2fa(p_user_id INTEGER) RETURNS VOID AS $$ -BEGIN - UPDATE user_authentication_methods - SET is_enabled = FALSE, updated_at = NOW() - WHERE user_id = p_user_id; -END; -$$ LANGUAGE plpgsql; - --- Authenticate a user and log the result -CREATE OR REPLACE FUNCTION authenticate_user( - p_username VARCHAR, - p_password_hash VARCHAR, - p_ip_address INET, - p_user_agent TEXT -) RETURNS BOOLEAN AS $$ -DECLARE - v_user_id INTEGER; -BEGIN - -- Attempt to find the user by username and hashed password - SELECT user_id INTO v_user_id - FROM users - WHERE username = p_username AND password_hash = p_password_hash - LIMIT 1; - - IF v_user_id IS NOT NULL THEN - -- Successful login: handle and log - CALL handle_successful_login(v_user_id, p_ip_address, p_user_agent); - RETURN TRUE; - ELSE - -- Failed login: log with NULL user_id - CALL log_login_attempt(NULL, p_ip_address, p_user_agent, FALSE); - RETURN FALSE; - END IF; -END; -$$ LANGUAGE plpgsql; diff --git a/database/procedures/handle_successful_login.sql b/database/procedures/handle_successful_login.sql new file mode 100644 index 0000000..ffd2e8a --- /dev/null +++ b/database/procedures/handle_successful_login.sql @@ -0,0 +1,16 @@ +-- Update last_login and log successful attempt +CREATE OR REPLACE PROCEDURE handle_successful_login( + p_user_id INTEGER, + p_ip_address INET, + p_user_agent TEXT +) +AS $$ +BEGIN + -- Update login timestamp + UPDATE users SET last_login_at = NOW(), updated_at = NOW() + WHERE user_id = p_user_id; + + -- Log success + CALL log_login_attempt(p_user_id, p_ip_address, p_user_agent, TRUE); +END; +$$ LANGUAGE plpgsql; diff --git a/database/procedures/log_login_attempt.sql b/database/procedures/log_login_attempt.sql new file mode 100644 index 0000000..c8f7d07 --- /dev/null +++ b/database/procedures/log_login_attempt.sql @@ -0,0 +1,13 @@ +-- Log a login attempt (used in both success and failure cases) +CREATE OR REPLACE PROCEDURE log_login_attempt( + p_user_id INTEGER, + p_ip_address INET, + p_user_agent TEXT, + p_success BOOLEAN +) +LANGUAGE plpgsql AS $$ +BEGIN + INSERT INTO login_attempts (user_id, ip_address, user_agent, success) + VALUES (p_user_id, p_ip_address, p_user_agent, p_success); +END; +$$; diff --git a/database/procedures/register_user.sql b/database/procedures/register_user.sql new file mode 100644 index 0000000..05877d8 --- /dev/null +++ b/database/procedures/register_user.sql @@ -0,0 +1,36 @@ +-- Register a new user +CREATE OR REPLACE PROCEDURE register_user( + p_email_encrypted TEXT, + p_email_hash TEXT, + p_username VARCHAR, + p_password_hash VARCHAR, + p_phone_encrypted TEXT, + p_phone_hash TEXT, + p_preferred_language VARCHAR +) +LANGUAGE plpgsql AS $$ +BEGIN + INSERT INTO users ( + email_encrypted, + email_hash, + username, + password_hash, + phone_encrypted, + phone_hash, + preferred_language + ) + VALUES ( + p_email_encrypted, + p_email_hash, + p_username, + p_password_hash, + p_phone_encrypted, + p_phone_hash, + p_preferred_language + ) + ON CONFLICT (username) DO NOTHING; + IF NOT FOUND THEN + RAISE EXCEPTION 'Username % already exists', p_username; + END IF; +END; +$$; From 7245eb2e465fd0528c35fc6f80f717181e00476b Mon Sep 17 00:00:00 2001 From: Vianpyro Date: Sat, 7 Jun 2025 15:26:45 +0000 Subject: [PATCH 07/16] Refactor register_user procedure to handle unique constraint violations for phone numbers and improve error handling --- .vscode/settings.json | 4 +- database/procedures/register_user.sql | 54 ++++++++++++++++----------- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 3b3e650..afbb0ef 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -22,6 +22,8 @@ } ], "triggerTaskOnSave.tasks": { - "Lint SQL File": ["**/*.sql"] + "Lint SQL File": [ + "database/**/*.sql" + ] } } diff --git a/database/procedures/register_user.sql b/database/procedures/register_user.sql index 05877d8..38c4acc 100644 --- a/database/procedures/register_user.sql +++ b/database/procedures/register_user.sql @@ -10,27 +10,37 @@ CREATE OR REPLACE PROCEDURE register_user( ) LANGUAGE plpgsql AS $$ BEGIN - INSERT INTO users ( - email_encrypted, - email_hash, - username, - password_hash, - phone_encrypted, - phone_hash, - preferred_language - ) - VALUES ( - p_email_encrypted, - p_email_hash, - p_username, - p_password_hash, - p_phone_encrypted, - p_phone_hash, - p_preferred_language - ) - ON CONFLICT (username) DO NOTHING; - IF NOT FOUND THEN - RAISE EXCEPTION 'Username % already exists', p_username; - END IF; + BEGIN + INSERT INTO users ( + email_encrypted, + email_hash, + username, + password_hash, + phone_encrypted, + phone_hash, + preferred_language + ) + VALUES ( + p_email_encrypted, + p_email_hash, + p_username, + p_password_hash, + p_phone_encrypted, + p_phone_hash, + p_preferred_language + ); + EXCEPTION + WHEN unique_violation THEN + -- Identify the constraint that caused the error + IF SQLERRM LIKE '%username%' THEN + RAISE EXCEPTION 'Username % already exists', p_username; + ELSIF SQLERRM LIKE '%email_hash%' THEN + RAISE EXCEPTION 'Email address already exists'; + ELSIF SQLERRM LIKE '%phone_hash%' THEN + RAISE EXCEPTION 'Phone number already exists'; + ELSE + RAISE; + END IF; + END; END; $$; From fa052cb8f119fed0552ae8c72bf3dad896c6a41d Mon Sep 17 00:00:00 2001 From: Vianpyro Date: Sat, 7 Jun 2025 15:45:33 +0000 Subject: [PATCH 08/16] Add GitHub Actions workflows for PR label retrieval and version bump suggestion --- .github/workflows/get-pr-labels.yml | 35 +++++++++++++++++++++ .github/workflows/suggest-version-bump.yml | 36 ++++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 .github/workflows/get-pr-labels.yml create mode 100644 .github/workflows/suggest-version-bump.yml diff --git a/.github/workflows/get-pr-labels.yml b/.github/workflows/get-pr-labels.yml new file mode 100644 index 0000000..3cb4d49 --- /dev/null +++ b/.github/workflows/get-pr-labels.yml @@ -0,0 +1,35 @@ +--- +name: Get PR Labels + +permissions: + contents: read + statuses: read + pull-requests: read + +on: + workflow_call: + outputs: + labels: + description: 'Labels on the pull request' + value: ${{ jobs.get-labels.outputs.labels }} + +jobs: + get-labels: + name: Get PR Labels + runs-on: ubuntu-latest + outputs: + labels: ${{ steps.labels.outputs.labels }} + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Get PR labels + id: labels + run: | + LABELS=$(gh pr view "${{ github.event.pull_request.number }}" --json labels --jq '[.labels[].name] | join(" ")') + echo "labels=$LABELS" >> "$GITHUB_OUTPUT" + env: + GH_TOKEN: ${{ github.token }} diff --git a/.github/workflows/suggest-version-bump.yml b/.github/workflows/suggest-version-bump.yml new file mode 100644 index 0000000..013b3b0 --- /dev/null +++ b/.github/workflows/suggest-version-bump.yml @@ -0,0 +1,36 @@ +--- +name: Suggest Version Bump + +permissions: + contents: read + pull-requests: read + +on: + pull_request: + branches: + - 'main' + paths: + - 'database/**/*' + +jobs: + get-labels: + uses: ./.github/workflows/get-pr-labels.yml + + suggest-bump: + name: Suggest Version Bump + needs: get-labels + runs-on: ubuntu-latest + steps: + - name: Determine bump type + id: bump + run: | + LABELS="${{ needs.get-labels.outputs.labels }}" + BUMP="patch" + echo "$LABELS" | grep -q 'type: feature' && BUMP="minor" + echo "$LABELS" | grep -q 'type: security' && BUMP="minor" + echo "$LABELS" | grep -q 'type: breaking' && BUMP="major" + echo "bump=$BUMP" >> "$GITHUB_OUTPUT" + + - name: Report summary + run: | + echo "### 🚀 Suggested Version Bump: **${{ steps.bump.outputs.bump }}**" >> "$GITHUB_STEP_SUMMARY" From 108131f3e056e97a159007b1f662d5abf5618cc2 Mon Sep 17 00:00:00 2001 From: Vianpyro Date: Sat, 7 Jun 2025 15:59:18 +0000 Subject: [PATCH 09/16] Add workflow for creating releases with version bump suggestion --- .github/workflows/create-release.yml | 35 +++++++++++++++++ .github/workflows/suggest-version-bump.yml | 45 ++++++++++++++++------ 2 files changed, 69 insertions(+), 11 deletions(-) create mode 100644 .github/workflows/create-release.yml diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml new file mode 100644 index 0000000..c35ae56 --- /dev/null +++ b/.github/workflows/create-release.yml @@ -0,0 +1,35 @@ +--- +name: Create Release + +permissions: + contents: write + +on: + push: + branches: + - 'main' + paths: + - 'database/**/*' + +jobs: + suggest-bump: + uses: ./.github/workflows/suggest-version-bump.yml + + create-release: + runs-on: ubuntu-latest + needs: suggest-bump + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Create release draft + uses: actions/create-release@v1 + with: + tag_name: ${{ needs.suggest-bump.outputs.next_version }} + release_name: ${{ needs.suggest-bump.outputs.next_version }} + draft: false + prerelease: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/suggest-version-bump.yml b/.github/workflows/suggest-version-bump.yml index 013b3b0..f6e9c11 100644 --- a/.github/workflows/suggest-version-bump.yml +++ b/.github/workflows/suggest-version-bump.yml @@ -1,16 +1,12 @@ --- name: Suggest Version Bump -permissions: - contents: read - pull-requests: read - on: - pull_request: - branches: - - 'main' - paths: - - 'database/**/*' + workflow_call: + outputs: + next_version: + description: 'The next suggested version' + value: ${{ jobs.suggest-bump.outputs.next_version }} jobs: get-labels: @@ -20,6 +16,8 @@ jobs: name: Suggest Version Bump needs: get-labels runs-on: ubuntu-latest + outputs: + next_version: ${{ steps.next_version.outputs.next_version }} steps: - name: Determine bump type id: bump @@ -31,6 +29,31 @@ jobs: echo "$LABELS" | grep -q 'type: breaking' && BUMP="major" echo "bump=$BUMP" >> "$GITHUB_OUTPUT" - - name: Report summary + - name: Get latest tag + id: latest_tag + run: | + TAG=$(git tag --list 'v*' --sort=-v:refname | head -n1) + echo "tag=$TAG" >> "$GITHUB_OUTPUT" + + - name: Calculate next version + id: next_version run: | - echo "### 🚀 Suggested Version Bump: **${{ steps.bump.outputs.bump }}**" >> "$GITHUB_STEP_SUMMARY" + TAG="${{ steps.latest_tag.outputs.tag }}" + BUMP="${{ steps.bump.outputs.bump }}" + if [ -z "$TAG" ]; then + TAG="v0.0.0" + fi + VERSION=$(echo "$TAG" | sed -E 's/^v([0-9]+\.[0-9]+\.[0-9]+).*/\1/') + PRERELEASE=$(echo "$TAG" | sed -nE 's/^v[0-9]+\.[0-9]+\.[0-9]+(-[A-Za-z0-9.-]+)?$/\1/p') + IFS='.' read -r MAJOR MINOR PATCH <<< "$VERSION" + case "$BUMP" in + major) MAJOR=$((MAJOR + 1)); MINOR=0; PATCH=0 ;; + minor) MINOR=$((MINOR + 1)); PATCH=0 ;; + patch) PATCH=$((PATCH + 1)) ;; + esac + if [ -n "$PRERELEASE" ]; then + NEXT_VERSION="v${MAJOR}.${MINOR}.${PATCH}${PRERELEASE}" + else + NEXT_VERSION="v${MAJOR}.${MINOR}.${PATCH}" + fi + echo "next_version=$NEXT_VERSION" >> "$GITHUB_OUTPUT" From 26326545c9e5ec0a0ed15e9bb558b100761e4ada Mon Sep 17 00:00:00 2001 From: Vianpyro Date: Sat, 7 Jun 2025 16:07:33 +0000 Subject: [PATCH 10/16] Add permissions section to suggest version bump workflow --- .github/workflows/suggest-version-bump.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/suggest-version-bump.yml b/.github/workflows/suggest-version-bump.yml index f6e9c11..4df9819 100644 --- a/.github/workflows/suggest-version-bump.yml +++ b/.github/workflows/suggest-version-bump.yml @@ -1,6 +1,9 @@ --- name: Suggest Version Bump +permissions: + contents: read + on: workflow_call: outputs: From 319d2a93e75839bfdb32b5478673a2bfb507c17f Mon Sep 17 00:00:00 2001 From: Vianpyro Date: Sat, 7 Jun 2025 16:09:08 +0000 Subject: [PATCH 11/16] Update workflow triggers to limit actions to SQL files in the database directory --- .github/workflows/create-release.yml | 2 +- .github/workflows/suggest-version-bump.yml | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml index c35ae56..d533e66 100644 --- a/.github/workflows/create-release.yml +++ b/.github/workflows/create-release.yml @@ -9,7 +9,7 @@ on: branches: - 'main' paths: - - 'database/**/*' + - 'database/**/*.sql' jobs: suggest-bump: diff --git a/.github/workflows/suggest-version-bump.yml b/.github/workflows/suggest-version-bump.yml index 4df9819..3a3a836 100644 --- a/.github/workflows/suggest-version-bump.yml +++ b/.github/workflows/suggest-version-bump.yml @@ -5,6 +5,11 @@ permissions: contents: read on: + pull_request: + branches: + - main + paths: + - 'database/**/*.sql' workflow_call: outputs: next_version: From 492d8b7473623eda3040bebd971edb0e96cfb99a Mon Sep 17 00:00:00 2001 From: Vianpyro Date: Sat, 7 Jun 2025 16:10:03 +0000 Subject: [PATCH 12/16] Add permissions for pull-requests and statuses in version bump workflow --- .github/workflows/suggest-version-bump.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/suggest-version-bump.yml b/.github/workflows/suggest-version-bump.yml index 3a3a836..7ab9c2d 100644 --- a/.github/workflows/suggest-version-bump.yml +++ b/.github/workflows/suggest-version-bump.yml @@ -3,6 +3,8 @@ name: Suggest Version Bump permissions: contents: read + pull-requests: read + statuses: read on: pull_request: From 2e9a029b33466f12e5bc0982ff46f56f706703f9 Mon Sep 17 00:00:00 2001 From: Vianpyro <10519369+Vianpyro@users.noreply.github.com> Date: Sat, 7 Jun 2025 16:11:04 +0000 Subject: [PATCH 13/16] chore: fix linting issues --- .vscode/settings.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index afbb0ef..b408a93 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -22,8 +22,6 @@ } ], "triggerTaskOnSave.tasks": { - "Lint SQL File": [ - "database/**/*.sql" - ] + "Lint SQL File": ["database/**/*.sql"] } } From 5fe12b266222ae4996dc8433105805be99889d6f Mon Sep 17 00:00:00 2001 From: Vianpyro Date: Sat, 7 Jun 2025 16:14:29 +0000 Subject: [PATCH 14/16] feat: enhance version bump summary reporting in workflow --- .github/workflows/suggest-version-bump.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/suggest-version-bump.yml b/.github/workflows/suggest-version-bump.yml index 7ab9c2d..4db72d4 100644 --- a/.github/workflows/suggest-version-bump.yml +++ b/.github/workflows/suggest-version-bump.yml @@ -67,3 +67,9 @@ jobs: NEXT_VERSION="v${MAJOR}.${MINOR}.${PATCH}" fi echo "next_version=$NEXT_VERSION" >> "$GITHUB_OUTPUT" + + - name: Report summary + run: | + echo "### 🚀 Suggested Version Bump: **${{ steps.bump.outputs.bump }}**" >> "$GITHUB_STEP_SUMMARY" + echo "#### Latest tag: \`${{ steps.latest_tag.outputs.tag }}\`" >> "$GITHUB_STEP_SUMMARY" + echo "#### Next version: \`${{ steps.next_version.outputs.next_version }}\`" >> "$GITHUB_STEP_SUMMARY" From 1f490c77047fb440b69e532f1ccbe162827ec8fc Mon Sep 17 00:00:00 2001 From: Vianpyro Date: Sat, 7 Jun 2025 16:17:19 +0000 Subject: [PATCH 15/16] chore: add missing job name for PR labels in version bump workflow --- .github/workflows/suggest-version-bump.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/suggest-version-bump.yml b/.github/workflows/suggest-version-bump.yml index 4db72d4..2b88f37 100644 --- a/.github/workflows/suggest-version-bump.yml +++ b/.github/workflows/suggest-version-bump.yml @@ -20,6 +20,7 @@ on: jobs: get-labels: + name: Get PR Labels uses: ./.github/workflows/get-pr-labels.yml suggest-bump: @@ -29,6 +30,11 @@ jobs: outputs: next_version: ${{ steps.next_version.outputs.next_version }} steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Determine bump type id: bump run: | From a51264c39a6ea6bb5a09fde7332bd9b497ad65dd Mon Sep 17 00:00:00 2001 From: Vianpyro Date: Sat, 7 Jun 2025 16:19:51 +0000 Subject: [PATCH 16/16] refactor: improve summary reporting format in version bump workflow --- .github/workflows/suggest-version-bump.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/suggest-version-bump.yml b/.github/workflows/suggest-version-bump.yml index 2b88f37..4eb20a2 100644 --- a/.github/workflows/suggest-version-bump.yml +++ b/.github/workflows/suggest-version-bump.yml @@ -76,6 +76,8 @@ jobs: - name: Report summary run: | - echo "### 🚀 Suggested Version Bump: **${{ steps.bump.outputs.bump }}**" >> "$GITHUB_STEP_SUMMARY" - echo "#### Latest tag: \`${{ steps.latest_tag.outputs.tag }}\`" >> "$GITHUB_STEP_SUMMARY" - echo "#### Next version: \`${{ steps.next_version.outputs.next_version }}\`" >> "$GITHUB_STEP_SUMMARY" + { + echo "### 🚀 Suggested Version Bump: **${{ steps.bump.outputs.bump }}**" + echo "#### Latest tag: \`${{ steps.latest_tag.outputs.tag }}\`" + echo "#### Next version: \`${{ steps.next_version.outputs.next_version }}\`" + } >> "$GITHUB_STEP_SUMMARY"