├── .gitignore ├── README.md ├── action.yml ├── dist └── index.js ├── package-lock.json ├── package.json └── src └── action.js /.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 | # Pre-req 5 | 6 | - Register an account at [instawp.com](https://instawp.com) 7 | - Create a site and upload your plugin/theme (download a zip from github and upload) 8 | - Save the site as Template, give a unique slug 9 | - Go to Deployment, enter the details of your WordPress plugin/theme repo. 10 | - Go back to Templates, connect the git repo to the template. 11 | - Paste this Yaml file into your repo as shown below. 12 | 13 | # Yaml File 14 | 15 | Paste this code in your `.github/workflows/instawp.yml` file 16 | 17 | ``` 18 | name: InstaWP WordPress Testing 19 | 20 | on: 21 | pull_request: 22 | types: [opened] 23 | 24 | jobs: 25 | create-wp-for-testing: 26 | runs-on: ubuntu-latest 27 | steps: 28 | - uses: instawp/wordpress-testing-automation@latest 29 | with: 30 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 31 | INSTAWP_TOKEN: ${{secrets.INSTAWP_TOKEN}} 32 | EXPIRY_HOURS: 24 //optional 33 | INSTAWP_TEMPLATE_SLUG: gutenademonew //instawp template slug 34 | REPO_ID: 123 //instawp repo ID 35 | ARTIFACT_URL: https://yoursite.com/url.zip //optional 36 | ``` 37 | 38 | - INSTAWP_TOKEN can be obtained from your "API Tokens" screen inside the InstaWP interface. 39 | - INSTAWP_TEMPLATE_SLUG is shown on the "Templates" screen. 40 | - REPO_ID is shown in the "Deployment" screen. 41 | - EXPIRY_HOURS is the number of hours the site will be active. 42 | - 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, you can use this input to specify the URL of the zip file. 43 | 44 | # Changelog 45 | 46 | - 1.0.2 - Updated to use the new InstaWP API v2 and updated the Node version to 16 47 | - 1.0.1 - Added support for expiry hours 48 | - 1.0.0 - Initial release -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: 'InstaWP WordPress Automation for Github' 2 | description: 'WordPress Automation & QA - Simplied 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 | REPO_ID: 23 | description: 'InstaWP Repo ID (action: create-site-template)' 24 | required: false 25 | type: number 26 | INSTAWP_DOMAIN: 27 | description: 'For testing purpose only' 28 | required: false 29 | ARTIFACT_URL: 30 | description: 'Override the Artifact URL (.zip) file' 31 | required: false 32 | EXPIRY_HOURS: 33 | description: 'Number of hours after which the site will expire' 34 | required: false 35 | type: number 36 | 37 | outputs: 38 | instawp_url: 39 | description: "URL of the newly created InstaWP site" 40 | magic_login: 41 | description: "Automatic Login URL to wp-admin for the new site" 42 | iwp_wp_username: 43 | description: "WP username of the new site" 44 | iwp_wp_password: 45 | description: "WP password of the new site" 46 | 47 | 48 | runs: 49 | using: 'node16' 50 | main: 'dist/index.js' 51 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wordpress-testing-automation", 3 | "version": "1.0.1", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "wordpress-testing-automation", 9 | "version": "1.0.1", 10 | "license": "ISC", 11 | "devDependencies": { 12 | "@actions/core": "^1.6.0", 13 | "@actions/github": "^5.0.1", 14 | "@vercel/ncc": "^0.33.3", 15 | "node-fetch": "^2.6.1" 16 | } 17 | }, 18 | "node_modules/@actions/core": { 19 | "version": "1.10.1", 20 | "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.1.tgz", 21 | "integrity": "sha512-3lBR9EDAY+iYIpTnTIXmWcNbX3T2kCkAEQGIQx4NVQ0575nk2k3GRZDTPQG+vVtS2izSLmINlxXf0uLtnrTP+g==", 22 | "dev": true, 23 | "dependencies": { 24 | "@actions/http-client": "^2.0.1", 25 | "uuid": "^8.3.2" 26 | } 27 | }, 28 | "node_modules/@actions/github": { 29 | "version": "5.1.1", 30 | "resolved": "https://registry.npmjs.org/@actions/github/-/github-5.1.1.tgz", 31 | "integrity": "sha512-Nk59rMDoJaV+mHCOJPXuvB1zIbomlKS0dmSIqPGxd0enAXBnOfn4VWF+CGtRCwXZG9Epa54tZA7VIRlJDS8A6g==", 32 | "dev": true, 33 | "dependencies": { 34 | "@actions/http-client": "^2.0.1", 35 | "@octokit/core": "^3.6.0", 36 | "@octokit/plugin-paginate-rest": "^2.17.0", 37 | "@octokit/plugin-rest-endpoint-methods": "^5.13.0" 38 | } 39 | }, 40 | "node_modules/@actions/http-client": { 41 | "version": "2.2.1", 42 | "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.1.tgz", 43 | "integrity": "sha512-KhC/cZsq7f8I4LfZSJKgCvEwfkE8o1538VoBeoGzokVLLnbFDEAdFD3UhoMklxo2un9NJVBdANOresx7vTHlHw==", 44 | "dev": true, 45 | "dependencies": { 46 | "tunnel": "^0.0.6", 47 | "undici": "^5.25.4" 48 | } 49 | }, 50 | "node_modules/@fastify/busboy": { 51 | "version": "2.1.1", 52 | "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", 53 | "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", 54 | "dev": true, 55 | "engines": { 56 | "node": ">=14" 57 | } 58 | }, 59 | "node_modules/@octokit/auth-token": { 60 | "version": "2.5.0", 61 | "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", 62 | "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==", 63 | "dev": true, 64 | "dependencies": { 65 | "@octokit/types": "^6.0.3" 66 | } 67 | }, 68 | "node_modules/@octokit/core": { 69 | "version": "3.6.0", 70 | "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz", 71 | "integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==", 72 | "dev": true, 73 | "dependencies": { 74 | "@octokit/auth-token": "^2.4.4", 75 | "@octokit/graphql": "^4.5.8", 76 | "@octokit/request": "^5.6.3", 77 | "@octokit/request-error": "^2.0.5", 78 | "@octokit/types": "^6.0.3", 79 | "before-after-hook": "^2.2.0", 80 | "universal-user-agent": "^6.0.0" 81 | } 82 | }, 83 | "node_modules/@octokit/endpoint": { 84 | "version": "6.0.12", 85 | "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz", 86 | "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==", 87 | "dev": true, 88 | "dependencies": { 89 | "@octokit/types": "^6.0.3", 90 | "is-plain-object": "^5.0.0", 91 | "universal-user-agent": "^6.0.0" 92 | } 93 | }, 94 | "node_modules/@octokit/graphql": { 95 | "version": "4.8.0", 96 | "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz", 97 | "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==", 98 | "dev": true, 99 | "dependencies": { 100 | "@octokit/request": "^5.6.0", 101 | "@octokit/types": "^6.0.3", 102 | "universal-user-agent": "^6.0.0" 103 | } 104 | }, 105 | "node_modules/@octokit/openapi-types": { 106 | "version": "12.11.0", 107 | "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.11.0.tgz", 108 | "integrity": "sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ==", 109 | "dev": true 110 | }, 111 | "node_modules/@octokit/plugin-paginate-rest": { 112 | "version": "2.21.3", 113 | "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz", 114 | "integrity": "sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==", 115 | "dev": true, 116 | "dependencies": { 117 | "@octokit/types": "^6.40.0" 118 | }, 119 | "peerDependencies": { 120 | "@octokit/core": ">=2" 121 | } 122 | }, 123 | "node_modules/@octokit/plugin-rest-endpoint-methods": { 124 | "version": "5.16.2", 125 | "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz", 126 | "integrity": "sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw==", 127 | "dev": true, 128 | "dependencies": { 129 | "@octokit/types": "^6.39.0", 130 | "deprecation": "^2.3.1" 131 | }, 132 | "peerDependencies": { 133 | "@octokit/core": ">=3" 134 | } 135 | }, 136 | "node_modules/@octokit/request": { 137 | "version": "5.6.3", 138 | "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz", 139 | "integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==", 140 | "dev": true, 141 | "dependencies": { 142 | "@octokit/endpoint": "^6.0.1", 143 | "@octokit/request-error": "^2.1.0", 144 | "@octokit/types": "^6.16.1", 145 | "is-plain-object": "^5.0.0", 146 | "node-fetch": "^2.6.7", 147 | "universal-user-agent": "^6.0.0" 148 | } 149 | }, 150 | "node_modules/@octokit/request-error": { 151 | "version": "2.1.0", 152 | "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz", 153 | "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==", 154 | "dev": true, 155 | "dependencies": { 156 | "@octokit/types": "^6.0.3", 157 | "deprecation": "^2.0.0", 158 | "once": "^1.4.0" 159 | } 160 | }, 161 | "node_modules/@octokit/types": { 162 | "version": "6.41.0", 163 | "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.41.0.tgz", 164 | "integrity": "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==", 165 | "dev": true, 166 | "dependencies": { 167 | "@octokit/openapi-types": "^12.11.0" 168 | } 169 | }, 170 | "node_modules/@vercel/ncc": { 171 | "version": "0.33.4", 172 | "resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.33.4.tgz", 173 | "integrity": "sha512-ln18hs7dMffelP47tpkaR+V5Tj6coykNyxJrlcmCormPqRQjB/Gv4cu2FfBG+PMzIfdZp2CLDsrrB1NPU22Qhg==", 174 | "dev": true, 175 | "bin": { 176 | "ncc": "dist/ncc/cli.js" 177 | } 178 | }, 179 | "node_modules/before-after-hook": { 180 | "version": "2.2.3", 181 | "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", 182 | "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==", 183 | "dev": true 184 | }, 185 | "node_modules/deprecation": { 186 | "version": "2.3.1", 187 | "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", 188 | "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", 189 | "dev": true 190 | }, 191 | "node_modules/is-plain-object": { 192 | "version": "5.0.0", 193 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", 194 | "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", 195 | "dev": true, 196 | "engines": { 197 | "node": ">=0.10.0" 198 | } 199 | }, 200 | "node_modules/node-fetch": { 201 | "version": "2.7.0", 202 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", 203 | "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", 204 | "dev": true, 205 | "dependencies": { 206 | "whatwg-url": "^5.0.0" 207 | }, 208 | "engines": { 209 | "node": "4.x || >=6.0.0" 210 | }, 211 | "peerDependencies": { 212 | "encoding": "^0.1.0" 213 | }, 214 | "peerDependenciesMeta": { 215 | "encoding": { 216 | "optional": true 217 | } 218 | } 219 | }, 220 | "node_modules/once": { 221 | "version": "1.4.0", 222 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 223 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 224 | "dev": true, 225 | "dependencies": { 226 | "wrappy": "1" 227 | } 228 | }, 229 | "node_modules/tr46": { 230 | "version": "0.0.3", 231 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", 232 | "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", 233 | "dev": true 234 | }, 235 | "node_modules/tunnel": { 236 | "version": "0.0.6", 237 | "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", 238 | "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", 239 | "dev": true, 240 | "engines": { 241 | "node": ">=0.6.11 <=0.7.0 || >=0.7.3" 242 | } 243 | }, 244 | "node_modules/undici": { 245 | "version": "5.28.4", 246 | "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", 247 | "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", 248 | "dev": true, 249 | "dependencies": { 250 | "@fastify/busboy": "^2.0.0" 251 | }, 252 | "engines": { 253 | "node": ">=14.0" 254 | } 255 | }, 256 | "node_modules/universal-user-agent": { 257 | "version": "6.0.1", 258 | "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz", 259 | "integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==", 260 | "dev": true 261 | }, 262 | "node_modules/uuid": { 263 | "version": "8.3.2", 264 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", 265 | "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", 266 | "dev": true, 267 | "bin": { 268 | "uuid": "dist/bin/uuid" 269 | } 270 | }, 271 | "node_modules/webidl-conversions": { 272 | "version": "3.0.1", 273 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", 274 | "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", 275 | "dev": true 276 | }, 277 | "node_modules/whatwg-url": { 278 | "version": "5.0.0", 279 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", 280 | "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", 281 | "dev": true, 282 | "dependencies": { 283 | "tr46": "~0.0.3", 284 | "webidl-conversions": "^3.0.0" 285 | } 286 | }, 287 | "node_modules/wrappy": { 288 | "version": "1.0.2", 289 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 290 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", 291 | "dev": true 292 | } 293 | } 294 | } 295 | -------------------------------------------------------------------------------- /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 | 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /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 | 7 | async function run() { 8 | //console.log('Hello, world!'); 9 | 10 | const GITHUB_TOKEN = core.getInput('GITHUB_TOKEN'); 11 | const INSTAWP_TOKEN = core.getInput('INSTAWP_TOKEN'); 12 | const INSTAWP_ACTION = core.getInput('INSTAWP_ACTION', { required: false }) || 'create-site-template'; 13 | 14 | if ( typeof GITHUB_TOKEN !== 'string' ) { 15 | throw new Error('Invalid GITHUB_TOKEN: did you forget to set it in your action config?'); 16 | } 17 | 18 | if ( typeof INSTAWP_TOKEN !== 'string' || !INSTAWP_TOKEN) { 19 | throw new Error('Invalid INSTAWP_TOKEN: did you forget to set it in your action config?'); 20 | } 21 | 22 | const octokit = github.getOctokit(GITHUB_TOKEN); 23 | 24 | const { context = {} } = github; 25 | let { pull_request } = context.payload; 26 | 27 | if ( !pull_request ) { 28 | console.log('Could not find a pull request with this run, commenting disabled!') 29 | pull_request = { number: 0 } 30 | }; 31 | 32 | const domain = core.getInput('INSTAWP_DOMAIN', { required: false }) || 'app.instawp.io' 33 | 34 | switch(INSTAWP_ACTION) { 35 | case 'create-site-template': 36 | const INSTAWP_TEMPLATE_SLUG = core.getInput('INSTAWP_TEMPLATE_SLUG'); 37 | const REPO_ID = core.getInput('REPO_ID'); 38 | const ARTIFACT_URL = core.getInput('ARTIFACT_URL', { required: false }) || false; 39 | const EXPIRY_HOURS = core.getInput('EXPIRY_HOURS', { required: false }) || null; 40 | 41 | const url = `https://${domain}/api/v2/sites/git` 42 | 43 | console.log(`Creating InstaWP site from template ${INSTAWP_TEMPLATE_SLUG}`) 44 | 45 | let data = { "pr_num": pull_request.number, "template_slug" : INSTAWP_TEMPLATE_SLUG, "git_deployment" : true, repo_id: REPO_ID }; 46 | 47 | if (ARTIFACT_URL != false) { 48 | data['override_url'] = ARTIFACT_URL 49 | } 50 | 51 | if (EXPIRY_HOURS !== null) { 52 | data['expiry_hours'] = parseInt(EXPIRY_HOURS); 53 | } 54 | 55 | // console.log(data); 56 | 57 | const config = { 58 | method: 'POST', 59 | headers: { 60 | 'Accept': 'application/json', 61 | 'Authorization': `Bearer ${INSTAWP_TOKEN}`, 62 | 'Content-Type': 'application/json', 63 | }, 64 | body: JSON.stringify(data) 65 | } 66 | const response = await fetch(url, config) 67 | 68 | const results = await response.json(); 69 | 70 | if (results.status == false) { 71 | let msg = "An error has occurred: Please check if you have permissions or limits might have been exhausted."; 72 | if (results.message) { 73 | msg += ', Server: ' + results.message; 74 | } 75 | console.log(msg); 76 | return; 77 | } 78 | 79 | console.log(results); 80 | 81 | const results_url = results.data.wp_url; 82 | const results_site_id = results.data.id; 83 | const results_login = `https://${domain}/wordpress-auto-login?site=${results.data.s_hash}`; 84 | 85 | 86 | 87 | // core.setOutput('instawp_site_id', results_site_id); 88 | core.setOutput('instawp_url', results_url); 89 | core.setOutput('iwp_url', results_url); 90 | core.setOutput('magic_login', results_login); 91 | core.setOutput('iwp_magic_login', results_login); 92 | 93 | if (!results.data.is_pool) { 94 | console.log(`Waiting for the site ${results_url} (${results_site_id}) to be spawned...`); 95 | 96 | const url_check = `https://${domain}/api/v1/site/user-installation-status/${results_site_id}`; 97 | const config_check = { 98 | method: 'GET', 99 | headers: { 100 | 'Accept': 'application/json', 101 | 'Authorization': `Bearer ${INSTAWP_TOKEN}`, 102 | 'Content-Type': 'application/json', 103 | } 104 | }; 105 | 106 | let wait_count = 1; 107 | 108 | while (wait_count <= 25) { 109 | let response_check = await fetch(url_check, config_check); 110 | let results_check = await response_check.json(); 111 | 112 | if (results_check.data.installation_status.status === 'completed') { 113 | const wp_username = results_check.data.wp_username; 114 | const wp_password = results_check.data.wp_password; 115 | 116 | core.setOutput('iwp_wp_username', wp_username); 117 | core.setOutput('iwp_wp_password', wp_password); 118 | 119 | console.log("Site created.. completing stage"); 120 | break; 121 | } 122 | 123 | console.log("Site creation progress : ", results_check.data.installation_status.percentage_complete); 124 | wait_count++; 125 | await new Promise(r => setTimeout(r, 3000)); 126 | } 127 | } 128 | 129 | if(pull_request.number > 0) { 130 | 131 | const comments = await octokit.rest.issues.listComments({ 132 | ...context.repo, 133 | issue_number: pull_request.number, 134 | per_page: 100 135 | }); 136 | 137 | const comment = comments.data.find( comment => comment.body.includes( '' ) ); 138 | 139 | if ( undefined === comment ) { 140 | await octokit.rest.issues.createComment({ 141 | ...context.repo, 142 | issue_number: pull_request.number, 143 | body: `\nWordPress Instance Deployed.\n\nURL: [${results_url}](${results_url})\nMagic Login: [${results_login}](${results_login})` 144 | }); 145 | } else { 146 | await octokit.rest.issues.updateComment({ 147 | ...context.repo, 148 | issue_number: pull_request.number, 149 | comment_id: comment.id, 150 | body: `\nWordPress Instance Deployed.\n\nURL: [${results_url}](${results_url})\nMagic Login: [${results_login}](${results_login})` 151 | }); 152 | } 153 | } 154 | 155 | break; 156 | case 'destroy-site': 157 | const REPO_ID_DELETE = parseInt(core.getInput('REPO_ID')); 158 | const INSTAWP_TEMPLATE_SLUG_DELETE = core.getInput('INSTAWP_TEMPLATE_SLUG'); 159 | const PR_NUM_DELETE = pull_request.number; 160 | 161 | console.log(typeof REPO_ID_DELETE) 162 | 163 | if ( typeof REPO_ID_DELETE !== 'number' ) { 164 | throw new Error('Invalid REPO_ID: Enter a numeric Repo ID'); 165 | } 166 | 167 | if ( typeof INSTAWP_TEMPLATE_SLUG_DELETE !== 'string' ) { 168 | throw new Error('Invalid INSTAWP_TEMPLATE_SLUG: Enter a string template slug'); 169 | } 170 | 171 | const url_delete = `https://${domain}/api/v1/sites-pr` 172 | console.log(`Destroying InstaWP site from template ${INSTAWP_TEMPLATE_SLUG_DELETE} & PR ${PR_NUM_DELETE} (0=no PR)`) 173 | // console.log(data); 174 | 175 | const data_delete = { "pr_num": PR_NUM_DELETE, "template_slug" : INSTAWP_TEMPLATE_SLUG_DELETE, "repo_id": REPO_ID_DELETE }; 176 | 177 | const config_delete = { 178 | method: 'DELETE', 179 | headers: { 180 | 'Accept': 'application/json', 181 | 'Authorization': `Bearer ${INSTAWP_TOKEN}`, 182 | 'Content-Type': 'application/json', 183 | }, 184 | body: JSON.stringify(data_delete) 185 | } 186 | 187 | const response_delete = await fetch(url_delete, config_delete) 188 | 189 | const results_delete = await response_delete.json(); 190 | 191 | console.log(results_delete); 192 | break; 193 | } 194 | 195 | 196 | } 197 | 198 | run().catch(e => core.setFailed(e.message)); --------------------------------------------------------------------------------