Sfoglia il codice sorgente

Create a Deploy Script (#4469)

Created a deploy script (for both SVN and GIT sandboxes)

Co-authored-by: Ben Dwyer <ben@scruffian.com>
Jason Crist 3 anni fa
parent
commit
3bb95665d8
7 ha cambiato i file con 760 aggiunte e 113 eliminazioni
  1. 1 0
      .gitignore
  2. 2 0
      .sandbox-ignore
  3. 1 1
      blockbase/package-lock.json
  4. 386 5
      package-lock.json
  5. 15 7
      package.json
  6. 125 0
      sandbox-git.sh
  7. 230 100
      theme-utils.mjs

+ 1 - 0
.gitignore

@@ -11,6 +11,7 @@ vendor/
 .svnignore
 .svnignore
 .svn
 .svn
 .sandbox-config
 .sandbox-config
+.github_token
 .wp-env.override.json
 .wp-env.override.json
 
 
 #Ignoring headstart files
 #Ignoring headstart files

+ 2 - 0
.sandbox-ignore

@@ -1,5 +1,6 @@
 .git
 .git
 .github
 .github
+.github_token
 .gitignore
 .gitignore
 .github_token
 .github_token
 .sandbox-config
 .sandbox-config
@@ -13,4 +14,5 @@ sandbox.sh
 theme-utils.mjs
 theme-utils.mjs
 vendor
 vendor
 node_modules
 node_modules
+theme-utils.mjs
 **/*.zip
 **/*.zip

+ 1 - 1
blockbase/package-lock.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "blockbase",
   "name": "blockbase",
-  "version": "1.2.3",
+  "version": "1.2.4",
   "lockfileVersion": 1,
   "lockfileVersion": 1,
   "requires": true,
   "requires": true,
   "dependencies": {
   "dependencies": {

+ 386 - 5
package-lock.json

@@ -1883,6 +1883,145 @@
 				}
 				}
 			}
 			}
 		},
 		},
+		"@octokit/auth-token": {
+			"version": "2.5.0",
+			"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz",
+			"integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==",
+			"dev": true,
+			"requires": {
+				"@octokit/types": "^6.0.3"
+			}
+		},
+		"@octokit/core": {
+			"version": "3.5.1",
+			"resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.5.1.tgz",
+			"integrity": "sha512-omncwpLVxMP+GLpLPgeGJBF6IWJFjXDS5flY5VbppePYX9XehevbDykRH9PdCdvqt9TS5AOTiDide7h0qrkHjw==",
+			"dev": true,
+			"requires": {
+				"@octokit/auth-token": "^2.4.4",
+				"@octokit/graphql": "^4.5.8",
+				"@octokit/request": "^5.6.0",
+				"@octokit/request-error": "^2.0.5",
+				"@octokit/types": "^6.0.3",
+				"before-after-hook": "^2.2.0",
+				"universal-user-agent": "^6.0.0"
+			}
+		},
+		"@octokit/endpoint": {
+			"version": "6.0.12",
+			"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz",
+			"integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==",
+			"dev": true,
+			"requires": {
+				"@octokit/types": "^6.0.3",
+				"is-plain-object": "^5.0.0",
+				"universal-user-agent": "^6.0.0"
+			},
+			"dependencies": {
+				"is-plain-object": {
+					"version": "5.0.0",
+					"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
+					"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
+					"dev": true
+				}
+			}
+		},
+		"@octokit/graphql": {
+			"version": "4.8.0",
+			"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz",
+			"integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==",
+			"dev": true,
+			"requires": {
+				"@octokit/request": "^5.6.0",
+				"@octokit/types": "^6.0.3",
+				"universal-user-agent": "^6.0.0"
+			}
+		},
+		"@octokit/openapi-types": {
+			"version": "10.6.0",
+			"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-10.6.0.tgz",
+			"integrity": "sha512-/iQtZq+zuQJrwawFyjixh333xPu4/KJKk0bFM/Omm4kFlTGw0dWXfq6xCOe5DqONW0faW29Cc9r6p2mvl72aTQ==",
+			"dev": true
+		},
+		"@octokit/plugin-paginate-rest": {
+			"version": "2.16.5",
+			"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.16.5.tgz",
+			"integrity": "sha512-2PfRGymdBypqRes4Xelu0BAZZRCV/Qg0xgo8UB10UKoghCM+zg640+T5WkRsRD0edwfLBPP3VsJgDyDTG4EIYg==",
+			"dev": true,
+			"requires": {
+				"@octokit/types": "^6.31.0"
+			}
+		},
+		"@octokit/plugin-request-log": {
+			"version": "1.0.4",
+			"resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz",
+			"integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==",
+			"dev": true
+		},
+		"@octokit/plugin-rest-endpoint-methods": {
+			"version": "5.11.2",
+			"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.11.2.tgz",
+			"integrity": "sha512-oOJ/gC3e6XS5OyvLhS32BslGkKAyt/tgbLJUH1PKfIyDiRm4c6lSm+NHpy/L9WcdiCQji0RPglXTIH+8degjBg==",
+			"dev": true,
+			"requires": {
+				"@octokit/types": "^6.31.0",
+				"deprecation": "^2.3.1"
+			}
+		},
+		"@octokit/request": {
+			"version": "5.6.1",
+			"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.1.tgz",
+			"integrity": "sha512-Ls2cfs1OfXaOKzkcxnqw5MR6drMA/zWX/LIS/p8Yjdz7QKTPQLMsB3R+OvoxE6XnXeXEE2X7xe4G4l4X0gRiKQ==",
+			"dev": true,
+			"requires": {
+				"@octokit/endpoint": "^6.0.1",
+				"@octokit/request-error": "^2.1.0",
+				"@octokit/types": "^6.16.1",
+				"is-plain-object": "^5.0.0",
+				"node-fetch": "^2.6.1",
+				"universal-user-agent": "^6.0.0"
+			},
+			"dependencies": {
+				"is-plain-object": {
+					"version": "5.0.0",
+					"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
+					"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
+					"dev": true
+				}
+			}
+		},
+		"@octokit/request-error": {
+			"version": "2.1.0",
+			"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz",
+			"integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==",
+			"dev": true,
+			"requires": {
+				"@octokit/types": "^6.0.3",
+				"deprecation": "^2.0.0",
+				"once": "^1.4.0"
+			}
+		},
+		"@octokit/rest": {
+			"version": "18.11.1",
+			"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.11.1.tgz",
+			"integrity": "sha512-UadwFo10+5TQ/gm/E1r1M3Wkz8WUNyX3TLBO64YmlyZFoCPPLwdhVDHFJ+XGL/+sErPiyps3drvx1I9vMncunA==",
+			"dev": true,
+			"requires": {
+				"@octokit/core": "^3.5.1",
+				"@octokit/plugin-paginate-rest": "^2.16.0",
+				"@octokit/plugin-request-log": "^1.0.4",
+				"@octokit/plugin-rest-endpoint-methods": "5.11.2"
+			}
+		},
+		"@octokit/types": {
+			"version": "6.31.0",
+			"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.31.0.tgz",
+			"integrity": "sha512-xobpvYmMYoFSxZB6jL1TPTMMZkxZIBlY145ZKibBJDKCczP1FrLLougtuVOZywGVZdcYs8oq2Bxb3aMjqIFeiw==",
+			"dev": true,
+			"requires": {
+				"@octokit/openapi-types": "^10.5.0"
+			}
+		},
 		"@polka/url": {
 		"@polka/url": {
 			"version": "1.0.0-next.12",
 			"version": "1.0.0-next.12",
 			"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.12.tgz",
 			"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.12.tgz",
@@ -3554,6 +3693,12 @@
 				"tweetnacl": "^0.14.3"
 				"tweetnacl": "^0.14.3"
 			}
 			}
 		},
 		},
