Compare commits

..

4 Commits

Author SHA1 Message Date
MacDev
2d8baf6fce refactor(SwitchBundle): 重构h5子游戏拆分上传工具 2026-09-21 20:05:29 +08:00
WajeDev
7680b32a4b 书签 2026-06-18 16:14:55 +08:00
WajeDev
b32079c2a2 init 2026-06-18 16:10:43 +08:00
WajeDev
9b5bcc7410 some files 2026-06-18 15:11:23 +08:00
12 changed files with 422 additions and 219 deletions

View File

@@ -0,0 +1,18 @@
<!DOCTYPE NETSCAPE-Bookmark-file-1>
<!-- This is an automatically generated file.
It will be read and overwritten.
DO NOT EDIT! -->
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
<TITLE>Bookmarks</TITLE>
<H1>Bookmarks</H1>
<DL><p>
<DT><H3 ADD_DATE="1781347875" LAST_MODIFIED="1780466623" PERSONAL_TOOLBAR_FOLDER="true">书签栏</H3>
<DL><p>
<DT><A HREF="https://test.waje-special.com:8443/user/info" ADD_DATE="1776756668">GM-dev</A>
<DT><A HREF="devtools://devtools/bundled/js_app.html?v8only=true&ws=10.101.0.172:6086/00010002-0003-4004-8005-000600070008" ADD_DATE="1776757337">DevTools</A>
<DT><A HREF="https://jenkins.wgame2025.com/" ADD_DATE="1777018929" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAADJklEQVR4nGxS3UtTYRh/ztc+jtucm7U5m9s0tmkpgVFISRpFXURfFwWBgRWB4GUYRRdd9B/oXRfVhZhFkKVliHSj5sc0/Goo6rbcl+7jnM257Ww75/ROmLjwgffl5eX5Pc/v93seEg4Jq8FaXqZXviAIsDfW2xoxnJBhGLCBULh7wrHY7fV6U4Vc8n9w2717vQqavqEplUFn+21aIScxEAUQBEEx89v5LBqNXdXpdFdmZ2ez+XziIPjRg4cfLCbzXaWMj3R13NGQQhoT+SwI6KALDLoyWWNDbdXE9HzDumezP4/BC+DW5uYLHpfrltfnE69dalLluCR8/D4JYzPOIoa+YIiQSakWe2WltohBrc0+2NJ6UR8KR7BTVoNYqqRJhVwCDbVmEEURMGRCPkyVR+Fy82l5OJYI/JpbmtxnoFarS/2BAGIq7JgMZVIJiYPFqAOCkoPbF97LWXP5AVWCP2teyAmirUgCG90mKzVUKpPeyUTZRLrwP7/shKGR8b13KMrCxPQipFK7IJVS9MEC2JWWsyqMT8tbz9hxpUJOFQqctJrRNG7uvZsa61D3TThhs+SJhA6OUfRs+gPPO+8ep0iiDA6JCJOAMMMAiZaD4zLgDYQcRSaaDMf+fhkZazJVVan15ap9IFoimFtYheGf05BMcuDfCiMvfOGB0amnLMsm9j3o//ptYM65cWc7EsshGMTiu3v/+W6OhRWoMRtApaKh4/51mHeur7nd7mCRiflwuVyOT4OjLCktAZzAYWrOCRKKgLbbl8FWY4STSPvrvh+M0x0KFjD7EiwWi6nCWDPOZIkKv9efsVcbcEEU8Z43A5DjcwmkOdjz9nPKMb9RIjVa60pLaG1oyz+c3w7caq17JdMc6SyvP6/MZjjQZJnouQYrtdXXC7U4cCNclsf12u0L8WR1VhQl747VUwIbTUbci8dJ1LleZbY/kVdUU7FwAM1DhCSA5v3EMrSTRPAshetNFBnvZXb1DM+naQlJCjkeeZNY8Xg8WyTSvaQ22uMCn9PmwQfdX8UkcZpLJoaUWubxy65TXn8wOuL05ISFRSnPcesoTfgHAAD//1rfB0MAAAAGSURBVAMAg5JfV381m+kAAAAASUVORK5CYII=">Jenkins</A>
<DT><A HREF="https://ksg964l11fam.sg.larksuite.com/wiki/YtjqwNfDniTZ4okRC4bl9W79gO6?sheet=3IwNVv&table=tblQL121XoBMDalX&view=vewxboiv07" ADD_DATE="1779173794" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACiklEQVR4nGxTy0uUURT/nXu/mXHGGR/jgyRrI1SroJf5GCNNKkU3iQUF0aKCVkHQslV/RJuINrZIkggptcRIUXuQ0CZcuAnFLEYxRz/HmXtv536fj5nBw8f9uOeee36/8zv3OLA2dt45Gw5HksveDhXIt6T1xQF3Vakfl0bWc8/ILidHO7qdoHyut7QGDBGIcoMMyHiRZDaMxkAq5DyaTbxZs2eOXYRAiKSI2zghJCQJFJoxBsqoikB58H5sOX0EL9GNXmgvgTZGk9JGaOj1zAa52iV7QWwTUQwbkkHEZFRnVtJGBEXHifjl+hkamvIZcKjFTakUNVWeokTFGQqKADZV2ksQcSKYTc2Z1wvDJA2zE6QFoda/u20WLaXW0V7dgraqZsy7v3GhOoFzlQ1YdJdw6/BV6qntxGrmH4MJYlJqV4OdGuF9Gv0Lg3g4fQ/R5ghctYkH03chGp/hWKyO0jpjckXeTUDsEyyevdBV045YSx9aq5qscChpeYFEZT0mk988gS2WLbuAwR4Ts7PJ6zd5ID7Ynt/TgMW3zffULguWYGTpE+6MX8d7/g8ujuL2+A3+f0CRLOJInQewx4DdIVb+59qcuXmoh1TjU3TWtEHx2zINT9Bb24Wp5e/e06McCl4CLksqzl0aKDGv5t8S122ORuto9M8ExwscDB/A2N9JTCS/IiqLmWkBA53FvGRVDJksL+j7NUBptWUkN8zA18SihkXYFMsi20Fjy/YT8NlM/9CX0/HOd4F4qCO7uoVypyyP5o7xNdJckmQ0Fk34Cch2H2ptwrkWXUk/JiGuZLWKWC8fFQyV5c6vXGmhFdJ+dwrs+PDF4nCplHa09xtra3a0P7vuBlo/Zv8DAAD//9oe8JgAAAAGSURBVAMAcKAbn82j090AAAAASUVORK5CYII=">app版本</A>
<DT><A HREF="https://jira.wgame2025.com/browse/WAJE-269?filter=10101" ADD_DATE="1779765803" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABdklEQVR4nIxTQVICMRDsJJTlcT16El/ginhWf4A/gIMUN+UF6gvQG8JBfIH8AO4C7g/gZOlJjmpB4mQ26wZ3S5yqrSQzPb2TnkkBf9lB/Z3XpdxH1J7lQcTKqVS/IE+L3D0sP5tQGwnBLgr6HAY2fo1R5ypJkcg1EyDqzTlRmvjvRgRxSOzkV1BuHGPUHvK6+IiY4LclmMOzEE/dKCUIG0UoPaUdJYk+xnc1hNUAhc2Q4wvMuIpyvUXXqJCnCCFPLJnwBJtygMs0NSIKYj3sGU1IGcHogUPPMe5srWog8JDuRQvKDGkX8adln5IfPextVsTF141LsBZAi3sS8ZQ/xcmBi80cFqkGiVlxtBh44IQw/MHYrjgBswT5JKlZbSbdnu9SGdDL5BXbpTfSobIumQtCnikqnTvhI8VeHjRLYGdCi2fq89EKiR1jO0hrCZS5dBlV5+mnJPQe1hLApHfXakhtbHrByj8IvH7b8eVnzEMVm72iZ98AAAD//x6gYOcAAAAGSURBVAMAppSQxic+0AQAAAAASUVORK5CYII=">jira</A>
<DT><A HREF="https://www.figma.com/design/Hj3HAzj1sevpK88AxAH9xz/Waje-New?node-id=2-2&m=dev" ADD_DATE="1780466623" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACfUlEQVR4nHRSvU8UURCfmbe37B7cct4RBYxKDImJMTbIJTZWKlBg4p9gYoyEaKeJ3VkaS2IidhYmfnVAogUdFYHGWJnYWEgEA3t73LK3H2+Y3fvIQeBt9r15781v5vd+MwacMHim5Oy27dL4TPccFz54x30xA8gqBu9ND4+ZudyiRphgllMycGDsFqBhMOh0jxsQJvO48P53B0PdrHJNAs5bdFfuygqhbCCWUGEJkMqSqgy2PQWK3qS+HRy1aTBMgCVm5SDkUJIlkQaO07zyZTNjAkEQis8kzM5aGaYTIKUDmxDIsm6bZBLEoORHjgmVIiFLqCMlDMwE5RlLSwG3n089Ymgn+POg0Qw+RlTUERahSUWAwHchiWv7fU4InvdF/foxl/p2cEYLzNn8QrF52YKhAWoQkkYjgp3Va3/vr45feM2aKtvKcjxfnFewi+kyqIqgV4vJu+E83G5yP0VQAB8KuZWLV165g/mbHlk8eAamRm1+C1U+KqJE4hERkVlN1kMIiVhjoqGZZ8cgXTHqEBooysoqeW/ASCo4ck8Axi0RkZHXC31gkiilkGCggS5o2oQimOKk0JEVYR22UsH5qIhVQF38iQ/r+/DJt8PYt5twYDWjETeai+vwWfpqW9fgawI4D1XUrSK2SyGblir/H5/HnbOLg17/NAkJAXl7ledDched+879/6awASe1chbgZRXz9+gbDjl3ol03lvZVHEdeGI9egolHnvQCA7doZ3ZvGbPsG2CnnchuI1JaIWqSDjQgzHlxF9ADPFYFCbEMgSZag4KVywI6fUojr8H1Z37G8JRB7SeIilUdRPFTXWusyD5k118OCJ+0O+bUcQgAAP//N3B/bwAAAAZJREFUAwBYKhHkeb+KZAAAAABJRU5ErkJggg==">Waje – Figma</A>
</DL><p>
</DL><p>

