Compare commits

..

47 Commits

Author SHA1 Message Date
John Kleinschmidt
347f3c7dc2 v1.6.17 2018-01-31 15:12:28 -07:00
John Kleinschmidt
c29251cb9d Merge pull request #11778 from electron/parallel-releases-1-6-x
Allow multiple releases to run at once for 1-6-x
2018-01-31 13:42:38 -05:00
John Kleinschmidt
7f74a39346 Merge pull request #11786 from electron/case-insensitive-comparison-1-6-x
Do case insensitive comparisons
2018-01-31 13:38:05 -05:00
Samuel Attard
a7c8e7241b Do case insensitive comparisons 2018-01-31 10:40:24 -07:00
John Kleinschmidt
6360acb87b Allow multiple releases to run at once
Find draft release by draft flag and tag name;also backport release scripts to 1-6-x
2018-01-30 18:08:35 -07:00
John Kleinschmidt
acc04b9ca6 Backport for upload retry 2018-01-22 19:26:35 -05:00
John Kleinschmidt
fcd7692182 Bump v1.6.16 2018-01-22 17:10:13 -05:00
Aleš Pergl
ad0f44843d Disallow launching unknown apps via browser client.
CVE-2018-1000006
2018-01-22 15:26:47 -06:00
John Kleinschmidt
5a44e7c058 Bump for missing builds 2017-10-11 12:27:12 -04:00
John Kleinschmidt
bee5a70fbf Bump v1.6.15 2017-10-11 11:28:58 -04:00
John Kleinschmidt
73c4fe626b Merge pull request #10756 from electron/1-6-crankshaft-fix
Crankshaft RCE fix
2017-10-11 11:12:23 -04:00
John Kleinschmidt
befa1d9c79 Crankshaft RCE fix 2017-10-11 10:45:36 -04:00
John Kleinschmidt
40e37c68d5 Add publish-to-npm script 2017-09-28 09:20:28 -04:00
John Kleinschmidt
0c37f633b8 Remove arm64 references from prerelease check 2017-09-28 09:20:17 -04:00
John Kleinschmidt
1723c302f7 Bump for release build 2017-09-27 19:00:58 -04:00
John Kleinschmidt
f41051fe60 Merge branch 'release-1-6' of https://github.com/electron/electron into release-1-6 2017-09-27 18:55:18 -04:00
John Kleinschmidt
396a49e349 Bump for building with larger machines 2017-09-27 18:54:23 -04:00
John Kleinschmidt
482a1d2e2b Bump to add release logic to CircleCI 2017-09-27 18:50:30 -04:00
John Kleinschmidt
ca6127c802 Bump to properly set ELECTRON_RELEASE 2017-09-27 18:35:50 -04:00
John Kleinschmidt
588f906fba Bump to fix bootstrap call 2017-09-27 18:35:49 -04:00
John Kleinschmidt
14bdbbcc10 Bump to fix circleci indentation 2017-09-27 18:35:49 -04:00
John Kleinschmidt
a0cec63c91 Bump for circleCI config update 2017-09-27 18:35:49 -04:00
John Kleinschmidt
233fdeaef0 Bump to add release logic to CircleCI 2017-09-27 18:35:49 -04:00
John Kleinschmidt
54b12ba15d Bump to add prerelease check 2017-09-27 18:35:49 -04:00
John Kleinschmidt
cfa4fbc9c1 Change GitHub upload to use JS GitHub lib 2017-09-27 18:35:49 -04:00
John Kleinschmidt
4b03f5b87e Bump v1.6.14 2017-09-27 18:35:49 -04:00
John Kleinschmidt
acf6518317 Bump for building with larger machines 2017-09-27 17:44:32 -04:00
John Kleinschmidt
f7e07205b4 Bump to properly set ELECTRON_RELEASE 2017-09-27 15:59:45 -04:00
John Kleinschmidt
248c1e1118 Bump to fix bootstrap call 2017-09-27 15:37:49 -04:00
John Kleinschmidt
cb251892c2 Bump to fix circleci indentation 2017-09-27 15:30:59 -04:00
John Kleinschmidt
5fcf20a7aa Bump for circleCI config update 2017-09-27 15:27:27 -04:00
John Kleinschmidt
2e38f9ca1c Bump to add release logic to CircleCI 2017-09-27 14:42:09 -04:00
Birunthan Mohanathas
ece433f766 Merge pull request #10631 from electron/squirrel-avoid-double-update-1-6
Use Squirrel.Windows --checkForUpdate (1.6.x)
2017-09-27 21:20:30 +03:00
J.M
f6005ce28d Use Squirrel.Windows --checkForUpdate
This cherry-picks #10483 to fix #5057.
2017-09-27 20:35:08 +03:00
John Kleinschmidt
93cea48d04 Bump to add prerelease check 2017-09-27 11:27:36 -04:00
John Kleinschmidt
4fb6bef8ed Bump for release build 2017-09-24 14:41:19 +09:00
John Kleinschmidt
f4fd62db47 Change GitHub upload to use JS GitHub lib 2017-09-24 14:40:37 +09:00
John Kleinschmidt
2ede7d9ec9 Bump v1.6.14 2017-09-24 14:14:03 +09:00
John Kleinschmidt
7a67c36cdb Disable flaky cert tests 2017-09-24 10:09:46 +09:00
John Kleinschmidt
1131b5ae2f Merge pull request #10587 from electron/turbofan-fix
Apply turbofan-fix
2017-09-23 18:14:50 +09:00
John Kleinschmidt
9429eea12c Apply turbofan-fix 2017-09-23 16:54:55 +09:00
John Kleinschmidt
a0b04005a9 Fix CircleCI test step 2017-09-13 11:24:53 -04:00
John Kleinschmidt
a7d3cea6e8 Add CircleCI config 2017-09-13 10:36:20 -04:00
John Kleinschmidt
f2fe287b34 Bump v1.6.13 2017-09-06 13:17:43 -04:00
John Kleinschmidt
47242064ba Fix syntax error 2017-09-06 12:54:26 -04:00
John Kleinschmidt
da73284515 Make sure future 1.6 releases are tagged correctly 2017-09-06 12:30:47 -04:00
John Kleinschmidt
9b74f25770 Backport macOS IME backspace fix for 1.6.x (#10450) 2017-09-06 11:25:14 -04:00
36 changed files with 3187 additions and 124 deletions

212
.circleci/config.yml Normal file
View File

@@ -0,0 +1,212 @@
version: 2
jobs:
electron-linux-arm:
docker:
- image: electronbuilds/electron:0.0.4
environment:
TARGET_ARCH: arm
resource_class: 2xlarge
steps:
- checkout
- run:
name: Check for release
command: |
if [ -n "${RUN_RELEASE_BUILD}" ]; then
echo 'release build triggered from api'
echo 'export ELECTRON_RELEASE=1 TRIGGERED_BY_API=1' >> $BASH_ENV
fi
- run:
name: Bootstrap
command: |
if [ "$ELECTRON_RELEASE" == "1" ]; then
echo 'Bootstrapping Electron for release build'
script/bootstrap.py --target_arch=$TARGET_ARCH
else
echo 'Bootstrapping Electron for debug build'
script/bootstrap.py --target_arch=$TARGET_ARCH --dev
fi
- run: npm run lint
- run:
name: Build
command: |
if [ "$ELECTRON_RELEASE" == "1" ]; then
echo 'Building Electron for release'
script/build.py -c R
else
echo 'Building Electron for debug'
script/build.py -c D
fi
- run:
name: Create distribution
command: |
if [ "$ELECTRON_RELEASE" == "1" ]; then
echo 'Creating Electron release distribution'
script/create-dist.py
else
echo 'Skipping create distribution because build is not for release'
fi
- run:
name: Upload distribution
command: |
if [ "$ELECTRON_RELEASE" == "1" ] && [ "$TRIGGERED_BY_API" != "1" ]; then
echo 'Uploading Electron release distribution to github releases'
script/upload.py
elif [ "$ELECTRON_RELEASE" == "1" ] && [ "$TRIGGERED_BY_API" == "1" ]; then
echo 'Uploading Electron release distribution to s3'
script/upload.py --upload_to_s3
else
echo 'Skipping upload distribution because build is not for release'
fi
electron-linux-ia32:
docker:
- image: electronbuilds/electron:0.0.4
environment:
TARGET_ARCH: ia32
resource_class: xlarge
steps:
- checkout
- run:
name: Check for release
command: |
if [ -n "${RUN_RELEASE_BUILD}" ]; then
echo 'release build triggered from api'
echo 'export ELECTRON_RELEASE=1 TRIGGERED_BY_API=1' >> $BASH_ENV
fi
- run:
name: Bootstrap
command: |
if [ "$ELECTRON_RELEASE" == "1" ]; then
echo 'Bootstrapping Electron for release build'
script/bootstrap.py --target_arch=$TARGET_ARCH
else
echo 'Bootstrapping Electron for debug build'
script/bootstrap.py --target_arch=$TARGET_ARCH --dev
fi
- run: npm run lint
- run:
name: Build
command: |
if [ "$ELECTRON_RELEASE" == "1" ]; then
echo 'Building Electron for release'
script/build.py -c R
else
echo 'Building Electron for debug'
script/build.py -c D
fi
- run:
name: Create distribution
command: |
if [ "$ELECTRON_RELEASE" == "1" ]; then
echo 'Creating Electron release distribution'
script/create-dist.py
else
echo 'Skipping create distribution because build is not for release'
fi
- run:
name: Upload distribution
command: |
if [ "$ELECTRON_RELEASE" == "1" ] && [ "$TRIGGERED_BY_API" != "1" ]; then
echo 'Uploading Electron release distribution to github releases'
script/upload.py
elif [ "$ELECTRON_RELEASE" == "1" ] && [ "$TRIGGERED_BY_API" == "1" ]; then
echo 'Uploading Electron release distribution to s3'
script/upload.py --upload_to_s3
else
echo 'Skipping upload distribution because build is not for release'
fi
electron-linux-x64:
docker:
- image: electronbuilds/electron:0.0.4
environment:
TARGET_ARCH: x64
DISPLAY: ':99.0'
resource_class: xlarge
steps:
- checkout
- run:
name: Setup for headless testing
command: sh -e /etc/init.d/xvfb start
- run:
name: Check for release
command: |
if [ -n "${RUN_RELEASE_BUILD}" ]; then
echo 'release build triggered from api'
echo 'export ELECTRON_RELEASE=1 TRIGGERED_BY_API=1' >> $BASH_ENV
fi
- run:
name: Bootstrap
command: |
if [ "$ELECTRON_RELEASE" == "1" ]; then
echo 'Bootstrapping Electron for release build'
script/bootstrap.py --target_arch=$TARGET_ARCH
else
echo 'Bootstrapping Electron for debug build'
script/bootstrap.py --target_arch=$TARGET_ARCH --dev
fi
- run: npm run lint
- run:
name: Build
command: |
if [ "$ELECTRON_RELEASE" == "1" ]; then
echo 'Building Electron for release'
script/build.py -c R
else
echo 'Building Electron for debug'
script/build.py -c D
fi
- run:
name: Create distribution
command: |
if [ "$ELECTRON_RELEASE" == "1" ]; then
echo 'Creating Electron release distribution'
script/create-dist.py
else
echo 'Skipping create distribution because build is not for release'
fi
- run:
name: Upload distribution
command: |
if [ "$ELECTRON_RELEASE" == "1" ] && [ "$TRIGGERED_BY_API" != "1" ]; then
echo 'Uploading Electron release distribution to github releases'
script/upload.py
elif [ "$ELECTRON_RELEASE" == "1" ] && [ "$TRIGGERED_BY_API" == "1" ]; then
echo 'Uploading Electron release distribution to s3'
script/upload.py --upload_to_s3
else
echo 'Skipping upload distribution because build is not for release'
fi
- run:
name: Test
environment:
MOCHA_FILE: junit/test-results.xml
MOCHA_REPORTER: mocha-junit-reporter
command: |
if [ "$ELECTRON_RELEASE" != "1" ]; then
echo 'Testing Electron debug build'
mkdir junit
script/test.py --ci --rebuild_native_modules
else
echo 'Skipping testing on release build'
fi
- run:
name: Verify FFmpeg
command: |
if [ "$ELECTRON_RELEASE" != "1" ]; then
echo 'Verifying ffmpeg on debug build'
script/verify-ffmpeg.py
else
echo 'Skipping verify ffmpeg on release build'
fi
workflows:
version: 2
build-arm:
jobs:
- electron-linux-arm
build-ia32:
jobs:
- electron-linux-ia32
build-x64:
jobs:
- electron-linux-x64

View File

@@ -10,7 +10,7 @@
#if defined(OS_MACOSX)
extern "C" {
__attribute__((visibility("default")))
int AtomMain(int argc, const char* argv[]);
int AtomMain(int argc, char* argv[]);
__attribute__((visibility("default")))
int AtomInitializeICUandStartNode(int argc, char *argv[]);

View File

@@ -15,11 +15,11 @@
#include "content/public/app/content_main.h"
#if defined(OS_MACOSX)
int AtomMain(int argc, const char* argv[]) {
int AtomMain(int argc, char* argv[]) {
atom::AtomMainDelegate delegate;
content::ContentMainParams params(&delegate);
params.argc = argc;
params.argv = argv;
params.argv = const_cast<const char**>(argv);
atom::AtomCommandLine::Init(argc, argv);
return content::ContentMain(params);
}

View File

@@ -4,7 +4,8 @@
#include "atom/app/atom_main.h"
#include <stdlib.h>
#include <cstdlib>
#include <vector>
#if defined(OS_WIN)
#include <windows.h> // windows.h must be included first
@@ -14,9 +15,11 @@
#include <tchar.h>
#include "atom/app/atom_main_delegate.h"
#include "atom/app/command_line_args.h"
#include "atom/common/crash_reporter/win/crash_service_main.h"
#include "base/environment.h"
#include "base/process/launch.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/windows_version.h"
#include "content/public/app/sandbox_helper_win.h"
#include "sandbox/win/src/sandbox_types.h"
@@ -51,8 +54,39 @@ bool IsEnvSet(const char* name) {
#if defined(OS_WIN)
int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
int argc = 0;
wchar_t** wargv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
struct Arguments {
int argc = 0;
wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
~Arguments() { LocalFree(argv); }
} arguments;
if (!arguments.argv)
return -1;
#ifdef _DEBUG
// Don't display assert dialog boxes in CI test runs
static const auto kCI = "ELECTRON_CI";
bool is_ci = IsEnvSet(kCI);
if (!is_ci) {
for (int i = 0; i < arguments.argc; ++i) {
if (!_wcsicmp(arguments.argv[i], L"--ci")) {
is_ci = true;
_putenv_s(kCI, "1"); // set flag for child processes
break;
}
}
}
if (is_ci) {
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
_set_error_mode(_OUT_TO_STDERR);
}
#endif
bool run_as_node = IsEnvSet(kRunAsNode);
@@ -60,49 +94,24 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
if (run_as_node || !IsEnvSet("ELECTRON_NO_ATTACH_CONSOLE"))
base::RouteStdioToConsole(false);
// Convert argv to to UTF8
char** argv = new char*[argc];
for (int i = 0; i < argc; i++) {
// Compute the size of the required buffer
DWORD size = WideCharToMultiByte(CP_UTF8,
0,
wargv[i],
-1,
NULL,
0,
NULL,
NULL);
if (size == 0) {
// This should never happen.
fprintf(stderr, "Could not convert arguments to utf8.");
exit(1);
}
// Do the actual conversion
argv[i] = new char[size];
DWORD result = WideCharToMultiByte(CP_UTF8,
0,
wargv[i],
-1,
argv[i],
size,
NULL,
NULL);
if (result == 0) {
// This should never happen.
fprintf(stderr, "Could not convert arguments to utf8.");
exit(1);
}
}
if (run_as_node) {
// Now that argv conversion is done, we can finally start.
std::vector<char*> argv(arguments.argc);
std::transform(
arguments.argv, arguments.argv + arguments.argc, argv.begin(),
[](auto& a) { return _strdup(base::WideToUTF8(a).c_str()); });
base::AtExitManager atexit_manager;
base::i18n::InitializeICU();
return atom::NodeMain(argc, argv);
auto ret = atom::NodeMain(argv.size(), argv.data());
std::for_each(argv.begin(), argv.end(), free);
return ret;
} else if (IsEnvSet("ELECTRON_INTERNAL_CRASH_SERVICE")) {
return crash_service::Main(cmd);
}
if (!atom::CheckCommandLineArguments(arguments.argc, arguments.argv))
return -1;
sandbox::SandboxInterfaceInfo sandbox_info = {0};
content::InitializeSandboxInfo(&sandbox_info);
atom::AtomMainDelegate delegate;
@@ -110,33 +119,32 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
content::ContentMainParams params(&delegate);
params.instance = instance;
params.sandbox_info = &sandbox_info;
atom::AtomCommandLine::Init(argc, argv);
atom::AtomCommandLine::InitW(argc, wargv);
atom::AtomCommandLine::Init(arguments.argc, arguments.argv);
return content::ContentMain(params);
}
#elif defined(OS_LINUX) // defined(OS_WIN)
int main(int argc, const char* argv[]) {
int main(int argc, char* argv[]) {
if (IsEnvSet(kRunAsNode)) {
base::i18n::InitializeICU();
base::AtExitManager atexit_manager;
return atom::NodeMain(argc, const_cast<char**>(argv));
return atom::NodeMain(argc, argv);
}
atom::AtomMainDelegate delegate;
content::ContentMainParams params(&delegate);
params.argc = argc;
params.argv = argv;
params.argv = const_cast<const char**>(argv);
atom::AtomCommandLine::Init(argc, argv);
return content::ContentMain(params);
}
#else // defined(OS_LINUX)
int main(int argc, const char* argv[]) {
int main(int argc, char* argv[]) {
if (IsEnvSet(kRunAsNode)) {
return AtomInitializeICUandStartNode(argc, const_cast<char**>(argv));
return AtomInitializeICUandStartNode(argc, argv);
}
return AtomMain(argc, argv);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,17 @@
// Copyright (c) 2018 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_APP_COMMAND_LINE_ARGS_H_
#define ATOM_APP_COMMAND_LINE_ARGS_H_
#include "base/command_line.h"
namespace atom {
bool CheckCommandLineArguments(int argc, base::CommandLine::CharType** argv);
} // namespace atom
#endif // ATOM_APP_COMMAND_LINE_ARGS_H_

View File

@@ -754,11 +754,7 @@ bool App::Relaunch(mate::Arguments* js_args) {
}
if (!override_argv) {
#if defined(OS_WIN)
const relauncher::StringVector& argv = atom::AtomCommandLine::wargv();
#else
const relauncher::StringVector& argv = atom::AtomCommandLine::argv();
#endif
return relauncher::RelaunchApp(argv);
}

View File

@@ -22,6 +22,7 @@
#include "atom/common/options_switches.h"
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/path_service.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
@@ -37,6 +38,7 @@
#include "content/public/browser/resource_dispatcher_host.h"
#include "content/public/browser/site_instance.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_paths.h"
#include "content/public/common/url_constants.h"
#include "content/public/common/web_preferences.h"
#include "net/ssl/ssl_cert_request_info.h"
@@ -207,6 +209,11 @@ void AtomBrowserClient::OverrideSiteInstanceForNavigation(
void AtomBrowserClient::AppendExtraCommandLineSwitches(
base::CommandLine* command_line,
int process_id) {
// Make sure we're about to launch a known executable
base::FilePath child_path;
PathService::Get(content::CHILD_PROCESS_EXE, &child_path);
CHECK(base::MakeAbsoluteFilePath(command_line->GetProgram()) == child_path);
std::string process_type = command_line->GetSwitchValueASCII("type");
if (process_type != "renderer")
return;

View File

@@ -140,11 +140,7 @@ bool RelaunchAppWithHelper(const base::FilePath& helper,
}
int RelauncherMain(const content::MainFunctionParams& main_parameters) {
#if defined(OS_WIN)
const StringVector& argv = atom::AtomCommandLine::wargv();
#else
const StringVector& argv = atom::AtomCommandLine::argv();
#endif
if (argv.size() < 4 || argv[1] != internal::kRelauncherTypeArg) {
LOG(ERROR) << "relauncher process invoked with unexpected arguments";

View File

@@ -17,9 +17,9 @@
<key>CFBundleIconFile</key>
<string>electron.icns</string>
<key>CFBundleVersion</key>
<string>1.6.12</string>
<string>1.6.17</string>
<key>CFBundleShortVersionString</key>
<string>1.6.12</string>
<string>1.6.17</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.developer-tools</string>
<key>LSMinimumSystemVersion</key>

View File

@@ -56,8 +56,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,6,12,0
PRODUCTVERSION 1,6,12,0
FILEVERSION 1,6,17,0
PRODUCTVERSION 1,6,17,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -74,12 +74,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "GitHub, Inc."
VALUE "FileDescription", "Electron"
VALUE "FileVersion", "1.6.12"
VALUE "FileVersion", "1.6.17"
VALUE "InternalName", "electron.exe"
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
VALUE "OriginalFilename", "electron.exe"
VALUE "ProductName", "Electron"
VALUE "ProductVersion", "1.6.12"
VALUE "ProductVersion", "1.6.17"
VALUE "SquirrelAwareVersion", "1"
END
END

View File

@@ -10,31 +10,22 @@
namespace atom {
// static
std::vector<std::string> AtomCommandLine::argv_;
#if defined(OS_WIN)
// static
std::vector<std::wstring> AtomCommandLine::wargv_;
#endif
base::CommandLine::StringVector AtomCommandLine::argv_;
// static
void AtomCommandLine::Init(int argc, const char* const* argv) {
void AtomCommandLine::Init(int argc, base::CommandLine::CharType** argv) {
DCHECK(argv_.empty());
// NOTE: uv_setup_args does nothing on Windows, so we don't need to call it.
// Otherwise we'd have to convert the arguments from UTF16.
#if !defined(OS_WIN)
// Hack around with the argv pointer. Used for process.title = "blah"
char** new_argv = uv_setup_args(argc, const_cast<char**>(argv));
for (int i = 0; i < argc; ++i) {
argv_.push_back(new_argv[i]);
}
}
#if defined(OS_WIN)
// static
void AtomCommandLine::InitW(int argc, const wchar_t* const* argv) {
for (int i = 0; i < argc; ++i) {
wargv_.push_back(argv[i]);
}
}
argv = uv_setup_args(argc, argv);
#endif
argv_.assign(argv, argv + argc);
}
#if defined(OS_LINUX)
// static
void AtomCommandLine::InitializeFromCommandLine() {

View File

@@ -8,6 +8,7 @@
#include <string>
#include <vector>
#include "base/command_line.h"
#include "base/macros.h"
#include "build/build_config.h"
@@ -16,13 +17,9 @@ namespace atom {
// Singleton to remember the original "argc" and "argv".
class AtomCommandLine {
public:
static void Init(int argc, const char* const* argv);
static std::vector<std::string> argv() { return argv_; }
static const base::CommandLine::StringVector& argv() { return argv_; }
#if defined(OS_WIN)
static void InitW(int argc, const wchar_t* const* argv);
static std::vector<std::wstring> wargv() { return wargv_; }
#endif
static void Init(int argc, base::CommandLine::CharType** argv);
#if defined(OS_LINUX)
// On Linux the command line has to be read from base::CommandLine since
@@ -31,11 +28,7 @@ class AtomCommandLine {
#endif
private:
static std::vector<std::string> argv_;
#if defined(OS_WIN)
static std::vector<std::wstring> wargv_;
#endif
static base::CommandLine::StringVector argv_;
DISALLOW_IMPLICIT_CONSTRUCTORS(AtomCommandLine);
};

View File

@@ -7,7 +7,7 @@
#define ATOM_MAJOR_VERSION 1
#define ATOM_MINOR_VERSION 6
#define ATOM_PATCH_VERSION 12
#define ATOM_PATCH_VERSION 17
#define ATOM_VERSION_IS_RELEASE 1

View File

@@ -4,6 +4,7 @@
#include "atom/common/node_bindings.h"
#include <algorithm>
#include <string>
#include <vector>
@@ -17,6 +18,7 @@
#include "base/files/file_path.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/trace_event.h"
#include "content/public/browser/browser_thread.h"
@@ -149,7 +151,14 @@ void NodeBindings::Initialize() {
node::Environment* NodeBindings::CreateEnvironment(
v8::Handle<v8::Context> context) {
#if defined(OS_WIN)
auto& atom_args = AtomCommandLine::argv();
std::vector<std::string> args(atom_args.size());
std::transform(atom_args.cbegin(), atom_args.cend(), args.begin(),
[](auto& a) { return base::WideToUTF8(a); });
#else
auto args = AtomCommandLine::argv();
#endif
// Feed node the path to initialization script.
base::FilePath::StringType process_type;
@@ -169,8 +178,7 @@ node::Environment* NodeBindings::CreateEnvironment(
resources_path.Append(FILE_PATH_LITERAL("electron.asar"))
.Append(process_type)
.Append(FILE_PATH_LITERAL("init.js"));
std::string script_path_str = script_path.AsUTF8Unsafe();
args.insert(args.begin() + 1, script_path_str.c_str());
args.insert(args.begin() + 1, script_path.AsUTF8Unsafe());
std::unique_ptr<const char*[]> c_argv = StringVectorToArgArray(args);
node::Environment* env = node::CreateEnvironment(

View File

@@ -4,7 +4,7 @@
'product_name%': 'Electron',
'company_name%': 'GitHub, Inc',
'company_abbr%': 'github',
'version%': '1.6.12',
'version%': '1.6.17',
'js2c_input_dir': '<(SHARED_INTERMEDIATE_DIR)/js2c',
},
'includes': [

View File

@@ -97,6 +97,8 @@
'atom/app/atom_main_delegate.cc',
'atom/app/atom_main_delegate.h',
'atom/app/atom_main_delegate_mac.mm',
'atom/app/command_line_args.cc',
'atom/app/command_line_args.h',
'atom/app/node_main.cc',
'atom/app/node_main.h',
'atom/app/uv_task_runner.cc',

View File

@@ -29,7 +29,7 @@ class AutoUpdater extends EventEmitter {
return this.emitError('Can not find Squirrel')
}
this.emit('checking-for-update')
squirrelUpdate.download(this.updateURL, (error, update) => {
squirrelUpdate.checkForUpdate(this.updateURL, (error, update) => {
if (error != null) {
return this.emitError(error)
}

View File

@@ -82,8 +82,8 @@ exports.processStart = function () {
}
// Download the releases specified by the URL and write new results to stdout.
exports.download = function (updateURL, callback) {
return spawnUpdate(['--download', updateURL], false, function (error, stdout) {
exports.checkForUpdate = function (updateURL, callback) {
return spawnUpdate(['--checkForUpdate', updateURL], false, function (error, stdout) {
var json, ref, ref1, update
if (error != null) {
return callback(error)

10
npm/cli.js Executable file
View File

@@ -0,0 +1,10 @@
#!/usr/bin/env node
var electron = require('./')
var proc = require('child_process')
var child = proc.spawn(electron, process.argv.slice(2), {stdio: 'inherit'})
child.on('close', function (code) {
process.exit(code)
})

10
npm/index.js Normal file
View File

@@ -0,0 +1,10 @@
var fs = require('fs')
var path = require('path')
var pathFile = path.join(__dirname, 'path.txt')
if (fs.existsSync(pathFile)) {
module.exports = path.join(__dirname, fs.readFileSync(pathFile, 'utf-8'))
} else {
throw new Error('Electron failed to install correctly, please delete node_modules/electron and try installing again')
}

65
npm/install.js Executable file
View File

@@ -0,0 +1,65 @@
#!/usr/bin/env node
// maintainer note - x.y.z-ab version in package.json -> x.y.z
var version = require('./package').version.replace(/-.*/, '')
var fs = require('fs')
var os = require('os')
var path = require('path')
var extract = require('extract-zip')
var download = require('electron-download')
var installedVersion = null
try {
installedVersion = fs.readFileSync(path.join(__dirname, 'dist', 'version'), 'utf-8').replace(/^v/, '')
} catch (ignored) {
// do nothing
}
var platformPath = getPlatformPath()
if (installedVersion === version && fs.existsSync(path.join(__dirname, platformPath))) {
process.exit(0)
}
// downloads if not cached
download({
cache: process.env.electron_config_cache,
version: version,
platform: process.env.npm_config_platform,
arch: process.env.npm_config_arch,
strictSSL: process.env.npm_config_strict_ssl === 'true',
force: process.env.force_no_cache === 'true',
quiet: ['info', 'verbose', 'silly', 'http'].indexOf(process.env.npm_config_loglevel) === -1
}, extractFile)
// unzips and makes path.txt point at the correct executable
function extractFile (err, zipPath) {
if (err) return onerror(err)
extract(zipPath, {dir: path.join(__dirname, 'dist')}, function (err) {
if (err) return onerror(err)
fs.writeFile(path.join(__dirname, 'path.txt'), platformPath, function (err) {
if (err) return onerror(err)
})
})
}
function onerror (err) {
throw err
}
function getPlatformPath () {
var platform = process.env.npm_config_platform || os.platform()
switch (platform) {
case 'darwin':
return 'dist/Electron.app/Contents/MacOS/Electron'
case 'freebsd':
case 'linux':
return 'dist/electron'
case 'win32':
return 'dist/electron.exe'
default:
throw new Error('Electron builds are not available on platform: ' + platform)
}
}

26
npm/package.json Normal file
View File

@@ -0,0 +1,26 @@
{
"scripts": {
"cache-clean": "rm -rf ~/.electron && rm -rf dist",
"postinstall": "node install.js",
"pretest": "npm run cache-clean",
"test": "standard"
},
"bin": {
"electron": "cli.js"
},
"main": "index.js",
"types": "electron.d.ts",
"dependencies": {
"@types/node": "^7.0.18",
"electron-download": "^3.0.1",
"extract-zip": "^1.0.3"
},
"devDependencies": {
"home-path": "^0.1.1",
"path-exists": "^2.0.0",
"standard": "^5.4.1"
},
"directories": {
"test": "test"
}
}

View File

@@ -1,15 +1,22 @@
{
"name": "electron",
"version": "1.6.12",
"version": "1.6.17",
"devDependencies": {
"asar": "^0.11.0",
"browserify": "^13.1.0",
"colors": "^1.1.2",
"dugite": "^1.57.0",
"electabul": "~0.0.4",
"electron-docs-linter": "^2.3.3",
"electron-typescript-definitions": "1.2.7",
"github": "^9.2.0",
"heads": "^1.3.0",
"minimist": "^1.2.0",
"nugget": "^2.0.1",
"request": "*",
"standard": "^8.4.0",
"standard-markdown": "^2.1.1"
"standard-markdown": "^2.1.1",
"sumchecker": "^2.0.2"
},
"optionalDependencies": {
"runas": "^3.0.0"
@@ -43,7 +50,9 @@
"create-api-json": "electron-docs-linter docs --outfile=out/electron-api.json --version=$npm_package_version",
"create-typescript-definitions": "npm run create-api-json && electron-typescript-definitions --in=out/electron-api.json --out=out/electron.d.ts",
"preinstall": "node -e 'process.exit(0)'",
"release": "./script/upload.py -p",
"prepare-release": "node ./script/prepare-release.js",
"prerelease": "python ./script/bootstrap.py -v --dev && npm run build",
"release": "node ./script/release.js",
"repl": "python ./script/start.py --interactive",
"start": "python ./script/start.py",
"test": "python ./script/test.py"

View File

@@ -34,6 +34,7 @@ def main():
update_package_json(version)
tag_version(version)
print 'Bumped to version: {0}'.format(version)
def increase_version(versions, index):
for i in range(index + 1, 4):

209
script/ci-release-build.js Normal file
View File

@@ -0,0 +1,209 @@
const assert = require('assert')
const request = require('request')
const buildAppVeyorURL = 'https://windows-ci.electronjs.org/api/builds'
const jenkinsServer = 'https://mac-ci.electronjs.org'
const circleCIJobs = [
'electron-linux-arm',
'electron-linux-ia32',
'electron-linux-x64'
]
const jenkinsJobs = [
'electron-mas-x64-release',
'electron-osx-x64-release'
]
async function makeRequest (requestOptions, parseResponse) {
return new Promise((resolve, reject) => {
request(requestOptions, (err, res, body) => {
if (!err && res.statusCode >= 200 && res.statusCode < 300) {
if (parseResponse) {
const build = JSON.parse(body)
resolve(build)
} else {
resolve(body)
}
} else {
if (parseResponse) {
console.log('Error: ', `(status ${res.statusCode})`, err || JSON.parse(res.body), requestOptions)
} else {
console.log('Error: ', `(status ${res.statusCode})`, err || res.body, requestOptions)
}
reject(err)
}
})
})
}
async function circleCIcall (buildUrl, targetBranch, job, ghRelease) {
assert(process.env.CIRCLE_TOKEN, 'CIRCLE_TOKEN not found in environment')
console.log(`Triggering CircleCI to run build job: ${job} on branch: ${targetBranch} with release flag.`)
let buildRequest = {
'build_parameters': {
'CIRCLE_JOB': job
}
}
if (ghRelease) {
buildRequest.build_parameters.ELECTRON_RELEASE = 1
} else {
buildRequest.build_parameters.RUN_RELEASE_BUILD = 'true'
}
let circleResponse = await makeRequest({
method: 'POST',
url: buildUrl,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify(buildRequest)
}, true).catch(err => {
console.log('Error calling CircleCI:', err)
})
console.log(`Check ${circleResponse.build_url} for status. (${job})`)
}
async function buildAppVeyor (targetBranch, ghRelease) {
console.log(`Triggering AppVeyor to run build on branch: ${targetBranch} with release flag.`)
assert(process.env.APPVEYOR_TOKEN, 'APPVEYOR_TOKEN not found in environment')
let environmentVariables = {}
if (ghRelease) {
environmentVariables.ELECTRON_RELEASE = 1
} else {
environmentVariables.RUN_RELEASE_BUILD = 'true'
}
const requestOpts = {
url: buildAppVeyorURL,
auth: {
bearer: process.env.APPVEYOR_TOKEN
},
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
accountName: 'AppVeyor',
projectSlug: 'electron',
branch: targetBranch,
environmentVariables
}),
method: 'POST'
}
let appVeyorResponse = await makeRequest(requestOpts, true).catch(err => {
console.log('Error calling AppVeyor:', err)
})
const buildUrl = `https://windows-ci.electronjs.org/project/AppVeyor/electron/build/${appVeyorResponse.version}`
console.log(`AppVeyor release build request successful. Check build status at ${buildUrl}`)
}
function buildCircleCI (targetBranch, ghRelease, job) {
const circleBuildUrl = `https://circleci.com/api/v1.1/project/github/electron/electron/tree/${targetBranch}?circle-token=${process.env.CIRCLE_TOKEN}`
if (job) {
assert(circleCIJobs.includes(job), `Unknown CI job name: ${job}.`)
circleCIcall(circleBuildUrl, targetBranch, job, ghRelease)
} else {
circleCIJobs.forEach((job) => circleCIcall(circleBuildUrl, targetBranch, job, ghRelease))
}
}
async function buildJenkins (targetBranch, ghRelease, job) {
assert(process.env.JENKINS_AUTH_TOKEN, 'JENKINS_AUTH_TOKEN not found in environment')
assert(process.env.JENKINS_BUILD_TOKEN, 'JENKINS_BUILD_TOKEN not found in environment')
let jenkinsCrumb = await getJenkinsCrumb()
if (job) {
assert(jenkinsJobs.includes(job), `Unknown CI job name: ${job}.`)
callJenkinsBuild(job, jenkinsCrumb, targetBranch, ghRelease)
} else {
jenkinsJobs.forEach((job) => {
callJenkinsBuild(job, jenkinsCrumb, targetBranch, ghRelease)
})
}
}
async function callJenkins (path, requestParameters, requestHeaders) {
let requestOptions = {
url: `${jenkinsServer}/${path}`,
auth: {
user: 'build',
pass: process.env.JENKINS_AUTH_TOKEN
},
qs: requestParameters
}
if (requestHeaders) {
requestOptions.headers = requestHeaders
}
let jenkinsResponse = await makeRequest(requestOptions).catch(err => {
console.log(`Error calling Jenkins:`, err)
})
return jenkinsResponse
}
async function callJenkinsBuild (job, jenkinsCrumb, targetBranch, ghRelease) {
console.log(`Triggering Jenkins to run build job: ${job} on branch: ${targetBranch} with release flag.`)
let jenkinsParams = {
token: process.env.JENKINS_BUILD_TOKEN,
BRANCH: targetBranch
}
if (!ghRelease) {
jenkinsParams.RUN_RELEASE_BUILD = 1
}
await callJenkins(`job/${job}/buildWithParameters`, jenkinsParams, jenkinsCrumb)
.catch(err => {
console.log(`Error calling Jenkins build`, err)
})
let buildUrl = `${jenkinsServer}/job/${job}/lastBuild/`
console.log(`Jenkins build request successful. Check build status at ${buildUrl}.`)
}
async function getJenkinsCrumb () {
let crumbResponse = await callJenkins('crumbIssuer/api/xml', {
xpath: 'concat(//crumbRequestField,":",//crumb)'
}).catch(err => {
console.log(`Error getting jenkins crumb:`, err)
})
let crumbDetails = crumbResponse.split(':')
let crumbHeader = {}
crumbHeader[crumbDetails[0]] = crumbDetails[1]
return crumbHeader
}
function runRelease (targetBranch, options) {
if (options.ci) {
switch (options.ci) {
case 'CircleCI': {
buildCircleCI(targetBranch, options.ghRelease, options.job)
break
}
case 'AppVeyor': {
buildAppVeyor(targetBranch, options.ghRelease)
break
}
case 'Jenkins': {
buildJenkins(targetBranch, options.ghRelease, options.job)
break
}
}
} else {
buildCircleCI(targetBranch, options.ghRelease, options.job)
buildAppVeyor(targetBranch, options.ghRelease)
buildJenkins(targetBranch, options.ghRelease, options.job)
}
}
module.exports = runRelease
if (require.main === module) {
const args = require('minimist')(process.argv.slice(2))
const targetBranch = args._[0]
if (args._.length < 1) {
console.log(`Trigger CI to build release builds of electron.
Usage: ci-release-build.js [--job=CI_JOB_NAME] [--ci=CircleCI|AppVeyor|Jenkins] [--ghRelease] TARGET_BRANCH
`)
process.exit(0)
}
runRelease(targetBranch, args)
}

View File

@@ -55,10 +55,9 @@ def main():
deps += LINUX_DEPS_ARM
execute(['sudo', 'apt-get', 'install'] + deps)
execute(['sh', '-e', '/etc/init.d/xvfb', 'start'])
if PLATFORM == 'linux':
if PLATFORM == 'linux' and target_arch == 'x64':
os.environ['DISPLAY'] = ':99.0'
execute(['sh', '-e', '/etc/init.d/xvfb', 'start'])
# CI's npm is not reliable.
npm = 'npm.cmd' if PLATFORM == 'win32' else 'npm'

View File

@@ -9,7 +9,7 @@ import sys
BASE_URL = os.getenv('LIBCHROMIUMCONTENT_MIRROR') or \
'https://s3.amazonaws.com/github-janky-artifacts/libchromiumcontent'
LIBCHROMIUMCONTENT_COMMIT = os.getenv('LIBCHROMIUMCONTENT_COMMIT') or \
'f3e99add3753f82f9ce02788144b9ea9cd6367d8'
'19ca886975716c02d6de9fd41b8297a4e1774be2'
PLATFORM = {
'cygwin': 'win32',

116
script/merge-release.js Executable file
View File

@@ -0,0 +1,116 @@
#!/usr/bin/env node
require('colors')
const assert = require('assert')
const branchToRelease = process.argv[2]
const fail = '\u2717'.red
const { GitProcess, GitError } = require('dugite')
const pass = '\u2713'.green
const path = require('path')
const pkg = require('../package.json')
assert(process.env.ELECTRON_GITHUB_TOKEN, 'ELECTRON_GITHUB_TOKEN not found in environment')
if (!branchToRelease) {
console.log(`Usage: merge-release branch`)
process.exit(1)
}
const gitDir = path.resolve(__dirname, '..')
async function callGit (args, errorMessage, successMessage) {
let gitResult = await GitProcess.exec(args, gitDir)
if (gitResult.exitCode === 0) {
console.log(`${pass} ${successMessage}`)
return true
} else {
console.log(`${fail} ${errorMessage} ${gitResult.stderr}`)
process.exit(1)
}
}
async function checkoutBranch (branchName) {
console.log(`Checking out ${branchName}.`)
let errorMessage = `Error checking out branch ${branchName}:`
let successMessage = `Successfully checked out branch ${branchName}.`
return callGit(['checkout', branchName], errorMessage, successMessage)
}
async function commitMerge () {
console.log(`Committing the merge for v${pkg.version}`)
let errorMessage = `Error committing merge:`
let successMessage = `Successfully committed the merge for v${pkg.version}`
let gitArgs = ['commit', '-m', `v${pkg.version}`]
return callGit(gitArgs, errorMessage, successMessage)
}
async function mergeReleaseIntoBranch (branchName) {
console.log(`Merging release branch into ${branchName}.`)
let mergeArgs = ['merge', 'release-1-6-x', '--squash']
let mergeDetails = await GitProcess.exec(mergeArgs, gitDir)
if (mergeDetails.exitCode === 0) {
return true
} else {
const error = GitProcess.parseError(mergeDetails.stderr)
if (error === GitError.MergeConflicts) {
console.log(`${fail} Could not merge release branch into ${branchName} ` +
`due to merge conflicts.`)
return false
} else {
console.log(`${fail} Could not merge release branch into ${branchName} ` +
`due to an error: ${mergeDetails.stderr}.`)
process.exit(1)
}
}
}
async function pushBranch (branchName) {
console.log(`Pushing branch ${branchName}.`)
let pushArgs = ['push', 'origin', branchName]
let errorMessage = `Could not push branch ${branchName} due to an error:`
let successMessage = `Successfully pushed branch ${branchName}.`
return callGit(pushArgs, errorMessage, successMessage)
}
async function pull () {
console.log(`Performing a git pull`)
let errorMessage = `Could not pull due to an error:`
let successMessage = `Successfully performed a git pull`
return callGit(['pull'], errorMessage, successMessage)
}
async function rebase (targetBranch) {
console.log(`Rebasing release branch from ${targetBranch}`)
let errorMessage = `Could not rebase due to an error:`
let successMessage = `Successfully rebased release branch from ` +
`${targetBranch}`
return callGit(['rebase', targetBranch], errorMessage, successMessage)
}
async function mergeRelease () {
await checkoutBranch(branchToRelease)
let mergeSuccess = await mergeReleaseIntoBranch(branchToRelease)
if (mergeSuccess) {
console.log(`${pass} Successfully merged release branch into ` +
`${branchToRelease}.`)
await commitMerge()
let pushSuccess = await pushBranch(branchToRelease)
if (pushSuccess) {
console.log(`${pass} Success!!! ${branchToRelease} now has the latest release!`)
}
} else {
console.log(`Trying rebase of ${branchToRelease} into release branch.`)
await pull()
await checkoutBranch('release-1-6-x')
let rebaseResult = await rebase(branchToRelease)
if (rebaseResult) {
let pushResult = pushBranch('HEAD')
if (pushResult) {
console.log(`Rebase of ${branchToRelease} into release branch was ` +
`successful. Let release builds run and then try this step again.`)
}
// Exit as failure so release doesn't continue
process.exit(1)
}
}
}
mergeRelease()

182
script/prepare-release.js Executable file
View File

@@ -0,0 +1,182 @@
#!/usr/bin/env node
require('colors')
const args = require('minimist')(process.argv.slice(2))
const assert = require('assert')
const ciReleaseBuild = require('./ci-release-build')
const { execSync } = require('child_process')
const fail = '\u2717'.red
const { GitProcess, GitError } = require('dugite')
const GitHub = require('github')
const pass = '\u2713'.green
const path = require('path')
const pkg = require('../package.json')
const versionType = args._[0]
// TODO (future) automatically determine version based on conventional commits
// via conventional-recommended-bump
assert(process.env.ELECTRON_GITHUB_TOKEN, 'ELECTRON_GITHUB_TOKEN not found in environment')
if (!versionType && !args.notesOnly) {
console.log(`Usage: prepare-release versionType [major | minor | patch ]` +
` (--notesOnly)`)
process.exit(1)
}
const github = new GitHub()
const gitDir = path.resolve(__dirname, '..')
github.authenticate({type: 'token', token: process.env.ELECTRON_GITHUB_TOKEN})
async function createReleaseBranch () {
console.log(`Creating release branch.`)
let checkoutDetails = await GitProcess.exec([ 'checkout', '-b', 'release-1-6-x' ], gitDir)
if (checkoutDetails.exitCode === 0) {
console.log(`${pass} Successfully created the release branch.`)
} else {
const error = GitProcess.parseError(checkoutDetails.stderr)
if (error === GitError.BranchAlreadyExists) {
console.log(`${fail} Release branch already exists, aborting prepare ` +
`release process.`)
} else {
console.log(`${fail} Error creating release branch: ` +
`${checkoutDetails.stderr}`)
}
process.exit(1)
}
}
function getNewVersion () {
console.log(`Bumping for new "${versionType}" version.`)
let bumpScript = path.join(__dirname, 'bump-version.py')
let scriptArgs = [bumpScript, `${versionType}`]
if (args.stable) {
scriptArgs.push('--stable')
}
try {
let bumpVersion = execSync(scriptArgs.join(' '), {encoding: 'UTF-8'})
bumpVersion = bumpVersion.substr(bumpVersion.indexOf(':') + 1).trim()
let newVersion = `v${bumpVersion}`
console.log(`${pass} Successfully bumped version to ${newVersion}`)
return newVersion
} catch (err) {
console.log(`${fail} Could not bump version, error was:`, err)
}
}
async function getCurrentBranch (gitDir) {
console.log(`Determining current git branch`)
let gitArgs = ['rev-parse', '--abbrev-ref', 'HEAD']
let branchDetails = await GitProcess.exec(gitArgs, gitDir)
if (branchDetails.exitCode === 0) {
let currentBranch = branchDetails.stdout.trim()
console.log(`${pass} Successfully determined current git branch is ` +
`${currentBranch}`)
return currentBranch
} else {
let error = GitProcess.parseError(branchDetails.stderr)
console.log(`${fail} Could not get details for the current branch,
error was ${branchDetails.stderr}`, error)
process.exit(1)
}
}
async function getReleaseNotes (currentBranch) {
console.log(`Generating release notes for ${currentBranch}.`)
let githubOpts = {
owner: 'electron',
repo: 'electron',
base: `v${pkg.version}`,
head: currentBranch
}
let releaseNotes = '(placeholder)\n'
console.log(`Checking for commits from ${pkg.version} to ${currentBranch}`)
let commitComparison = await github.repos.compareCommits(githubOpts)
.catch(err => {
console.log(`{$fail} Error checking for commits from ${pkg.version} to ` +
`${currentBranch}`, err)
process.exit(1)
})
commitComparison.data.commits.forEach(commitEntry => {
let commitMessage = commitEntry.commit.message
if (commitMessage.toLowerCase().indexOf('merge') > -1) {
releaseNotes += `${commitMessage} \n`
}
})
console.log(`${pass} Done generating release notes for ${currentBranch}.`)
return releaseNotes
}
async function createRelease (branchToTarget, isBeta) {
let releaseNotes = await getReleaseNotes(branchToTarget)
let newVersion = getNewVersion()
const githubOpts = {
owner: 'electron',
repo: 'electron'
}
console.log(`Checking for existing draft release.`)
let releases = await github.repos.getReleases(githubOpts)
.catch(err => {
console.log('$fail} Could not get releases. Error was', err)
})
let drafts = releases.data.filter(release => release.draft &&
release.tag_name === newVersion)
if (drafts.length > 0) {
console.log(`${fail} Aborting because draft release for
${drafts[0].tag_name} already exists.`)
process.exit(1)
}
console.log(`${pass} A draft release does not exist; creating one.`)
githubOpts.body = releaseNotes
githubOpts.draft = true
githubOpts.name = `electron ${newVersion}`
if (isBeta) {
githubOpts.body = `Note: This is a beta release. Please file new issues ` +
`for any bugs you find in it.\n \n This release is published to npm ` +
`under the beta tag and can be installed via npm install electron@beta, ` +
`or npm i electron@${newVersion.substr(1)}.`
githubOpts.name = `${githubOpts.name}`
githubOpts.prerelease = true
}
githubOpts.tag_name = newVersion
githubOpts.target_commitish = branchToTarget
await github.repos.createRelease(githubOpts)
.catch(err => {
console.log(`${fail} Error creating new release: `, err)
process.exit(1)
})
console.log(`${pass} Draft release for ${newVersion} has been created.`)
}
async function pushRelease () {
let pushDetails = await GitProcess.exec(['push', 'origin', 'HEAD'], gitDir)
if (pushDetails.exitCode === 0) {
console.log(`${pass} Successfully pushed the release branch. Wait for ` +
`release builds to finish before running "npm run release".`)
} else {
console.log(`${fail} Error pushing the release branch: ` +
`${pushDetails.stderr}`)
process.exit(1)
}
}
async function runReleaseBuilds () {
await ciReleaseBuild('release-1-6-x', {
ghRelease: true
})
}
async function prepareRelease (isBeta, notesOnly) {
let currentBranch = await getCurrentBranch(gitDir)
if (notesOnly) {
let releaseNotes = await getReleaseNotes(currentBranch)
console.log(`Draft release notes are: ${releaseNotes}`)
} else {
await createReleaseBranch()
await createRelease(currentBranch, isBeta)
await pushRelease()
await runReleaseBuilds()
}
}
prepareRelease(!args.stable, args.notesOnly)

112
script/prerelease.js Executable file
View File

@@ -0,0 +1,112 @@
#!/usr/bin/env node
require('colors')
const assert = require('assert')
const GitHub = require('github')
const heads = require('heads')
const pkg = require('../package.json')
const pass = '\u2713'.green
const fail = '\u2717'.red
let failureCount = 0
assert(process.env.ELECTRON_GITHUB_TOKEN, 'ELECTRON_GITHUB_TOKEN not found in environment')
const github = new GitHub()
github.authenticate({type: 'token', token: process.env.ELECTRON_GITHUB_TOKEN})
github.repos.getReleases({owner: 'electron', repo: 'electron'})
.then(res => {
const releases = res.data
const drafts = releases
.filter(release => release.draft) // comment out for testing
// .filter(release => release.tag_name === 'v1.7.5') // uncomment for testing
check(drafts.length === 1, 'one draft exists', true)
const draft = drafts[0]
check(draft.tag_name === `v${pkg.version}`, `draft release version matches local package.json (v${pkg.version})`)
check(draft.prerelease, 'draft is a prerelease')
check(draft.body.length > 50 && !draft.body.includes('(placeholder)'), 'draft has release notes')
const requiredAssets = assetsForVersion(draft.tag_name).sort()
const extantAssets = draft.assets.map(asset => asset.name).sort()
requiredAssets.forEach(asset => {
check(extantAssets.includes(asset), asset)
})
const s3Urls = s3UrlsForVersion(draft.tag_name)
heads(s3Urls)
.then(results => {
results.forEach((result, i) => {
check(result === 200, s3Urls[i])
})
process.exit(failureCount > 0 ? 1 : 0)
})
.catch(err => {
console.error('Error making HEAD requests for S3 assets')
console.error(err)
process.exit(1)
})
})
function check (condition, statement, exitIfFail = false) {
if (condition) {
console.log(`${pass} ${statement}`)
} else {
failureCount++
console.log(`${fail} ${statement}`)
if (exitIfFail) process.exit(1)
}
}
function assetsForVersion (version) {
const patterns = [
'electron-{{VERSION}}-darwin-x64-dsym.zip',
'electron-{{VERSION}}-darwin-x64-symbols.zip',
'electron-{{VERSION}}-darwin-x64.zip',
'electron-{{VERSION}}-linux-arm-symbols.zip',
'electron-{{VERSION}}-linux-arm.zip',
'electron-{{VERSION}}-linux-armv7l-symbols.zip',
'electron-{{VERSION}}-linux-armv7l.zip',
'electron-{{VERSION}}-linux-ia32-symbols.zip',
'electron-{{VERSION}}-linux-ia32.zip',
'electron-{{VERSION}}-linux-x64-symbols.zip',
'electron-{{VERSION}}-linux-x64.zip',
'electron-{{VERSION}}-mas-x64-dsym.zip',
'electron-{{VERSION}}-mas-x64-symbols.zip',
'electron-{{VERSION}}-mas-x64.zip',
'electron-{{VERSION}}-win32-ia32-pdb.zip',
'electron-{{VERSION}}-win32-ia32-symbols.zip',
'electron-{{VERSION}}-win32-ia32.zip',
'electron-{{VERSION}}-win32-x64-pdb.zip',
'electron-{{VERSION}}-win32-x64-symbols.zip',
'electron-{{VERSION}}-win32-x64.zip',
'electron-api.json',
'electron.d.ts',
'ffmpeg-{{VERSION}}-darwin-x64.zip',
'ffmpeg-{{VERSION}}-linux-arm.zip',
'ffmpeg-{{VERSION}}-linux-armv7l.zip',
'ffmpeg-{{VERSION}}-linux-ia32.zip',
'ffmpeg-{{VERSION}}-linux-x64.zip',
'ffmpeg-{{VERSION}}-mas-x64.zip',
'ffmpeg-{{VERSION}}-win32-ia32.zip',
'ffmpeg-{{VERSION}}-win32-x64.zip'
]
return patterns.map(pattern => pattern.replace(/{{VERSION}}/g, version))
}
function s3UrlsForVersion (version) {
const bucket = 'https://gh-contractor-zcbenz.s3.amazonaws.com/'
const patterns = [
'atom-shell/dist/{{VERSION}}/iojs-{{VERSION}}-headers.tar.gz',
'atom-shell/dist/{{VERSION}}/iojs-{{VERSION}}.tar.gz',
'atom-shell/dist/{{VERSION}}/node-{{VERSION}}.tar.gz',
'atom-shell/dist/{{VERSION}}/node.lib',
'atom-shell/dist/{{VERSION}}/win-x64/iojs.lib',
'atom-shell/dist/{{VERSION}}/win-x86/iojs.lib',
'atom-shell/dist/{{VERSION}}/x64/node.lib',
'atom-shell/dist/index.json'
]
return patterns.map(pattern => bucket + pattern.replace(/{{VERSION}}/g, version))
}

125
script/publish-to-npm.js Normal file
View File

@@ -0,0 +1,125 @@
const temp = require('temp')
const fs = require('fs')
const path = require('path')
const childProcess = require('child_process')
const GitHubApi = require('github')
const request = require('request')
const assert = require('assert')
const rootPackageJson = require('../package.json')
const github = new GitHubApi({
// debug: true,
headers: { 'User-Agent': 'electron-npm-publisher' },
followRedirects: false
})
let tempDir
temp.track() // track and cleanup files at exit
const files = [
'cli.js',
'index.js',
'install.js',
'package.json',
'README.md'
]
const jsonFields = [
'name',
'version',
'repository',
'description',
'license',
'author',
'keywords'
]
let npmTag = ''
new Promise((resolve, reject) => {
temp.mkdir('electron-npm', (err, dirPath) => {
if (err) {
reject(err)
} else {
resolve(dirPath)
}
})
})
.then((dirPath) => {
tempDir = dirPath
// copy files from `/npm` to temp directory
files.forEach((name) => {
fs.writeFileSync(
path.join(tempDir, name),
fs.readFileSync(path.join(__dirname, '..', name === 'README.md' ? '' : 'npm', name))
)
})
// copy from root package.json to temp/package.json
const packageJson = require(path.join(tempDir, 'package.json'))
jsonFields.forEach((fieldName) => {
packageJson[fieldName] = rootPackageJson[fieldName]
})
fs.writeFileSync(
path.join(tempDir, 'package.json'),
JSON.stringify(packageJson, null, 2)
)
return github.repos.getReleases({
owner: 'electron',
repo: 'electron'
})
})
.then((releases) => {
// download electron.d.ts from release
const release = releases.data.find(
(release) => release.tag_name === `v${rootPackageJson.version}`
)
if (!release) {
throw new Error(`cannot find release with tag v${rootPackageJson.version}`)
}
return release
})
.then((release) => {
const tsdAsset = release.assets.find((asset) => asset.name === 'electron.d.ts')
if (!tsdAsset) {
throw new Error(`cannot find electron.d.ts from v${rootPackageJson.version} release assets`)
}
return new Promise((resolve, reject) => {
request.get({
url: tsdAsset.url,
headers: {
'accept': 'application/octet-stream',
'user-agent': 'electron-npm-publisher'
}
}, (err, response, body) => {
if (err || response.statusCode !== 200) {
reject(err || new Error('Cannot download electron.d.ts'))
} else {
fs.writeFileSync(path.join(tempDir, 'electron.d.ts'), body)
resolve(release)
}
})
})
})
.then((release) => {
npmTag = release.prerelease ? 'beta' : 'latest'
})
.then(() => childProcess.execSync('npm pack', { cwd: tempDir }))
.then(() => {
// test that the package can install electron prebuilt from github release
const tarballPath = path.join(tempDir, `${rootPackageJson.name}-${rootPackageJson.version}.tgz`)
return new Promise((resolve, reject) => {
childProcess.execSync(`npm install ${tarballPath} --force --silent`, {
env: Object.assign({}, process.env, { electron_config_cache: tempDir }),
cwd: tempDir
})
const checkVersion = childProcess.execSync(`${path.join(tempDir, 'node_modules', '.bin', 'electron')} -v`)
assert.strictEqual(checkVersion.toString().trim(), `v${rootPackageJson.version}`)
resolve(tarballPath)
})
})
.then((tarballPath) => childProcess.execSync(`npm publish ${tarballPath} --tag ${npmTag}`))
.catch((err) => {
console.error(`Error: ${err}`)
process.exit(1)
})

456
script/release.js Executable file
View File

@@ -0,0 +1,456 @@
#!/usr/bin/env node
require('colors')
const args = require('minimist')(process.argv.slice(2))
const assert = require('assert')
const fs = require('fs')
const { execSync } = require('child_process')
const GitHub = require('github')
const { GitProcess } = require('dugite')
const nugget = require('nugget')
const pkg = require('../package.json')
const pkgVersion = `v${pkg.version}`
const pass = '\u2713'.green
const path = require('path')
const fail = '\u2717'.red
const sumchecker = require('sumchecker')
const temp = require('temp').track()
const { URL } = require('url')
let failureCount = 0
assert(process.env.ELECTRON_GITHUB_TOKEN, 'ELECTRON_GITHUB_TOKEN not found in environment')
const github = new GitHub({
followRedirects: false
})
github.authenticate({type: 'token', token: process.env.ELECTRON_GITHUB_TOKEN})
const gitDir = path.resolve(__dirname, '..')
async function getDraftRelease (version, skipValidation) {
let releaseInfo = await github.repos.getReleases({owner: 'electron', repo: 'electron'})
let drafts
let versionToCheck
if (version) {
versionToCheck = version
} else {
versionToCheck = pkgVersion
}
drafts = releaseInfo.data
.filter(release => release.tag_name === versionToCheck &&
release.draft === true)
const draft = drafts[0]
if (!skipValidation) {
failureCount = 0
check(drafts.length === 1, 'one draft exists', true)
if (versionToCheck.indexOf('beta') > -1) {
check(draft.prerelease, 'draft is a prerelease')
}
check(draft.body.length > 50 && !draft.body.includes('(placeholder)'), 'draft has release notes')
check((failureCount === 0), `Draft release looks good to go.`, true)
}
return draft
}
async function validateReleaseAssets (release) {
const requiredAssets = assetsForVersion(release.tag_name).sort()
const extantAssets = release.assets.map(asset => asset.name).sort()
const downloadUrls = release.assets.map(asset => asset.browser_download_url).sort()
failureCount = 0
requiredAssets.forEach(asset => {
check(extantAssets.includes(asset), asset)
})
check((failureCount === 0), `All required GitHub assets exist for release`, true)
if (release.draft) {
await verifyAssets(release)
} else {
await verifyShasums(downloadUrls)
.catch(err => {
console.log(`${fail} error verifyingShasums`, err)
})
}
const s3Urls = s3UrlsForVersion(release.tag_name)
await verifyShasums(s3Urls, true)
}
function check (condition, statement, exitIfFail = false) {
if (condition) {
console.log(`${pass} ${statement}`)
} else {
failureCount++
console.log(`${fail} ${statement}`)
if (exitIfFail) process.exit(1)
}
}
function assetsForVersion (version) {
const patterns = [
`electron-${version}-darwin-x64-dsym.zip`,
`electron-${version}-darwin-x64-symbols.zip`,
`electron-${version}-darwin-x64.zip`,
`electron-${version}-linux-arm-symbols.zip`,
`electron-${version}-linux-arm.zip`,
`electron-${version}-linux-armv7l-symbols.zip`,
`electron-${version}-linux-armv7l.zip`,
`electron-${version}-linux-ia32-symbols.zip`,
`electron-${version}-linux-ia32.zip`,
`electron-${version}-linux-x64-symbols.zip`,
`electron-${version}-linux-x64.zip`,
`electron-${version}-mas-x64-dsym.zip`,
`electron-${version}-mas-x64-symbols.zip`,
`electron-${version}-mas-x64.zip`,
`electron-${version}-win32-ia32-pdb.zip`,
`electron-${version}-win32-ia32-symbols.zip`,
`electron-${version}-win32-ia32.zip`,
`electron-${version}-win32-x64-pdb.zip`,
`electron-${version}-win32-x64-symbols.zip`,
`electron-${version}-win32-x64.zip`,
`electron-api.json`,
`electron.d.ts`,
`ffmpeg-${version}-darwin-x64.zip`,
`ffmpeg-${version}-linux-arm.zip`,
`ffmpeg-${version}-linux-armv7l.zip`,
`ffmpeg-${version}-linux-ia32.zip`,
`ffmpeg-${version}-linux-x64.zip`,
`ffmpeg-${version}-mas-x64.zip`,
`ffmpeg-${version}-win32-ia32.zip`,
`ffmpeg-${version}-win32-x64.zip`,
`SHASUMS256.txt`
]
return patterns
}
function s3UrlsForVersion (version) {
const bucket = `https://gh-contractor-zcbenz.s3.amazonaws.com/`
const patterns = [
`${bucket}atom-shell/dist/${version}/iojs-${version}-headers.tar.gz`,
`${bucket}atom-shell/dist/${version}/iojs-${version}.tar.gz`,
`${bucket}atom-shell/dist/${version}/node-${version}.tar.gz`,
`${bucket}atom-shell/dist/${version}/node.lib`,
`${bucket}atom-shell/dist/${version}/win-x64/iojs.lib`,
`${bucket}atom-shell/dist/${version}/win-x86/iojs.lib`,
`${bucket}atom-shell/dist/${version}/x64/node.lib`,
`${bucket}atom-shell/dist/${version}/SHASUMS.txt`,
`${bucket}atom-shell/dist/${version}/SHASUMS256.txt`,
`${bucket}atom-shell/dist/index.json`
]
return patterns
}
function checkVersion () {
console.log(`Verifying that app version matches package version ${pkgVersion}.`)
let startScript = path.join(__dirname, 'start.py')
let appVersion = runScript(startScript, ['--version']).trim()
check((pkgVersion.indexOf(appVersion) === 0), `App version ${appVersion} matches ` +
`package version ${pkgVersion}.`, true)
}
function runScript (scriptName, scriptArgs, cwd) {
let scriptCommand = `${scriptName} ${scriptArgs.join(' ')}`
let scriptOptions = {
encoding: 'UTF-8'
}
if (cwd) {
scriptOptions.cwd = cwd
}
try {
return execSync(scriptCommand, scriptOptions)
} catch (err) {
console.log(`${fail} Error running ${scriptName}`, err)
process.exit(1)
}
}
function uploadNodeShasums () {
console.log('Uploading Node SHASUMS file to S3.')
let scriptPath = path.join(__dirname, 'upload-node-checksums.py')
runScript(scriptPath, ['-v', pkgVersion])
console.log(`${pass} Done uploading Node SHASUMS file to S3.`)
}
function uploadIndexJson () {
console.log('Uploading index.json to S3.')
let scriptPath = path.join(__dirname, 'upload-index-json.py')
runScript(scriptPath, [])
console.log(`${pass} Done uploading index.json to S3.`)
}
async function createReleaseShasums (release) {
let fileName = 'SHASUMS256.txt'
let existingAssets = release.assets.filter(asset => asset.name === fileName)
if (existingAssets.length > 0) {
console.log(`${fileName} already exists on GitHub; deleting before creating new file.`)
await github.repos.deleteAsset({
owner: 'electron',
repo: 'electron',
id: existingAssets[0].id
}).catch(err => {
console.log(`${fail} Error deleting ${fileName} on GitHub:`, err)
})
}
console.log(`Creating and uploading the release ${fileName}.`)
let scriptPath = path.join(__dirname, 'merge-electron-checksums.py')
let checksums = runScript(scriptPath, ['-v', pkgVersion])
console.log(`${pass} Generated release SHASUMS.`)
let filePath = await saveShaSumFile(checksums, fileName)
console.log(`${pass} Created ${fileName} file.`)
await uploadShasumFile(filePath, fileName, release)
console.log(`${pass} Successfully uploaded ${fileName} to GitHub.`)
}
async function uploadShasumFile (filePath, fileName, release) {
let githubOpts = {
owner: 'electron',
repo: 'electron',
id: release.id,
filePath,
name: fileName
}
return github.repos.uploadAsset(githubOpts)
.catch(err => {
console.log(`${fail} Error uploading ${filePath} to GitHub:`, err)
process.exit(1)
})
}
function saveShaSumFile (checksums, fileName) {
return new Promise((resolve, reject) => {
temp.open(fileName, (err, info) => {
if (err) {
console.log(`${fail} Could not create ${fileName} file`)
process.exit(1)
} else {
fs.writeFileSync(info.fd, checksums)
fs.close(info.fd, (err) => {
if (err) {
console.log(`${fail} Could close ${fileName} file`)
process.exit(1)
}
resolve(info.path)
})
}
})
})
}
async function publishRelease (release) {
let githubOpts = {
owner: 'electron',
repo: 'electron',
id: release.id,
tag_name: release.tag_name,
draft: false
}
return github.repos.editRelease(githubOpts)
.catch(err => {
console.log(`${fail} Error publishing release:`, err)
process.exit(1)
})
}
async function makeRelease (releaseToValidate) {
if (releaseToValidate) {
console.log(`Validating release ${args.validateRelease}`)
let release = await getDraftRelease(args.validateRelease)
await validateReleaseAssets(release)
} else {
checkVersion()
let draftRelease = await getDraftRelease()
uploadNodeShasums()
uploadIndexJson()
await createReleaseShasums(draftRelease)
// Fetch latest version of release before verifying
draftRelease = await getDraftRelease(pkgVersion, true)
await validateReleaseAssets(draftRelease)
await publishRelease(draftRelease)
await cleanupReleaseBranch()
console.log(`${pass} SUCCESS!!! Release has been published. Please run ` +
`"npm run publish-to-npm" to publish release to npm.`)
}
}
async function makeTempDir () {
return new Promise((resolve, reject) => {
temp.mkdir('electron-publish', (err, dirPath) => {
if (err) {
reject(err)
} else {
resolve(dirPath)
}
})
})
}
async function verifyAssets (release) {
let downloadDir = await makeTempDir()
let githubOpts = {
owner: 'electron',
repo: 'electron',
headers: {
Accept: 'application/octet-stream'
}
}
console.log(`Downloading files from GitHub to verify shasums`)
let shaSumFile = 'SHASUMS256.txt'
let filesToCheck = await Promise.all(release.assets.map(async (asset) => {
githubOpts.id = asset.id
let assetDetails = await github.repos.getAsset(githubOpts)
await downloadFiles(assetDetails.meta.location, downloadDir, false, asset.name)
return asset.name
})).catch(err => {
console.log(`${fail} Error downloading files from GitHub`, err)
process.exit(1)
})
filesToCheck = filesToCheck.filter(fileName => fileName !== shaSumFile)
let checkerOpts
await validateChecksums({
algorithm: 'sha256',
filesToCheck,
fileDirectory: downloadDir,
shaSumFile,
checkerOpts,
fileSource: 'GitHub'
})
}
function downloadFiles (urls, directory, quiet, targetName) {
return new Promise((resolve, reject) => {
let nuggetOpts = {
dir: directory
}
if (quiet) {
nuggetOpts.quiet = quiet
}
if (targetName) {
nuggetOpts.target = targetName
}
nugget(urls, nuggetOpts, (err) => {
if (err) {
reject(err)
} else {
resolve()
}
})
})
}
async function verifyShasums (urls, isS3) {
let fileSource = isS3 ? 'S3' : 'GitHub'
console.log(`Downloading files from ${fileSource} to verify shasums`)
let downloadDir = await makeTempDir()
let filesToCheck = []
try {
if (!isS3) {
await downloadFiles(urls, downloadDir)
filesToCheck = urls.map(url => {
let currentUrl = new URL(url)
return path.basename(currentUrl.pathname)
}).filter(file => file.indexOf('SHASUMS') === -1)
} else {
const s3VersionPath = `/atom-shell/dist/${pkgVersion}/`
await Promise.all(urls.map(async (url) => {
let currentUrl = new URL(url)
let dirname = path.dirname(currentUrl.pathname)
let filename = path.basename(currentUrl.pathname)
let s3VersionPathIdx = dirname.indexOf(s3VersionPath)
if (s3VersionPathIdx === -1 || dirname === s3VersionPath) {
if (s3VersionPathIdx !== -1 && filename.indexof('SHASUMS') === -1) {
filesToCheck.push(filename)
}
await downloadFiles(url, downloadDir, true)
} else {
let subDirectory = dirname.substr(s3VersionPathIdx + s3VersionPath.length)
let fileDirectory = path.join(downloadDir, subDirectory)
try {
fs.statSync(fileDirectory)
} catch (err) {
fs.mkdirSync(fileDirectory)
}
filesToCheck.push(path.join(subDirectory, filename))
await downloadFiles(url, fileDirectory, true)
}
}))
}
} catch (err) {
console.log(`${fail} Error downloading files from ${fileSource}`, err)
process.exit(1)
}
console.log(`${pass} Successfully downloaded the files from ${fileSource}.`)
let checkerOpts
if (isS3) {
checkerOpts = { defaultTextEncoding: 'binary' }
}
await validateChecksums({
algorithm: 'sha256',
filesToCheck,
fileDirectory: downloadDir,
shaSumFile: 'SHASUMS256.txt',
checkerOpts,
fileSource
})
if (isS3) {
await validateChecksums({
algorithm: 'sha1',
filesToCheck,
fileDirectory: downloadDir,
shaSumFile: 'SHASUMS.txt',
checkerOpts,
fileSource
})
}
}
async function validateChecksums (validationArgs) {
console.log(`Validating checksums for files from ${validationArgs.fileSource} ` +
`against ${validationArgs.shaSumFile}.`)
let shaSumFilePath = path.join(validationArgs.fileDirectory, validationArgs.shaSumFile)
let checker = new sumchecker.ChecksumValidator(validationArgs.algorithm,
shaSumFilePath, validationArgs.checkerOpts)
await checker.validate(validationArgs.fileDirectory, validationArgs.filesToCheck)
.catch(err => {
if (err instanceof sumchecker.ChecksumMismatchError) {
console.error(`${fail} The checksum of ${err.filename} from ` +
`${validationArgs.fileSource} did not match the shasum in ` +
`${validationArgs.shaSumFile}`)
} else if (err instanceof sumchecker.ChecksumParseError) {
console.error(`${fail} The checksum file ${validationArgs.shaSumFile} ` +
`from ${validationArgs.fileSource} could not be parsed.`, err)
} else if (err instanceof sumchecker.NoChecksumFoundError) {
console.error(`${fail} The file ${err.filename} from ` +
`${validationArgs.fileSource} was not in the shasum file ` +
`${validationArgs.shaSumFile}.`)
} else {
console.error(`${fail} Error matching files from ` +
`${validationArgs.fileSource} shasums in ${validationArgs.shaSumFile}.`, err)
}
process.exit(1)
})
console.log(`${pass} All files from ${validationArgs.fileSource} match ` +
`shasums defined in ${validationArgs.shaSumFile}.`)
}
async function cleanupReleaseBranch () {
console.log(`Cleaning up release branch.`)
let errorMessage = `Could not delete local release branch.`
let successMessage = `Successfully deleted local release branch.`
await callGit(['branch', '-D', 'release-1-6-x'], errorMessage, successMessage)
errorMessage = `Could not delete remote release branch.`
successMessage = `Successfully deleted remote release branch.`
return callGit(['push', 'origin', ':release'], errorMessage, successMessage)
}
async function callGit (args, errorMessage, successMessage) {
let gitResult = await GitProcess.exec(args, gitDir)
if (gitResult.exitCode === 0) {
console.log(`${pass} ${successMessage}`)
return true
} else {
console.log(`${fail} ${errorMessage} ${gitResult.stderr}`)
process.exit(1)
}
}
makeRelease(args.validateRelease)

View File

@@ -0,0 +1,51 @@
const GitHub = require('github')
const github = new GitHub()
github.authenticate({type: 'token', token: process.env.ELECTRON_GITHUB_TOKEN})
if (process.argv.length < 5) {
console.log('Usage: upload-to-github filePath fileName releaseId')
process.exit(1)
}
let filePath = process.argv[2]
let fileName = process.argv[3]
let releaseId = process.argv[4]
let githubOpts = {
owner: 'electron',
repo: 'electron',
id: releaseId,
filePath: filePath,
name: fileName
}
let retry = 0
function uploadToGitHub () {
github.repos.uploadAsset(githubOpts).then(() => {
console.log(`Successfully uploaded ${fileName} to GitHub.`)
process.exit()
}).catch((err) => {
if (retry < 4) {
console.log(`Error uploading ${fileName} to GitHub, will retry. Error was:`, err)
retry++
github.repos.getRelease(githubOpts).then(release => {
let existingAssets = release.data.assets.filter(asset => asset.name === fileName)
if (existingAssets.length > 0) {
console.log(`${fileName} already exists; will delete before retrying upload.`)
github.repos.deleteAsset({
owner: 'electron',
repo: 'electron',
id: existingAssets[0].id
}).then(uploadToGitHub).catch(uploadToGitHub)
} else {
uploadToGitHub()
}
})
} else {
console.log(`Error retrying uploading ${fileName} to GitHub:`, err)
process.exitCode = 1
}
})
}
uploadToGitHub()

View File

@@ -67,7 +67,7 @@ def main():
run_python_script('upload-index-json.py')
# Create and upload the Electron SHASUMS*.txt
release_electron_checksums(github, release)
release_electron_checksums(release)
# Press the publish button.
publish_release(github, release['id'])
@@ -172,7 +172,7 @@ def get_text_with_editor(name):
def create_or_get_release_draft(github, releases, tag, tag_exists):
# Search for existing draft.
for release in releases:
if release['draft']:
if release['draft'] and release['tag_name'] == tag:
return release
if tag_exists:
@@ -189,17 +189,20 @@ def create_release_draft(github, tag):
if body == '':
sys.stderr.write('Quit due to empty release note.\n')
sys.exit(0)
data = dict(tag_name=tag, name=name, body=body, draft=True)
data = dict(tag_name=tag, name=name, body=body, draft=True,
target_commitish='1-6-x')
r = github.repos(ELECTRON_REPO).releases.post(data=data)
return r
def release_electron_checksums(github, release):
def release_electron_checksums(release):
checksums = run_python_script('merge-electron-checksums.py',
'-v', ELECTRON_VERSION)
upload_io_to_github(github, release, 'SHASUMS256.txt',
StringIO(checksums.decode('utf-8')), 'text/plain')
filename = 'SHASUMS256.txt'
filepath = os.path.join(SOURCE_ROOT, filename)
with open(filepath, 'w') as sha_file:
sha_file.write(checksums.decode('utf-8'))
upload_io_to_github(release, filename, filepath)
def upload_electron(github, release, file_path):
@@ -214,8 +217,7 @@ def upload_electron(github, release, file_path):
pass
# Upload the file.
with open(file_path, 'rb') as f:
upload_io_to_github(github, release, filename, f, 'application/zip')
upload_io_to_github(release, filename, file_path)
# Upload the checksum file.
upload_sha256_checksum(release['tag_name'], file_path)
@@ -229,11 +231,11 @@ def upload_electron(github, release, file_path):
upload_electron(github, release, arm_file_path)
def upload_io_to_github(github, release, name, io, content_type):
params = {'name': name}
headers = {'Content-Type': content_type}
github.repos(ELECTRON_REPO).releases(release['id']).assets.post(
params=params, headers=headers, data=io, verify=False)
def upload_io_to_github(release, filename, filepath):
print 'Uploading %s to Github' % \
(filename)
script_path = os.path.join(SOURCE_ROOT, 'script', 'upload-to-github.js')
execute(['node', script_path, filepath, filename, str(release['id'])])
def upload_sha256_checksum(version, file_path):

View File

@@ -208,7 +208,7 @@ describe('app module', function () {
})
})
describe('app.importCertificate', function () {
xdescribe('app.importCertificate', function () {
if (process.platform !== 'linux') return
var w = null
@@ -405,7 +405,7 @@ describe('app module', function () {
})
})
describe('select-client-certificate event', function () {
xdescribe('select-client-certificate event', function () {
let w = null
beforeEach(function () {
@@ -469,6 +469,54 @@ describe('app module', function () {
})
})
describe('app launch through uri', () => {
before(function () {
if (process.platform !== 'win32') {
this.skip()
}
})
it('does not launch for blacklisted argument', function (done) {
const appPath = path.join(__dirname, 'fixtures', 'api', 'quit-app')
// App should exit with non 123 code.
const first = ChildProcess.spawn(remote.process.execPath, [appPath, 'electron-test://?', '--no-sandbox', '--gpu-launcher=cmd.exe /c start calc'])
first.once('exit', (code) => {
assert.notEqual(code, 123)
done()
})
})
it('launches successfully for multiple uris in cmd args', function (done) {
const appPath = path.join(__dirname, 'fixtures', 'api', 'quit-app')
// App should exit with code 123.
const first = ChildProcess.spawn(remote.process.execPath, [appPath, 'http://electronjs.org', 'electron-test://testdata'])
first.once('exit', (code) => {
assert.equal(code, 123)
done()
})
})
it('does not launch for encoded space', function (done) {
const appPath = path.join(__dirname, 'fixtures', 'api', 'quit-app')
// App should exit with non 123 code.
const first = ChildProcess.spawn(remote.process.execPath, [appPath, 'electron-test://?', '--no-sandbox', '--gpu-launcher%20"cmd.exe /c start calc'])
first.once('exit', (code) => {
assert.notEqual(code, 123)
done()
})
})
it('launches successfully for argnames similar to blacklisted ones', function (done) {
const appPath = path.join(__dirname, 'fixtures', 'api', 'quit-app')
// inspect is blacklisted, but inspector should work, and app launch should succeed
const first = ChildProcess.spawn(remote.process.execPath, [appPath, 'electron-test://?', '--inspector'])
first.once('exit', (code) => {
assert.equal(code, 123)
done()
})
})
})
describe('getFileIcon() API', function () {
// FIXME Get these specs running on Linux CI
if (process.platform === 'linux' && isCI) return