Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Codespaces #341

Merged
merged 24 commits into from
Jul 18, 2022
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
a4c4dbc
Allow "altis.dev" TLD to be configured
joehoyle Nov 29, 2020
0fdce48
Update inc/namespace.php
joehoyle Dec 4, 2020
ba2827f
Update inc/composer/class-command.php
joehoyle Dec 4, 2020
f165a39
Merge branch 'master' into configure-tld
Jun 14, 2021
7ee71d4
Support empty TLDs (eg localhost)
rmccue Sep 4, 2021
5729a48
Avoid configuring bad S3 host if TLD is empty
rmccue Sep 6, 2021
e2e29ce
Use Codespaces host if available
rmccue Sep 6, 2021
6f07264
Add Codespaces helper method
rmccue Sep 19, 2021
1ce9e34
Fix S3 behaviour by setting domain explicitly
rmccue Sep 19, 2021
68a6348
Enable Codespaces integration by default
rmccue Sep 19, 2021
661f471
Use forwarded host when on Codespaces
rmccue Mar 6, 2022
a511e28
Merge remote-tracking branch 'origin/master' into support-codespaces
shadyvb May 6, 2022
7c79864
Merge branch '477/skip-self-ssl-validation' into support-codespaces
shadyvb May 9, 2022
885abdb
Merge remote-tracking branch 'origin/master' into support-codespaces
shadyvb May 13, 2022
8b5b5d4
Fix tachyon and s3 uploads
shadyvb May 13, 2022
b291d4c
Do not attempt generating SSL on Codespaces
shadyvb May 16, 2022
ef268b6
Fix secure bit detection
shadyvb May 16, 2022
a2781ea
Use explicit S3 endpoint URLs for Tachyon
shadyvb May 17, 2022
4cd650e
Use modified URL explicitly to fix Tachyon URLs in Codespaces
shadyvb May 17, 2022
337cbf7
:nail_care: Ignore CS rule
shadyvb May 17, 2022
7dc1b35
Update tachyon image version
shadyvb May 17, 2022
89a906b
Remove the double slash
shadyvb May 17, 2022
eacbd85
Remove obsolete todo comment.
shadyvb May 23, 2022
1e62153
Merge remote-tracking branch 'origin/master' into support-codespaces
shadyvb Jul 18, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion docker/conf/traefik.toml
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,6 @@ address = ":8080"
# Optional
# Default: ""
#
domain = "altis.dev"

# Expose containers by default in traefik
#
Expand Down
78 changes: 56 additions & 22 deletions inc/composer/class-command.php
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ protected function execute( InputInterface $input, OutputInterface $output ) : i
'xdebug' => 'off',
'mutagen' => 'off',
'tmp' => false,
'secure' => $this->get_composer_config()['secure'] ?? true,
'secure' => static::get_composer_config()['secure'] ?? true,
];

// If Xdebug switch is passed add to docker compose args.
Expand Down Expand Up @@ -232,8 +232,9 @@ protected function start( InputInterface $input, OutputInterface $output ) {
return 1;
}