2
backup/vpn.txt Normal file
View File

@@ -0,0 +1,2 @@
https://liangxin.xyz/api/v1/liangxin?OwO=5283cdcedb78ceb09e5d92d1f12f016e#%E8%89%AF%E5%BF%83%E4%BA%91
https://sub.grempt.com/link/206326/9069266d26c00da2f69f#9069266d26c00da2f69f

BIN
docs/20251009-145903.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 KiB

BIN
docs/20251009-151651.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 685 KiB

BIN
python.zip Normal file

Binary file not shown.

7
python/main.py Normal file
View File

@@ -0,0 +1,7 @@
import sys
from switch_bundle_common import main
if __name__ == '__main__':
main(sys.argv)

View File

@@ -1,110 +0,0 @@
import os
import sys
import subprocess
import hvac
if len(sys.argv) < 3:
exit()
if '123!@#' != sys.argv[2]:
exit()
ProjDir = sys.argv[1]
BuildDir = ProjDir + '\\build\\web-mobile\\'
SubgamePath = 's3://web-h5game-test/internal/'
# Vault 地址和 Token
# VAULT_ADDR = 'https://keys.wehavefun.email'
VAULT_ADDR = 'https://keys.i-see--you.icu'
VAULT_TOKEN = 'hvs.CAESINwE2A36YcHcC_CWSzaBtUrGq-1OcUgKjDegSMUAuB5-Gh4KHGh2cy53ZmN5UzNMb0pvcUJ6QlJXdURmZnh1MlU'
# 创建客户端
client = hvac.Client(url=VAULT_ADDR, token=VAULT_TOKEN)
if client.is_authenticated():
secret = client.secrets.kv.v2.read_secret_version(
path='default',
mount_point='aws',
raise_on_deleted_version=True
)
SwitchBundle = secret['data']['data']['switchBundle']
if "1" != SwitchBundle:
print("script exit, switchBundle status is " + SwitchBundle)
exit()
else:
print("running script failed!")
exit()
print("start running script...")
BundleConfig = {
'6001': 'whot',
'6002': 'whot',
'6003': 'whot',
'6005': 'BRWhot',
'2001': 'roulette',
'2002': 'wajeSpin',
'2003': 'bottleSpin',
'2004': 'blackjack',
'2006': 'betterjack',
'6007': 'BRWhot',
'2008': 'slots',
'2005': 'christmas',
}
unlinkArray = [
'cocos2d-js.109f3.js',
'cocos2d-js-min.13181.js',
'physics.9d2de.js',
'physics-min.ce5ee.js',
'style-desktop.dfd76.css',
'style-mobile.6e9cd.css',
'splash.85cfd.png'
]
def remove_folder(path):
print('remove path: ', path)
if os.path.exists(path):
if os.path.isfile(path) or os.path.islink(path):
os.remove(path)
else:
for filename in os.listdir(path):
remove_folder(os.path.join(path, filename))
os.rmdir(path)
# 上传src相共用文件
SrcDir = BuildDir + '\\src\\'
SrcDst = SubgamePath + 'lib/src/'
rmResult = subprocess.run(['cmd', '/c', 'aws s3 rm ' + SrcDst + ' --recursive'], capture_output=True, text=True)
print('remove dir src result: ', rmResult)
cmd = 'call aws s3 cp '+ SrcDir +' '+SrcDst + ' --recursive --region ap-east-1'
result = subprocess.run(['cmd', '/c', cmd], capture_output=True, text=True)
print('upload dir src result: ', result)
remove_folder(SrcDir)
for filename in os.listdir(BuildDir):
file_path = os.path.join(BuildDir, filename)
if filename in unlinkArray:
os.remove(file_path)
for gameid in BundleConfig:
awsPath = SubgamePath + gameid + '/assets/' + BundleConfig[gameid] +'/'
rmResult = subprocess.run(['cmd', '/c', 'aws s3 rm ' + awsPath + ' --recursive'], capture_output=True, text=True)
print('remove game gameid: ', gameid, ' result: ', rmResult)
subgameDir = BuildDir + 'assets\\' + BundleConfig[gameid] +'\\'
cmd = 'call aws s3 cp '+ subgameDir +' '+awsPath + ' --recursive --region ap-east-1'
result = subprocess.run(['cmd', '/c', cmd], capture_output=True, text=True)
print(result)
for gameid in BundleConfig:
awsPath = SubgamePath + gameid + '/assets/' + BundleConfig[gameid] +'/'
subgameDir = BuildDir + 'assets\\' + BundleConfig[gameid]
remove_folder(subgameDir)
for gameid in BundleConfig:
awsPath = SubgamePath + gameid + '/'
cmd = 'call aws s3 cp '+ BuildDir +' '+awsPath + ' --recursive --region ap-east-1'
result = subprocess.run(['cmd', '/c', cmd], capture_output=True, text=True)
print('upload game gameid: ', gameid, ' result: ', result)

