diff --git a/package-lock.json b/package-lock.json index 3b93fcb0..cadc1819 100644 --- a/package-lock.json +++ b/package-lock.json @@ -648,6 +648,12 @@ "integrity": "sha512-yALhelO3i0hqZwhjtcr6dYyaLoCHbAMshwtj6cGxTvHZAKXHsYGdff6E8EPw3xLKY0ELUTQ69Q1rQiJENnccMA==", "dev": true }, + "@types/lodash": { + "version": "4.14.130", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.130.tgz", + "integrity": "sha512-H++wk0tbneBsRVfLkgAAd0IIpmpVr2Bj4T0HncoOsQf3/xrJexRYQK2Tqo0Ej3pFslM8GkMgdis9bu6xIb1ycw==", + "dev": true + }, "@types/node": { "version": "8.10.48", "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.48.tgz", @@ -865,6 +871,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "optional": true, "requires": { "kind-of": "^3.0.2", "longest": "^1.0.1", @@ -904,6 +911,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-1.3.0.tgz", "integrity": "sha1-5QtMCccL89aA4y/xt5lOn52JUXQ=", + "optional": true, "requires": { "glob": "^7.0.0", "graceful-fs": "^4.1.0", @@ -917,6 +925,7 @@ "version": "7.1.4", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "optional": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -930,6 +939,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", + "optional": true, "requires": { "readable-stream": "^2.0.5" } @@ -989,6 +999,7 @@ "version": "4.10.1", "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "optional": true, "requires": { "bn.js": "^4.0.0", "inherits": "^2.0.1", @@ -1283,7 +1294,8 @@ "bn.js": { "version": "4.11.8", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "optional": true }, "boom": { "version": "2.10.1", @@ -1332,7 +1344,8 @@ "brorand": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "optional": true }, "browser-process-hrtime": { "version": "0.1.3", @@ -1361,6 +1374,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "optional": true, "requires": { "buffer-xor": "^1.0.3", "cipher-base": "^1.0.0", @@ -1397,6 +1411,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "optional": true, "requires": { "bn.js": "^4.1.0", "randombytes": "^2.0.1" @@ -1473,7 +1488,8 @@ "buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "optional": true }, "buffer-equal-constant-time": { "version": "1.0.1", @@ -1495,7 +1511,8 @@ "buffer-xor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "optional": true }, "builtin-modules": { "version": "1.1.1", @@ -1610,6 +1627,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "optional": true, "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -1838,6 +1856,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "optional": true, "requires": { "cipher-base": "^1.0.1", "inherits": "^2.0.1", @@ -1850,6 +1869,7 @@ "version": "1.1.7", "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "optional": true, "requires": { "cipher-base": "^1.0.3", "create-hash": "^1.1.0", @@ -2143,6 +2163,7 @@ "version": "6.4.1", "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz", "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==", + "optional": true, "requires": { "bn.js": "^4.4.0", "brorand": "^1.0.1", @@ -2189,6 +2210,7 @@ "version": "0.1.7", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "optional": true, "requires": { "prr": "~1.0.1" } @@ -2582,6 +2604,7 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "optional": true, "requires": { "d": "1", "es5-ext": "~0.10.14" @@ -2597,6 +2620,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "optional": true, "requires": { "md5.js": "^1.3.4", "safe-buffer": "^5.1.1" @@ -2936,7 +2960,8 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true + "bundled": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -2954,11 +2979,13 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true + "bundled": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2971,15 +2998,18 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "concat-map": { "version": "0.0.1", - "bundled": true + "bundled": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -3082,7 +3112,8 @@ }, "inherits": { "version": "2.0.3", - "bundled": true + "bundled": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -3092,6 +3123,7 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -3104,17 +3136,20 @@ "minimatch": { "version": "3.0.4", "bundled": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true + "bundled": true, + "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -3131,6 +3166,7 @@ "mkdirp": { "version": "0.5.1", "bundled": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -3203,7 +3239,8 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true + "bundled": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -3213,6 +3250,7 @@ "once": { "version": "1.4.0", "bundled": true, + "optional": true, "requires": { "wrappy": "1" } @@ -3288,7 +3326,8 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true + "bundled": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -3318,6 +3357,7 @@ "string-width": { "version": "1.0.2", "bundled": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -3335,6 +3375,7 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -3373,11 +3414,13 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true + "bundled": true, + "optional": true }, "yallist": { "version": "3.0.3", - "bundled": true + "bundled": true, + "optional": true } } }, @@ -3575,6 +3618,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", + "optional": true, "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -3584,6 +3628,7 @@ "version": "1.1.7", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "optional": true, "requires": { "inherits": "^2.0.3", "minimalistic-assert": "^1.0.1" @@ -3604,6 +3649,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "optional": true, "requires": { "hash.js": "^1.0.3", "minimalistic-assert": "^1.0.0", @@ -3833,7 +3879,8 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "optional": true }, "is-fullwidth-code-point": { "version": "2.0.0", @@ -5321,7 +5368,8 @@ "longest": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=" + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "optional": true }, "loose-envify": { "version": "1.4.0", @@ -5390,6 +5438,7 @@ "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "optional": true, "requires": { "hash-base": "^3.0.0", "inherits": "^2.0.1", @@ -5409,6 +5458,7 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "optional": true, "requires": { "errno": "^0.1.3", "readable-stream": "^2.0.1" @@ -5481,12 +5531,14 @@ "minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "optional": true }, "minimalistic-crypto-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "optional": true }, "minimatch": { "version": "3.0.4", @@ -5737,7 +5789,8 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "optional": true }, "object-copy": { "version": "0.1.0", @@ -5951,6 +6004,7 @@ "version": "5.1.4", "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.4.tgz", "integrity": "sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw==", + "optional": true, "requires": { "asn1.js": "^4.0.0", "browserify-aes": "^1.0.0", @@ -6037,6 +6091,7 @@ "version": "3.0.17", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", + "optional": true, "requires": { "create-hash": "^1.1.2", "create-hmac": "^1.1.4", @@ -6054,7 +6109,8 @@ "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "optional": true }, "pirates": { "version": "4.0.1", @@ -6185,7 +6241,8 @@ "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "optional": true }, "pseudomap": { "version": "1.0.2", @@ -6239,6 +6296,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "optional": true, "requires": { "safe-buffer": "^5.1.0" } @@ -6565,6 +6623,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "optional": true, "requires": { "hash-base": "^3.0.0", "inherits": "^2.0.1" @@ -6757,6 +6816,7 @@ "version": "7.1.4", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "optional": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -6825,6 +6885,7 @@ "version": "2.4.11", "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "optional": true, "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -6985,7 +7046,8 @@ "source-list-map": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", - "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==" + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", + "optional": true }, "source-map": { "version": "0.7.3", @@ -7322,7 +7384,8 @@ "tapable": { "version": "0.2.9", "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.9.tgz", - "integrity": "sha512-2wsvQ+4GwBvLPLWsNfLCDYGsW6xb7aeC6utq2Qh0PFwgEy7K7dsma9Jsmb2zSQj7GvYAyUGSntLtsv++GmgL1A==" + "integrity": "sha512-2wsvQ+4GwBvLPLWsNfLCDYGsW6xb7aeC6utq2Qh0PFwgEy7K7dsma9Jsmb2zSQj7GvYAyUGSntLtsv++GmgL1A==", + "optional": true }, "tar-stream": { "version": "1.6.2", @@ -8060,6 +8123,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.3.0.tgz", "integrity": "sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA==", + "optional": true, "requires": { "source-list-map": "^2.0.0", "source-map": "~0.6.1" @@ -8068,7 +8132,8 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true } } }, diff --git a/package.json b/package.json index debd41f7..72410b16 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ }, "devDependencies": { "@types/jest": "^24.0.13", + "@types/lodash": "^4.14.130", "@types/open": "^6.1.0", "@types/request": "^2.48.1", "@types/serverless": "^1.18.2", diff --git a/src/index.ts b/src/index.ts index e262c764..538f2c1c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,15 +4,13 @@ This way only one plugin needs to be added to the service in order to get access whole provider implementation. */ -import * as Serverless from 'serverless'; +import Serverless from 'serverless'; import AzureProvider from './provider/azureProvider'; import { AzureInvoke } from './plugins/invoke/azureInvoke'; import { AzureLogs } from './plugins/logs/azureLogs'; import { AzureRemove } from './plugins/remove/azureRemove'; import { AzurePackage } from './plugins/package/azurePackage'; -import { AzurePackageFunction } from './plugins/package/azurePackageFunction'; import { AzureDeployPlugin } from './plugins/deploy/azureDeployPlugin'; -import { AzureDeployFunctionPlugin } from './plugins/deploy/azureDeployFunctionPlugin'; import { AzureLoginPlugin } from './plugins/login/loginPlugin'; import { AzureApimServicePlugin } from './plugins/apim/apimServicePlugin'; import { AzureApimFunctionPlugin } from './plugins/apim/apimFunctionPlugin'; @@ -23,14 +21,12 @@ export class AzureIndex { // To be refactored this.serverless.pluginManager.addPlugin(AzurePackage); - this.serverless.pluginManager.addPlugin(AzurePackageFunction); this.serverless.pluginManager.addPlugin(AzureInvoke); this.serverless.pluginManager.addPlugin(AzureLogs); this.serverless.pluginManager.addPlugin(AzureRemove); // Refactored this.serverless.pluginManager.addPlugin(AzureLoginPlugin); this.serverless.pluginManager.addPlugin(AzureDeployPlugin); - this.serverless.pluginManager.addPlugin(AzureDeployFunctionPlugin); this.serverless.pluginManager.addPlugin(AzureApimServicePlugin); this.serverless.pluginManager.addPlugin(AzureApimFunctionPlugin); } diff --git a/src/plugins/apim/apimFunctionPlugin.ts b/src/plugins/apim/apimFunctionPlugin.ts index c96acba2..c4dcd6f0 100644 --- a/src/plugins/apim/apimFunctionPlugin.ts +++ b/src/plugins/apim/apimFunctionPlugin.ts @@ -1,4 +1,4 @@ -import * as Serverless from 'serverless'; +import Serverless from 'serverless'; import { ApimService } from '../../services/apimService'; export class AzureApimFunctionPlugin { diff --git a/src/plugins/apim/apimServicePlugin.ts b/src/plugins/apim/apimServicePlugin.ts index 7cecb977..a5255f65 100644 --- a/src/plugins/apim/apimServicePlugin.ts +++ b/src/plugins/apim/apimServicePlugin.ts @@ -1,4 +1,4 @@ -import * as Serverless from 'serverless'; +import Serverless from 'serverless'; import { ApimService } from '../../services/apimService'; export class AzureApimServicePlugin { @@ -11,6 +11,11 @@ export class AzureApimServicePlugin { } private async deploy() { + const apimConfig = this.serverless.service.provider['apim']; + if (!apimConfig) { + return Promise.resolve(); + } + this.serverless.cli.log('Starting APIM service deployment'); const apimService = new ApimService(this.serverless, this.options); diff --git a/src/plugins/deploy/azureDeployFunctionPlugin.ts b/src/plugins/deploy/azureDeployFunctionPlugin.ts deleted file mode 100644 index 6886f22a..00000000 --- a/src/plugins/deploy/azureDeployFunctionPlugin.ts +++ /dev/null @@ -1,27 +0,0 @@ -import * as Serverless from 'serverless'; -import { FunctionAppService } from '../../services/functionAppService'; - -export class AzureDeployFunctionPlugin { - public hooks: { [eventName: string]: Promise }; - - constructor(private serverless: Serverless, private options: Serverless.Options) { - this.hooks = { - 'deploy:function:packageFunction': this.beforeDeploy.bind(this), - 'deploy:function:deploy': this.deploy.bind(this) - }; - } - - private async beforeDeploy() { - // Spawn 'package:function' to create the single-function zip artifact - this.serverless.pluginManager.spawn('package:function'); - } - - private async deploy() { - const functionAppService = new FunctionAppService(this.serverless, this.options); - const functionApp = await functionAppService.get(); - - await functionAppService.deleteFunction(this.options.function); - await functionAppService.uploadFunction(functionApp, this.options.function); - await functionAppService.syncTriggers(functionApp); - } -} diff --git a/src/plugins/deploy/azureDeployPlugin.ts b/src/plugins/deploy/azureDeployPlugin.ts index 56925a43..c6acbb10 100644 --- a/src/plugins/deploy/azureDeployPlugin.ts +++ b/src/plugins/deploy/azureDeployPlugin.ts @@ -1,4 +1,4 @@ -import * as Serverless from 'serverless'; +import Serverless from 'serverless'; import { ResourceService } from '../../services/resourceService'; import { FunctionAppService } from '../../services/functionAppService'; diff --git a/src/plugins/invoke/azureInvoke.ts b/src/plugins/invoke/azureInvoke.ts index 3cb44766..a672e345 100644 --- a/src/plugins/invoke/azureInvoke.ts +++ b/src/plugins/invoke/azureInvoke.ts @@ -1,12 +1,10 @@ -import * as Serverless from 'serverless'; -import { getAdminKey } from '../../shared/getAdminKey'; +import Serverless from 'serverless'; import { join, isAbsolute } from 'path'; import AzureProvider from '../../provider/azureProvider'; export class AzureInvoke { public hooks: { [eventName: string]: Promise }; private provider: AzureProvider; - private getAdminKey = getAdminKey; constructor(private serverless: Serverless, private options: Serverless.Options) { this.provider = (this.serverless.getProvider('azure') as any) as AzureProvider; @@ -24,7 +22,7 @@ export class AzureInvoke { } this.hooks = { - 'before:invoke:invoke': this.getAdminKey.bind(this), + 'before:invoke:invoke': this.provider.getAdminKey.bind(this), 'invoke:invoke': this.invoke.bind(this) }; } diff --git a/src/plugins/login/loginPlugin.ts b/src/plugins/login/loginPlugin.ts index 0d645468..e2425e2a 100644 --- a/src/plugins/login/loginPlugin.ts +++ b/src/plugins/login/loginPlugin.ts @@ -1,6 +1,6 @@ -import * as open from 'open'; +import open from 'open'; import { interactiveLoginWithAuthResponse, loginWithServicePrincipalSecretWithAuthResponse } from '@azure/ms-rest-nodeauth'; -import * as Serverless from 'serverless'; +import Serverless from 'serverless'; import AzureProvider from '../../provider/azureProvider'; export class AzureLoginPlugin { diff --git a/src/plugins/logs/azureLogs.ts b/src/plugins/logs/azureLogs.ts index 8634fdec..86c522ec 100644 --- a/src/plugins/logs/azureLogs.ts +++ b/src/plugins/logs/azureLogs.ts @@ -1,4 +1,4 @@ -import * as Serverless from 'serverless'; +import Serverless from 'serverless'; import AzureProvider from '../../provider/azureProvider'; export class AzureLogs { diff --git a/src/plugins/package/azurePackage.ts b/src/plugins/package/azurePackage.ts index 6b39a112..7d44762d 100644 --- a/src/plugins/package/azurePackage.ts +++ b/src/plugins/package/azurePackage.ts @@ -1,7 +1,5 @@ -import { existsSync, renameSync, statSync } from 'fs'; -import { join } from "path"; -import * as Serverless from 'serverless'; +import Serverless from 'serverless'; import AzureProvider from '../../provider/azureProvider'; import { createEventsBindings } from '../../shared/bindings'; import { getFunctionMetaData } from '../../shared/utils'; @@ -13,7 +11,6 @@ export class AzurePackage { constructor(private serverless: Serverless, private options: Serverless.Options) { this.hooks = { 'package:setupProviderConfiguration': this.setupProviderConfiguration.bind(this), - 'before:webpack:package:packageModules': this.webpackFunctionJson.bind(this) }; } @@ -29,36 +26,4 @@ export class AzurePackage { return Promise.all(createEventsPromises); } - - private async webpackFunctionJson(): Promise { - if (existsSync('.webpack')) { - const webpackJsonPromises = this.serverless.service.getAllFunctions() - .map((functionName) => this.moveJsonFile(functionName)); - - return Promise.all(webpackJsonPromises); - } - - return Promise.resolve(); - } - - private async moveJsonFile(functionName): Promise { - const dirPath = join(this.serverless.config.servicePath, '.webpack', functionName); - const jsonFileName = `${functionName}-function.json`; - const jsonFileSrcPath = join(this.serverless.config.servicePath, jsonFileName); - const jsonFileDestPath = join(dirPath, jsonFileName); - - return new Promise((resolve) => { - if (existsSync(dirPath) && statSync(dirPath).isDirectory()) { - if (existsSync(jsonFileSrcPath)) { - this.serverless.cli.log(`Moving ${jsonFileName} to .webpack directory.`); - renameSync(jsonFileSrcPath, jsonFileDestPath); - } - else { - this.serverless.cli.log(`Warning: No generated ${functionName}-function.json file was found. It will not be included in the package.`); - } - } - - resolve(); - }); - } } diff --git a/src/plugins/package/azurePackageFunction.ts b/src/plugins/package/azurePackageFunction.ts deleted file mode 100644 index e0b09260..00000000 --- a/src/plugins/package/azurePackageFunction.ts +++ /dev/null @@ -1,26 +0,0 @@ - -import * as Serverless from 'serverless'; -import { createEventsBindings } from '../../shared/bindings'; -import { getFunctionMetaData } from '../../shared/utils'; - -export class AzurePackageFunction { - public hooks: { [eventName: string]: Promise }; - - constructor(private serverless: Serverless, private options: Serverless.Options) { - this.hooks = { - 'before:deploy:function:packageFunction': this.packageFunction.bind(this) - }; - } - - private async packageFunction() { - this.serverless.cli.log('Building Azure Events Hooks'); - await this.compileEventsForFunction(); - } - - private async compileEventsForFunction(): Promise { - const functionName = this.options.function; - const metaData = getFunctionMetaData(functionName, this.serverless); - - return createEventsBindings(this.serverless.config.servicePath, functionName, metaData); - } -} diff --git a/src/plugins/remove/azureRemove.ts b/src/plugins/remove/azureRemove.ts index 40cc2665..f9bf78d6 100644 --- a/src/plugins/remove/azureRemove.ts +++ b/src/plugins/remove/azureRemove.ts @@ -1,4 +1,4 @@ -import * as Serverless from 'serverless'; +import Serverless from 'serverless'; import { ResourceService } from '../../services/resourceService'; export class AzureRemove { diff --git a/src/provider/azureProvider.ts b/src/provider/azureProvider.ts index 1db46850..a3d752a3 100644 --- a/src/provider/azureProvider.ts +++ b/src/provider/azureProvider.ts @@ -1,7 +1,7 @@ -import * as fs from 'fs'; +import fs from 'fs'; import { join } from 'path'; -import * as request from 'request'; -import * as Serverless from 'serverless'; +import request from 'request'; +import Serverless from 'serverless'; import config from '../config'; let functionAppName; diff --git a/src/services/apimService.ts b/src/services/apimService.ts index ceda0a91..1e0bc364 100644 --- a/src/services/apimService.ts +++ b/src/services/apimService.ts @@ -1,4 +1,4 @@ -import * as Serverless from 'serverless'; +import Serverless from 'serverless'; import { ApiManagementClient } from '@azure/arm-apimanagement'; import { FunctionAppService } from './functionAppService'; import { BaseService } from './baseService'; @@ -22,11 +22,7 @@ export class ApimService extends BaseService { /** * Deploys the APIM top level api */ - async deployApi() { - if (!this.config) { - return; - } - + public async deployApi() { const functionApp = await this.functionAppService.get(); await this.ensureApi(); @@ -37,12 +33,8 @@ export class ApimService extends BaseService { /** * Deploys all the functions of the serverless service to APIM */ - async deployFunctions() { - if (!this.config) { - return; - } - - this.serverless.cli.log('Starting to deploy API Operations'); + public async deployFunctions() { + this.serverless.cli.log('-> Deploying API Operations'); const deployApiTasks = this.serverless.service .getAllFunctions() @@ -55,7 +47,7 @@ export class ApimService extends BaseService { * Deploys the specified serverless function to APIM * @param options */ - async deployFunction(options) { + public async deployFunction(options) { const functionConfig = this.serverless.service['functions'][options.function]; if (!functionConfig.apim) { @@ -75,7 +67,9 @@ export class ApimService extends BaseService { /** * Deploys the APIM API referenced by the serverless service */ - async ensureApi() { + private async ensureApi() { + this.serverless.cli.log('-> Deploying API') + try { await this.apimClient.api.createOrUpdate(this.resourceGroup, this.config.resourceId, this.config.name, { isCurrent: true, @@ -96,7 +90,8 @@ export class ApimService extends BaseService { * Deploys the APIM Backend referenced by the serverless service * @param functionAppUrl The host name for the deployed function app */ - async ensureBackend(functionApp) { + private async ensureBackend(functionApp) { + this.serverless.cli.log('-> Deploying API Backend') try { const functionAppResourceId = `https://management.azure.com${functionApp.id}`; @@ -122,8 +117,8 @@ export class ApimService extends BaseService { * @param serverless The serverless framework * @param options The plugin options */ - async deployOperation(options) { - this.serverless.cli.log(`-> Deploying API operation ${options.function}`); + private async deployOperation(options) { + this.serverless.cli.log(`--> Deploying API operation ${options.function}`); try { const client = new ApiManagementClient(this.credentials, this.subscriptionId); @@ -167,7 +162,8 @@ export class ApimService extends BaseService { * Gets the master key for the function app and stores a reference in the APIM instance * @param functionAppUrl The host name for the Azure function app */ - async ensureFunctionAppKeys(functionApp) { + private async ensureFunctionAppKeys(functionApp) { + this.serverless.cli.log('-> Deploying API keys') try { const masterKey = await this.functionAppService.getMasterKey(functionApp); const keyName = `${this.serviceName}-key`; diff --git a/src/services/baseService.ts b/src/services/baseService.ts index 5c517f0b..cb7d9761 100644 --- a/src/services/baseService.ts +++ b/src/services/baseService.ts @@ -1,5 +1,7 @@ -import * as Serverless from 'serverless'; +import Serverless from 'serverless'; import axios from 'axios'; +import request from 'request' +import fs from 'fs'; export abstract class BaseService { protected baseUrl: string; @@ -63,4 +65,22 @@ export abstract class BaseService { }, interval); }); } + + /** + * Uploads the specified file via HTTP request + * @param requestOptions The HTTP request options + * @param filePath The local file path + */ + protected sendFile(requestOptions, filePath) { + return new Promise((resolve, reject) => { + fs.createReadStream(filePath) + .pipe(request(requestOptions, (err, response) => { + if (err) { + this.serverless.cli.log(JSON.stringify(err, null, 4)); + return reject(err); + } + resolve(response); + })); + }); + } } \ No newline at end of file diff --git a/src/services/functionAppService.ts b/src/services/functionAppService.ts index 5f38c2d1..84f6eeb8 100644 --- a/src/services/functionAppService.ts +++ b/src/services/functionAppService.ts @@ -1,13 +1,12 @@ +import fs from 'fs'; +import path from 'path'; import { WebSiteManagementClient } from '@azure/arm-appservice'; import { ResourceManagementClient } from '@azure/arm-resources'; import { Deployment } from '@azure/arm-resources/esm/models'; -import * as fs from 'fs'; import jsonpath from 'jsonpath'; -import * as _ from 'lodash'; -import * as path from 'path'; -import * as Serverless from 'serverless'; +import _ from 'lodash'; +import Serverless from 'serverless'; import { BaseService } from './baseService'; -import * as request from 'request'; export class FunctionAppService extends BaseService { private resourceClient: ResourceManagementClient; @@ -20,7 +19,7 @@ export class FunctionAppService extends BaseService { this.webClient = new WebSiteManagementClient(this.credentials, this.subscriptionId); } - async get() { + public async get() { const response: any = await this.webClient.webApps.get(this.resourceGroup, this.serviceName); if (response.error && (response.error.code === 'ResourceNotFound' || response.error.code === 'ResourceGroupNotFound')) { return null; @@ -29,26 +28,34 @@ export class FunctionAppService extends BaseService { return response; } - async getMasterKey(functionApp) { + public async getMasterKey(functionApp) { functionApp = functionApp || await this.get(); - const adminToken = await this._getAuthKey(functionApp); + const adminToken = await this.getAuthKey(functionApp); + const keyUrl = `https://${functionApp.defaultHostName}/admin/host/systemkeys/_master`; - return await this._getMasterKey(functionApp.defaultHostName, adminToken); + const response = await this.sendApiRequest('GET', keyUrl, { + json: true, + headers: { + 'Authorization': `Bearer ${adminToken}` + } + }); + + return response.data.value; } - async deleteFunction(functionName) { + public async deleteFunction(functionName) { this.serverless.cli.log(`-> Deleting function: ${functionName}`); return await this.webClient.webApps.deleteFunction(this.resourceGroup, this.serviceName, functionName); } - async syncTriggers(functionApp) { + public async syncTriggers(functionApp) { this.serverless.cli.log('Syncing function triggers'); const syncTriggersUrl = `${this.baseUrl}${functionApp.id}/syncfunctiontriggers?api-version=2016-08-01`; await this.sendApiRequest('POST', syncTriggersUrl); } - async cleanUp(functionApp) { + public async cleanUp(functionApp) { this.serverless.cli.log('Cleaning up existing functions'); const deleteTasks = []; @@ -65,55 +72,35 @@ export class FunctionAppService extends BaseService { return await Promise.all(deleteTasks); } - async listFunctions(functionApp) { + public async listFunctions(functionApp) { const getTokenUrl = `${this.baseUrl}${functionApp.id}/functions?api-version=2016-08-01`; const response = await this.sendApiRequest('GET', getTokenUrl); return response.data.value || []; } - async uploadFunctions(functionApp) { + public async uploadFunctions(functionApp): Promise { this.serverless.cli.log('Creating azure functions'); - // Perform additional operations per function - const serviceFunctions = this.serverless.service.getAllFunctions(); - const uploadTasks = serviceFunctions.map((functionName) => this.uploadFunction(functionApp, functionName)); - - return await Promise.all(uploadTasks); - } - - async uploadFunction(functionApp, functionName) { - this.serverless.cli.log(`-> Creating function: ${functionName}`); - const scmDomain = functionApp.enabledHostNames[0]; + const functionZipFile = this.serverless.service['artifact']; - // Upload function artifact if it exists, otherwise the full service is handled in 'uploadFunctions' method - const functionZipFile = this.serverless.service['functions'][functionName].package.artifact || this.serverless.service['artifact']; - if (functionZipFile) { - this.serverless.cli.log(`-> Uploading function package: ${functionName}`); - - const requestOptions = { - method: 'PUT', - uri: `https://${scmDomain}/api/zip/site/wwwroot/${functionName}/`, - json: true, - headers: { - Authorization: `Bearer ${this.credentials.tokenCache._entries[0].accessToken}`, - Accept: '*/*' - } - }; + this.serverless.cli.log(`-> Deploying service package @ ${functionZipFile}`); - await this._sendFile(requestOptions, functionZipFile); - this.serverless.cli.log(`-> Function package uploaded successfully: ${functionName}`); + const requestOptions = { + method: 'POST', + uri: `https://${scmDomain}/api/zipdeploy/`, + json: true, + headers: { + Authorization: `Bearer ${this.credentials.tokenCache._entries[0].accessToken}`, + Accept: '*/*' + } + }; - // Rename function json - const fromPath = path.join(functionName, `${functionName}-function.json`); - const toPath = path.join(functionName, 'function.json'); - const command = `mv ${fromPath} ${toPath}`; - await this._runKuduCommand(functionApp, command); - } + await this.sendFile(requestOptions, functionZipFile); } - async deploy() { + public async deploy() { this.serverless.cli.log(`Creating function app: ${this.serviceName}`); let parameters: any = { functionAppName: { value: this.serviceName } }; @@ -181,48 +168,7 @@ export class FunctionAppService extends BaseService { return await this.get(); } - /** - * Uploads the specified file via HTTP request - * @param requestOptions The HTTP request options - * @param filePath The local file path - */ - _sendFile(requestOptions, filePath) { - return new Promise((resolve, reject) => { - fs.createReadStream(filePath) - .pipe(request(requestOptions, (err, response) => { - if (err) { - this.serverless.cli.log(JSON.stringify(err, null, 4)); - return reject(err); - } - resolve(response); - })); - }); - } - - _wait(timeout) { - return new Promise((resolve) => setTimeout(resolve, timeout)); - } - - _waitForCondition(predicate, interval = 2000) { - return new Promise((resolve, reject) => { - let retries = 0; - const id = setInterval(async () => { - if (retries >= 20) { - clearInterval(id); - return reject('Failed conditional check 20 times'); - } - - retries++; - const result = await predicate(); - if (result) { - clearInterval(id); - resolve(result); - } - }, interval); - }); - } - - async _runKuduCommand(functionApp, command) { + private async runKuduCommand(functionApp, command) { this.serverless.cli.log(`-> Running Kudu command ${command}...`); const scmDomain = functionApp.enabledHostNames[0]; @@ -248,28 +194,10 @@ export class FunctionAppService extends BaseService { /** * Gets a short lived admin token used to retrieve function keys */ - async _getAuthKey(functionApp) { + private async getAuthKey(functionApp) { const adminTokenUrl = `${this.baseUrl}${functionApp.id}/functions/admin/token?api-version=2016-08-01`; const response = await this.sendApiRequest('GET', adminTokenUrl); return response.data.replace(/"/g, ''); } - - /** - * Gets the master key for the specified function app - * @param functionAppUrl The function app url - * @param authToken The JWT access token used for authorization - */ - async _getMasterKey(functionAppUrl, authToken) { - const keyUrl = `https://${functionAppUrl}/admin/host/systemkeys/_master`; - - const response = await this.sendApiRequest('GET', keyUrl, { - json: true, - headers: { - 'Authorization': `Bearer ${authToken}` - } - }); - - return response.data.value; - } } diff --git a/src/services/resourceService.ts b/src/services/resourceService.ts index c2f0436d..fa53d3f3 100644 --- a/src/services/resourceService.ts +++ b/src/services/resourceService.ts @@ -1,4 +1,4 @@ -import * as Serverless from 'serverless'; +import Serverless from 'serverless'; import { ResourceManagementClient } from '@azure/arm-resources'; import { BaseService } from './baseService'; @@ -11,7 +11,7 @@ export class ResourceService extends BaseService { this.resourceClient = new ResourceManagementClient(this.credentials, this.subscriptionId); } - async deployResourceGroup() { + public async deployResourceGroup() { this.serverless.cli.log(`Creating resource group: ${this.resourceGroup}`); const groupParameters = { @@ -21,12 +21,12 @@ export class ResourceService extends BaseService { return await this.resourceClient.resourceGroups.createOrUpdate(this.resourceGroup, groupParameters); } - async deleteDeployment() { + public async deleteDeployment() { this.serverless.cli.log(`Deleting deployment: ${this.deploymentName}`); return await this.resourceClient.deployments.deleteMethod(this.resourceGroup, this.deploymentName); } - async deleteResourceGroup() { + public async deleteResourceGroup() { this.serverless.cli.log(`Deleting resource group: ${this.resourceGroup}`); return await this.resourceClient.resourceGroups.deleteMethod(this.resourceGroup); } diff --git a/src/shared/bindings.ts b/src/shared/bindings.ts index c288f8f9..e4d44210 100644 --- a/src/shared/bindings.ts +++ b/src/shared/bindings.ts @@ -1,7 +1,6 @@ import { writeFileSync } from 'fs'; import { join } from 'path'; import { FunctionMetadata } from './utils'; - const bindingsJson = require('./bindings.json'); const constants = { @@ -34,14 +33,12 @@ export function getBindingsMetaData(serverless) { bindingSettingsNames[bindingsIndex] = settingsNames; } - const parsedBindings = { + return { bindingDisplayNames: bindingDisplayNames, bindingTypes: bindingTypes, bindingSettings: bindingSettings, bindingSettingsNames: bindingSettingsNames }; - - return parsedBindings; } export async function createEventsBindings(servicePath: string, functionName: string, functionMetadata: FunctionMetadata): Promise { diff --git a/src/shared/getAdminKey.ts b/src/shared/getAdminKey.ts deleted file mode 100644 index 41568a79..00000000 --- a/src/shared/getAdminKey.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function getAdminKey() { - return this.provider.getAdminKey(); -} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index ef135d13..d4d9522e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,11 +6,15 @@ "outDir": "./lib", "strict": false, "resolveJsonModule": true, - "types": ["jest", "node"] + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "types": [ + "jest", + "node" + ] }, "include": [ "src", - "src/shared/bindings.json", - "src/provider/armTemplates/azuredeploy.json" + "src/**/*.json" ] } \ No newline at end of file