+		"before-after-hook": {
+			"version": "2.2.2",
+			"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz",
+			"integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==",
+			"dev": true
+		},
 		"big.js": {
 		"big.js": {
 			"version": "5.2.2",
 			"version": "5.2.2",
 			"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
 			"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
@@ -4005,6 +4150,12 @@
 			"integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==",
 			"integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==",
 			"dev": true
 			"dev": true
 		},
 		},
+		"chardet": {
+			"version": "0.7.0",
+			"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
+			"integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
+			"dev": true
+		},
 		"check-node-version": {
 		"check-node-version": {
 			"version": "4.1.0",
 			"version": "4.1.0",
 			"resolved": "https://registry.npmjs.org/check-node-version/-/check-node-version-4.1.0.tgz",
 			"resolved": "https://registry.npmjs.org/check-node-version/-/check-node-version-4.1.0.tgz",
@@ -4296,6 +4447,12 @@
 				"restore-cursor": "^3.1.0"
 				"restore-cursor": "^3.1.0"
 			}
 			}
 		},
 		},
+		"cli-spinners": {
+			"version": "2.6.0",
+			"resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.0.tgz",
+			"integrity": "sha512-t+4/y50K/+4xcCRosKkA7W4gTr1MySvLV0q+PxmG7FJ5g+66ChKurYjxBCjHggHH3HA5Hh9cy+lcUGWDqVH+4Q==",
+			"dev": true
+		},
 		"cli-truncate": {
 		"cli-truncate": {
 			"version": "2.1.0",
 			"version": "2.1.0",
 			"resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz",
 			"resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz",
@@ -4357,6 +4514,12 @@
 				}
 				}
 			}
 			}
 		},
 		},
+		"cli-width": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz",
+			"integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==",
+			"dev": true
+		},
 		"cliui": {
 		"cliui": {
 			"version": "5.0.0",
 			"version": "5.0.0",
 			"resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
 			"resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
@@ -4368,6 +4531,12 @@
 				"wrap-ansi": "^5.1.0"
 				"wrap-ansi": "^5.1.0"
 			}
 			}
 		},
 		},
+		"clone": {
+			"version": "1.0.4",
+			"resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
+			"integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
+			"dev": true
+		},
 		"clone-deep": {
 		"clone-deep": {
 			"version": "0.2.4",
 			"version": "0.2.4",
 			"resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-0.2.4.tgz",
 			"resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-0.2.4.tgz",
@@ -5055,6 +5224,21 @@
 			"integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==",
 			"integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==",
 			"dev": true
 			"dev": true
 		},
 		},
+		"defaults": {
+			"version": "1.0.3",
+			"resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz",
+			"integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=",
+			"dev": true,
+			"requires": {
+				"clone": "^1.0.2"
+			}
+		},
+		"define-lazy-prop": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
+			"integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==",
+			"dev": true
+		},
 		"define-properties": {
 		"define-properties": {
 			"version": "1.1.3",
 			"version": "1.1.3",
 			"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
 			"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
@@ -5164,6 +5348,12 @@
 			"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
 			"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
 			"dev": true
 			"dev": true
 		},
 		},
+		"deprecation": {
+			"version": "2.3.1",
+			"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
+			"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==",
+			"dev": true
+		},
 		"des.js": {
 		"des.js": {
 			"version": "1.0.1",
 			"version": "1.0.1",
 			"resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz",
 			"resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz",
@@ -6489,6 +6679,17 @@
 				}
 				}
 			}
 			}
 		},
 		},
+		"external-editor": {
+			"version": "3.1.0",
+			"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
+			"integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
+			"dev": true,
+			"requires": {
+				"chardet": "^0.7.0",
+				"iconv-lite": "^0.4.24",
+				"tmp": "^0.0.33"
+			}
+		},
 		"extglob": {
 		"extglob": {
 			"version": "2.0.4",
 			"version": "2.0.4",
 			"resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
 			"resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
@@ -7775,6 +7976,93 @@
 			"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
 			"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
 			"dev": true
 			"dev": true
 		},
 		},
+		"inquirer": {
+			"version": "8.1.5",
+			"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.1.5.tgz",
+			"integrity": "sha512-G6/9xUqmt/r+UvufSyrPpt84NYwhKZ9jLsgMbQzlx804XErNupor8WQdBnBRrXmBfTPpuwf1sV+ss2ovjgdXIg==",
+			"dev": true,
+			"requires": {
+				"ansi-escapes": "^4.2.1",
+				"chalk": "^4.1.1",
+				"cli-cursor": "^3.1.0",
+				"cli-width": "^3.0.0",
+				"external-editor": "^3.0.3",
+				"figures": "^3.0.0",
+				"lodash": "^4.17.21",
+				"mute-stream": "0.0.8",
+				"ora": "^5.4.1",
+				"run-async": "^2.4.0",
+				"rxjs": "^7.2.0",
+				"string-width": "^4.1.0",
+				"strip-ansi": "^6.0.0",
+				"through": "^2.3.6"
+			},
+			"dependencies": {
+				"ansi-regex": {
+					"version": "5.0.1",
+					"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+					"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+					"dev": true
+				},
+				"chalk": {
+					"version": "4.1.2",
+					"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+					"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+					"dev": true,
+					"requires": {
+						"ansi-styles": "^4.1.0",
+						"supports-color": "^7.1.0"
+					}
+				},
+				"emoji-regex": {
+					"version": "8.0.0",
+					"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+					"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+					"dev": true
+				},
+				"is-fullwidth-code-point": {
+					"version": "3.0.0",
+					"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+					"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+					"dev": true
+				},
+				"rxjs": {
+					"version": "7.3.0",
+					"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.3.0.tgz",
+					"integrity": "sha512-p2yuGIg9S1epc3vrjKf6iVb3RCaAYjYskkO+jHIaV0IjOPlJop4UnodOoFb2xeNwlguqLYvGw1b1McillYb5Gw==",
+					"dev": true,
+					"requires": {
+						"tslib": "~2.1.0"
+					}
+				},
+				"string-width": {
+					"version": "4.2.3",
+					"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+					"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+					"dev": true,
+					"requires": {
+						"emoji-regex": "^8.0.0",
+						"is-fullwidth-code-point": "^3.0.0",
+						"strip-ansi": "^6.0.1"
+					}
+				},
+				"strip-ansi": {
+					"version": "6.0.1",
+					"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+					"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+					"dev": true,
+					"requires": {
+						"ansi-regex": "^5.0.1"
+					}
+				},
+				"tslib": {
+					"version": "2.1.0",
+					"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz",
+					"integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==",
+					"dev": true
+				}
+			}
+		},
 		"internal-slot": {
 		"internal-slot": {
 			"version": "1.0.3",
 			"version": "1.0.3",
 			"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz",
 			"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz",
@@ -7955,8 +8243,7 @@
 			"version": "2.1.1",
 			"version": "2.1.1",
 			"resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz",
 			"resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz",
 			"integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw==",
 			"integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw==",
-			"dev": true,
-			"optional": true
+			"dev": true
 		},
 		},
 		"is-extendable": {
 		"is-extendable": {
 			"version": "0.1.1",
 			"version": "0.1.1",
@@ -7997,6 +8284,12 @@
 			"integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==",
 			"integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==",
 			"dev": true
 			"dev": true
 		},
 		},