View File

@@ -1,109 +0,0 @@
import os
import sys
import subprocess
import hvac
if len(sys.argv) < 3:
exit()
if '123!@#' != sys.argv[2]:
exit()
ProjDir = sys.argv[1]
BuildDir = ProjDir + '\\build\\web-mobile\\'
SubgamePath = 's3://web-h5game-prod/internal/'
# Vault 地址和 Token
VAULT_ADDR = 'https://keys.i-see--you.icu'
VAULT_TOKEN = 'hvs.CAESINwE2A36YcHcC_CWSzaBtUrGq-1OcUgKjDegSMUAuB5-Gh4KHGh2cy53ZmN5UzNMb0pvcUJ6QlJXdURmZnh1MlU'
# 创建客户端
client = hvac.Client(url=VAULT_ADDR, token=VAULT_TOKEN)
if client.is_authenticated():
secret = client.secrets.kv.v2.read_secret_version(
path='default',
mount_point='aws',
raise_on_deleted_version=True
)
SwitchBundle = secret['data']['data']['switchBundle']
if "1" != SwitchBundle:
print("script exit, switchBundle status is " + SwitchBundle)
exit()
else:
print("running script failed!")
exit()
print("start running script...")
BundleConfig = {
'6001': 'whot',
'6002': 'whot',
'6003': 'whot',
'6005': 'BRWhot',
'2001': 'roulette',
'2002': 'wajeSpin',
'2003': 'bottleSpin',
'2004': 'blackjack',
'2006': 'betterjack',
'6007': 'BRWhot',
'2008': 'slots',
'2005': 'christmas',
}
unlinkArray = [
'cocos2d-js.109f3.js',
'cocos2d-js-min.13181.js',
'physics.9d2de.js',
'physics-min.ce5ee.js',
'style-desktop.dfd76.css',
'style-mobile.6e9cd.css',
'splash.85cfd.png'
]
def remove_folder(path):
print('remove path: ', path)
if os.path.exists(path):
if os.path.isfile(path) or os.path.islink(path):
os.remove(path)
else:
for filename in os.listdir(path):
remove_folder(os.path.join(path, filename))
os.rmdir(path)
SrcDir = BuildDir + '\\src\\'
SrcDst = SubgamePath + 'lib/src/'
rmResult = subprocess.run(['cmd', '/c', 'aws s3 rm ' + SrcDst + ' --recursive'], capture_output=True, text=True)
print('remove dir src result: ', rmResult)
cmd = 'call aws s3 cp '+ SrcDir +' '+SrcDst + ' --recursive --region eu-west-3'
result = subprocess.run(['cmd', '/c', cmd], capture_output=True, text=True)
print('upload dir src result: ', result)
remove_folder(SrcDir)
for filename in os.listdir(BuildDir):
file_path = os.path.join(BuildDir, filename)
if filename in unlinkArray:
os.remove(file_path)
for gameid in BundleConfig:
awsPath = SubgamePath + gameid + '/assets/' + BundleConfig[gameid] +'/'
rmResult = subprocess.run(['cmd', '/c', 'aws s3 rm ' + awsPath + ' --recursive'], capture_output=True, text=True)
print('remove game gameid: ', gameid, ' result: ', rmResult)
subgameDir = BuildDir + 'assets\\' + BundleConfig[gameid] +'\\'
cmd = 'call aws s3 cp '+ subgameDir +' '+awsPath + ' --recursive --region eu-west-3'
result = subprocess.run(['cmd', '/c', cmd], capture_output=True, text=True)
print(result)
for gameid in BundleConfig:
awsPath = SubgamePath + gameid + '/assets/' + BundleConfig[gameid] +'/'
subgameDir = BuildDir + 'assets\\' + BundleConfig[gameid]
remove_folder(subgameDir)
for gameid in BundleConfig:
awsPath = SubgamePath + gameid + '/'
cmd = 'call aws s3 cp '+ BuildDir +' '+awsPath + ' --recursive --region eu-west-3'
result = subprocess.run(['cmd', '/c', cmd], capture_output=True, text=True)
print('upload game gameid: ', gameid, ' result: ', result)

