@@ -318,6 +318,7 @@ struct VersionCheckParams
318318 TSettingsComponent component;
319319 tNewVersionCallback callback;
320320 CProgressDlg *progress;
321+ bool nightly = false ;
321322};
322323
323324// 0 - fail, 1 - success, 2 - cancel
@@ -342,7 +343,7 @@ static DWORD WINAPI ThreadVersionCheck( void *param )
342343 VersionData data;
343344
344345 {
345- auto load = data.Load ();
346+ auto load = params. nightly ? data. LoadNightly () : data.Load ();
346347
347348#ifdef UPDATE_LOG
348349 LogToFile (UPDATE_LOG, L" Load result: %d" , load);
@@ -450,6 +451,21 @@ DWORD CheckForNewVersion( HWND owner, TSettingsComponent component, TVersionChec
450451 params->callback =callback;
451452 params->progress =NULL ;
452453
454+ // check the Update setting (uses the current value in the registry, not the one from memory
455+ {
456+ CRegKey regSettings, regSettingsUser, regPolicy, regPolicyUser;
457+ bool bUpgrade = OpenSettingsKeys (COMPONENT_SHARED, regSettings, regSettingsUser, regPolicy, regPolicyUser);
458+
459+ CSetting settings[] = {
460+ {L" Nightly" ,CSetting::TYPE_BOOL,0 ,0 ,0 },
461+ {NULL }
462+ };
463+
464+ settings[0 ].LoadValue (regSettings, regSettingsUser, regPolicy, regPolicyUser);
465+
466+ params->nightly = GetSettingBool (settings[0 ]);
467+ }
468+
453469 if (!owner)
454470 return ThreadVersionCheck (params);
455471
@@ -495,26 +511,31 @@ DWORD CheckForNewVersion( HWND owner, TSettingsComponent component, TVersionChec
495511 return 0 ; // check weekly
496512
497513 // check the Update setting (uses the current value in the registry, not the one from memory
514+ bool nightly = false ;
498515 {
499516 CRegKey regSettings, regSettingsUser, regPolicy, regPolicyUser;
500517 bool bUpgrade=OpenSettingsKeys (COMPONENT_SHARED,regSettings,regSettingsUser,regPolicy,regPolicyUser);
501518
502519 CSetting settings[]={
503520 {L" Update" ,CSetting::TYPE_BOOL,0 ,0 ,1 },
521+ {L" Nightly" ,CSetting::TYPE_BOOL,0 ,0 ,0 },
504522 {NULL }
505523 };
506524
507525 settings[0 ].LoadValue (regSettings,regSettingsUser,regPolicy,regPolicyUser);
526+ settings[1 ].LoadValue (regSettings,regSettingsUser,regPolicy,regPolicyUser);
508527
509528 if (!GetSettingBool (settings[0 ]))
510- return 0 ;
529+ return 0 ;
530+ nightly = GetSettingBool (settings[1 ]);
511531 }
512532
513533 VersionCheckParams *params=new VersionCheckParams;
514534 params->check =check;
515535 params->component =component;
516536 params->callback =callback;
517537 params->progress =NULL ;
538+ params->nightly =nightly;
518539
519540 g_bCheckingVersion=true ;
520541 if (check==CHECK_AUTO_WAIT)
@@ -810,6 +831,116 @@ VersionData::TLoadResult VersionData::Load()
810831 }
811832}
812833
834+ VersionData::TLoadResult VersionData::LoadNightly ()
835+ {
836+ Clear ();
837+
838+ auto buf = DownloadUrl (L" https://ci.appveyor.com/api/projects/passionate-coder/open-shell-menu/branch/master" );
839+ if (buf.empty ())
840+ return LOAD_ERROR;
841+
842+ try
843+ {
844+ auto data = json::parse (buf.begin (), buf.end ());
845+ auto build = data[" build" ];
846+
847+ // get version
848+ auto version = build[" version" ].get <std::string>();
849+ if (version.empty ())
850+ return LOAD_BAD_FILE;
851+
852+ {
853+ int v1, v2, v3;
854+ if (sscanf_s (version.c_str (), " %d.%d.%d" , &v1, &v2, &v3) != 3 )
855+ return LOAD_BAD_FILE;
856+
857+ newVersion = (v1 << 24 ) | (v2 << 16 ) | v3;
858+
859+ if (newVersion <= GetVersionEx (g_Instance))
860+ return LOAD_OK;
861+ }
862+
863+ // artifact url
864+ {
865+ auto jobId = build[" jobs" ][0 ][" jobId" ].get <std::string>();
866+ if (jobId.empty ())
867+ return LOAD_BAD_FILE;
868+
869+ std::wstring jobUrl (L" https://ci.appveyor.com/api/buildjobs/" );
870+ jobUrl += std::wstring (jobId.begin (), jobId.end ());
871+ jobUrl += L" /artifacts" ;
872+
873+ buf = DownloadUrl (jobUrl.c_str ());
874+ if (buf.empty ())
875+ return LOAD_ERROR;
876+
877+ auto artifacts = json::parse (buf.begin (), buf.end ());
878+
879+ std::string fileName;
880+ for (const auto & artifact : artifacts)
881+ {
882+ auto name = artifact[" fileName" ].get <std::string>();
883+ if (name.find (" OpenShellSetup" ) == 0 )
884+ {
885+ fileName = name;
886+ break ;
887+ }
888+ }
889+
890+ if (fileName.empty ())
891+ return LOAD_BAD_FILE;
892+
893+ auto artifactUrl (jobUrl);
894+ artifactUrl += L' /' ;
895+ artifactUrl += std::wstring (fileName.begin (), fileName.end ());
896+
897+ downloadUrl = artifactUrl.c_str ();
898+ }
899+
900+ // changelog
901+ news.Append (CA2T (version.c_str ()));
902+ news.Append (L" \r\n\r\n " );
903+ try
904+ {
905+ // use Github API to compare commit that actual version was built from (APPVEYOR_REPO_COMMIT)
906+ // and commit that AppVeyor version was built from (commitId)
907+ auto commitId = build[" commitId" ].get <std::string>();
908+
909+ std::wstring compareUrl (L" https://api.github.com/repos/Open-Shell/Open-Shell-Menu/compare/" );
910+ compareUrl += _T (APPVEYOR_REPO_COMMIT);
911+ compareUrl += L" ..." ;
912+ compareUrl += std::wstring (commitId.begin (), commitId.end ());
913+
914+ buf = DownloadUrl (compareUrl.c_str ());
915+ auto compare = json::parse (buf.begin (), buf.end ());
916+
917+ // then use first lines (subjects) of commit messages as changelog
918+ auto commits = compare[" commits" ];
919+ for (const auto & commit : commits)
920+ {
921+ auto message = commit[" commit" ][" message" ].get <std::string>();
922+
923+ auto pos = message.find (' \n ' );
924+ if (pos != message.npos )
925+ message.resize (pos);
926+
927+ news.Append (L" - " );
928+ news.Append (CA2T (message.c_str ()));
929+ news.Append (L" \r\n " );
930+ }
931+ }
932+ catch (...)
933+ {
934+ }
935+ }
936+ catch (...)
937+ {
938+ return LOAD_BAD_FILE;
939+ }
940+
941+ return LOAD_OK;
942+ }
943+
813944VersionData::TLoadResult VersionData::Load ( const wchar_t *fname, bool bLoadFlags )
814945{
815946 Clear ();
0 commit comments