+		"is-interactive": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz",
+			"integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==",
+			"dev": true
+		},
 		"is-negative-zero": {
 		"is-negative-zero": {
 			"version": "2.0.1",
 			"version": "2.0.1",
 			"resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz",
 			"resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz",
@@ -8156,7 +8449,6 @@
 			"resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
 			"resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
 			"integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
 			"integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
 			"dev": true,
 			"dev": true,
-			"optional": true,
 			"requires": {
 			"requires": {
 				"is-docker": "^2.0.0"
 				"is-docker": "^2.0.0"
 			}
 			}
@@ -10354,6 +10646,12 @@
 			"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
 			"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
 			"dev": true
 			"dev": true
 		},
 		},
+		"mute-stream": {
+			"version": "0.0.8",
+			"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
+			"integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
+			"dev": true
+		},
 		"nan": {
 		"nan": {
 			"version": "2.14.2",
 			"version": "2.14.2",
 			"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz",
 			"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz",
@@ -10840,6 +11138,17 @@
 				"mimic-fn": "^2.1.0"
 				"mimic-fn": "^2.1.0"
 			}
 			}
 		},
 		},
+		"open": {
+			"version": "8.2.1",
+			"resolved": "https://registry.npmjs.org/open/-/open-8.2.1.tgz",
+			"integrity": "sha512-rXILpcQlkF/QuFez2BJDf3GsqpjGKbkUUToAIGo9A0Q6ZkoSGogZJulrUdwRkrAsoQvoZsrjCYt8+zblOk7JQQ==",
+			"dev": true,
+			"requires": {
+				"define-lazy-prop": "^2.0.0",
+				"is-docker": "^2.1.1",
+				"is-wsl": "^2.2.0"
+			}
+		},
 		"opencollective-postinstall": {
 		"opencollective-postinstall": {
 			"version": "2.0.3",
 			"version": "2.0.3",
 			"resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz",
 			"resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz",
@@ -10866,6 +11175,40 @@
 				"word-wrap": "^1.2.3"
 				"word-wrap": "^1.2.3"
 			}
 			}
 		},
 		},
+		"ora": {
+			"version": "5.4.1",
+			"resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz",
+			"integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==",
+			"dev": true,
+			"requires": {
+				"bl": "^4.1.0",
+				"chalk": "^4.1.0",
+				"cli-cursor": "^3.1.0",
+				"cli-spinners": "^2.5.0",
+				"is-interactive": "^1.0.0",
+				"is-unicode-supported": "^0.1.0",
+				"log-symbols": "^4.1.0",
+				"strip-ansi": "^6.0.0",
+				"wcwidth": "^1.0.1"
+			},
+			"dependencies": {
+				"ansi-regex": {
+					"version": "5.0.1",
+					"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+					"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+					"dev": true
+				},
+				"strip-ansi": {
+					"version": "6.0.1",
+					"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+					"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+					"dev": true,
+					"requires": {
+						"ansi-regex": "^5.0.1"
+					}
+				}
+			}
+		},
 		"os-browserify": {
 		"os-browserify": {
 			"version": "0.3.0",
 			"version": "0.3.0",
 			"resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
 			"resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
@@ -10878,6 +11221,12 @@
 			"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
 			"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
 			"dev": true
 			"dev": true
 		},
 		},
+		"os-tmpdir": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+			"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
+			"dev": true
+		},
 		"p-each-series": {
 		"p-each-series": {
 			"version": "2.2.0",
 			"version": "2.2.0",
 			"resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz",
 			"resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz",
@@ -12540,6 +12889,12 @@
 			"integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==",
 			"integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==",
 			"dev": true
 			"dev": true
 		},
 		},
+		"run-async": {
+			"version": "2.4.1",
+			"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
+			"integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==",
+			"dev": true
+		},
 		"run-parallel": {
 		"run-parallel": {
 			"version": "1.2.0",
 			"version": "1.2.0",
 			"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
 			"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
@@ -13820,7 +14175,8 @@
 					"dependencies": {
 					"dependencies": {
 						"hosted-git-info": {
 						"hosted-git-info": {
 							"version": "2.8.8",
 							"version": "2.8.8",
-							"resolved": "",
+							"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz",
+							"integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==",
 							"dev": true
 							"dev": true
 						},
 						},
 						"normalize-package-data": {
 						"normalize-package-data": {
@@ -14403,6 +14759,15 @@
 				}
 				}
 			}
 			}
 		},
 		},
+		"tmp": {
+			"version": "0.0.33",
+			"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+			"integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+			"dev": true,
+			"requires": {
+				"os-tmpdir": "~1.0.2"
+			}
+		},
 		"tmpl": {
 		"tmpl": {
 			"version": "1.0.4",
 			"version": "1.0.4",
 			"resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz",
 			"resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz",
@@ -14785,6 +15150,12 @@
 				"unist-util-is": "^3.0.0"
 				"unist-util-is": "^3.0.0"
 			}
 			}
 		},
 		},
+		"universal-user-agent": {
+			"version": "6.0.0",
+			"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
+			"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==",
+			"dev": true
+		},
 		"universalify": {
 		"universalify": {
 			"version": "0.1.2",
 			"version": "0.1.2",
 			"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
 			"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
@@ -15422,6 +15793,15 @@
 				}
 				}
 			}
 			}
 		},
 		},
