├── package.json ├── action.yml ├── CLAUDE.md ├── .gitignore ├── README.md └── src └── action.js /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wordpress-testing-automation", 3 | "version": "1.0.2", 4 | "description": "Automate WordPress testing in less than a minute.", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "ncc build src/action.js -o dist", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/InstaWP/wordpress-testing-automation.git" 13 | }, 14 | "author": "", 15 | "license": "ISC", 16 | "bugs": { 17 | "url": "https://github.com/InstaWP/wordpress-testing-automation/issues" 18 | }, 19 | "homepage": "https://github.com/InstaWP/wordpress-testing-automation#readme", 20 | "devDependencies": { 21 | "@actions/core": "^1.6.0", 22 | "@actions/github": "^5.0.1", 23 | "@vercel/ncc": "^0.33.3", 24 | "node-fetch": "^2.6.1" 25 | }, 26 | "dependencies": { 27 | "form-data": "^4.0.4" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: 'InstaWP WordPress Automation for Github' 2 | description: 'WordPress Automation & QA - Simplified with InstaWP' 3 | author: 'InstaWP' 4 | branding: 5 | icon: 'zap' 6 | color: 'green' 7 | 8 | inputs: 9 | GITHUB_TOKEN: 10 | description: 'GitHub token' 11 | required: true 12 | INSTAWP_ACTION: 13 | description: 'Action to perform, supported create-site-template & destroy-site' 14 | required: true 15 | default: 'create-site-template' 16 | INSTAWP_TOKEN: 17 | description: 'InstaWP API Token (site:create)' 18 | required: true 19 | INSTAWP_TEMPLATE_SLUG: 20 | description: 'InstaWP Template Slug (action: create-site-template)' 21 | required: false 22 | INSTAWP_SNAPSHOT_SLUG: 23 | description: 'InstaWP Snapshot Slug - alias for INSTAWP_TEMPLATE_SLUG (action: create-site-template)' 24 | required: false 25 | REPO_ID: 26 | description: 'InstaWP Repo ID (action: create-site-template)' 27 | required: false 28 | type: number 29 | INSTAWP_DOMAIN: 30 | description: 'For testing purpose only' 31 | required: false 32 | ARTIFACT_URL: 33 | description: 'Override the Artifact URL (.zip) file' 34 | required: false 35 | EXPIRY_HOURS: 36 | description: 'Number of hours after which the site will expire' 37 | required: false 38 | type: number 39 | 40 | outputs: 41 | instawp_url: 42 | description: "URL of the newly created InstaWP site" 43 | magic_login: 44 | description: "Automatic Login URL to wp-admin for the new site" 45 | iwp_wp_username: 46 | description: "WP username of the new site" 47 | iwp_wp_password: 48 | description: "WP password of the new site" 49 | 50 | 51 | runs: 52 | using: 'node16' 53 | main: 'dist/index.js' 54 | -------------------------------------------------------------------------------- /CLAUDE.md: -------------------------------------------------------------------------------- 1 | # CLAUDE.md 2 | 3 | This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. 4 | 5 | ## Commands 6 | 7 | ### Build 8 | ```bash 9 | npm run build 10 | ``` 11 | Compiles `src/action.js` into `dist/index.js` using @vercel/ncc. The dist file must be committed for the GitHub Action to work. 12 | 13 | ### Install Dependencies 14 | ```bash 15 | npm install 16 | ``` 17 | 18 | ### Testing 19 | Currently no tests are implemented. The test script exits with error. 20 | 21 | ## Architecture 22 | 23 | This is a GitHub Action for WordPress testing automation that integrates with InstaWP's API. The entire action logic lives in a single file: `src/action.js`. 24 | 25 | ### Key Components 26 | 27 | 1. **Action Entry Point** (`src/action.js`): 28 | - Validates inputs (GitHub token, InstaWP credentials) 29 | - Switches between `create-site-template` and `destroy-site` actions 30 | - Handles API interactions with InstaWP (v1 and v2 endpoints) 31 | - Manages GitHub PR comments 32 | 33 | 2. **Build Output** (`dist/index.js`): 34 | - Bundled version of the action for GitHub Actions runtime 35 | - Must be rebuilt and committed after any changes to `src/action.js` 36 | 37 | ### API Integration Points 38 | 39 | - **InstaWP API v2**: Site creation from templates (`/api/v2/sites/git`) 40 | - **InstaWP API v1**: Site status checking and deletion 41 | - **GitHub API**: PR comment creation/updates via @actions/github 42 | 43 | ### Key Behaviors 44 | 45 | - Polls InstaWP API for site creation status (max 25 attempts, 3-second intervals) 46 | - Creates or updates PR comments with site URLs and magic login links 47 | - Supports both pooled sites and on-demand creation 48 | - Outputs site URL, magic login URL, and WordPress credentials 49 | - Accepts both INSTAWP_TEMPLATE_SLUG and INSTAWP_SNAPSHOT_SLUG (as an alias) for template identification 50 | 51 | ### Development Notes 52 | 53 | - The code uses mixed module syntax (ES6 imports + CommonJS require) 54 | - No linting configuration exists 55 | - Error handling is basic - mainly catches and logs errors 56 | - All logic is in a single file with switch-case pattern for different actions -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | #dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # InstaWP WordPress Testing Automation 2 | This custom action automates your WordPress testing. Integrate it with your InstaWP account and get going within minutes. 3 | 4 | ## 🧪 Testing GitHub Artifacts Support (Dev Branch) 5 | 6 | **NEW:** GitHub Artifacts support is now available for testing! To use the latest GitHub Artifacts feature, please use the `dev` branch until it's fully tested and merged: 7 | 8 | ```yaml 9 | - uses: instawp/wordpress-testing-automation@dev 10 | ``` 11 | 12 | This new feature allows you to use artifacts from previous jobs without uploading to third-party services. See the [GitHub Artifacts Support](#github-artifacts-support) section below for details. 13 | 14 | # Pre-req 15 | 16 | - Register an account at [instawp.com](https://instawp.com) 17 | - Create a site and upload your plugin/theme (download a zip from github and upload) 18 | - Save the site as Template, give a unique slug 19 | - Go to Deployment, enter the details of your WordPress plugin/theme repo. 20 | - Go back to Templates, connect the git repo to the template. 21 | - Paste this Yaml file into your repo as shown below. 22 | 23 | # Yaml File 24 | 25 | Paste this code in your `.github/workflows/instawp.yml` file 26 | 27 | ``` 28 | name: InstaWP WordPress Testing 29 | 30 | on: 31 | pull_request: 32 | types: [opened] 33 | 34 | jobs: 35 | create-wp-for-testing: 36 | runs-on: ubuntu-latest 37 | steps: 38 | - uses: instawp/wordpress-testing-automation@latest 39 | with: 40 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 41 | INSTAWP_TOKEN: ${{secrets.INSTAWP_TOKEN}} 42 | EXPIRY_HOURS: 24 //optional 43 | INSTAWP_TEMPLATE_SLUG: gutenademonew //instawp template slug 44 | REPO_ID: 123 //instawp repo ID 45 | ARTIFACT_URL: https://yoursite.com/url.zip //optional 46 | ``` 47 | 48 | - INSTAWP_TOKEN can be obtained from your "API Tokens" screen inside the InstaWP interface. 49 | - INSTAWP_TEMPLATE_SLUG is shown on the "Templates" screen. You can also use INSTAWP_SNAPSHOT_SLUG as an alias. 50 | - REPO_ID is shown in the "Deployment" screen. 51 | - EXPIRY_HOURS is the number of hours the site will be active. 52 | - ARTIFACT_URL is the URL of the artifact to download. This is useful if you have a custom build process and generated a zip file. Supports both public URLs and GitHub artifacts (see GitHub Artifacts section below). 53 | 54 | # GitHub Artifacts Support 55 | 56 | The action now supports GitHub artifacts directly without requiring uploads to third-party services. When you use `actions/upload-artifact` in a previous job, you can reference the artifact URL directly. 57 | 58 | ## Example with GitHub Artifacts 59 | 60 | ```yaml 61 | name: InstaWP WordPress Testing 62 | 63 | on: 64 | pull_request: 65 | types: [opened] 66 | 67 | jobs: 68 | build-artifact: 69 | runs-on: ubuntu-latest 70 | outputs: 71 | artifact-url: ${{ steps.upload.outputs.artifact-url }} 72 | steps: 73 | - uses: actions/checkout@v4 74 | 75 | - name: Build plugin 76 | run: | 77 | # Your build process here 78 | zip -r my-plugin.zip . -x "*.git*" "node_modules/*" 79 | 80 | - name: Upload Artifact 81 | id: upload 82 | uses: actions/upload-artifact@v4 83 | with: 84 | name: "my-plugin" 85 | path: ./my-plugin.zip 86 | 87 | create-wp-for-testing: 88 | needs: build-artifact 89 | runs-on: ubuntu-latest 90 | steps: 91 | - name: Start InstaWP 92 | uses: instawp/wordpress-testing-automation@latest 93 | with: 94 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 95 | INSTAWP_TOKEN: ${{secrets.INSTAWP_TOKEN}} 96 | INSTAWP_TEMPLATE_SLUG: your-template-slug 97 | REPO_ID: 123 98 | ARTIFACT_URL: ${{ needs.build-artifact.outputs.artifact-url }} 99 | ``` 100 | 101 | ## How GitHub Artifacts Work 102 | 103 | - The action automatically detects GitHub artifact URLs 104 | - Uses your `GITHUB_TOKEN` to securely download the artifact 105 | - Sends the artifact data directly to InstaWP API 106 | - Works with private repositories (respects GitHub permissions) 107 | - No third-party file uploads required 108 | 109 | ## Supported URL Formats 110 | 111 | The action supports these GitHub artifact URL formats: 112 | - `https://github.com/owner/repo/actions/runs/123456/artifacts/789012` 113 | - `https://api.github.com/repos/owner/repo/actions/artifacts/123456/zip` 114 | - Regular public URLs (backward compatibility) 115 | 116 | # Changelog 117 | 118 | - 1.0.3 - Added GitHub Artifacts support - directly download and use artifacts from previous jobs without third-party uploads (resolves issue #18) 119 | - 1.0.2 - Updated to use the new InstaWP API v2 and updated the Node version to 16 120 | - 1.0.1 - Added support for expiry hours 121 | - 1.0.0 - Initial release -------------------------------------------------------------------------------- /src/action.js: -------------------------------------------------------------------------------- 1 | // require('dotenv').config(); 2 | import fetch from 'node-fetch'; 3 | 4 | const core = require('@actions/core'); 5 | const github = require('@actions/github'); 6 | const FormData = require('form-data'); 7 | 8 | // Helper function to detect if URL is a GitHub artifact URL 9 | function isGitHubArtifactUrl(url) { 10 | if (!url || typeof url !== 'string') return false; 11 | return url.includes('github.com') && url.includes('artifacts'); 12 | } 13 | 14 | // Helper function to extract artifact ID and repo info from GitHub artifact URL 15 | function parseGitHubArtifactUrl(url) { 16 | try { 17 | // GitHub artifact URLs typically look like: 18 | // https://github.com/owner/repo/actions/runs/123456/artifacts/789012 19 | const urlObj = new URL(url); 20 | const pathParts = urlObj.pathname.split('/'); 21 | 22 | if (pathParts.length >= 7 && pathParts[4] === 'actions' && pathParts[5] === 'runs' && pathParts[7] === 'artifacts') { 23 | return { 24 | owner: pathParts[1], 25 | repo: pathParts[2], 26 | run_id: pathParts[6], 27 | artifact_id: pathParts[8] 28 | }; 29 | } 30 | 31 | // Also support direct artifact URLs from actions/upload-artifact output 32 | // These might be in format: https://api.github.com/repos/owner/repo/actions/artifacts/123456/zip 33 | if (urlObj.hostname === 'api.github.com' && pathParts.includes('artifacts')) { 34 | const artifactIndex = pathParts.indexOf('artifacts'); 35 | if (artifactIndex > 0 && pathParts[artifactIndex + 1]) { 36 | return { 37 | owner: pathParts[2], 38 | repo: pathParts[3], 39 | artifact_id: pathParts[artifactIndex + 1] 40 | }; 41 | } 42 | } 43 | 44 | return null; 45 | } catch (error) { 46 | console.log('Error parsing GitHub artifact URL:', error.message); 47 | return null; 48 | } 49 | } 50 | 51 | // Helper function to download GitHub artifact using Octokit 52 | async function downloadGitHubArtifact(octokit, artifactInfo) { 53 | try { 54 | console.log(`Downloading GitHub artifact ${artifactInfo.artifact_id}...`); 55 | 56 | const response = await octokit.rest.actions.downloadArtifact({ 57 | owner: artifactInfo.owner, 58 | repo: artifactInfo.repo, 59 | artifact_id: parseInt(artifactInfo.artifact_id), 60 | archive_format: 'zip' 61 | }); 62 | 63 | console.log('GitHub artifact downloaded successfully'); 64 | return Buffer.from(response.data); 65 | } catch (error) { 66 | console.error('Error downloading GitHub artifact:', error.message); 67 | throw new Error(`Failed to download GitHub artifact: ${error.message}`); 68 | } 69 | } 70 | 71 | async function run() { 72 | //console.log('Hello, world!'); 73 | 74 | const GITHUB_TOKEN = core.getInput('GITHUB_TOKEN'); 75 | const INSTAWP_TOKEN = core.getInput('INSTAWP_TOKEN'); 76 | const INSTAWP_ACTION = core.getInput('INSTAWP_ACTION', { required: false }) || 'create-site-template'; 77 | 78 | if ( typeof GITHUB_TOKEN !== 'string' ) { 79 | throw new Error('Invalid GITHUB_TOKEN: did you forget to set it in your action config?'); 80 | } 81 | 82 | if ( typeof INSTAWP_TOKEN !== 'string' || !INSTAWP_TOKEN) { 83 | throw new Error('Invalid INSTAWP_TOKEN: did you forget to set it in your action config?'); 84 | } 85 | 86 | const octokit = github.getOctokit(GITHUB_TOKEN); 87 | 88 | const { context = {} } = github; 89 | let { pull_request } = context.payload; 90 | 91 | if ( !pull_request ) { 92 | console.log('Could not find a pull request with this run, commenting disabled!') 93 | pull_request = { number: 0 } 94 | }; 95 | 96 | const domain = core.getInput('INSTAWP_DOMAIN', { required: false }) || 'app.instawp.io' 97 | 98 | switch(INSTAWP_ACTION) { 99 | case 'create-site-template': 100 | // Support both INSTAWP_TEMPLATE_SLUG and INSTAWP_SNAPSHOT_SLUG (as an alias) 101 | const INSTAWP_TEMPLATE_SLUG = core.getInput('INSTAWP_TEMPLATE_SLUG') || core.getInput('INSTAWP_SNAPSHOT_SLUG'); 102 | const REPO_ID = core.getInput('REPO_ID'); 103 | const ARTIFACT_URL = core.getInput('ARTIFACT_URL', { required: false }) || false; 104 | const EXPIRY_HOURS = core.getInput('EXPIRY_HOURS', { required: false }) || null; 105 | 106 | const url = `https://${domain}/api/v2/sites/git` 107 | 108 | console.log(`Creating InstaWP site from template ${INSTAWP_TEMPLATE_SLUG}`) 109 | 110 | let data = { "pr_num": pull_request.number, "template_slug" : INSTAWP_TEMPLATE_SLUG, "git_deployment" : true, repo_id: REPO_ID }; 111 | let config; 112 | let artifactBuffer = null; 113 | 114 | // Check if ARTIFACT_URL is a GitHub artifact 115 | if (ARTIFACT_URL && isGitHubArtifactUrl(ARTIFACT_URL)) { 116 | console.log('Detected GitHub artifact URL, downloading artifact...'); 117 | 118 | const artifactInfo = parseGitHubArtifactUrl(ARTIFACT_URL); 119 | if (!artifactInfo) { 120 | throw new Error('Unable to parse GitHub artifact URL. Please ensure the URL is valid.'); 121 | } 122 | 123 | try { 124 | artifactBuffer = await downloadGitHubArtifact(octokit, artifactInfo); 125 | console.log(`Downloaded artifact, size: ${artifactBuffer.length} bytes`); 126 | } catch (error) { 127 | console.error('Failed to download GitHub artifact:', error.message); 128 | throw error; 129 | } 130 | } 131 | 132 | if (EXPIRY_HOURS !== null) { 133 | data['expiry_hours'] = parseInt(EXPIRY_HOURS); 134 | } 135 | 136 | // If we have an artifact buffer, send as form data, otherwise use JSON 137 | if (artifactBuffer) { 138 | // Create form data with the artifact 139 | const formData = new FormData(); 140 | 141 | // Add all the data fields to form data 142 | Object.keys(data).forEach(key => { 143 | formData.append(key, data[key]); 144 | }); 145 | 146 | // Add the artifact file 147 | formData.append('override_file', artifactBuffer, { 148 | filename: 'artifact.zip', 149 | contentType: 'application/zip' 150 | }); 151 | 152 | config = { 153 | method: 'POST', 154 | headers: { 155 | 'Accept': 'application/json', 156 | 'Authorization': `Bearer ${INSTAWP_TOKEN}`, 157 | ...formData.getHeaders() 158 | }, 159 | body: formData 160 | }; 161 | } else { 162 | // Regular JSON request 163 | if (ARTIFACT_URL != false) { 164 | data['override_url'] = ARTIFACT_URL 165 | } 166 | 167 | config = { 168 | method: 'POST', 169 | headers: { 170 | 'Accept': 'application/json', 171 | 'Authorization': `Bearer ${INSTAWP_TOKEN}`, 172 | 'Content-Type': 'application/json', 173 | }, 174 | body: JSON.stringify(data) 175 | }; 176 | } 177 | 178 | const response = await fetch(url, config) 179 | 180 | const results = await response.json(); 181 | 182 | if (results.status == false) { 183 | let msg = "An error has occurred: Please check if you have permissions or limits might have been exhausted."; 184 | if (results.message) { 185 | msg += ', Server: ' + results.message; 186 | } 187 | console.log(msg); 188 | return; 189 | } 190 | 191 | console.log(results); 192 | 193 | const results_url = results.data.wp_url; 194 | const results_site_id = results.data.id; 195 | const results_login = `https://${domain}/wordpress-auto-login?site=${results.data.s_hash}`; 196 | 197 | 198 | 199 | // core.setOutput('instawp_site_id', results_site_id); 200 | core.setOutput('instawp_url', results_url); 201 | core.setOutput('iwp_url', results_url); 202 | core.setOutput('magic_login', results_login); 203 | core.setOutput('iwp_magic_login', results_login); 204 | 205 | if (!results.data.is_pool) { 206 | console.log(`Waiting for the site ${results_url} (${results_site_id}) to be spawned...`); 207 | 208 | const url_check = `https://${domain}/api/v1/site/user-installation-status/${results_site_id}`; 209 | const config_check = { 210 | method: 'GET', 211 | headers: { 212 | 'Accept': 'application/json', 213 | 'Authorization': `Bearer ${INSTAWP_TOKEN}`, 214 | 'Content-Type': 'application/json', 215 | } 216 | }; 217 | 218 | let wait_count = 1; 219 | 220 | while (wait_count <= 25) { 221 | let response_check = await fetch(url_check, config_check); 222 | let results_check = await response_check.json(); 223 | 224 | if (results_check.data.installation_status.status === 'completed') { 225 | const wp_username = results_check.data.wp_username; 226 | const wp_password = results_check.data.wp_password; 227 | 228 | core.setOutput('iwp_wp_username', wp_username); 229 | core.setOutput('iwp_wp_password', wp_password); 230 | 231 | console.log("Site created.. completing stage"); 232 | break; 233 | } 234 | 235 | console.log("Site creation progress : ", results_check.data.installation_status.percentage_complete); 236 | wait_count++; 237 | await new Promise(r => setTimeout(r, 3000)); 238 | } 239 | } 240 | 241 | if(pull_request.number > 0) { 242 | 243 | const comments = await octokit.rest.issues.listComments({ 244 | ...context.repo, 245 | issue_number: pull_request.number, 246 | per_page: 100 247 | }); 248 | 249 | const comment = comments.data.find( comment => comment.body.includes( '' ) ); 250 | 251 | if ( undefined === comment ) { 252 | await octokit.rest.issues.createComment({ 253 | ...context.repo, 254 | issue_number: pull_request.number, 255 | body: `\nWordPress Instance Deployed.\n\nURL: [${results_url}](${results_url})\nMagic Login: [${results_login}](${results_login})` 256 | }); 257 | } else { 258 | await octokit.rest.issues.updateComment({ 259 | ...context.repo, 260 | issue_number: pull_request.number, 261 | comment_id: comment.id, 262 | body: `\nWordPress Instance Deployed.\n\nURL: [${results_url}](${results_url})\nMagic Login: [${results_login}](${results_login})` 263 | }); 264 | } 265 | } 266 | 267 | break; 268 | case 'destroy-site': 269 | const REPO_ID_DELETE = parseInt(core.getInput('REPO_ID')); 270 | // Support both INSTAWP_TEMPLATE_SLUG and INSTAWP_SNAPSHOT_SLUG (as an alias) 271 | const INSTAWP_TEMPLATE_SLUG_DELETE = core.getInput('INSTAWP_TEMPLATE_SLUG') || core.getInput('INSTAWP_SNAPSHOT_SLUG'); 272 | const PR_NUM_DELETE = pull_request.number; 273 | 274 | console.log(typeof REPO_ID_DELETE) 275 | 276 | if ( typeof REPO_ID_DELETE !== 'number' ) { 277 | throw new Error('Invalid REPO_ID: Enter a numeric Repo ID'); 278 | } 279 | 280 | if ( typeof INSTAWP_TEMPLATE_SLUG_DELETE !== 'string' ) { 281 | throw new Error('Invalid INSTAWP_TEMPLATE_SLUG/INSTAWP_SNAPSHOT_SLUG: Enter a string template or snapshot slug'); 282 | } 283 | 284 | const url_delete = `https://${domain}/api/v1/sites-pr` 285 | console.log(`Destroying InstaWP site from template ${INSTAWP_TEMPLATE_SLUG_DELETE} & PR ${PR_NUM_DELETE} (0=no PR)`) 286 | // console.log(data); 287 | 288 | const data_delete = { "pr_num": PR_NUM_DELETE, "template_slug" : INSTAWP_TEMPLATE_SLUG_DELETE, "repo_id": REPO_ID_DELETE }; 289 | 290 | const config_delete = { 291 | method: 'DELETE', 292 | headers: { 293 | 'Accept': 'application/json', 294 | 'Authorization': `Bearer ${INSTAWP_TOKEN}`, 295 | 'Content-Type': 'application/json', 296 | }, 297 | body: JSON.stringify(data_delete) 298 | } 299 | 300 | const response_delete = await fetch(url_delete, config_delete) 301 | 302 | const results_delete = await response_delete.json(); 303 | 304 | console.log(results_delete); 305 | break; 306 | } 307 | 308 | 309 | } 310 | 311 | run().catch(e => core.setFailed(e.message)); --------------------------------------------------------------------------------