View File

@@ -0,0 +1,196 @@
"""Shared Vault authorization and bundle publishing for both environments."""
import os
import sys
import subprocess
import hashlib
from vault_options import parse_vault_options, read_switch_bundle
REGION_CONFIG = {
'dev': 'ap-east-1',
'prod': 'eu-west-3',
}
OSS_PATH_CONFIG = {
'dev': {
'waje': 's3://web-h5game-test-waje/internal/',
'wtan': 's3://web-h5game-test-wtan/internal/',
},
'prod': {
'waje': 's3://web-h5game-prod/internal/',
'wtan': ''
},
}
PROFILE_CONFIG = {
'dev': {
'waje': 'h5-new',
'wtan': 'h5-new',
},
'prod': {
'waje': 'default',
'wtan': 'h5-new',
}
}
VAULT_ADDR = 'https://keys.i-see--you.icu'
VAULT_TOKEN = 'hvs.CAESIJrOb65T9ylAMyzlqQOJjI-yutFmTysRbvYbN3IpGra5Gh4KHGh2cy5GeXU4N3FuVEhIQ3A5YmpIM1BETFdYMDc'
BUNDLE_CONFIG = {
'6001': 'whot',
'6002': 'whot',
'6003': 'whot',
'6005': 'BRWhot',
'2001': 'roulette',
'2002': 'wajeSpin',
'2003': 'bottleSpin',
'2004': 'blackjack',
'2006': 'betterjack',
'6007': 'BRWhot',
'2008': 'slots',
'2005': 'christmas',
}
UNLINK_ARRAY = [
'cocos2d-js.109f3.js',
'cocos2d-js-min.13181.js',
'physics.9d2de.js',
'physics-min.ce5ee.js',
'style-desktop.dfd76.css',
'style-mobile.6e9cd.css',
'splash.85cfd.png',
]
def create_vault_client(**kwargs):
"""Create the default Vault client only when a real publish is run."""
import hvac
return hvac.Client(**kwargs)
def remove_folder(path):
print('remove path: ', path)
if os.path.exists(path):
if os.path.isfile(path) or os.path.islink(path):
os.remove(path)
else:
for filename in os.listdir(path):
remove_folder(os.path.join(path, filename))
os.rmdir(path)
def run_publish(proj_dir, subgame_path, region, profile,
run_command=subprocess.run):
"""Upload shared resources and bundles, then publish each game's shell."""
build_dir = proj_dir + '\\build\\web-mobile\\'
src_dir = build_dir + '\\src\\'
src_dst = subgame_path + 'lib/src/'
remove_result = run_command(
['cmd', '/c', 'aws s3 rm ' + src_dst + ' --recursive' + ' --profile ' + profile + ' --region ' + region],
capture_output=True,
text=True,
)
print('remove dir src result: ', remove_result)
command = (
'call aws s3 cp ' + src_dir + ' ' + src_dst
+ ' --recursive'
+ ' --profile ' + profile
+ ' --region ' + region
)
result = run_command(
['cmd', '/c', command],
capture_output=True,
text=True,
)
print('upload dir src result: ', result)
remove_folder(src_dir)
for filename in os.listdir(build_dir):
file_path = os.path.join(build_dir, filename)
if filename in UNLINK_ARRAY:
os.remove(file_path)
for gameid in BUNDLE_CONFIG:
aws_path = (
subgame_path + gameid + '/assets/'
+ BUNDLE_CONFIG[gameid] + '/'
)
remove_result = run_command(
['cmd', '/c', 'aws s3 rm ' + aws_path + ' --recursive' + ' --profile ' + profile + ' --region ' + region],
capture_output=True,
text=True,
)
print('remove game gameid: ', gameid, ' result: ', remove_result)
subgame_dir = build_dir + 'assets\\' + BUNDLE_CONFIG[gameid] + '\\'
command = (
'call aws s3 cp ' + subgame_dir + ' ' + aws_path
+ ' --recursive'
+ ' --profile ' + profile
+ ' --region ' + region
)
result = run_command(
['cmd', '/c', command],
capture_output=True,
text=True,
)
print(result)
for gameid in BUNDLE_CONFIG:
subgame_dir = build_dir + 'assets\\' + BUNDLE_CONFIG[gameid]
remove_folder(subgame_dir)
for gameid in BUNDLE_CONFIG:
aws_path = subgame_path + gameid + '/'
command = (
'call aws s3 cp ' + build_dir + ' ' + aws_path
+ ' --recursive'
+ ' --profile ' + profile
+ ' --region ' + region
)
result = run_command(
['cmd', '/c', command],
capture_output=True,
text=True,
)
print('upload game gameid: ', gameid, ' result: ', result)
def main(argv, client_factory=None, publish=None):
"""Parse the legacy CLI arguments and publish when Vault permits it."""
proj_dir, pwd, env, cat, vault_path, vault_mount_point = parse_vault_options(argv)
if len(argv) < 5:
print('argv error!')
sys.exit(-1)
md5_obj = hashlib.md5()
md5_obj.update((env + cat).encode('utf-8'))
hash_value = md5_obj.hexdigest()
print('hash = ' + hash_value)
if hash_value != pwd:
print('argv verify failed!')
sys.exit(-2)
if client_factory is None:
client_factory = create_vault_client
if publish is None:
publish = run_publish
client = client_factory(url=VAULT_ADDR, token=VAULT_TOKEN)
if client.is_authenticated():
secret = read_switch_bundle(client, vault_path, vault_mount_point)
switch_bundle = secret['data']['data']['enable']
print(switch_bundle)
if '1' != switch_bundle:
print('script exit, switchBundle status is ' + switch_bundle)
sys.exit(-999)
else:
print('running script failed!')
sys.exit(-1000)
print('start running script...')
publish(proj_dir, OSS_PATH_CONFIG[env][cat], REGION_CONFIG[env], PROFILE_CONFIG[env][cat])