+		"wcwidth": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
+			"integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=",
+			"dev": true,
+			"requires": {
+				"defaults": "^1.0.3"
+			}
+		},
 		"webidl-conversions": {
 		"webidl-conversions": {
 			"version": "6.1.0",
 			"version": "6.1.0",
 			"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz",
 			"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz",
@@ -15721,7 +16101,8 @@
 				},
 				},
 				"ssri": {
 				"ssri": {
 					"version": "6.0.1",
 					"version": "6.0.1",
-					"resolved": "",
+					"resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz",
+					"integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==",
 					"dev": true,
 					"dev": true,
 					"requires": {
 					"requires": {
 						"figgy-pudding": "^3.5.1"
 						"figgy-pudding": "^3.5.1"

+ 15 - 7
package.json

@@ -6,29 +6,37 @@
 	"license": "GPL-2.0",
 	"license": "GPL-2.0",
 	"prettier": "@wordpress/prettier-config",
 	"prettier": "@wordpress/prettier-config",
 	"scripts": {
 	"scripts": {
-		"sandbox:clean": "./sandbox.sh clean",
 		"sandbox:pull": "./sandbox.sh pull",
 		"sandbox:pull": "./sandbox.sh pull",
 		"sandbox:push": "./sandbox.sh push",
 		"sandbox:push": "./sandbox.sh push",
 		"sandbox:push:ignore": "./sandbox.sh push --ignore",
 		"sandbox:push:ignore": "./sandbox.sh push --ignore",
 		"sandbox:push:force": "./sandbox.sh push --force",
 		"sandbox:push:force": "./sandbox.sh push --force",
 		"sandbox:watch": "chokidar '**/*' -i '*/node_modules' -i '.git' -c './sandbox.sh push --ignore' --initial",
 		"sandbox:watch": "chokidar '**/*' -i '*/node_modules' -i '.git' -c './sandbox.sh push --ignore' --initial",
+		"sandbox:clean:git": "node ./theme-utils.mjs clean-sandbox-git",
+		"sandbox:clean:svn": "node ./theme-utils.mjs clean-sandbox-svn",
+		"sandbox:clean-all:git": "node ./theme-utils.mjs clean-all-sandbox-git",
+		"sandbox:clean-all:svn": "node ./theme-utils.mjs clean-all-sandbox-svn",
 		"local:clean": "git reset --hard HEAD; git clean -fd",
 		"local:clean": "git reset --hard HEAD; git clean -fd",
-		"batch:build:changed": "./theme-batch-utils.sh build",
-		"batch:build:all": "./theme-batch-utils.sh build-all",
-		"batch:build:zip:all": "./theme-batch-utils.sh build-org-zip-all",
-		"batch:build:zip:changed": "./theme-batch-utils.sh build-org-zip-if-changed",
 		"batch:install": "./theme-batch-utils.sh install-dependencies",
 		"batch:install": "./theme-batch-utils.sh install-dependencies",
 		"batch:audit:fix": "./theme-batch-utils.sh audit-dependencies",
 		"batch:audit:fix": "./theme-batch-utils.sh audit-dependencies",
-		"batch:version-bump": "./theme-batch-utils.sh version-bump"
+		"deploy:version-bump": "node ./theme-utils.mjs version-bump-themes",
+		"deploy:push:all": "node ./theme-utils.mjs push-to-sandbox",
+		"deploy:push:changes": "node ./theme-utils.mjs push-changes-to-sandbox",
+		"deploy:git": "node ./theme-utils.mjs push-button-deploy-git",
+		"deploy:svn": "node ./theme-utils.mjs push-button-deploy-svn",
+		"deploy:preview": "node ./theme-utils.mjs deploy-preview"
+
 	},
 	},
 	"devDependencies": {
 	"devDependencies": {
+		"@octokit/rest": "^18.11.1",
 		"@wordpress/prettier-config": "^1.0.1",
 		"@wordpress/prettier-config": "^1.0.1",
 		"@wordpress/scripts": "^14.0.1",
 		"@wordpress/scripts": "^14.0.1",
 		"@wordpress/stylelint-config": "^19.0.1",
 		"@wordpress/stylelint-config": "^19.0.1",
 		"chokidar-cli": "^2.1.0",
 		"chokidar-cli": "^2.1.0",
 		"husky": "^4.3.0",
 		"husky": "^4.3.0",
+		"inquirer": "^8.1.5",
 		"lint-staged": "^10.5.4",
 		"lint-staged": "^10.5.4",
-		"lodash": "^4.17.21"
+		"lodash": "^4.17.21",
+		"open": "^8.2.1"
 	},
 	},
 	"husky": {
 	"husky": {
 		"hooks": {
 		"hooks": {

+ 125 - 0
sandbox-git.sh

@@ -0,0 +1,125 @@
+#!/bin/bash
+
+SANDBOX_PUBLIC_THEMES_FOLDER='/home/wpdev/public_html/wp-content/themes/pub';
+
+# Display the status of the repo on sandbox
+if [[ $1 == "status" ]]; then
+ssh -TA wpcom-sandbox << EOF 
+  cd '$SANDBOX_PUBLIC_THEMES_FOLDER'; 
+  git status;
+  echo
+EOF
+
+# Clean the sandbox.
+# checkout origin/trunk and ensure it's up-to-date.
+# Remove any other changes.
+elif [[ $1 == "clean" ]]; then
+ssh -TA wpcom-sandbox << EOF 
+  cd '$SANDBOX_PUBLIC_THEMES_FOLDER'; 
+  git reset --hard HEAD;
+  git clean -fd;
+  git checkout trunk;
+  git pull;
+  echo
+EOF
+
+# Add the public github as a remote to your sandbox
+# This is useful to checkout branches from github directly to your sandbox
+elif [[ $1 == "add-github-remote" ]]; then
+ssh -TA wpcom-sandbox << EOF 
+  cd '$SANDBOX_PUBLIC_THEMES_FOLDER'; 
+  git remote add github git@github.com:Automattic/themes.git
+  git fetch github
+  echo
+EOF
+
+# Add the sandbox as a remote to your local
+# This doesn't seem to actually work right now...
+# This allows you to refer to the github as "origin" and your sandbox as "sandbox"
+# Note that for this to work your ~/.ssh/config must have 
+# Host wpcom-sandbox
+#     User wpdev
+#     HostName SANDBOXURL.wordpress.com
+#     ForwardAgent yes
+elif [[ $1 == "add-sandbox-remote" ]]; then
+git remote add sandbox wpdev@wpcom-sandbox:/home/wpdev/public_html/wp-content/themes/pub/.git
+
+# Switch the sandbox to a given github branch.
+# Defaults to current branch if not provided.
+elif [[ $1 == "checkout-branch" ]]; then
+  if [[ -z $2 ]]; then
+    BRANCH_NAME=$(git symbolic-ref --short HEAD)
+  else
+    BRANCH_NAME=$2;
+  fi
+
+ssh -TA wpcom-sandbox << EOF 
+  cd '$SANDBOX_PUBLIC_THEMES_FOLDER'
+  git fetch
+  git checkout github/$BRANCH_NAME
+  echo
+EOF
+
+# First ensure that the local and sandbox are on the same branch.
+# Then push whatever has changed in the local branch to the sandbox via rsync.
+# This isn't going to work because the public repo (github) and private repo (a8c)
+# don't have common ancestry
+elif [[ $1 == "push-local-diff" ]]; then
+ssh -TA wpcom-sandbox << EOF 
+  echo '#TODO: Everything';
+EOF
+
+elif [[ $1 == "push" ]]; then
+rsync -av --no-p --no-times --exclude-from='.sandbox-ignore' ./ wpcom-sandbox:$SANDBOX_PUBLIC_THEMES_FOLDER/
+
+elif [[ $1 == "create-diff" ]]; then
+
+#TODO: Do some fancy git stuff to build the commit message
+commit_message="Deploy Themes [THEME UMBRELLA PROJECT VERSION] to wpcom
+   
+Summary:
+This is a test.  Please ignore this diff
+This should reflect all of the Pull Requests between THIS BRANCH and TRUNK (stating at the point of diversion)
+
+Test Plan: Execute Smoke Test
+   
+Reviewers:
+   
+Subscribers:
+"
+
+ssh -TA wpcom-sandbox << EOF 
+  cd $SANDBOX_PUBLIC_THEMES_FOLDER
+  git branch -D deploy
+  git checkout -b deploy
+  git add --all
+  git commit -m "$commit_message"
+  arc diff --create --verbatim
+EOF
+#TODO: Pull the Phabricator URL from the output above
+# Open phabricator URL in my browser
+# Add Phabricator URL to the PR I'm working with (as a comment) ???
+
+elif [[ $1 == "checkout-diff" ]]; then
+diff_id=$2
+ssh -TA wpcom-sandbox << EOF 
+  cd $SANDBOX_PUBLIC_THEMES_FOLDER
+  arc patch $diff_id
+EOF
+
+
+elif [[ $1 == "deploy-diff" ]]; then
+ssh -TA wpcom-sandbox << EOF 
+  cd $SANDBOX_PUBLIC_THEMES_FOLDER
+  arc land --onto trunk --preview
+EOF
+
+# Clone the sandbox here.
+# I don't think you would ever actually do this one... if you have this script then you've already cloned the repo from SOMEWHERE.
+# It's mostly here as a reference.
+elif [[ $1 == "clone" ]]; then
+git clone wpdev@wpcom-sandbox:/home/wpdev/public_html/wp-content/themes/pub/.git .
+
+
+# All Done
+fi

+ 230 - 100
theme-utils.mjs

@@ -1,6 +1,7 @@
 import { spawn } from 'child_process';
 import { spawn } from 'child_process';
 import fs from 'fs';
 import fs from 'fs';
 import open from 'open';
 import open from 'open';
+import inquirer from 'inquirer';
 
 
 const remoteSSH = 'wpcom-sandbox';
 const remoteSSH = 'wpcom-sandbox';
 const sandboxPublicThemesFolder = '/home/wpdev/public_html/wp-content/themes/pub';
 const sandboxPublicThemesFolder = '/home/wpdev/public_html/wp-content/themes/pub';
@@ -11,8 +12,8 @@ const isWin = process.platform === 'win32';
 	let args = process.argv.slice(2);
 	let args = process.argv.slice(2);
 	let command = args?.[0];
 	let command = args?.[0];
 	switch (command) {
 	switch (command) {
-		case "push-button-deploy-git": return pushButtonDeployGit();
-		case "push-button-deploy-svn": return pushButtonDeploySvn();
+		case "push-button-deploy-git": return pushButtonDeploy('git');
+		case "push-button-deploy-svn": return pushButtonDeploy('svn');
 		case "clean-sandbox-git": return cleanSandboxGit();
 		case "clean-sandbox-git": return cleanSandboxGit();
 		case "clean-sandbox-svn": return cleanSandboxSvn();
 		case "clean-sandbox-svn": return cleanSandboxSvn();
 		case "clean-all-sandbox-git": return cleanAllSandboxGit();
 		case "clean-all-sandbox-git": return cleanAllSandboxGit();
@@ -20,6 +21,9 @@ const isWin = process.platform === 'win32';
 		case "push-to-sandbox": return pushToSandbox();
 		case "push-to-sandbox": return pushToSandbox();
 		case "push-changes-to-sandbox": return pushChangesToSandbox();
 		case "push-changes-to-sandbox": return pushChangesToSandbox();
 		case "version-bump-themes": return versionBumpThemes();
 		case "version-bump-themes": return versionBumpThemes();
+		case "land-diff-git": return landChangesGit(args?.[1]);
+		case "land-diff-svn": return landChangesSvn(args?.[1]);
+		case "deploy-preview": return deployPreview();
 	}
 	}
 	return showHelp();
 	return showHelp();
 })();
 })();
@@ -29,6 +33,29 @@ function showHelp(){
 	console.log('Help info can go here');
 	console.log('Help info can go here');
 }
 }
 
 
+/* 
+ Determine what changes would be deployed
+*/
+async function deployPreview() {
+	console.clear();
+	console.log('To ensure accuracy clean your sandbox before previewing. (It is not automatically done).');
+	console.log('npm run sandbox:clean:git OR npm run sandbox:clean:svn')
+
+	let message = await checkForDeployability();
+	if (message) {
+		console.log(`\n${message}\n\n`);
+	}
+
+	let hash = await getLastDeployedHash();
+	console.log(`Last deployed hash: ${hash}`);
+
+	let changedThemes = await getChangedThemes(hash);
+	console.log(`The following themes have changes:\n${changedThemes}`);
+	
+	let logs = await executeCommand(`git log --reverse --pretty=format:%s ${hash}..HEAD`);
+	console.log(`\n\nCommit log of changes to be deployed:\n\n${logs}\n\n`);
+}
+
 /*
 /*
  Execute the first phase of a deployment.
  Execute the first phase of a deployment.
  Leverages git on the sandbox.
  Leverages git on the sandbox.
@@ -42,69 +69,173 @@ function showHelp(){
 	* Open the Phabricator Diff in your browser
 	* Open the Phabricator Diff in your browser
 	* Create a tag in the github repository at this point of change which includes the phabricator link in the description
 	* Create a tag in the github repository at this point of change which includes the phabricator link in the description
 */
 */
-async function pushButtonDeployGit() {
+async function pushButtonDeploy(repoType) {
 
 
-	//TODO: If this branch isn't trunk exit
-	//TODO: If this branch isn't current with origin exit and require a pull
-	//TODO: If the sandbox isn't in 'git' mode exit
+	if (repoType != 'svn' && repoType != 'git' ) {
+		return console.log('Specify a repo type to use push-button deploy');
+	}
 
 
-	let hash = await getLastDeployedHash();
+	let message = await checkForDeployability();
+	if (message) {
+		return console.log(`\n\n${message}\n\n`);
+	}
 
 
-	await versionBumpThemes({
-		commit: true
-	});
+	try {
+		console.clear();
+		let prompt = await inquirer.prompt([{
+			type: 'confirm',
+			message: 'You are about to deploy /trunk.  Are you ready to continue?',
+			name: "continue",
+			default: false
+		}]);
+
+		if(!prompt.continue){
+			return;
+		}
 
 
-	//TODO: Can these be automagically uploaded?
-	//await buildChangedOrgZips();
+		let hash = await getLastDeployedHash();
+		let diffUrl;
 
 
-	await cleanSandboxGit();
-	await pushChangesToSandbox();
-	await updateLastDeployedHash();
-	let diffUrl = await createGitPhabricatorDiff(hash);
+		await versionBumpThemes();
 
 
-	await tagDeployment({
-		hash: hash,
-		diffUrl: diffUrl
-	});
+		let changedThemes = await getChangedThemes(hash);
+
+		//TODO: Can these be automagically uploaded?
+		//await buildChangedOrgZips();
+
+		if (repoType === 'git' ) {
+			await cleanSandboxGit();
+		}
+		else {
+			await cleanSandboxSvn();
+		}
+		await pushChangesToSandbox();
+		await updateLastDeployedHash();
+
+		if (repoType === 'git' ) {
+			diffUrl = await createGitPhabricatorDiff(hash);
+		}
+		else {
+			diffUrl = await createSvnPhabricatorDiff(hash);
+		}
+		let diffId = diffUrl.split('a8c.com/')[1];
+
+		//push changes (from version bump)
+		await executeCommand('git push');
+
+		await tagDeployment({
+			hash: hash,
+			diffId: diffId
+		});
+
+		console.log(`\n\nPhase One Complete\n\nYour sandbox has been updated and the diff is available for review.\nPlease give your sandbox a smoke test to determine that the changes work as expected.\nThe following themes have had changes: \n\n${changedThemes}\n\n\n`);
+
+		prompt = await inquirer.prompt([{
+			type: 'confirm',
+			message: 'Are you ready to land these changes?',
+			name: "continue",
+			default: false
+		}]);
+
+		if(!prompt.continue){
+			console.log(`Aborted Automated Deploy Process Landing Phase\n\nYou will have to land these changes manually.  The ID of the diff to land: ${diffId}` );
+			return;
+		}
+
+		if (repoType === 'git' ) {
+			landChangesGit(diffId);
+		}
+		else {
+			landChangesSvn(diffId);
+		}
+
+		prompt = await inquirer.prompt([{
+			type: 'confirm',
+			message: 'The changes have landed.  Do you wish to deploy the changed themes now?',
+			name: "continue",
+			default: false
+		}]);
+
+		if(!prompt.continue){
+			console.log(`Aborted Automated Deploy Process Deploy Phase.  Please deploy the following themes manually:\n${changedThemes}` );
+			return;
+		}
+
+		await deployThemes(changedThemes);
+
+		//TODO: Can this be automated?
+		open('https://mc.a8c.com/themes/downloads/');
+		console.log('Please build the .zip files for the themes manually');
+
+		console.log('\n\nAll Done!!\n\n');
+	}
+	catch (err) {
+		console.log("ERROR with deply script: ", err);
+	}
 }
 }
 
 
 /*
 /*
- Execute the first phase of a deployment.
- Leverages subversion on the sandbox.
-	* Gets the last deployed hash from the sandbox
-	* Version bump all themes have have changes since the last deployment
-	* Commit the version bump change to github
-	* Clean the sandbox and ensure it is up-to-date
-	* Push all changed files (including removal of deleted files) since the last deployment
-	* Update the 'last deployed' hash on the sandbox
-	* Create a phabricator diff based on the changes since the last deployment.  The description including the commit messages since the last deployment.
-	* Open the Phabricator Diff in your browser
-	* Create a tag in the github repository at this point of change which includes the phabricator link in the description
+ Check to ensure that:
+  * The current branch is /trunk
+  * That trunk is up-to-date with origin/trunk
 */
 */
-async function pushButtonDeploySvn(){
-
-	//TODO: If this branch isn't trunk exit
-	//TODO: If this branch isn't current with origin exit and require a pull
-	//TODO: If the sandbox isn't in 'svn' mode exit
+async function checkForDeployability(){
+	let branchName = await executeCommand('git symbolic-ref --short HEAD');
+	if(branchName !== 'trunk' ) {
+		return 'Only the /trunk branch can be deployed.';
+	}
 
 
-	let hash = await getLastDeployedHash();
+	await executeCommand('git remote update', true);
+	let localMasterHash = await executeCommand('git rev-parse trunk')
+	let remoteMasterHash = await executeCommand('git rev-parse origin/trunk')
+	if(localMasterHash !== remoteMasterHash) {
+		return 'Local /trunk is out-of-date.  Pull changes to continue.'
+	}
+	return null;
+}
 
 
-	await versionBumpThemes({
-		commit: true
-	});
+/*
+ Land the changes from the given diff ID.  This is the "production merge".
+ This is the git version of that action.
+*/
+async function landChangesGit(diffId){
+	return await executeOnSandbox(`
+		cd ${sandboxPublicThemesFolder};
+		arc patch ${diffId}
+		arc land
+	`, true);
+}
 
 
-	//TODO: Can these be automagically uploaded?
-	//await buildChangedOrgZips();
+/*
+ Land the changes from the given diff ID.  This is the "production merge".
+ This is the svn version of that action.
+*/
+async function landChangesSvn(diffId){
+	return await executeOnSandbox(`
+		cd ${sandboxPublicThemesFolder};
+		svn ci -m ${diffId} 
+	`, true); 
+}
 
 
-	await cleanSandboxSvn();
-	await pushChangesToSandbox();
-	await updateLastDeployedHash();
-	let diffUrl = await createSvnPhabricatorDiff(hash);
+async function getChangedThemes(hash) {
+	console.log('Determining all changed themes')
+	let themes = await getActionableThemes();
+	let changedThemes = [];
+	for (let theme of themes) {
+		let hasChanges = await checkThemeForChanges(theme, hash);
+		if(hasChanges){
+			changedThemes.push(theme.replace('./', ''));
+		}
+	}
+	return changedThemes;
+}
 
 
-	await tagDeployment({
-		hash: hash,
-		diffUrl: diffUrl
-	});
+async function deployThemes(themes) {
+	let response;
+	for (let theme of themes ) {
+		response = await executeOnSandbox(`deploy pub ${theme}`, true);
+		//TODO: if the response wasn't happy then prompt to try again.
+	}
 }
 }
 
 
 /*
 /*
@@ -130,11 +261,11 @@ async function updateLastDeployedHash() {
 
 
 /*
 /*
  Version bump (increment version patch) any theme project that has had changes since the last deployment.
  Version bump (increment version patch) any theme project that has had changes since the last deployment.
- If a theme's version has already been changed since that last deployment then do not version bump it. 
+ If a theme's version has already been changed since that last deployment then do not version bump it.
  If any theme projects have had a version bump also version bump the parent project.
  If any theme projects have had a version bump also version bump the parent project.
- Optionally commit and push the version bump to git.
+ Commit the change.
 */
 */
-async function versionBumpThemes(options) {
+async function versionBumpThemes() {
 	console.log("Version Bumping");
 	console.log("Version Bumping");
 
 
 	let themes = await getActionableThemes();
 	let themes = await getActionableThemes();
@@ -165,13 +296,11 @@ async function versionBumpThemes(options) {
 		await executeCommand(`npm version patch --no-git-tag-version`);
 		await executeCommand(`npm version patch --no-git-tag-version`);
 	}
 	}
 
 
-	if (options?.commit && versionBumpCount > 0 && !rootHasVersionBump) {
+	if (versionBumpCount > 0 && !rootHasVersionBump) {
 		console.log('commiting version-bump');
 		console.log('commiting version-bump');
-		let commitResult = await executeCommand(`
+		await executeCommand(`
 			git commit -a -m "Version Bump";
 			git commit -a -m "Version Bump";
-			git push
-		`);
-		console.log(commitResult);
+		`, true);
 	}
 	}
 }
 }
 
 
@@ -206,13 +335,13 @@ async function checkThemeForVersionBump(theme, hash){
 	`);
 	`);
 	let previousPackage = JSON.parse(previousPackageString);
 	let previousPackage = JSON.parse(previousPackageString);
 	let currentPackage = JSON.parse(fs.readFileSync(`${theme}/package.json`))
 	let currentPackage = JSON.parse(fs.readFileSync(`${theme}/package.json`))
-	return previousPackage.version != currentPackage.version;	
+	return previousPackage.version != currentPackage.version;
 }
 }
 
 
 /*
 /*
  Determine if a theme has had changes since a given hash.
  Determine if a theme has had changes since a given hash.
  Used by versionBumpThemes
  Used by versionBumpThemes
-*/ 
+*/
 async function checkThemeForChanges(theme, hash){
 async function checkThemeForChanges(theme, hash){
 	let uncomittedChanges = await executeCommand(`git diff-index --name-only HEAD -- ${theme}`);
 	let uncomittedChanges = await executeCommand(`git diff-index --name-only HEAD -- ${theme}`);
 	let comittedChanges = await executeCommand(`git diff --name-only ${hash} HEAD -- ${theme}`);
 	let comittedChanges = await executeCommand(`git diff --name-only ${hash} HEAD -- ${theme}`);
@@ -230,8 +359,7 @@ async function getActionableThemes() {
 
 
 async function buildChangedOrgZips() {
 async function buildChangedOrgZips() {
 	console.log("Building .org Zip files");
 	console.log("Building .org Zip files");
-	let result = await executeCommand(`./theme-batch-utils.sh build-org-zip-if-changed`);
-	console.log(result);
+	await executeCommand(`./theme-batch-utils.sh build-org-zip-if-changed`, true);
 }
 }
 
 
 /*
 /*
@@ -242,7 +370,7 @@ async function buildChangedOrgZips() {
 */
 */
 async function cleanSandboxGit() {
 async function cleanSandboxGit() {
 	console.log('Cleaning the Themes Sandbox');
 	console.log('Cleaning the Themes Sandbox');
-	let response = await executeOnSandbox(`
+	await executeOnSandbox(`
 		cd ${sandboxPublicThemesFolder};
 		cd ${sandboxPublicThemesFolder};
 		git reset --hard HEAD;
 		git reset --hard HEAD;
 		git clean -fd;
 		git clean -fd;
@@ -250,8 +378,7 @@ async function cleanSandboxGit() {
 		git pull;
 		git pull;
 		echo;
 		echo;
 		git status
 		git status
-	`)
-	console.log(response);
+	`, true);
 	console.log('All done cleaning.');
 	console.log('All done cleaning.');
 }
 }
 
 
@@ -271,8 +398,7 @@ async function cleanAllSandboxGit() {
 		git pull;
 		git pull;
 		echo;
 		echo;
 		git status
 		git status
-	`)
-	console.log(response);
+	`, true);
 	console.log('All done cleaning.');
 	console.log('All done cleaning.');
 }
 }
 
 
@@ -284,13 +410,12 @@ async function cleanAllSandboxGit() {
 */
 */
 async function cleanSandboxSvn() {
 async function cleanSandboxSvn() {
 	console.log('Cleaning the theme sandbox');
 	console.log('Cleaning the theme sandbox');
-	let response = await executeOnSandbox(`
+	await executeOnSandbox(`
 		cd ${sandboxPublicThemesFolder};
 		cd ${sandboxPublicThemesFolder};
   		svn revert -R .;
   		svn revert -R .;
   		svn cleanup --remove-unversioned;
   		svn cleanup --remove-unversioned;
   		svn up;
   		svn up;
-	`);
-	console.log(response);
+	`, true);
 	console.log('All done cleaning.');
 	console.log('All done cleaning.');
 }
 }
 
 
@@ -302,13 +427,12 @@ async function cleanSandboxSvn() {
 */
 */
 async function cleanAllSandboxSvn() {
 async function cleanAllSandboxSvn() {
 	console.log('Cleaning the entire sandbox');
 	console.log('Cleaning the entire sandbox');
-	let response = await executeOnSandbox(`
+	await executeOnSandbox(`
 		cd ${sandboxRootFolder};
 		cd ${sandboxRootFolder};
   		svn revert -R .;
   		svn revert -R .;
   		svn cleanup --remove-unversioned;
   		svn cleanup --remove-unversioned;
   		svn up .;
   		svn up .;
-	`);
-	console.log(response);
+	`, true);
 	console.log('All done cleaning.');
 	console.log('All done cleaning.');
 }
 }
 
 
@@ -342,19 +466,17 @@ async function pushChangesToSandbox() {
 
 
 	if(deletedFiles.length > 0) {
 	if(deletedFiles.length > 0) {
 		console.log('deleting from sandbox: ', deletedFiles);
 		console.log('deleting from sandbox: ', deletedFiles);
-		let deleteResponse = await executeOnSandbox(`
+		await executeOnSandbox(`
 			cd ${sandboxPublicThemesFolder};
 			cd ${sandboxPublicThemesFolder};
 			rm -f ${deletedFiles.join(' ')}
 			rm -f ${deletedFiles.join(' ')}
-		`);
-		console.log(deleteResponse);
+		`, true);
 	}
 	}
 
 
 	if(changedFiles.length > 0) {
 	if(changedFiles.length > 0) {
 		console.log('pushing changed files to sandbox:', changedFiles);
 		console.log('pushing changed files to sandbox:', changedFiles);
-		let pushResponse = await executeCommand(`
+		await executeCommand(`
 			rsync -avR --no-p --no-times --exclude-from='.sandbox-ignore' ${changedFiles.join(' ')} wpcom-sandbox:${sandboxPublicThemesFolder}/
 			rsync -avR --no-p --no-times --exclude-from='.sandbox-ignore' ${changedFiles.join(' ')} wpcom-sandbox:${sandboxPublicThemesFolder}/
-		`);
-		console.log(pushResponse);
+		`, true);
 	}
 	}
 }
 }
 
 
@@ -365,7 +487,7 @@ async function pushChangesToSandbox() {
 async function getComittedChangesSinceHash(hash) {
 async function getComittedChangesSinceHash(hash) {
 
 
 	let comittedChanges = await executeCommand(`git diff ${hash} HEAD --name-only`);
 	let comittedChanges = await executeCommand(`git diff ${hash} HEAD --name-only`);
-	comittedChanges = comittedChanges.replace(/\r?\n|\r/g, " ").split(" "); 
+	comittedChanges = comittedChanges.replace(/\r?\n|\r/g, " ").split(" ");
 
 
 	let uncomittedChanges = await executeCommand(`git diff HEAD --name-only`);
 	let uncomittedChanges = await executeCommand(`git diff HEAD --name-only`);
 	uncomittedChanges = uncomittedChanges.replace(/\r?\n|\r/g, " ").split(" ");
 	uncomittedChanges = uncomittedChanges.replace(/\r?\n|\r/g, " ").split(" ");
@@ -382,12 +504,12 @@ async function getDeletedFilesSince(hash){
 	let deletedSinceHash = await executeCommand(`
 	let deletedSinceHash = await executeCommand(`
 		git log --format=format:"" --name-only -M100% --diff-filter=D ${hash}..HEAD
 		git log --format=format:"" --name-only -M100% --diff-filter=D ${hash}..HEAD
 	`);
 	`);
-	deletedSinceHash = deletedSinceHash.replace(/\r?\n|\r/g, " ").trim().split(" "); 
+	deletedSinceHash = deletedSinceHash.replace(/\r?\n|\r/g, " ").trim().split(" ");
 
 
 	let deletedAndUncomitted = await executeCommand(`
 	let deletedAndUncomitted = await executeCommand(`
 		git diff HEAD --name-only --diff-filter=D
 		git diff HEAD --name-only --diff-filter=D
 	`);
 	`);
-	deletedAndUncomitted = deletedAndUncomitted.replace(/\r?\n|\r/g, " ").trim().split(" "); 
+	deletedAndUncomitted = deletedAndUncomitted.replace(/\r?\n|\r/g, " ").trim().split(" ");
 
 
 	return deletedSinceHash.concat(deletedAndUncomitted).filter( item => {
 	return deletedSinceHash.concat(deletedAndUncomitted).filter( item => {
 		return item != '';
 		return item != '';
@@ -404,14 +526,14 @@ async function buildPhabricatorCommitMessageSince(hash){
 	let projectVersion = await executeCommand(`node -p "require('./package.json').version"`);
 	let projectVersion = await executeCommand(`node -p "require('./package.json').version"`);
 	let logs = await executeCommand(`git log --reverse --pretty=format:%s ${hash}..HEAD`);
 	let logs = await executeCommand(`git log --reverse --pretty=format:%s ${hash}..HEAD`);
 	return `Deploy Themes ${projectVersion} to wpcom
 	return `Deploy Themes ${projectVersion} to wpcom
-   
+
 Summary:
 Summary:
 ${logs}
 ${logs}
 
 
 Test Plan: Execute Smoke Test
 Test Plan: Execute Smoke Test
-   
+
 Reviewers:
 Reviewers:
-   
+
 Subscribers:
 Subscribers:
 `;
 `;
 }
 }
@@ -434,7 +556,7 @@ async function createGitPhabricatorDiff(hash) {
 		git add --all
 		git add --all
 		git commit -m "${commitMessage}"
 		git commit -m "${commitMessage}"
 		arc diff --create --verbatim
 		arc diff --create --verbatim
-	`);
+	`, true);
 
 
 	let phabricatorUrl = getPhabricatorUrlFromResponse(result);
 	let phabricatorUrl = getPhabricatorUrlFromResponse(result);
 
 
@@ -455,14 +577,17 @@ async function createGitPhabricatorDiff(hash) {
 async function createSvnPhabricatorDiff(hash) {
 async function createSvnPhabricatorDiff(hash) {
 	console.log('creating Phabricator Diff');
 	console.log('creating Phabricator Diff');
 
 
-	let commitMessage = await buildPhabricatorCommitMessageSince(hash);
+	const commitTempFileLocation = '/tmp/theme-deploy-comment.txt';
+	const commitMessage = await buildPhabricatorCommitMessageSince(hash);
 
 
-	let result = await executeOnSandbox(`
+	const result = await executeOnSandbox(`
 		cd ${sandboxPublicThemesFolder};
 		cd ${sandboxPublicThemesFolder};
-		arc diff --create --message ${commitMessage}
-	`);
+		echo '${commitMessage}' > ${commitTempFileLocation}
+		svn add --force * --auto-props --parents --depth infinity -q
+		arc diff --create --message-file ${commitTempFileLocation}
+	`, true);
 
 
-	let phabricatorUrl = getPhabricatorUrlFromResponse(result);
+	const phabricatorUrl = getPhabricatorUrlFromResponse(result);
 
 
 	console.log('Diff Created at: ', phabricatorUrl);
 	console.log('Diff Created at: ', phabricatorUrl);
 
 
@@ -478,7 +603,7 @@ async function createSvnPhabricatorDiff(hash) {
  Used by createGitPhabricatorDiff
  Used by createGitPhabricatorDiff
 */
 */
 function getPhabricatorUrlFromResponse(response){
 function getPhabricatorUrlFromResponse(response){
-	return response 
+	return response
 		?.split('\n')
 		?.split('\n')
 		?.find( item => {
 		?.find( item => {
 			return item.includes('Revision URI: ');
 			return item.includes('Revision URI: ');
@@ -486,7 +611,6 @@ function getPhabricatorUrlFromResponse(response){
 		?.split("Revision URI: ")[1];
 		?.split("Revision URI: ")[1];
 }
 }
 
 
-
 /*
 /*
  Create a git tag at the current hash.
  Create a git tag at the current hash.
  In the description include the commit logs since the given hash.
  In the description include the commit logs since the given hash.
@@ -497,8 +621,8 @@ async function tagDeployment(options={}) {
 	let hash = options.hash || await getLastDeployedHash();
 	let hash = options.hash || await getLastDeployedHash();
 
 
 	let workInTheOpenPhabricatorUrl = '';
 	let workInTheOpenPhabricatorUrl = '';
-	if (options.diffUrl) {
-		workInTheOpenPhabricatorUrl = `Phabricator: ${options.diffUrl.split('a8c.com/')[1]}-code`;
+	if (options.diffId) {
+		workInTheOpenPhabricatorUrl = `Phabricator: ${diffId}-code`;
 	}
 	}
 	let projectVersion = await executeCommand(`node -p "require('./package.json').version"`);
 	let projectVersion = await executeCommand(`node -p "require('./package.json').version"`);
 	let logs = await executeCommand(`git log --reverse --pretty=format:%s ${hash}..HEAD`);
 	let logs = await executeCommand(`git log --reverse --pretty=format:%s ${hash}..HEAD`);
@@ -520,16 +644,16 @@ Host wpcom-sandbox
 	HostName SANDBOXURL.wordpress.com
 	HostName SANDBOXURL.wordpress.com
 	ForwardAgent yes
 	ForwardAgent yes
 */
 */
-function executeOnSandbox(command){
-	return executeCommand(`ssh -TA ${remoteSSH} << EOF 
-${command} 
-EOF`);
+function executeOnSandbox(command, logResponse){
+	return executeCommand(`ssh -TA ${remoteSSH} << EOF
+${command}
+EOF`, logResponse);
 }
 }
 
 
 /*
 /*
  Execute a command locally.
  Execute a command locally.
 */
 */
-async function executeCommand(command) {
+async function executeCommand(command, logResponse) {
 	return new Promise((resolove, reject) => {
 	return new Promise((resolove, reject) => {
 
 
 		let child;
 		let child;
@@ -547,10 +671,16 @@ async function executeCommand(command) {
 
 
 		child.stdout.on('data', (data) => {
 		child.stdout.on('data', (data) => {
 			response += data;
 			response += data;
+			if(logResponse){
+				console.log(data.toString());
+			}
 		});
 		});
 
 
 		child.stderr.on('data', (data) => {
 		child.stderr.on('data', (data) => {
 			errResponse += data;
 			errResponse += data;
+			if(logResponse){
+				console.log(data.toString());
+			}
 		});
 		});
 
 
 		child.on('exit', (code) => {
 		child.on('exit', (code) => {