// Generate SSL certificate if not found.
if ( ! file_exists( 'vendor/ssl-cert.pem' ) ) {
// Generate SSL certificate if not found, and the secure flag is turned on.
$is_secure = $this->is_using_codespaces() ? false : static::get_composer_config()['secure'] ?? true;
if ( $is_secure && ! file_exists( 'vendor/ssl-cert.pem' ) ) {
// Create the certificate programmatically.
$not_generated = $this->getApplication()->find( 'local-server' )->run( new ArrayInput( [
'subcommand' => 'ssl',
Expand Down Expand Up @@ -955,7 +956,7 @@ protected function check_host_entries( InputInterface $input, OutputInterface $o
* @return void
*/
protected function generate_docker_compose( array $args = [] ) : void {
$docker_compose = new Docker_Compose_Generator( $this->get_project_subdomain(), getcwd(), $this->get_project_tld(), $args );
$docker_compose = new Docker_Compose_Generator( getcwd(), $this->get_project_subdomain(), $this->get_project_tld(), $this->get_project_url(), $args );
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_file_put_contents
file_put_contents(
getcwd() . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'docker-compose.yml',
Expand Down Expand Up @@ -1065,7 +1066,7 @@ protected function minio_client( string $command ) {
*
* @return array
*/
protected function get_composer_config() : array {
protected static function get_composer_config() : array {
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
$composer_json = json_decode( file_get_contents( getcwd() . '/composer.json' ), true );
$config = $composer_json['extra']['altis']['modules']['local-server'] ?? [];
Expand All @@ -1079,6 +1080,10 @@ protected function get_composer_config() : array {
* @return string
*/
protected function get_project_tld() : string {
if ( $this->is_using_codespaces() ) {
return '';
}

$config = $this->get_composer_config();

if ( isset( $config['tld'] ) ) {
Expand All @@ -1095,33 +1100,39 @@ protected function get_project_tld() : string {
*
* @return string
*/
protected function get_project_subdomain() : string {
protected function get_project_url() : string {
$config = $this->get_composer_config();

if ( isset( $config['name'] ) ) {
$project_name = $config['name'];
} else {
$project_name = basename( getcwd() );
if ( $this->is_using_codespaces() ) {
return 'https://' . getenv( 'CODESPACE_NAME' ) . '-80.githubpreview.dev/';
}

return preg_replace( '/[^A-Za-z0-9\-\_]/', '', $project_name );
$tld = $this->get_project_tld();
$site_url = sprintf( static::set_url_scheme( 'https://%s%s/' ),
$this->get_project_subdomain(),
$tld ? '.' . $tld : ''
);
return $site_url;
}

/**
* Get the name of the project for the local subdomain
*
* @return string
*/
protected function get_project_url() : string {
$is_secure = $this->get_composer_config()['secure'] ?? true;
$tld = $this->get_project_tld();
$site_url = sprintf(
'http%s://%s%s/',
$is_secure ? 's' : '',
$this->get_project_subdomain(),
$tld ? '.' . $tld : ''
);
return $site_url;
protected function get_project_subdomain() : string {
if ( $this->is_using_codespaces() ) {
return 'localhost';
}

$config = $this->get_composer_config();

if ( isset( $config['name'] ) ) {
$project_name = $config['name'];
} else {
$project_name = basename( getcwd() );
}

return preg_replace( '/[^A-Za-z0-9\-\_]/', '', $project_name );
}

/**
Expand Down Expand Up @@ -1160,6 +1171,16 @@ public static function is_macos() : bool {
return php_uname( 's' ) === 'Darwin';
}

/**
* Check if within Codespaces environment, and that Codespaces integration is activated.
*
* @return boolean
*/
public static function is_using_codespaces() : bool {
$config = static::get_composer_config();
return getenv( 'CODESPACES' ) === 'true' && ( $config['codespaces_integration'] ?? true );
}

/**
* Check if the current host is Windows.
*
Expand Down Expand Up @@ -1217,4 +1238,17 @@ protected function get_compose_command( string $command = '', bool $mutagen = fa
);
}

/**
* Convert URLs to secure or non-secure based on configurations.
*
* @param string $url URL to update the scheme for.
*
* @return string
*/
public static function set_url_scheme( $url ) {
$is_secure = static::get_composer_config()['secure'] ?? ! static::is_using_codespaces();

return preg_replace( '/^https?/', 'http' . ( $is_secure ? 's' : '' ), $url );
}

}
35 changes: 23 additions & 12 deletions inc/composer/class-docker-compose-generator.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ class Docker_Compose_Generator {
*/
protected $hostname;

/**
* The client facing domain name for the project.
*
* @var string
*/
protected $url;

/**
* An array of data passed to
*
Expand All @@ -59,17 +66,19 @@ class Docker_Compose_Generator {
/**
* Create and configure the generator.
*
* @param string $project_name The docker compose project name.
* @param string $root_dir The project root directory.
* @param string $project_name The docker compose project name.
* @param string $tld The primary top level domain for the server.
* @param string $url The client facing URL.
* @param array $args An optional array of arguments to modify the behaviour of the generator.
roborourke marked this conversation as resolved.
Show resolved Hide resolved
*/
public function __construct( string $project_name, string $root_dir, string $tld, array $args = [] ) {
public function __construct( string $root_dir, string $project_name, string $tld, string $url, array $args = [] ) {
$this->project_name = $project_name;
$this->config_dir = dirname( __DIR__, 2 ) . '/docker';
$this->root_dir = $root_dir;
$this->tld = $tld;
$this->hostname = $this->tld ? $this->project_name . '.' . $this->tld : $this->project_name;
$this->url = $url;
$this->args = $args;
}

Expand Down Expand Up @@ -124,6 +133,7 @@ protected function get_php_reusable() : array {
"proxy:cognito-{$this->hostname}",
"proxy:elasticsearch-{$this->hostname}",
"proxy:s3-{$this->hostname}",
"proxy:s3-{$this->project_name}.localhost",
],
'volumes' => [
$this->get_app_volume(),
Expand Down Expand Up @@ -153,17 +163,17 @@ protected function get_php_reusable() : array {
'ELASTICSEARCH_HOST' => 'elasticsearch',
'ELASTICSEARCH_PORT' => 9200,
'AWS_XRAY_DAEMON_HOST' => 'xray',
'S3_UPLOADS_ENDPOINT' => "https://s3-{$this->hostname}/s3-{$this->project_name}/",
'S3_UPLOADS_ENDPOINT' => Command::set_url_scheme( "https://s3-{$this->hostname}/s3-{$this->project_name}/" ), // TODO .localhost.
shadyvb marked this conversation as resolved.
Show resolved Hide resolved
'S3_UPLOADS_BUCKET' => "s3-{$this->project_name}",
'S3_UPLOADS_BUCKET_URL' => "https://s3-{$this->hostname}",
'S3_UPLOADS_BUCKET_URL' => Command::set_url_scheme( "https://s3-{$this->hostname}" ),
'S3_UPLOADS_KEY' => 'admin',
'S3_UPLOADS_SECRET' => 'password',
'S3_UPLOADS_REGION' => 'us-east-1',
'S3_CONSOLE_URL' => "https://s3-console-{$this->hostname}",
'TACHYON_URL' => "https://{$this->hostname}/tachyon",
'S3_CONSOLE_URL' => Command::set_url_scheme( "https://s3-console-{$this->hostname}" ),
'TACHYON_URL' => Command::set_url_scheme( "{$this->url}tachyon" ),
'PHP_SENDMAIL_PATH' => '/usr/sbin/sendmail -t -i -S mailhog:1025',
'ALTIS_ANALYTICS_PINPOINT_ENDPOINT' => "https://pinpoint-{$this->hostname}",
'ALTIS_ANALYTICS_COGNITO_ENDPOINT' => "https://cognito-{$this->hostname}",
'ALTIS_ANALYTICS_PINPOINT_ENDPOINT' => Command::set_url_scheme( "https://pinpoint-{$this->hostname}" ),
'ALTIS_ANALYTICS_COGNITO_ENDPOINT' => Command::set_url_scheme( "https://cognito-{$this->hostname}" ),
// Enables XDebug for all processes and allows setting remote_host externally for Linux support.
'XDEBUG_CONFIG' => sprintf(
'client_host=%s',
Expand Down Expand Up @@ -508,7 +518,7 @@ protected function get_service_s3() : array {
'default',
],
'environment' => [
'MINIO_DOMAIN' => "s3.localhost,{$this->hostname},s3-{$this->hostname},s3",
'MINIO_DOMAIN' => "s3.localhost,{$this->hostname},s3-{$this->hostname},s3,localhost",
'MINIO_REGION_NAME' => 'us-east-1',
'MINIO_ROOT_USER' => 'admin',
'MINIO_ROOT_PASSWORD' => 'password',
Expand Down Expand Up @@ -536,7 +546,7 @@ protected function get_service_s3() : array {
'traefik.client.port=9000',
'traefik.client.protocol=http',
'traefik.client.frontend.passHostHeader=false',
"traefik.client.frontend.rule=HostRegexp:{$this->hostname},{subdomain:[a-z.-_]+}.{$this->hostname};PathPrefix:/uploads;AddPrefix:/s3-{$this->project_name}",
"traefik.client.frontend.rule=HostRegexp:{$this->hostname},{subdomain:[a-z.-_]+}.{$this->hostname},s3-{$this->hostname},localhost,s3-{$this->project_name}.localhost;PathPrefix:/uploads;AddPrefix:/s3-{$this->project_name}",
"traefik.domain=s3-{$this->hostname},s3-console-{$this->hostname}",
],
],
Expand Down Expand Up @@ -569,7 +579,7 @@ protected function get_service_s3() : array {
protected function get_service_tachyon() : array {
return [
'tachyon' => [
'image' => 'humanmade/tachyon:v2.4.0',
'image' => 'humanmade/tachyon:v2.6.0',
'container_name' => "{$this->project_name}-tachyon",
'ports' => [
'8080',
Expand All @@ -586,7 +596,8 @@ protected function get_service_tachyon() : array {
'environment' => [
'AWS_REGION' => 'us-east-1',
'AWS_S3_BUCKET' => "s3-{$this->project_name}",
'AWS_S3_ENDPOINT' => "https://{$this->tld}/s3-{$this->project_name}/",
'AWS_S3_ENDPOINT' => Command::set_url_scheme( "https://s3-{$this->hostname}/" ),
'AWS_S3_CLIENT_ARGS' => 's3BucketEndpoint=true',
'NODE_TLS_REJECT_UNAUTHORIZED' => 0,
],
'external_links' => [
Expand Down
9 changes: 9 additions & 0 deletions inc/namespace.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,15 @@ function bootstrap() {
add_filter( 'altis.search.packages_dir', __NAMESPACE__ . '\\set_search_packages_dir' );
add_filter( 'altis.search.create_package_id', __NAMESPACE__ . '\\set_search_package_id', 10, 3 );

// If we're on Codespaces, the native host will be localhost.
if ( $config['codespaces_integration'] ?? null && $_SERVER['HTTP_HOST'] === 'localhost' ) {
// Use forwarded host if we can.
if ( ! empty( $_SERVER['HTTP_X_FORWARDED_HOST'] ) ) {
// phpcs:ignore HM.Security.ValidatedSanitizedInput
$_SERVER['HTTP_HOST'] = $_SERVER['HTTP_X_FORWARDED_HOST'];
}
}

// Disable HTTPS validation for local URLs.
add_filter( 'https_ssl_verify', __NAMESPACE__ . '\\disable_self_ssl_verification', 10, 2 );
}
Expand Down
1 change: 1 addition & 0 deletions load.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
'analytics' => true,
'elasticsearch' => '7',
'php' => '8.0',
'codespaces_integration' => true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really understand the purpose of this config option.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We detect the CODESPACES environment variable and override a bunch of stuff if it's set. If you didn't want those overrides applied, this allows this to turn those off.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get that much but why wouldn't you want those overrides?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you wanted to set up different domains for testing purposes; without this, there's no way to avoid codespaces overriding the settings, so you wouldn't be able to test other domains/etc.

];
$options = [
'defaults' => $default_settings,
Expand Down