From 57179862267b91855dec110d00ce3b4106382527 Mon Sep 17 00:00:00 2001 From: Eitan-brightleaf Date: Wed, 16 Apr 2025 13:53:34 +0300 Subject: [PATCH 01/15] fixed deprecation warning from `::set-output` --- .gitignore | 1 + deploy.php | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..723ef36 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea \ No newline at end of file diff --git a/deploy.php b/deploy.php index 49a37aa..5db9486 100644 --- a/deploy.php +++ b/deploy.php @@ -64,7 +64,7 @@ file_put_contents($zipname_free,file_get_contents($zip_free)); echo "- Downloaded Freemius free version to ".$zipname_free."\n"; - echo "::set-output name=free_version::" . $zipname_free . "\n"; + file_put_contents(getenv('GITHUB_OUTPUT'), "free_version=" . $zipname_free . "\n", FILE_APPEND); // Generate url to download the pro zip $zip_pro = $api->GetSignedUrl('plugins/'.$_ENV['PLUGIN_ID'].'/tags/'.$deploy->id.'.zip?is_premium=true', array()); @@ -75,7 +75,7 @@ file_put_contents($zipname_pro,file_get_contents($zip_pro)); echo "- Downloaded Freemius pro version to ".$zipname_pro."\n"; - echo "::set-output name=pro_version::" . $zipname_pro . "\n"; + file_put_contents(getenv('GITHUB_OUTPUT'), "pro_version=" . $zipname_pro . "\n", FILE_APPEND); } catch (Exception $e) { echo "- Freemius server has problems\n"; From 73f38eae7e47b9ca9b7f1f6a874ab6b5005c8b1b Mon Sep 17 00:00:00 2001 From: Eitan-brightleaf Date: Thu, 17 Apr 2025 00:21:46 +0300 Subject: [PATCH 02/15] Improve deployment script and documentation Enhanced `deploy.php` with validation checks, detailed error handling, and support for managing existing versions. Updated README for clarity and migrated Dockerfile to PHP 8.2 CLI with optimized image size. --- Dockerfile | 16 +---- README.md | 25 +++++-- deploy.php | 201 +++++++++++++++++++++++++++++++++++------------------ 3 files changed, 154 insertions(+), 88 deletions(-) diff --git a/Dockerfile b/Dockerfile index 492ea17..2b76d39 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,20 +1,10 @@ -FROM php:7.4-cli +FROM php:8.2-cli -# install git -RUN apt-get update -RUN apt-get install -y git - - -ARG file_name -ARG version -ARG sandbox -ARG release_mode +# Install git and clean up in one step to reduce image size +RUN apt-get update && apt-get install -y git && apt-get clean && rm -rf /var/lib/apt/lists/* COPY deploy.php /deploy.php COPY ${file_name} /${file_name} RUN git clone https://github.com/Freemius/freemius-php-sdk.git /freemius-php-api -EXPOSE 80/tcp -EXPOSE 80/udp - CMD php /deploy.php \ No newline at end of file diff --git a/README.md b/README.md index a5aebdb..1069369 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Freemius Deploy -This Github Action deploys your wordpress plugin on Freemius. It uses the [Freemius PHP SDK](https://github.com/Freemius/freemius-php-sdk.git) and uses some of the functionality of [CodeAtCode/freemius-suite](https://github.com/CodeAtCode/freemius-suite) +This GitHub Action deploys your WordPress plugin on Freemius. It uses the [Freemius PHP SDK](https://github.com/Freemius/freemius-php-sdk.git) and uses some functionality of [CodeAtCode/freemius-suite](https://github.com/CodeAtCode/freemius-suite) ## Arguments @@ -15,29 +15,42 @@ This Github Action deploys your wordpress plugin on Freemius. It uses the [Freem **Required**: -- `PUBLIC_KEY` +- `PUBLIC_KEY` (Developer Public Key) - `DEV_ID` -- `SECRET_KEY` +- `SECRET_KEY` (Developer Secret Key) - `PLUGIN_SLUG` - `PLUGIN_ID` -All these are found in your Freemius dashboard. +Note: The PUBLIC_KEY and SECRET_KEY are your developer keys from Freemius, not the plugin-specific keys. + +All these are found in your Freemius dashboard. You can find your public and secret keys, as well as your Dev ID under +the keys section on the bottom of the 'My Profile' page. Your plugin slug and ID you can find on the products' settings +page or in the SDK integration snippet. _Tip: store these variables in your [secrets](https://help.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets)_ ## Action outputs (since v0.1.1) -The action downloads both the **free** and **pro** version and outputs their filenames as outputs: +The action downloads both the **free** and **pro** versions and outputs their filenames as outputs: - free_version - pro_version -You can access these by setting an **id** to your workflow step. Consequently you can upload these as artifacts, or upload them to the wordpress svn repository, for example with [yukihiko-shinoda/action-deploy-wordpress-plugin](https://github.com/yukihiko-shinoda/action-deploy-wordpress-plugin). +You can access these by setting an **id** to your workflow step. In a later step reference them like this: + +``` +${{ steps.deploy_step_id.outputs.free_version }} +${{ steps.deploy_step_id.outputs.pro_version }} +``` + +These files can then be uploaded as artifacts or deployed to the WordPress SVN repository using actions like +[10up/action-wordpress-plugin-deploy](https://github.com/10up/action-wordpress-plugin-deploy). ## Example ```yml - name: Deploy to Freemius + id: freemius_deploy uses: buttonizer/freemius-deploy@v0.1.2 with: file_name: my_wordpress_plugin.zip diff --git a/deploy.php b/deploy.php index 5db9486..81cf8b2 100644 --- a/deploy.php +++ b/deploy.php @@ -1,82 +1,145 @@ Api('plugins/' . $_ENV['PLUGIN_ID'] . '/tags.json', 'GET'); + + // Check if version already exists + $version_exists = false; + $existing_tag = null; + foreach ($tags_response->tags as $tag) { + if ($tag->version === $version) { + $version_exists = true; + $existing_tag = $tag; + break; } + } - $deploy = $api->Api('plugins/'.$_ENV['PLUGIN_ID'].'/tags.json', 'GET'); - if ( $deploy->tags[0]->version === $version ) { - $deploy = $deploy->tags[0]; - echo '-Package already deployed on Freemius'."\n"; - } else { - // Upload the zip - $deploy = $api->Api('plugins/'.$_ENV['PLUGIN_ID'].'/tags.json', 'POST', array( - 'add_contributor' => false - ), array( - 'file' => $file_name - )); - - if (!property_exists($deploy, 'id')) { - print_r($deploy); - die(); - } - - echo "- Deploy done on Freemius\n"; - - $is_released = $api->Api('plugins/'.$_ENV['PLUGIN_ID'].'/tags/'.$deploy->id.'.json', 'PUT', array( - 'release_mode' => $release_mode - ), array()); - - echo "- Set as released on Freemius\n"; + // Handle existing version + if ($version_exists) { + $deploy = $existing_tag; + echo "Package version $version already deployed on Freemius"; + } else { + // Upload the zip + $deploy = $api->Api('plugins/' . $_ENV['PLUGIN_ID'] . '/tags.json', 'POST', array( + 'add_contributor' => false + ), array( + 'file' => $file_name + )); + + if (!property_exists($deploy, 'id')) { + print_r($deploy); + die(); } - echo "- Download Freemius free version\n"; + echo "- Deploy done on Freemius\n"; - // Generate url to download the zip - $zip_free = $api->GetSignedUrl('plugins/'.$_ENV['PLUGIN_ID'].'/tags/'.$deploy->id.'.zip', array()); - $path = pathinfo($file_name); - $zipname_free = $path['dirname'] . '/' . basename($file_name, '.zip'); - $zipname_free .= '__free.zip'; + $is_released = $api->Api('plugins/' . $_ENV['PLUGIN_ID'] . '/tags/' . $deploy->id . '.json', 'PUT', array( + 'release_mode' => $release_mode + ), array()); - file_put_contents($zipname_free,file_get_contents($zip_free)); + echo "- Set as released on Freemius\n"; + } - echo "- Downloaded Freemius free version to ".$zipname_free."\n"; - file_put_contents(getenv('GITHUB_OUTPUT'), "free_version=" . $zipname_free . "\n", FILE_APPEND); + echo "- Download Freemius free version\n"; - // Generate url to download the pro zip - $zip_pro = $api->GetSignedUrl('plugins/'.$_ENV['PLUGIN_ID'].'/tags/'.$deploy->id.'.zip?is_premium=true', array()); - $path = pathinfo($file_name); - $zipname_pro = $path['dirname'] . '/' . basename($file_name, '.zip'); - $zipname_pro .= '.zip'; + // Generate url to download the zip + $zip_free = $api->GetSignedUrl('plugins/' . $_ENV['PLUGIN_ID'] . '/tags/' . $deploy->id . '.zip', array()); + $path = pathinfo($file_name); + $zipname_free = $path['dirname'] . '/' . basename($file_name, '.zip'); + $zipname_free .= '__free.zip'; - file_put_contents($zipname_pro,file_get_contents($zip_pro)); + file_put_contents($zipname_free, file_get_contents($zip_free)); - echo "- Downloaded Freemius pro version to ".$zipname_pro."\n"; - file_put_contents(getenv('GITHUB_OUTPUT'), "pro_version=" . $zipname_pro . "\n", FILE_APPEND); + if (!file_exists($zipname_free) || filesize($zipname_free) == 0) { + echo "Error: Failed to download free version or file is empty\n"; + exit(1); } - catch (Exception $e) { - echo "- Freemius server has problems\n"; + + echo "- Downloaded Freemius free version to " . $zipname_free . "\n"; + file_put_contents(getenv('GITHUB_OUTPUT'), "free_version=" . $zipname_free . "\n", FILE_APPEND); + + // Generate url to download the pro-zip + $zip_pro = $api->GetSignedUrl('plugins/' . $_ENV['PLUGIN_ID'] . '/tags/' . $deploy->id . '.zip?is_premium=true', array()); + $path = pathinfo($file_name); + $zipname_pro = $path['dirname'] . '/' . basename($file_name, '.zip'); + $zipname_pro .= '.zip'; + + file_put_contents($zipname_pro, file_get_contents($zip_pro)); + + if (!file_exists($zipname_pro) || filesize($zipname_pro) == 0) { + echo "Error: Failed to download pro version or file is empty\n"; + exit(1); } + + echo "- Downloaded Freemius pro version to " . $zipname_pro . "\n"; + file_put_contents(getenv('GITHUB_OUTPUT'), "pro_version=" . $zipname_pro . "\n", FILE_APPEND); +} catch (Exception $e) { + // Handle any errors during deployment and provide detailed error information + // Exit with non-zero status to indicate failure to GitHub Actions + echo "- Error: " . $e->getMessage() . "\n"; + echo "- Error occurred at line " . $e->getLine() . " in " . $e->getFile() . "\n"; + exit(1); // Return non-zero exit code to indicate failure to GitHub Actions +} \ No newline at end of file From 4ae4dcd0d12d419629eb632c576bd2eb7a2fcdde Mon Sep 17 00:00:00 2001 From: Eitan-brightleaf <160501761+Eitan-brightleaf@users.noreply.github.com> Date: Mon, 5 May 2025 15:48:46 +0300 Subject: [PATCH 03/15] Update deploy.php --- deploy.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy.php b/deploy.php index 81cf8b2..3da2b28 100644 --- a/deploy.php +++ b/deploy.php @@ -26,7 +26,7 @@ // Other validations $file_name = $_ENV['INPUT_FILE_NAME']; -if (!file_exists("/$file_name")) { +if (!file_exists("$file_name")) { echo "Error: File '$file_name' not found\n"; exit(1); } @@ -142,4 +142,4 @@ echo "- Error: " . $e->getMessage() . "\n"; echo "- Error occurred at line " . $e->getLine() . " in " . $e->getFile() . "\n"; exit(1); // Return non-zero exit code to indicate failure to GitHub Actions -} \ No newline at end of file +} From 12178b98514f6144d93050b4804f56ae00630e22 Mon Sep 17 00:00:00 2001 From: Eitan-brightleaf <160501761+Eitan-brightleaf@users.noreply.github.com> Date: Mon, 5 May 2025 16:52:12 +0300 Subject: [PATCH 04/15] made small fixes and added debugging --- README.md | 10 +++++----- deploy.php | 35 +++++++++++++++++------------------ 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 1069369..67763e2 100644 --- a/README.md +++ b/README.md @@ -4,12 +4,12 @@ This GitHub Action deploys your WordPress plugin on Freemius. It uses the [Freem ## Arguments -| Argument | Required | Function | Default | -| -------------- | -------- | ------- | ------- | -| `file_name` | Yes | File name of the to be uploaded wordpress plugin (zip extension). _Note: the file has to be in the root folder of your repository_ | | +| Argument | Required | Function | Default | +| -------------- | -------- |-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ------- | +| `file_name` | Yes | File name of the to be uploaded wordpress plugin (zip extension). _Note: the file has to be in the root folder of your repository_ | | | `release_mode` | No | `pending`, `beta`, or `released`. Set to beta to release the product to valid license holders that opted into the beta list. Set to released to release it to all valid license holders. When the product is released, it will be available for download right within the WP Admin dashboard. | `pending` | -| `version` | Yes | This is used to check whether the release is already uploaded. **Action will fail if the release has already been uploaded** | | -| `sandbox` | No | Whether to upload in sandbox mode | `false` | +| `version` | Yes | This is used to check whether the release is already uploaded. Uploading will be skipped if version already exists. | | +| `sandbox` | No | Whether to upload in sandbox mode | `false` | ## Environment variables diff --git a/deploy.php b/deploy.php index 3da2b28..f91a3f8 100644 --- a/deploy.php +++ b/deploy.php @@ -10,7 +10,7 @@ // Validate required environment variables $required_env = ['DEV_ID', 'PUBLIC_KEY', 'SECRET_KEY', 'PLUGIN_SLUG', 'PLUGIN_ID']; foreach ($required_env as $env) { - if (!isset($_ENV[$env]) || empty($_ENV[$env])) { + if ( empty($_ENV[$env]) ) { echo "Error: Required environment variable $env is missing or empty\n"; exit(1); } @@ -18,7 +18,7 @@ // Validate release mode $allowed_release_modes = ['pending', 'beta', 'released']; -$release_mode = !isset($_ENV['INPUT_RELEASE_MODE']) || empty($_ENV['INPUT_RELEASE_MODE']) ? 'pending' : $_ENV['INPUT_RELEASE_MODE']; +$release_mode = empty($_ENV['INPUT_RELEASE_MODE']) ? 'pending' : $_ENV['INPUT_RELEASE_MODE']; if (!in_array($release_mode, $allowed_release_modes)) { echo "Error: Invalid release mode '$release_mode'. Allowed values are: " . implode(', ', $allowed_release_modes) . "\n"; exit(1); @@ -36,7 +36,7 @@ $file_name = $_ENV['INPUT_FILE_NAME']; $version = $_ENV['INPUT_VERSION']; $sandbox = ($_ENV['INPUT_SANDBOX'] === 'true'); -$release_mode = !isset($_ENV['INPUT_RELEASE_MODE']) || empty($_ENV['INPUT_RELEASE_MODE']) ? 'pending' : $_ENV['INPUT_RELEASE_MODE']; +$release_mode = empty($_ENV['INPUT_RELEASE_MODE']) ? 'pending' : $_ENV['INPUT_RELEASE_MODE']; echo "\n- Deploying " . $_ENV['PLUGIN_SLUG'] . " to Freemius, with arguments: "; echo "\n- file_name: " . $file_name . " version: " . $version . " sandbox: " . $sandbox . " release_mode: " . $release_mode; @@ -55,7 +55,8 @@ try { // Init SDK. - $api = new Freemius_Api(FS__API_SCOPE, FS__API_DEV_ID, FS__API_PUBLIC_KEY, FS__API_SECRET_KEY, $sandbox); + echo "::debug::Initializing Freemius API client\n"; + $api = new Freemius_Api(FS__API_SCOPE, FS__API_DEV_ID, FS__API_PUBLIC_KEY, FS__API_SECRET_KEY, $sandbox); if (!is_object($api)) { echo "Error: Failed to initialize Freemius API client\n"; @@ -64,7 +65,9 @@ // Fetch all existing version tags for the plugin // This is used to check if the current version already exists - $tags_response = $api->Api('plugins/' . $_ENV['PLUGIN_ID'] . '/tags.json', 'GET'); + echo "::debug::Fetching existing version tags for plugin ID: " . $_ENV['PLUGIN_ID'] . "\n"; + $tags_response = $api->Api('plugins/' . $_ENV['PLUGIN_ID'] . '/tags.json', 'GET'); + echo "::debug:: Fetched existing version tags: " . print_r($tags_response, true) . "\n"; // Check if version already exists $version_exists = false; @@ -89,24 +92,20 @@ 'file' => $file_name )); - if (!property_exists($deploy, 'id')) { - print_r($deploy); - die(); - } + echo "::debug:: response: " . print_r($deploy, true) . "\n"; echo "- Deploy done on Freemius\n"; - - $is_released = $api->Api('plugins/' . $_ENV['PLUGIN_ID'] . '/tags/' . $deploy->id . '.json', 'PUT', array( - 'release_mode' => $release_mode - ), array()); - - echo "- Set as released on Freemius\n"; } + $is_released = $api->Api('plugins/' . $_ENV['PLUGIN_ID'] . '/tags/' . $deploy->id . '.json', 'PUT', array( + 'release_mode' => $release_mode + ), array()); + + echo "- Set as $release_mode on Freemius\n"; - echo "- Download Freemius free version\n"; + echo "- Download Freemius free version\n"; // Generate url to download the zip - $zip_free = $api->GetSignedUrl('plugins/' . $_ENV['PLUGIN_ID'] . '/tags/' . $deploy->id . '.zip', array()); + $zip_free = $api->GetSignedUrl('plugins/' . $_ENV['PLUGIN_ID'] . '/tags/' . $deploy->id . '.zip', array()); $path = pathinfo($file_name); $zipname_free = $path['dirname'] . '/' . basename($file_name, '.zip'); $zipname_free .= '__free.zip'; @@ -122,7 +121,7 @@ file_put_contents(getenv('GITHUB_OUTPUT'), "free_version=" . $zipname_free . "\n", FILE_APPEND); // Generate url to download the pro-zip - $zip_pro = $api->GetSignedUrl('plugins/' . $_ENV['PLUGIN_ID'] . '/tags/' . $deploy->id . '.zip?is_premium=true', array()); + $zip_pro = $api->GetSignedUrl('plugins/' . $_ENV['PLUGIN_ID'] . '/tags/' . $deploy->id . '.zip?is_premium=true', array()); $path = pathinfo($file_name); $zipname_pro = $path['dirname'] . '/' . basename($file_name, '.zip'); $zipname_pro .= '.zip'; From 72571e9a9cefbdcad428d0745a71fa13eccbc0b6 Mon Sep 17 00:00:00 2001 From: Eitan-brightleaf <160501761+Eitan-brightleaf@users.noreply.github.com> Date: Mon, 5 May 2025 16:56:07 +0300 Subject: [PATCH 05/15] download as new file and don't overwrite uploaded file --- deploy.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy.php b/deploy.php index f91a3f8..14c8927 100644 --- a/deploy.php +++ b/deploy.php @@ -124,7 +124,7 @@ $zip_pro = $api->GetSignedUrl('plugins/' . $_ENV['PLUGIN_ID'] . '/tags/' . $deploy->id . '.zip?is_premium=true', array()); $path = pathinfo($file_name); $zipname_pro = $path['dirname'] . '/' . basename($file_name, '.zip'); - $zipname_pro .= '.zip'; + $zipname_pro .= '__pro.zip'; file_put_contents($zipname_pro, file_get_contents($zip_pro)); From 011b3b35b53f0aae75192d5f5ad3636cd7cffdba Mon Sep 17 00:00:00 2001 From: Eitan-brightleaf <160501761+Eitan-brightleaf@users.noreply.github.com> Date: Mon, 5 May 2025 17:39:17 +0300 Subject: [PATCH 06/15] updated default input value --- action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yml b/action.yml index d66076d..240da22 100644 --- a/action.yml +++ b/action.yml @@ -4,7 +4,7 @@ inputs: sandbox: description: 'Sandbox mode' required: false - default: false + default: 'false' file_name: description: 'file to deploy' required: true From d5cfef8be6df2fedb43d862051dd8fc2321fae56 Mon Sep 17 00:00:00 2001 From: Eitan-brightleaf <160501761+Eitan-brightleaf@users.noreply.github.com> Date: Mon, 5 May 2025 18:01:14 +0300 Subject: [PATCH 07/15] Refactor debug logging in deployment script. Replace unconditional debug logs with conditional checks based on `ACTIONS_STEP_DEBUG` environment variable. Added validation for deployment response to ensure the presence of an ID before proceeding. --- deploy.php | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/deploy.php b/deploy.php index 14c8927..3067c14 100644 --- a/deploy.php +++ b/deploy.php @@ -55,7 +55,6 @@ try { // Init SDK. - echo "::debug::Initializing Freemius API client\n"; $api = new Freemius_Api(FS__API_SCOPE, FS__API_DEV_ID, FS__API_PUBLIC_KEY, FS__API_SECRET_KEY, $sandbox); if (!is_object($api)) { @@ -65,11 +64,12 @@ // Fetch all existing version tags for the plugin // This is used to check if the current version already exists - echo "::debug::Fetching existing version tags for plugin ID: " . $_ENV['PLUGIN_ID'] . "\n"; $tags_response = $api->Api('plugins/' . $_ENV['PLUGIN_ID'] . '/tags.json', 'GET'); - echo "::debug:: Fetched existing version tags: " . print_r($tags_response, true) . "\n"; + if (!empty($_ENV['ACTIONS_STEP_DEBUG']) && $_ENV['ACTIONS_STEP_DEBUG'] === 'true' ) { + echo "::debug:: Fetched existing version tags: " . print_r( $tags_response, true ) . "\n"; + } - // Check if version already exists + // Check if version already exists $version_exists = false; $existing_tag = null; foreach ($tags_response->tags as $tag) { @@ -92,9 +92,16 @@ 'file' => $file_name )); - echo "::debug:: response: " . print_r($deploy, true) . "\n"; + if (!empty($_ENV['ACTIONS_STEP_DEBUG']) && $_ENV['ACTIONS_STEP_DEBUG'] === 'true' ) { + echo "::debug:: response: " . print_r( $deploy, true ) . "\n"; + } - echo "- Deploy done on Freemius\n"; + if (!property_exists($deploy, 'id')) { + echo "Deploy failed. No id in response object."; + exit(1); + } + + echo "- Deploy done on Freemius\n"; } $is_released = $api->Api('plugins/' . $_ENV['PLUGIN_ID'] . '/tags/' . $deploy->id . '.json', 'PUT', array( 'release_mode' => $release_mode From ed086c2008155eac0824a99e71a04177ae1801f6 Mon Sep 17 00:00:00 2001 From: Eitan-brightleaf <160501761+Eitan-brightleaf@users.noreply.github.com> Date: Thu, 8 May 2025 17:09:57 +0300 Subject: [PATCH 08/15] Normalize line endings to LF --- Dockerfile | 18 ++++---- README.md | 132 ++++++++++++++++++++++++++--------------------------- action.yml | 56 +++++++++++------------ 3 files changed, 103 insertions(+), 103 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2b76d39..1f82200 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,10 @@ -FROM php:8.2-cli - -# Install git and clean up in one step to reduce image size -RUN apt-get update && apt-get install -y git && apt-get clean && rm -rf /var/lib/apt/lists/* - -COPY deploy.php /deploy.php -COPY ${file_name} /${file_name} -RUN git clone https://github.com/Freemius/freemius-php-sdk.git /freemius-php-api - +FROM php:8.2-cli + +# Install git and clean up in one step to reduce image size +RUN apt-get update && apt-get install -y git && apt-get clean && rm -rf /var/lib/apt/lists/* + +COPY deploy.php /deploy.php +COPY ${file_name} /${file_name} +RUN git clone https://github.com/Freemius/freemius-php-sdk.git /freemius-php-api + CMD php /deploy.php \ No newline at end of file diff --git a/README.md b/README.md index 67763e2..bd80b63 100644 --- a/README.md +++ b/README.md @@ -1,66 +1,66 @@ -# Freemius Deploy - -This GitHub Action deploys your WordPress plugin on Freemius. It uses the [Freemius PHP SDK](https://github.com/Freemius/freemius-php-sdk.git) and uses some functionality of [CodeAtCode/freemius-suite](https://github.com/CodeAtCode/freemius-suite) - -## Arguments - -| Argument | Required | Function | Default | -| -------------- | -------- |-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ------- | -| `file_name` | Yes | File name of the to be uploaded wordpress plugin (zip extension). _Note: the file has to be in the root folder of your repository_ | | -| `release_mode` | No | `pending`, `beta`, or `released`. Set to beta to release the product to valid license holders that opted into the beta list. Set to released to release it to all valid license holders. When the product is released, it will be available for download right within the WP Admin dashboard. | `pending` | -| `version` | Yes | This is used to check whether the release is already uploaded. Uploading will be skipped if version already exists. | | -| `sandbox` | No | Whether to upload in sandbox mode | `false` | - -## Environment variables - -**Required**: - -- `PUBLIC_KEY` (Developer Public Key) -- `DEV_ID` -- `SECRET_KEY` (Developer Secret Key) -- `PLUGIN_SLUG` -- `PLUGIN_ID` - -Note: The PUBLIC_KEY and SECRET_KEY are your developer keys from Freemius, not the plugin-specific keys. - -All these are found in your Freemius dashboard. You can find your public and secret keys, as well as your Dev ID under -the keys section on the bottom of the 'My Profile' page. Your plugin slug and ID you can find on the products' settings -page or in the SDK integration snippet. - -_Tip: store these variables in your [secrets](https://help.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets)_ - -## Action outputs (since v0.1.1) - -The action downloads both the **free** and **pro** versions and outputs their filenames as outputs: - -- free_version -- pro_version - -You can access these by setting an **id** to your workflow step. In a later step reference them like this: - -``` -${{ steps.deploy_step_id.outputs.free_version }} -${{ steps.deploy_step_id.outputs.pro_version }} -``` - -These files can then be uploaded as artifacts or deployed to the WordPress SVN repository using actions like -[10up/action-wordpress-plugin-deploy](https://github.com/10up/action-wordpress-plugin-deploy). - -## Example - -```yml -- name: Deploy to Freemius - id: freemius_deploy - uses: buttonizer/freemius-deploy@v0.1.2 - with: - file_name: my_wordpress_plugin.zip - release_mode: pending - version: 1.1.0 - sandbox: false - env: - PUBLIC_KEY: ${{ secrets.FREEMIUS_PUBLIC_KEY }} - DEV_ID: 1234 - SECRET_KEY: ${{ secrets.FREEMIUS_SECRET_KEY }} - PLUGIN_SLUG: my-wordpress-plugin - PLUGIN_ID: 4321 -``` +# Freemius Deploy + +This GitHub Action deploys your WordPress plugin on Freemius. It uses the [Freemius PHP SDK](https://github.com/Freemius/freemius-php-sdk.git) and uses some functionality of [CodeAtCode/freemius-suite](https://github.com/CodeAtCode/freemius-suite) + +## Arguments + +| Argument | Required | Function | Default | +| -------------- | -------- |-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ------- | +| `file_name` | Yes | File name of the to be uploaded wordpress plugin (zip extension). _Note: the file has to be in the root folder of your repository_ | | +| `release_mode` | No | `pending`, `beta`, or `released`. Set to beta to release the product to valid license holders that opted into the beta list. Set to released to release it to all valid license holders. When the product is released, it will be available for download right within the WP Admin dashboard. | `pending` | +| `version` | Yes | This is used to check whether the release is already uploaded. Uploading will be skipped if version already exists. | | +| `sandbox` | No | Whether to upload in sandbox mode | `false` | + +## Environment variables + +**Required**: + +- `PUBLIC_KEY` (Developer Public Key) +- `DEV_ID` +- `SECRET_KEY` (Developer Secret Key) +- `PLUGIN_SLUG` +- `PLUGIN_ID` + +Note: The PUBLIC_KEY and SECRET_KEY are your developer keys from Freemius, not the plugin-specific keys. + +All these are found in your Freemius dashboard. You can find your public and secret keys, as well as your Dev ID under +the keys section on the bottom of the 'My Profile' page. Your plugin slug and ID you can find on the products' settings +page or in the SDK integration snippet. + +_Tip: store these variables in your [secrets](https://help.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets)_ + +## Action outputs (since v0.1.1) + +The action downloads both the **free** and **pro** versions and outputs their filenames as outputs: + +- free_version +- pro_version + +You can access these by setting an **id** to your workflow step. In a later step reference them like this: + +``` +${{ steps.deploy_step_id.outputs.free_version }} +${{ steps.deploy_step_id.outputs.pro_version }} +``` + +These files can then be uploaded as artifacts or deployed to the WordPress SVN repository using actions like +[10up/action-wordpress-plugin-deploy](https://github.com/10up/action-wordpress-plugin-deploy). + +## Example + +```yml +- name: Deploy to Freemius + id: freemius_deploy + uses: buttonizer/freemius-deploy@v0.1.2 + with: + file_name: my_wordpress_plugin.zip + release_mode: pending + version: 1.1.0 + sandbox: false + env: + PUBLIC_KEY: ${{ secrets.FREEMIUS_PUBLIC_KEY }} + DEV_ID: 1234 + SECRET_KEY: ${{ secrets.FREEMIUS_SECRET_KEY }} + PLUGIN_SLUG: my-wordpress-plugin + PLUGIN_ID: 4321 +``` diff --git a/action.yml b/action.yml index 240da22..52911fc 100644 --- a/action.yml +++ b/action.yml @@ -1,28 +1,28 @@ -name: "Deploy on Freemius" -description: "Uploads and deploys your plugin on Freemius" -inputs: - sandbox: - description: 'Sandbox mode' - required: false - default: 'false' - file_name: - description: 'file to deploy' - required: true - version: - description: 'tag version' - required: true - release_mode: - description: 'release mode' - required: false - default: 'pending' -outputs: - free_version: - description: 'The Free version file' - pro_version: - description: 'The Pro version file' -runs: - using: 'docker' - image: 'Dockerfile' -branding: - icon: 'arrow-up-circle' - color: 'green' +name: "Deploy on Freemius" +description: "Uploads and deploys your plugin on Freemius" +inputs: + sandbox: + description: 'Sandbox mode' + required: false + default: 'false' + file_name: + description: 'file to deploy' + required: true + version: + description: 'tag version' + required: true + release_mode: + description: 'release mode' + required: false + default: 'pending' +outputs: + free_version: + description: 'The Free version file' + pro_version: + description: 'The Pro version file' +runs: + using: 'docker' + image: 'Dockerfile' +branding: + icon: 'arrow-up-circle' + color: 'green' From 6ef3a4652769731269510f7a3cf8da884735d0df Mon Sep 17 00:00:00 2001 From: eitan-brightleaf Date: Sun, 11 May 2025 21:34:22 +0300 Subject: [PATCH 09/15] working on adding new inputs --- action.yml | 79 +++++++++++++++++++++++++++++++++++------------------- deploy.php | 43 ++++++++++++++++------------- 2 files changed, 75 insertions(+), 47 deletions(-) diff --git a/action.yml b/action.yml index 52911fc..4a1c868 100644 --- a/action.yml +++ b/action.yml @@ -1,28 +1,51 @@ -name: "Deploy on Freemius" -description: "Uploads and deploys your plugin on Freemius" -inputs: - sandbox: - description: 'Sandbox mode' - required: false - default: 'false' - file_name: - description: 'file to deploy' - required: true - version: - description: 'tag version' - required: true - release_mode: - description: 'release mode' - required: false - default: 'pending' -outputs: - free_version: - description: 'The Free version file' - pro_version: - description: 'The Pro version file' -runs: - using: 'docker' - image: 'Dockerfile' -branding: - icon: 'arrow-up-circle' - color: 'green' +name: "Deploy on Freemius" +description: "Uploads and deploys your plugin on Freemius" +inputs: + file_name: + description: 'file to deploy' + required: true + release_mode: + description: 'release mode' + required: false + default: 'pending' + version: + description: 'tag version. used to compare against existing tags.' + required: true + sandbox: + description: 'Sandbox mode' + required: false + default: 'false' + limit: + description: 'limit of serving updates' + required: false + percentage_limit: + description: 'The percentage (1-100%) of license owners who will receive an update' + required: false + is_incremental: + description: 'Whether to flag the version as incremental or not' + required: false + default: 'false' + add_contributor: + description: 'add freemius as a contributor to the plugin' + required: false + default: 'false' + overwrite: + description: 'overwrite a tag with the same version, otherwise skips upload' + default: 'false' + required: false + num_versions: + description: 'Number of existing tags to compare version against' + required: false + default: '1' + +outputs: + free_version: + description: 'The Free version file' + pro_version: + description: 'The Pro version file' +runs: + using: 'docker' + image: 'Dockerfile' +branding: + icon: 'arrow-up-circle' + color: 'green' diff --git a/deploy.php b/deploy.php index 3067c14..c039895 100644 --- a/deploy.php +++ b/deploy.php @@ -15,28 +15,30 @@ exit(1); } } +$file_name = $_ENV['INPUT_FILE_NAME']; +if (!file_exists("$file_name")) { + echo "Error: File '$file_name' not found\n"; + exit(1); +} // Validate release mode -$allowed_release_modes = ['pending', 'beta', 'released']; $release_mode = empty($_ENV['INPUT_RELEASE_MODE']) ? 'pending' : $_ENV['INPUT_RELEASE_MODE']; -if (!in_array($release_mode, $allowed_release_modes)) { - echo "Error: Invalid release mode '$release_mode'. Allowed values are: " . implode(', ', $allowed_release_modes) . "\n"; - exit(1); -} - -// Other validations -$file_name = $_ENV['INPUT_FILE_NAME']; -if (!file_exists("$file_name")) { - echo "Error: File '$file_name' not found\n"; - exit(1); +if (!in_array($release_mode, ['pending', 'beta', 'released'])) { + $release_mode = 'pending'; //fallback to default + echo "Warning: Invalid release mode '$release_mode', falling back to 'pending'\n"; } -// run as: php /deploy.php $file_name $version $sandbox $release_mode -// with env vars: USER_ID, PUBLIC_KEY, SECRET_KEY, PLUGIN_SLUG, PLUGIN_ID -$file_name = $_ENV['INPUT_FILE_NAME']; +// set other input variables $version = $_ENV['INPUT_VERSION']; $sandbox = ($_ENV['INPUT_SANDBOX'] === 'true'); -$release_mode = empty($_ENV['INPUT_RELEASE_MODE']) ? 'pending' : $_ENV['INPUT_RELEASE_MODE']; +$release_limit = intval($_ENV['INPUT_LIMIT']); +$percentage_limit = intval($_ENV['INPUT_LIMIT_PERCENTAGE']); +$is_incremental = ($_ENV['INPUT_IS_INCREMENTAL'] === 'true'); +$add_contributor = ($_ENV['INPUT_ADD_CONTRIBUTOR'] === 'true'); +$overwrite = ($_ENV['INPUT_OVERWRITE'] === 'true'); +$num_versions = intval($_ENV['INPUT_NUM_VERSIONS']); + +$debugging = !empty($_ENV['ACTIONS_STEP_DEBUG']) && $_ENV['ACTIONS_STEP_DEBUG'] === 'true'; echo "\n- Deploying " . $_ENV['PLUGIN_SLUG'] . " to Freemius, with arguments: "; echo "\n- file_name: " . $file_name . " version: " . $version . " sandbox: " . $sandbox . " release_mode: " . $release_mode; @@ -65,7 +67,7 @@ // Fetch all existing version tags for the plugin // This is used to check if the current version already exists $tags_response = $api->Api('plugins/' . $_ENV['PLUGIN_ID'] . '/tags.json', 'GET'); - if (!empty($_ENV['ACTIONS_STEP_DEBUG']) && $_ENV['ACTIONS_STEP_DEBUG'] === 'true' ) { + if ($debugging ) { echo "::debug:: Fetched existing version tags: " . print_r( $tags_response, true ) . "\n"; } @@ -92,12 +94,15 @@ 'file' => $file_name )); - if (!empty($_ENV['ACTIONS_STEP_DEBUG']) && $_ENV['ACTIONS_STEP_DEBUG'] === 'true' ) { + if ($debugging ) { echo "::debug:: response: " . print_r( $deploy, true ) . "\n"; } if (!property_exists($deploy, 'id')) { echo "Deploy failed. No id in response object."; + if (!$debugging) { //we didn't already echo the response + echo "Response: " . print_r($deploy, true) . "\n"; + } exit(1); } @@ -112,7 +117,7 @@ echo "- Download Freemius free version\n"; // Generate url to download the zip - $zip_free = $api->GetSignedUrl('plugins/' . $_ENV['PLUGIN_ID'] . '/tags/' . $deploy->id . '.zip', array()); + $zip_free = $api->GetSignedUrl('plugins/' . $_ENV['PLUGIN_ID'] . '/tags/' . $deploy->id . '.zip'); $path = pathinfo($file_name); $zipname_free = $path['dirname'] . '/' . basename($file_name, '.zip'); $zipname_free .= '__free.zip'; @@ -128,7 +133,7 @@ file_put_contents(getenv('GITHUB_OUTPUT'), "free_version=" . $zipname_free . "\n", FILE_APPEND); // Generate url to download the pro-zip - $zip_pro = $api->GetSignedUrl('plugins/' . $_ENV['PLUGIN_ID'] . '/tags/' . $deploy->id . '.zip?is_premium=true', array()); + $zip_pro = $api->GetSignedUrl('plugins/' . $_ENV['PLUGIN_ID'] . '/tags/' . $deploy->id . '.zip?is_premium=true'); $path = pathinfo($file_name); $zipname_pro = $path['dirname'] . '/' . basename($file_name, '.zip'); $zipname_pro .= '__pro.zip'; From 2b6e7024e8b6c274c44c98a7fdd1f8e7e92b8efe Mon Sep 17 00:00:00 2001 From: Eitan-brightleaf <160501761+Eitan-brightleaf@users.noreply.github.com> Date: Wed, 28 May 2025 14:43:30 +0300 Subject: [PATCH 10/15] working some more on inputs removed version input since that is just used to check version that we shouldn't upload existing version. but api rejects that making it unnecessary --- action.yml | 7 ------ deploy.php | 67 +++++++++++++++++------------------------------------- 2 files changed, 21 insertions(+), 53 deletions(-) diff --git a/action.yml b/action.yml index 4a1c868..b918da9 100644 --- a/action.yml +++ b/action.yml @@ -8,9 +8,6 @@ inputs: description: 'release mode' required: false default: 'pending' - version: - description: 'tag version. used to compare against existing tags.' - required: true sandbox: description: 'Sandbox mode' required: false @@ -33,10 +30,6 @@ inputs: description: 'overwrite a tag with the same version, otherwise skips upload' default: 'false' required: false - num_versions: - description: 'Number of existing tags to compare version against' - required: false - default: '1' outputs: free_version: diff --git a/deploy.php b/deploy.php index c039895..daec5aa 100644 --- a/deploy.php +++ b/deploy.php @@ -29,19 +29,17 @@ } // set other input variables -$version = $_ENV['INPUT_VERSION']; $sandbox = ($_ENV['INPUT_SANDBOX'] === 'true'); $release_limit = intval($_ENV['INPUT_LIMIT']); $percentage_limit = intval($_ENV['INPUT_LIMIT_PERCENTAGE']); $is_incremental = ($_ENV['INPUT_IS_INCREMENTAL'] === 'true'); $add_contributor = ($_ENV['INPUT_ADD_CONTRIBUTOR'] === 'true'); $overwrite = ($_ENV['INPUT_OVERWRITE'] === 'true'); -$num_versions = intval($_ENV['INPUT_NUM_VERSIONS']); $debugging = !empty($_ENV['ACTIONS_STEP_DEBUG']) && $_ENV['ACTIONS_STEP_DEBUG'] === 'true'; echo "\n- Deploying " . $_ENV['PLUGIN_SLUG'] . " to Freemius, with arguments: "; -echo "\n- file_name: " . $file_name . " version: " . $version . " sandbox: " . $sandbox . " release_mode: " . $release_mode; +echo "\n- file_name: " . $file_name . " sandbox: " . $sandbox . " release_mode: " . $release_mode; // Include Freemius SDK files require_once '/freemius-php-api/freemius/FreemiusBase.php'; @@ -64,53 +62,30 @@ exit(1); } - // Fetch all existing version tags for the plugin - // This is used to check if the current version already exists - $tags_response = $api->Api('plugins/' . $_ENV['PLUGIN_ID'] . '/tags.json', 'GET'); - if ($debugging ) { - echo "::debug:: Fetched existing version tags: " . print_r( $tags_response, true ) . "\n"; + // Upload the zip + $deploy = $api->Api( 'plugins/' . $_ENV['PLUGIN_ID'] . '/tags.json', 'POST', [ + 'add_contributor' => $add_contributor + ], [ + 'file' => $file_name + ] ); + + if ( $debugging ) { + echo "::debug:: response: " . print_r( $deploy, true ) . "\n"; } - // Check if version already exists - $version_exists = false; - $existing_tag = null; - foreach ($tags_response->tags as $tag) { - if ($tag->version === $version) { - $version_exists = true; - $existing_tag = $tag; - break; - } - } + if ( ! property_exists( $deploy, 'id' ) ) { + echo "Deploy failed. No id in response object."; + if ( ! $debugging ) { //we didn't already echo the response + echo "Response: " . print_r( $deploy, true ) . "\n"; + } + exit( 1 ); + } - // Handle existing version - if ($version_exists) { - $deploy = $existing_tag; - echo "Package version $version already deployed on Freemius"; - } else { - // Upload the zip - $deploy = $api->Api('plugins/' . $_ENV['PLUGIN_ID'] . '/tags.json', 'POST', array( - 'add_contributor' => false - ), array( - 'file' => $file_name - )); - - if ($debugging ) { - echo "::debug:: response: " . print_r( $deploy, true ) . "\n"; - } - - if (!property_exists($deploy, 'id')) { - echo "Deploy failed. No id in response object."; - if (!$debugging) { //we didn't already echo the response - echo "Response: " . print_r($deploy, true) . "\n"; - } - exit(1); - } - - echo "- Deploy done on Freemius\n"; - } - $is_released = $api->Api('plugins/' . $_ENV['PLUGIN_ID'] . '/tags/' . $deploy->id . '.json', 'PUT', array( + echo "- Deploy done on Freemius\n"; + + $is_released = $api->Api('plugins/' . $_ENV['PLUGIN_ID'] . '/tags/' . $deploy->id . '.json', 'PUT', [ 'release_mode' => $release_mode - ), array()); + ], [] ); echo "- Set as $release_mode on Freemius\n"; From 5721288a7d36ec4a7418f4afb7f972ee3712712e Mon Sep 17 00:00:00 2001 From: eitan-brightleaf Date: Wed, 28 May 2025 18:37:09 +0300 Subject: [PATCH 11/15] I think i finished all the major work. just have to update readme --- .gitignore | 3 +- Dockerfile | 8 ++--- deploy.php | 93 ++++++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 82 insertions(+), 22 deletions(-) diff --git a/.gitignore b/.gitignore index 723ef36..3f03813 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -.idea \ No newline at end of file +.idea +openapi.yaml \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 1f82200..9d50d65 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,10 @@ -FROM php:8.2-cli +FROM php:8.4.7-cli-alpine -# Install git and clean up in one step to reduce image size -RUN apt-get update && apt-get install -y git && apt-get clean && rm -rf /var/lib/apt/lists/* +RUN apk add --no-cache git && \ + git clone https://github.com/Freemius/freemius-php-sdk.git /freemius-php-api && \ + rm -rf /freemius-php-api/.git COPY deploy.php /deploy.php COPY ${file_name} /${file_name} -RUN git clone https://github.com/Freemius/freemius-php-sdk.git /freemius-php-api CMD php /deploy.php \ No newline at end of file diff --git a/deploy.php b/deploy.php index daec5aa..adec5f7 100644 --- a/deploy.php +++ b/deploy.php @@ -39,14 +39,15 @@ $debugging = !empty($_ENV['ACTIONS_STEP_DEBUG']) && $_ENV['ACTIONS_STEP_DEBUG'] === 'true'; echo "\n- Deploying " . $_ENV['PLUGIN_SLUG'] . " to Freemius, with arguments: "; -echo "\n- file_name: " . $file_name . " sandbox: " . $sandbox . " release_mode: " . $release_mode; +echo "\n- file_name: $file_name release_mode: $release_mode sandbox: $sandbox release_limit: $release_limit percentage_limit: $percentage_limit +is_incremental: $is_incremental add_contributor: $add_contributor overwrite: $overwrite\n"; // Include Freemius SDK files require_once '/freemius-php-api/freemius/FreemiusBase.php'; require_once '/freemius-php-api/freemius/Freemius.php'; // Configure Freemius API constants -define('FS__API_SCOPE', 'developer'); +const FS__API_SCOPE = 'developer'; define('FS__API_DEV_ID', $_ENV['DEV_ID']); define('FS__API_PUBLIC_KEY', $_ENV['PUBLIC_KEY']); define('FS__API_SECRET_KEY', $_ENV['SECRET_KEY']); @@ -63,33 +64,91 @@ } // Upload the zip - $deploy = $api->Api( 'plugins/' . $_ENV['PLUGIN_ID'] . '/tags.json', 'POST', [ - 'add_contributor' => $add_contributor - ], [ - 'file' => $file_name - ] ); + $deploy = $api->Api( 'plugins/' . $_ENV['PLUGIN_ID'] . '/tags.json', 'POST', [ 'add_contributor' => $add_contributor ], [ 'file' => $file_name ] ); if ( $debugging ) { echo "::debug:: response: " . print_r( $deploy, true ) . "\n"; } - if ( ! property_exists( $deploy, 'id' ) ) { - echo "Deploy failed. No id in response object."; - if ( ! $debugging ) { //we didn't already echo the response - echo "Response: " . print_r( $deploy, true ) . "\n"; + // if no id then it failed + if ( ! property_exists( $deploy, 'id' ) && property_exists( $deploy, 'error' ) ) { + // if it's a duplicate version error, then our response depends on whether we want to overwrite or not + if ( $deploy->error->http == 400 && 'duplicate_plugin_version' === $deploy->error->code ) { + // if we want to overwrite, then we need to delete the existing version and redeploy it. but have to find id first + if ( $overwrite ) { + echo "Product already exists. Searching for id of existing product version\n"; + $id = null; + $version = $deploy->error->data->version; + $query = ['offset' => 0]; + while ( is_null( $id ) ) { + $tags_response = $api->Api('plugins/' . $_ENV['PLUGIN_ID'] . '/tags.json', 'GET', $query ); + if ( $debugging ) { + echo "::debug:: tags_response: " . print_r( $tags_response, true ) . "\n"; + } + + if (empty($tags_response->tags)) { + // no more tags and still didn't find id. something wrong so exit + echo "Could not find version $version. Aborting.\n"; + exit(1); + } + + foreach ($tags_response->tags as $tag) { + if ($tag->version === $version) { + $id = $tag->id; + if ( $debugging ) { + echo "::debug:: Found id: $id\n"; + } + break; + } + } + $query['offset'] += 25; + } + echo "Deleting existing product version\n"; + $api->Api('plugins/' . $_ENV['PLUGIN_ID'] . '/tags/' . $id . '.zip', 'DELETE'); + echo "Redeploying product\n"; + $deploy = $api->Api( 'plugins/' . $_ENV['PLUGIN_ID'] . '/tags.json', 'POST', [ 'add_contributor' => $add_contributor ], [ 'file' => $file_name ] ); + if ( $debugging ) { + echo "::debug:: response: " . print_r( $deploy, true ) . "\n"; + } + if ( ! property_exists( $deploy, 'id' ) ) { + echo "Deploy failed. No id in response object.\n"; + if ( ! $debugging ) { + echo "Response: " . print_r( $deploy, true ) . "\n"; + } + exit( 1 ); + } + + } else { + // not overwriting, continue with script + echo "Deploy failed. Product version already exists.\n"; + } + } else { + // wasn't a duplicate version error, so exit with error + echo "Deploy failed. No id in response object."; + if ( ! $debugging ) { //we didn't already echo the response + echo "Response: " . print_r( $deploy, true ) . "\n"; + } + exit( 1 ); } - exit( 1 ); } echo "- Deploy done on Freemius\n"; - $is_released = $api->Api('plugins/' . $_ENV['PLUGIN_ID'] . '/tags/' . $deploy->id . '.json', 'PUT', [ - 'release_mode' => $release_mode - ], [] ); + $params = [ + 'release_mode' => $release_mode, + 'is_incremental' => $is_incremental, + ]; + if ( ! empty( $release_limit ) ) { + $params['release_limit'] = $release_limit; + } + if ( ! empty( $percentage_limit ) && $percentage_limit > 0 && $percentage_limit < 100 ) { + $params['percentage_limit'] = $percentage_limit; + } + $is_released = $api->Api('plugins/' . $_ENV['PLUGIN_ID'] . '/tags/' . $deploy->id . '.json', 'PUT', $params ); - echo "- Set as $release_mode on Freemius\n"; + echo "- Updated on Freemius with settings " . var_export( $params, true ) . "\n"; - echo "- Download Freemius free version\n"; + echo "- Downloading Freemius free version\n"; // Generate url to download the zip $zip_free = $api->GetSignedUrl('plugins/' . $_ENV['PLUGIN_ID'] . '/tags/' . $deploy->id . '.zip'); From 86971155c6c007c4add6cb7eb56ac2b10afed866 Mon Sep 17 00:00:00 2001 From: eitan-brightleaf Date: Thu, 29 May 2025 01:24:57 +0300 Subject: [PATCH 12/15] finished readme, added fail_on_duplicate input and fixed < to <= --- README.md | 144 ++++++++++++++++++++++++++++++++++++++++------------- action.yml | 4 ++ deploy.php | 7 ++- 3 files changed, 120 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index bd80b63..ccc14bc 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,42 @@ # Freemius Deploy -This GitHub Action deploys your WordPress plugin on Freemius. It uses the [Freemius PHP SDK](https://github.com/Freemius/freemius-php-sdk.git) and uses some functionality of [CodeAtCode/freemius-suite](https://github.com/CodeAtCode/freemius-suite) +This GitHub Action deploys your WordPress plugin on Freemius. It uses the [Freemius PHP SDK](https://github.com/Freemius/freemius-php-sdk.git) and uses some functionality of [CodeAtCode/freemius-suite](https://github.com/CodeAtCode/freemius-suite). +It was created as a fork from [buttonizer/freemius-deploy](https://github.com/buttonizer/freemius-deploy) but with some +updates that clean up the code and allow for more customization. + +## Inputs + +| Input | Required | Description | Default | +|---------------------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------| +| `file_name` | Yes | File name of the to be uploaded WordPress plugin (zip extension). _Note: the file has to be in the root folder of your repository_ | none | +| `release_mode` | No | `pending`, `beta`, or `released`. Set to beta to release the product to valid license holders that opted into the beta list. Set to released to release it to all valid license holders. When the product is released, it will be available for download right within the WP Admin dashboard. | `pending` | +| `sandbox` | No | Whether to upload in sandbox mode. `True` or `false`. | `false` | +| `limit` | No | The absolute limit of license owners who will receive an update (expected `int`) | none | +| `percentage_limit` | No | The percentage (1-100%) of license owners who will receive an update (expected `int`) | none | +| `is_incremental` | No | Whether to flag the version as incremental or not. `True` or `false`. | `false` | +| `add_contributor` | No | Add Freemius as a contributor to the plugin. `True` or `false`. | `false` | +| `fail_on_duplicate` | No | If the action should fail if the version already exisits on Freemius. | `true` | +| `overwrite` | No | Overwrite a tag with the same version, otherwise skips upload and continues with the rest of the action. `True` or `false`. | `false` | -## Arguments +## Environment variables -| Argument | Required | Function | Default | -| -------------- | -------- |-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ------- | -| `file_name` | Yes | File name of the to be uploaded wordpress plugin (zip extension). _Note: the file has to be in the root folder of your repository_ | | -| `release_mode` | No | `pending`, `beta`, or `released`. Set to beta to release the product to valid license holders that opted into the beta list. Set to released to release it to all valid license holders. When the product is released, it will be available for download right within the WP Admin dashboard. | `pending` | -| `version` | Yes | This is used to check whether the release is already uploaded. Uploading will be skipped if version already exists. | | -| `sandbox` | No | Whether to upload in sandbox mode | `false` | +Set the following required environment variables in your GitHub repository [secrets](https://help.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets): -## Environment variables +- `DEV_ID`: Your Freemius Developer ID -**Required**: +- `FREEMIUS_PUBLIC_KEY`: Your Freemius Public Key -- `PUBLIC_KEY` (Developer Public Key) -- `DEV_ID` -- `SECRET_KEY` (Developer Secret Key) -- `PLUGIN_SLUG` -- `PLUGIN_ID` +- `FREEMIUS_SECRET_KEY`: Your Freemius Secret Key -Note: The PUBLIC_KEY and SECRET_KEY are your developer keys from Freemius, not the plugin-specific keys. +- `PLUGIN_SLUG`: Your plugin's slug -All these are found in your Freemius dashboard. You can find your public and secret keys, as well as your Dev ID under -the keys section on the bottom of the 'My Profile' page. Your plugin slug and ID you can find on the products' settings -page or in the SDK integration snippet. +- `PLUGIN_ID`: Your plugin's ID -_Tip: store these variables in your [secrets](https://help.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets)_ +Note: The `PUBLIC_KEY` and `SECRET_KEY` are your developer keys from Freemius, not the plugin-specific keys. + +These are all found in your Freemius dashboard. You can find your public key, secret key, and your Dev ID under +the keys section on the bottom of the 'My Profile' page. Your plugin slug and ID can be found on the products' settings +page or in the SDK integration snippet. ## Action outputs (since v0.1.1) @@ -49,18 +58,85 @@ These files can then be uploaded as artifacts or deployed to the WordPress SVN r ## Example ```yml -- name: Deploy to Freemius - id: freemius_deploy - uses: buttonizer/freemius-deploy@v0.1.2 - with: - file_name: my_wordpress_plugin.zip - release_mode: pending - version: 1.1.0 - sandbox: false - env: - PUBLIC_KEY: ${{ secrets.FREEMIUS_PUBLIC_KEY }} - DEV_ID: 1234 - SECRET_KEY: ${{ secrets.FREEMIUS_SECRET_KEY }} - PLUGIN_SLUG: my-wordpress-plugin - PLUGIN_ID: 4321 +name: Deploy Plugin to Freemius + +on: + push: + branches: + - main + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.0' + + # If needed + - name: Install dependencies + run: composer install --no-dev --no-progress --optimize-autoloader + + # replace "includes vendor *.php *.txt" with whatever is relevant for you + - name: Zip plugin + run: | + mkdir -p build + zip -r build/plugin.zip includes vendor *.php *.txt + + - name: Deploy to Freemius + uses: Eitan-brightleaf/freemius-deploy@main + with: + file_name: build/plugin.zip + release_mode: released + env: + DEV_ID: ${{ secrets.DEV_ID }} + PUBLIC_KEY: ${{ secrets.FREEMIUS_PUBLIC_KEY }} + SECRET_KEY: ${{ secrets.FREEMIUS_SECRET_KEY }} + PLUGIN_SLUG: my-plugin + PLUGIN_ID: 1234 + + - name: Unzip plugin for WP.org + run: | + mkdir plugin-dir + unzip ${{ steps.freemius_deploy.outputs.free_version }} -d plugin-dir + if [ -d "plugin-dir/${{ inputs.plugin_slug }}" ]; then + mv "plugin-dir/${{ inputs.plugin_slug }}"/* plugin-dir/ + rm -rf "plugin-dir/${{ inputs.plugin_slug }}" + fi + + # Deploy to WordPress.org SVN + - name: Deploy to WordPress.org + uses: 10up/action-wordpress-plugin-deploy@stable + env: + SVN_USERNAME: ${{ secrets.WP_SVN_USERNAME }} + SVN_PASSWORD: ${{ secrets.WP_SVN_PASSWORD }} + BUILD_DIR: plugin-dir + SLUG: ${{ inputs.plugin_slug }} + VERSION: ${{ inputs.version }} + ``` + +## Notes + +- Ensure that your plugin ZIP file is present in the root of your repository before running the action. This can be +done through steps prior to this one as in the example. + +- If the `fail_on_duplicate` input is set to true the action will fail if the version you are trying to upload already +exists on Freemius. Default is `true`. Note that if the value is `true` the value of the `overwrite` input will be ignored. + +- If the `overwrite` input is set to true, it will delete the existing version and redeploy it with the provided zip file. +Otherwise, if the version exists already the API will reject the upload, and the action will log this and continue with +updating the status of the deploy (release mode, release limits, etc.). This obviates the need for the previous `version` input +as the Freemius API itself will reject duplicates, removing the need for an extra API call and searching existing versions. + +- If an invalid value was passed to the `release_mode` input it will fall back to pending. +- If a number less than 1 or greater than 100 is given for `percentage_limit` the input will be ignored. +- `limit` and `percentage_limit` are **not** mutually inclusive. You can use them both. +- I plan on potentially updating the action to a JS GitHub action in the future. This should have no impact on your workflow files, +just some performance benefits and the like. +- Any feedback and contributions are welcome. diff --git a/action.yml b/action.yml index b918da9..f124c9d 100644 --- a/action.yml +++ b/action.yml @@ -26,6 +26,10 @@ inputs: description: 'add freemius as a contributor to the plugin' required: false default: 'false' + fail_on_duplicate: + description: 'if the action should fail if the version was already uploaded' + default: 'true' + required: false overwrite: description: 'overwrite a tag with the same version, otherwise skips upload' default: 'false' diff --git a/deploy.php b/deploy.php index adec5f7..fe3ac40 100644 --- a/deploy.php +++ b/deploy.php @@ -35,6 +35,7 @@ $is_incremental = ($_ENV['INPUT_IS_INCREMENTAL'] === 'true'); $add_contributor = ($_ENV['INPUT_ADD_CONTRIBUTOR'] === 'true'); $overwrite = ($_ENV['INPUT_OVERWRITE'] === 'true'); +$fail_on_duplicate = ($_ENV['INPUT_FAIL_ON_DUPLICATE'] === 'true'); $debugging = !empty($_ENV['ACTIONS_STEP_DEBUG']) && $_ENV['ACTIONS_STEP_DEBUG'] === 'true'; @@ -74,6 +75,10 @@ if ( ! property_exists( $deploy, 'id' ) && property_exists( $deploy, 'error' ) ) { // if it's a duplicate version error, then our response depends on whether we want to overwrite or not if ( $deploy->error->http == 400 && 'duplicate_plugin_version' === $deploy->error->code ) { + if ( $fail_on_duplicate ) { + echo "Deploy failed. Product version already exists.\n"; + exit(1); + } // if we want to overwrite, then we need to delete the existing version and redeploy it. but have to find id first if ( $overwrite ) { echo "Product already exists. Searching for id of existing product version\n"; @@ -141,7 +146,7 @@ if ( ! empty( $release_limit ) ) { $params['release_limit'] = $release_limit; } - if ( ! empty( $percentage_limit ) && $percentage_limit > 0 && $percentage_limit < 100 ) { + if ( ! empty( $percentage_limit ) && $percentage_limit > 0 && $percentage_limit <= 100 ) { $params['percentage_limit'] = $percentage_limit; } $is_released = $api->Api('plugins/' . $_ENV['PLUGIN_ID'] . '/tags/' . $deploy->id . '.json', 'PUT', $params ); From 1ef38a0c7ed0de56cbccee18bfac638d3b05719a Mon Sep 17 00:00:00 2001 From: eitan-brightleaf Date: Thu, 29 May 2025 01:50:19 +0300 Subject: [PATCH 13/15] fixed wrong env variable names --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ccc14bc..a456e65 100644 --- a/README.md +++ b/README.md @@ -24,9 +24,9 @@ Set the following required environment variables in your GitHub repository [secr - `DEV_ID`: Your Freemius Developer ID -- `FREEMIUS_PUBLIC_KEY`: Your Freemius Public Key +- `PUBLIC_KEY`: Your Freemius Public Key -- `FREEMIUS_SECRET_KEY`: Your Freemius Secret Key +- `SECRET_KEY`: Your Freemius Secret Key - `PLUGIN_SLUG`: Your plugin's slug From 1316d3ad6cde1685395291c194a3663b1e4a6701 Mon Sep 17 00:00:00 2001 From: eitan-brightleaf Date: Thu, 29 May 2025 11:02:18 +0300 Subject: [PATCH 14/15] fixed input name --- deploy.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy.php b/deploy.php index fe3ac40..d8ef5e6 100644 --- a/deploy.php +++ b/deploy.php @@ -31,7 +31,7 @@ // set other input variables $sandbox = ($_ENV['INPUT_SANDBOX'] === 'true'); $release_limit = intval($_ENV['INPUT_LIMIT']); -$percentage_limit = intval($_ENV['INPUT_LIMIT_PERCENTAGE']); +$percentage_limit = intval($_ENV['INPUT_PERCENTAGE_LIMIT']); $is_incremental = ($_ENV['INPUT_IS_INCREMENTAL'] === 'true'); $add_contributor = ($_ENV['INPUT_ADD_CONTRIBUTOR'] === 'true'); $overwrite = ($_ENV['INPUT_OVERWRITE'] === 'true'); From eb62821fc0f16f9d73e924b4a5f67ee8531e4195 Mon Sep 17 00:00:00 2001 From: eitan-brightleaf Date: Sun, 22 Jun 2025 16:14:19 +0300 Subject: [PATCH 15/15] added inputs to control downloading free and premium versions --- README.md | 4 +++- action.yml | 8 +++++++ deploy.php | 61 ++++++++++++++++++++++++++++++++---------------------- 3 files changed, 47 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index a456e65..848d273 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,8 @@ updates that clean up the code and allow for more customization. | `add_contributor` | No | Add Freemius as a contributor to the plugin. `True` or `false`. | `false` | | `fail_on_duplicate` | No | If the action should fail if the version already exisits on Freemius. | `true` | | `overwrite` | No | Overwrite a tag with the same version, otherwise skips upload and continues with the rest of the action. `True` or `false`. | `false` | +| `download_free` | No | Controls whether or not to download the free version as part of the action. | `true` | +| `download_premium` | No | Controls whether or not to download the premium version as part of the action. | `true` | ## Environment variables @@ -40,7 +42,7 @@ page or in the SDK integration snippet. ## Action outputs (since v0.1.1) -The action downloads both the **free** and **pro** versions and outputs their filenames as outputs: +The action by default downloads both the **free** and **pro** versions and outputs their filenames as outputs: - free_version - pro_version diff --git a/action.yml b/action.yml index f124c9d..75a4cd3 100644 --- a/action.yml +++ b/action.yml @@ -34,6 +34,14 @@ inputs: description: 'overwrite a tag with the same version, otherwise skips upload' default: 'false' required: false + download_free: + description: 'should the action download the free version after deployment' + required: false + default: 'true' + download_premium: + description: 'should the action download the premium version after deployment' + required: false + default: 'true' outputs: free_version: diff --git a/deploy.php b/deploy.php index d8ef5e6..14e09aa 100644 --- a/deploy.php +++ b/deploy.php @@ -36,6 +36,8 @@ $add_contributor = ($_ENV['INPUT_ADD_CONTRIBUTOR'] === 'true'); $overwrite = ($_ENV['INPUT_OVERWRITE'] === 'true'); $fail_on_duplicate = ($_ENV['INPUT_FAIL_ON_DUPLICATE'] === 'true'); +$download_free = ($_ENV['INPUT_DOWNLOAD_FREE'] === 'true'); +$download_premium = ($_ENV['INPUT_DOWNLOAD_PREMIUM'] === 'true'); $debugging = !empty($_ENV['ACTIONS_STEP_DEBUG']) && $_ENV['ACTIONS_STEP_DEBUG'] === 'true'; @@ -153,39 +155,48 @@ echo "- Updated on Freemius with settings " . var_export( $params, true ) . "\n"; - echo "- Downloading Freemius free version\n"; + if ( $download_free ) { + echo "- Downloading Freemius free version\n"; - // Generate url to download the zip - $zip_free = $api->GetSignedUrl('plugins/' . $_ENV['PLUGIN_ID'] . '/tags/' . $deploy->id . '.zip'); - $path = pathinfo($file_name); - $zipname_free = $path['dirname'] . '/' . basename($file_name, '.zip'); - $zipname_free .= '__free.zip'; + // Generate url to download the zip + $zip_free = $api->GetSignedUrl('plugins/' . $_ENV['PLUGIN_ID'] . '/tags/' . $deploy->id . '.zip'); + $path = pathinfo($file_name); + $zipname_free = $path['dirname'] . '/' . basename($file_name, '.zip'); + $zipname_free .= '__free.zip'; - file_put_contents($zipname_free, file_get_contents($zip_free)); + file_put_contents($zipname_free, file_get_contents($zip_free)); - if (!file_exists($zipname_free) || filesize($zipname_free) == 0) { - echo "Error: Failed to download free version or file is empty\n"; - exit(1); - } + if (!file_exists($zipname_free) || filesize($zipname_free) == 0) { + echo "Error: Failed to download free version or file is empty\n"; + exit(1); + } - echo "- Downloaded Freemius free version to " . $zipname_free . "\n"; - file_put_contents(getenv('GITHUB_OUTPUT'), "free_version=" . $zipname_free . "\n", FILE_APPEND); + echo "- Downloaded Freemius free version to " . $zipname_free . "\n"; + file_put_contents(getenv('GITHUB_OUTPUT'), "free_version=" . $zipname_free . "\n", FILE_APPEND); + } elseif ( $debugging ) { + echo "::debug:: skipping free version download"; + } - // Generate url to download the pro-zip - $zip_pro = $api->GetSignedUrl('plugins/' . $_ENV['PLUGIN_ID'] . '/tags/' . $deploy->id . '.zip?is_premium=true'); - $path = pathinfo($file_name); - $zipname_pro = $path['dirname'] . '/' . basename($file_name, '.zip'); - $zipname_pro .= '__pro.zip'; + if ( $download_premium ) { + echo "- Downloading Freemius premium version\n"; + // Generate url to download the pro-zip + $zip_pro = $api->GetSignedUrl('plugins/' . $_ENV['PLUGIN_ID'] . '/tags/' . $deploy->id . '.zip?is_premium=true'); + $path = pathinfo($file_name); + $zipname_pro = $path['dirname'] . '/' . basename($file_name, '.zip'); + $zipname_pro .= '__pro.zip'; - file_put_contents($zipname_pro, file_get_contents($zip_pro)); + file_put_contents($zipname_pro, file_get_contents($zip_pro)); - if (!file_exists($zipname_pro) || filesize($zipname_pro) == 0) { - echo "Error: Failed to download pro version or file is empty\n"; - exit(1); - } + if (!file_exists($zipname_pro) || filesize($zipname_pro) == 0) { + echo "Error: Failed to download pro version or file is empty\n"; + exit(1); + } - echo "- Downloaded Freemius pro version to " . $zipname_pro . "\n"; - file_put_contents(getenv('GITHUB_OUTPUT'), "pro_version=" . $zipname_pro . "\n", FILE_APPEND); + echo "- Downloaded Freemius pro version to " . $zipname_pro . "\n"; + file_put_contents(getenv('GITHUB_OUTPUT'), "pro_version=" . $zipname_pro . "\n", FILE_APPEND); + } elseif ( $debugging ) { + echo "::debug:: skipping premium version download"; + } } catch (Exception $e) { // Handle any errors during deployment and provide detailed error information // Exit with non-zero status to indicate failure to GitHub Actions