View File

@@ -0,0 +1,104 @@
import runpy
import unittest
from pathlib import Path
from unittest.mock import patch
from switch_bundle_common import main
class _FakeVaultV2(object):
def __init__(self, switch_bundle='1'):
self.calls = []
self.switch_bundle = switch_bundle
def read_secret_version(self, **kwargs):
self.calls.append(kwargs)
return {'data': {'data': {'switchBundle': self.switch_bundle}}}
class _FakeClient(object):
def __init__(self, authenticated=True, switch_bundle='1'):
self.authenticated = authenticated
self.v2 = _FakeVaultV2(switch_bundle)
self.secrets = self
self.kv = self
def is_authenticated(self):
return self.authenticated
class SwitchBundleCommonTests(unittest.TestCase):
def test_main_passes_vault_options_and_environment_to_publish(self):
client = _FakeClient()
publish_calls = []
main(
['switchBundle.py', 'project', '123!@#', 'release', 'production'],
's3://web-h5game-test/internal/',
'ap-east-1',
client_factory=lambda **kwargs: client,
publish=lambda *args: publish_calls.append(args),
)
self.assertEqual(
client.v2.calls[0]['path'],
'release',
)
self.assertEqual(
client.v2.calls[0]['mount_point'],
'production',
)
self.assertEqual(
publish_calls,
[('project', 's3://web-h5game-test/internal/', 'ap-east-1')],
)
def test_main_skips_publish_when_password_is_invalid(self):
client_calls = []
publish_calls = []
main(
['switchBundle.py', 'project', 'wrong-password'],
's3://web-h5game-test/internal/',
'ap-east-1',
client_factory=lambda **kwargs: client_calls.append(kwargs),
publish=lambda *args: publish_calls.append(args),
)
self.assertEqual(client_calls, [])
self.assertEqual(publish_calls, [])
def test_main_skips_publish_when_vault_does_not_allow_it(self):
for authenticated, switch_bundle in [(False, '1'), (True, '0')]:
with self.subTest(authenticated=authenticated, switch_bundle=switch_bundle):
client = _FakeClient(authenticated, switch_bundle)
publish_calls = []
main(
['switchBundle.py', 'project', '123!@#'],
's3://web-h5game-test/internal/',
'ap-east-1',
client_factory=lambda **kwargs: client,
publish=lambda *args: publish_calls.append(args),
)
self.assertEqual(publish_calls, [])
self.assertEqual(len(client.v2.calls), int(authenticated))
def test_entry_points_keep_their_publish_destinations(self):
environments = [
('switchBundle.py', 's3://web-h5game-test/internal/', 'ap-east-1'),
('switchBundleR.py', 's3://web-h5game-prod/internal/', 'eu-west-3'),
]
for filename, destination, region in environments:
with self.subTest(filename=filename):
script = str(Path(__file__).with_name(filename))
argv = [script, 'project', '123!@#', 'release', 'production']
with patch('sys.argv', argv), patch('switch_bundle_common.main') as entry:
runpy.run_path(script, run_name='__main__')
entry.assert_called_once_with(argv, destination, region)
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,66 @@
import unittest
from vault_options import parse_vault_options, read_switch_bundle
class _FakeVaultV2(object):
def __init__(self):
self.calls = []
def read_secret_version(self, **kwargs):
self.calls.append(kwargs)
return {'data': {'data': {'switchBundle': '1'}}}
class _FakeClient(object):
def __init__(self):
self.v2 = _FakeVaultV2()
self.secrets = self
self.kv = self
class ParseVaultOptionsTests(unittest.TestCase):
def test_uses_default_path_and_mount_point(self):
options = parse_vault_options(['switchBundle.py', 'project', '123!@#'])
self.assertEqual(options, ('default', 'aws'))
def test_reads_path_and_mount_point_after_existing_arguments(self):
options = parse_vault_options(
['switchBundle.py', 'project', '123!@#', 'release', 'production']
)
self.assertEqual(options, ('release', 'production'))
def test_uses_default_mount_point_when_only_path_is_provided(self):
options = parse_vault_options(
['switchBundle.py', 'project', '123!@#', 'release']
)
self.assertEqual(options, ('release', 'aws'))
def test_passes_path_and_mount_point_to_vault(self):
client = _FakeClient()
read_switch_bundle(client, 'release', 'production')
self.assertEqual(
client.v2.calls,
[{
'path': 'release',
'mount_point': 'production',
'raise_on_deleted_version': True,
}],
)
def test_uses_default_vault_settings_when_not_provided(self):
client = _FakeClient()
read_switch_bundle(client)
self.assertEqual(client.v2.calls[0]['path'], 'default')
self.assertEqual(client.v2.calls[0]['mount_point'], 'aws')
if __name__ == '__main__':
unittest.main()

29
python/vault_options.py Normal file
View File

@@ -0,0 +1,29 @@
DEFAULT_VAULT_PATH = 'dev'
DEFAULT_VAULT_MOUNT_POINT = 'tokens'
def parse_vault_options(argv):
"""Return the Vault path and mount point from the script arguments.
The first two arguments are already used by the publishing scripts for
the project directory and access password. Vault settings therefore
remain optional arguments 3 and 4 so existing invocations keep working.
"""
proj = argv[1]
pwd = argv[2]
env = argv[3]
cat = argv[4]
path = argv[5] if len(argv) > 5 else DEFAULT_VAULT_PATH
mount_point = argv[6] if len(argv) > 6 else DEFAULT_VAULT_MOUNT_POINT
return proj, pwd, env, cat, path, mount_point
def read_switch_bundle(
client,
path=DEFAULT_VAULT_PATH,
mount_point=DEFAULT_VAULT_MOUNT_POINT):
return client.secrets.kv.v2.read_secret_version(
path=path,
mount_point=mount_point,
raise_on_deleted_version=True
)