Add Azure DevOps build pipeline (#7096)

This commit is contained in:
Ian Schmitz
2019-05-28 19:12:22 -07:00
committed by GitHub
parent 695ca7576a
commit 7b196fa4d6
17 changed files with 268 additions and 176 deletions

View File

@@ -1,4 +1,4 @@
# Create React App [![Build Status](https://travis-ci.org/facebook/create-react-app.svg?branch=master)](https://travis-ci.org/facebook/create-react-app) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-green.svg)](https://github.com/facebook/create-react-app/pulls)
# Create React App [![Build Status](https://dev.azure.com/facebook/create-react-app/_apis/build/status/facebook.create-react-app?branchName=master)](https://dev.azure.com/facebook/create-react-app/_build/latest?definitionId=1&branchName=master) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-green.svg)](https://github.com/facebook/create-react-app/pulls)
Create React apps with no build configuration.

View File

@@ -0,0 +1,40 @@
#
# Azure Pipelines job for building and testing create-react-app on Linux, Windows, and macOS.
#
parameters:
name: ''
testScript: ''
configurations:
LinuxNode8: { vmImage: 'ubuntu-16.04', nodeVersion: 8.x }
LinuxNode10: { vmImage: 'ubuntu-16.04', nodeVersion: 10.x }
WindowsNode8: { vmImage: 'vs2017-win2016', nodeVersion: 8.x }
WindowsNode10: { vmImage: 'vs2017-win2016', nodeVersion: 10.x }
jobs:
- job: ${{ parameters.name }}
strategy:
matrix:
${{ insert }}: ${{ parameters.configurations }}
pool:
vmImage: $(vmImage)
steps:
- script: |
git config --global core.autocrlf false
git config --global user.name "Create React App"
git config --global user.email "cra@email.com"
displayName: 'Initialize Git config'
- checkout: self
path: create-react-app
- task: NodeTool@0
inputs:
versionSpec: $(nodeVersion)
displayName: 'Install Node.js'
- script: yarn --frozen-lockfile
displayName: 'Run yarn'
- bash: ${{ parameters.testScript }}
displayName: 'Run tests'

78
azure-pipelines.yml Normal file
View File

@@ -0,0 +1,78 @@
#
# Azure Pipelines configuration for building and testing create-react-app on Linux, Windows, and macOS.
#
trigger:
- master
variables:
CI: true
# Overrides the Yarn and NPM cache directories so they are on the same drive as the source. This helps improve build performance on Windows hosted agents.
YARN_CACHE_FOLDER: $(Build.SourcesDirectory)/../yarn-cache
NPM_CONFIG_CACHE: $(Build.SourcesDirectory)/../npm-cache
# Sets TEMP to be on the same drive as the cloned source on Windows. This avoids test scripts that "cd" into a directory under TEMP from failing because this directory is on a different drive from the current directory.
VSTS_OVERWRITE_TEMP: True
# Override Verdaccio package to use. This is temoporary and is needed to avoid socket timeouts on hosted Windows agent (on Azure). This also changes Verdaccio to return a 503 (service unavailable) instead of a 404 (not found) when the connection to the uplink timesout.
VERDACCIO_PACKAGE: https://github.com/willsmythe/verdaccio/releases/download/create-react-app/verdaccio-4.0.0-alpha.8.tgz
# ******************************************************************************
# Simple test suite
# ******************************************************************************
jobs:
- template: azure-pipelines-test-job.yml
parameters:
name: Simple
testScript: tasks/e2e-simple.sh
# ******************************************************************************
# Installs test suite
# ******************************************************************************
- template: azure-pipelines-test-job.yml
parameters:
name: Installs
testScript: tasks/e2e-installs.sh
# ******************************************************************************
# Kitchensink test suite
# ******************************************************************************
- template: azure-pipelines-test-job.yml
parameters:
name: Kitchensink
testScript: tasks/e2e-kitchensink.sh
# ******************************************************************************
# Kitchensink Eject test suite
# ******************************************************************************
- template: azure-pipelines-test-job.yml
parameters:
name: KitchensinkEject
testScript: tasks/e2e-kitchensink-eject.sh
# ******************************************************************************
# Behavior test suite
# ******************************************************************************
- template: azure-pipelines-test-job.yml
parameters:
name: Behavior
testScript: tasks/e2e-behavior.sh
configurations:
LinuxNode8: { vmImage: 'ubuntu-16.04', nodeVersion: 8.x }
LinuxNode10: { vmImage: 'ubuntu-16.04', nodeVersion: 10.x }
WindowsNode8: { vmImage: 'vs2017-win2016', nodeVersion: 8.x }
WindowsNode10: { vmImage: 'vs2017-win2016', nodeVersion: 10.x }
MacNode8: { vmImage: 'macOS-10.13', nodeVersion: 8.x }
MacNode10: { vmImage: 'macOS-10.13', nodeVersion: 10.x }
# ******************************************************************************
# Old Node test suite
# ******************************************************************************
- job: OldNode
pool:
vmImage: ubuntu-16.04
steps:
- task: NodeTool@0
inputs:
versionSpec: 6.x
displayName: 'Install Node.js 6.x'
- bash: tasks/e2e-old-node.sh
displayName: 'Run tests'

View File

@@ -15,18 +15,16 @@ cd "$(dirname "$0")"
# CLI, app, and test module temporary locations
# http://unix.stackexchange.com/a/84980
temp_app_path=`mktemp -d 2>/dev/null || mktemp -d -t 'temp_app_path'`
temp_module_path=`mktemp -d 2>/dev/null || mktemp -d -t 'temp_module_path'`
custom_registry_url=http://localhost:4873
original_npm_registry_url=`npm get registry`
original_yarn_registry_url=`yarn config get registry`
# Load functions for working with local NPM registry (Verdaccio)
source local-registry.sh
function cleanup {
echo 'Cleaning up.'
ps -ef | grep 'verdaccio' | grep -v grep | awk '{print $2}' | xargs kill -9
echo 'Cleaning up.'
ps -ef | grep 'react-scripts' | grep -v grep | awk '{print $2}' | xargs kill -9
cd "$root_path"
npm set registry "$original_npm_registry_url"
yarn config set registry "$original_yarn_registry_url"
# Restore the original NPM and Yarn registry URLs and stop Verdaccio
stopLocalRegistry
}
# Error messages are redirected to stderr
@@ -75,22 +73,11 @@ yarn
# First, publish the monorepo.
# ******************************************************************************
# Start local registry
tmp_registry_log=`mktemp`
(cd && nohup npx verdaccio@3.8.2 -c "$root_path"/tasks/verdaccio.yaml &>$tmp_registry_log &)
# Wait for `verdaccio` to boot
grep -q 'http address' <(tail -f $tmp_registry_log)
# Set registry to local registry
npm set registry "$custom_registry_url"
yarn config set registry "$custom_registry_url"
# Login so we can publish packages
(cd && npx npm-auth-to-token@1.0.0 -u user -p password -e user@example.com -r "$custom_registry_url")
# Start the local NPM registry
startLocalRegistry "$root_path"/tasks/verdaccio.yaml
# Publish the monorepo
git clean -df
./tasks/publish.sh --yes --force-publish=* --skip-git --cd-version=prerelease --exact --npm-tag=latest
publishToLocalRegistry
# ******************************************************************************
# Now that we have published them, run all tests as if they were released.

View File

@@ -15,17 +15,16 @@ cd "$(dirname "$0")"
# CLI and app temporary locations
# http://unix.stackexchange.com/a/84980
temp_app_path=`mktemp -d 2>/dev/null || mktemp -d -t 'temp_app_path'`
custom_registry_url=http://localhost:4873
original_npm_registry_url=`npm get registry`
original_yarn_registry_url=`yarn config get registry`
# Load functions for working with local NPM registry (Verdaccio)
source local-registry.sh
function cleanup {
echo 'Cleaning up.'
ps -ef | grep 'verdaccio' | grep -v grep | awk '{print $2}' | xargs kill -9
cd "$root_path"
rm -rf "$temp_app_path"
npm set registry "$original_npm_registry_url"
yarn config set registry "$original_yarn_registry_url"
# Restore the original NPM and Yarn registry URLs and stop Verdaccio
stopLocalRegistry
}
# Error messages are redirected to stderr
@@ -96,22 +95,11 @@ yarn
# First, publish the monorepo.
# ******************************************************************************
# Start local registry
tmp_registry_log=`mktemp`
(cd && nohup npx verdaccio@3.8.2 -c "$root_path"/tasks/verdaccio.yaml &>$tmp_registry_log &)
# Wait for `verdaccio` to boot
grep -q 'http address' <(tail -f $tmp_registry_log)
# Set registry to local registry
npm set registry "$custom_registry_url"
yarn config set registry "$custom_registry_url"
# Login so we can publish packages
(cd && npx npm-auth-to-token@1.0.0 -u user -p password -e user@example.com -r "$custom_registry_url")
# Start the local NPM registry
startLocalRegistry "$root_path"/tasks/verdaccio.yaml
# Publish the monorepo
git clean -df
./tasks/publish.sh --yes --force-publish=* --skip-git --cd-version=prerelease --exact --npm-tag=latest
publishToLocalRegistry
echo "Create React App Version: "
npx create-react-app --version

View File

@@ -16,20 +16,19 @@ cd "$(dirname "$0")"
# http://unix.stackexchange.com/a/84980
temp_app_path=`mktemp -d 2>/dev/null || mktemp -d -t 'temp_app_path'`
temp_module_path=`mktemp -d 2>/dev/null || mktemp -d -t 'temp_module_path'`
custom_registry_url=http://localhost:4873
original_npm_registry_url=`npm get registry`
original_yarn_registry_url=`yarn config get registry`
# Load functions for working with local NPM registry (Verdaccio)
source local-registry.sh
function cleanup {
echo 'Cleaning up.'
unset BROWSERSLIST
ps -ef | grep 'verdaccio' | grep -v grep | awk '{print $2}' | xargs kill -9
ps -ef | grep 'react-scripts' | grep -v grep | awk '{print $2}' | xargs kill -9
cd "$root_path"
# TODO: fix "Device or resource busy" and remove ``|| $CI`
rm -rf "$temp_app_path" "$temp_module_path" || $CI
npm set registry "$original_npm_registry_url"
yarn config set registry "$original_yarn_registry_url"
# Restore the original NPM and Yarn registry URLs and stop Verdaccio
stopLocalRegistry
}
# Error messages are redirected to stderr
@@ -78,22 +77,11 @@ yarn
# First, publish the monorepo.
# ******************************************************************************
# Start local registry
tmp_registry_log=`mktemp`
(cd && nohup npx verdaccio@3.8.2 -c "$root_path"/tasks/verdaccio.yaml &>$tmp_registry_log &)
# Wait for `verdaccio` to boot
grep -q 'http address' <(tail -f $tmp_registry_log)
# Set registry to local registry
npm set registry "$custom_registry_url"
yarn config set registry "$custom_registry_url"
# Login so we can publish packages
(cd && npx npm-auth-to-token@1.0.0 -u user -p password -e user@example.com -r "$custom_registry_url")
# Start the local NPM registry
startLocalRegistry "$root_path"/tasks/verdaccio.yaml
# Publish the monorepo
git clean -df
./tasks/publish.sh --yes --force-publish=* --skip-git --cd-version=prerelease --exact --npm-tag=latest
publishToLocalRegistry
# ******************************************************************************
# Now that we have published them, create a clean app folder and install them.

View File

@@ -16,20 +16,19 @@ cd "$(dirname "$0")"
# http://unix.stackexchange.com/a/84980
temp_app_path=`mktemp -d 2>/dev/null || mktemp -d -t 'temp_app_path'`
temp_module_path=`mktemp -d 2>/dev/null || mktemp -d -t 'temp_module_path'`
custom_registry_url=http://localhost:4873
original_npm_registry_url=`npm get registry`
original_yarn_registry_url=`yarn config get registry`
# Load functions for working with local NPM registry (Verdaccio)
source local-registry.sh
function cleanup {
echo 'Cleaning up.'
unset BROWSERSLIST
ps -ef | grep 'verdaccio' | grep -v grep | awk '{print $2}' | xargs kill -9
ps -ef | grep 'react-scripts' | grep -v grep | awk '{print $2}' | xargs kill -9
cd "$root_path"
# TODO: fix "Device or resource busy" and remove ``|| $CI`
rm -rf "$temp_app_path" "$temp_module_path" || $CI
npm set registry "$original_npm_registry_url"
yarn config set registry "$original_yarn_registry_url"
# Restore the original NPM and Yarn registry URLs and stop Verdaccio
stopLocalRegistry
}
# Error messages are redirected to stderr
@@ -78,22 +77,11 @@ yarn
# First, publish the monorepo.
# ******************************************************************************
# Start local registry
tmp_registry_log=`mktemp`
(cd && nohup npx verdaccio@3.8.2 -c "$root_path"/tasks/verdaccio.yaml &>$tmp_registry_log &)
# Wait for `verdaccio` to boot
grep -q 'http address' <(tail -f $tmp_registry_log)
# Set registry to local registry
npm set registry "$custom_registry_url"
yarn config set registry "$custom_registry_url"
# Login so we can publish packages
(cd && npx npm-auth-to-token@1.0.0 -u user -p password -e user@example.com -r "$custom_registry_url")
# Start the local NPM registry
startLocalRegistry "$root_path"/tasks/verdaccio.yaml
# Publish the monorepo
git clean -df
./tasks/publish.sh --yes --force-publish=* --skip-git --cd-version=prerelease --exact --npm-tag=latest
publishToLocalRegistry
# ******************************************************************************
# Now that we have published them, create a clean app folder and install them.

View File

@@ -15,19 +15,18 @@ cd "$(dirname "$0")"
# App temporary location
# http://unix.stackexchange.com/a/84980
temp_app_path=`mktemp -d 2>/dev/null || mktemp -d -t 'temp_app_path'`
custom_registry_url=http://localhost:4873
original_npm_registry_url=`npm get registry`
original_yarn_registry_url=`yarn config get registry`
# Load functions for working with local NPM registry (Verdaccio)
source local-registry.sh
function cleanup {
echo 'Cleaning up.'
ps -ef | grep 'verdaccio' | grep -v grep | awk '{print $2}' | xargs kill -9
cd "$root_path"
# Uncomment when snapshot testing is enabled by default:
# rm ./packages/react-scripts/template/src/__snapshots__/App.test.js.snap
rm -rf "$temp_app_path"
npm set registry "$original_npm_registry_url"
yarn config set registry "$original_yarn_registry_url"
# Restore the original NPM and Yarn registry URLs and stop Verdaccio
stopLocalRegistry
}
# Error messages are redirected to stderr
@@ -85,18 +84,8 @@ fi
# Bootstrap monorepo
yarn
# Start local registry
tmp_registry_log=`mktemp`
(cd && nohup npx verdaccio@3.8.2 -c "$root_path"/tasks/verdaccio.yaml &>$tmp_registry_log &)
# Wait for `verdaccio` to boot
grep -q 'http address' <(tail -f $tmp_registry_log)
# Set registry to local registry
npm set registry "$custom_registry_url"
yarn config set registry "$custom_registry_url"
# Login so we can publish packages
(cd && npx npm-auth-to-token@1.0.0 -u user -p password -e user@example.com -r "$custom_registry_url")
# Start the local NPM registry
startLocalRegistry "$root_path"/tasks/verdaccio.yaml
# Lint own code
./node_modules/.bin/eslint --max-warnings 0 packages/babel-preset-react-app/
@@ -149,8 +138,8 @@ CI=true yarn test
# Test local start command
yarn start --smoke-test
git clean -df
./tasks/publish.sh --yes --force-publish=* --skip-git --cd-version=prerelease --exact --npm-tag=latest
# Publish the monorepo
publishToLocalRegistry
# ******************************************************************************
# Install react-scripts prerelease via create-react-app prerelease.

36
tasks/local-registry.sh Normal file
View File

@@ -0,0 +1,36 @@
#!/bin/bash
custom_registry_url=http://localhost:4873
original_npm_registry_url=`npm get registry`
original_yarn_registry_url=`yarn config get registry`
default_verdaccio_package=verdaccio@3.8.2
function startLocalRegistry {
# Start local registry
tmp_registry_log=`mktemp`
echo "Registry output file: $tmp_registry_log"
(cd && nohup npx ${VERDACCIO_PACKAGE:-$default_verdaccio_package} -c $1 &>$tmp_registry_log &)
# Wait for Verdaccio to boot
grep -q 'http address' <(tail -f $tmp_registry_log)
# Set registry to local registry
npm set registry "$custom_registry_url"
yarn config set registry "$custom_registry_url"
# Login so we can publish packages
(cd && npx npm-auth-to-token@1.0.0 -u user -p password -e user@example.com -r "$custom_registry_url")
}
function stopLocalRegistry {
# Restore the original NPM and Yarn registry URLs and stop Verdaccio
npm set registry "$original_npm_registry_url"
yarn config set registry "$original_yarn_registry_url"
# Kill Verdaccio process
ps -ef | grep 'verdaccio' | grep -v grep | awk '{print $2}' | xargs kill -9
}
function publishToLocalRegistry {
git clean -df
./tasks/publish.sh prerelease --yes --force-publish=* --no-git-tag-version --no-commit-hooks --no-push --exact --dist-tag=latest
}

View File

@@ -20,6 +20,13 @@ auth:
uplinks:
npmjs:
url: https://registry.npmjs.org/
max_fails: 40
maxage: 30m
timeout: 60s
agent_options:
keepAlive: true
maxSockets: 40
maxFreeSockets: 10
packages:
'@*/*':
@@ -45,5 +52,9 @@ packages:
# log settings
logs:
- {type: stdout, format: pretty, level: http}
- {type: stdout, format: pretty, level: warn}
#- {type: file, path: verdaccio.log, level: info}
# See https://github.com/verdaccio/verdaccio/issues/301
server:
keepAliveTimeout: 0

View File

@@ -33,9 +33,9 @@ function execaSafe(...args) {
stderr: stripYarn(
stripAnsi(
err.message
.split(os.EOL)
.split('\n')
.slice(2)
.join(os.EOL)
.join('\n')
)
),
}));

View File

@@ -96,7 +96,15 @@ module.exports = class TestSetup {
async teardown() {
if (this.testDirectory != null) {
await fs.remove(this.testDirectory);
try {
await fs.remove(this.testDirectory);
} catch (ex) {
if (this.isLocal) {
throw ex;
} else {
// In CI, don't worry if the test directory was not able to be deleted
}
}
this.testDirectory = null;
this._scripts = null;
}

View File

@@ -1,5 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`can use mjs library in development 1`] = `"Pikachu"`;
exports[`can use mjs library in development 1`] = `"world"`;
exports[`can use mjs library in production 1`] = `"Pikachu"`;
exports[`can use mjs library in production 1`] = `"world"`;

View File

@@ -9,11 +9,10 @@ test('can use mjs library in development', async () => {
try {
const page = await browser.newPage();
await page.goto(`http://localhost:${port}/`);
await page.waitForSelector('.Pokemon-Name-Data', { timeout: 0 });
await page.waitForSelector('.mjs-gql-result', { timeout: 0 });
const output = await page.evaluate(() => {
return Array.from(
document.getElementsByClassName('Pokemon-Name-Data')
).pop().innerHTML;
return Array.from(document.getElementsByClassName('mjs-gql-result')).pop()
.innerHTML;
});
expect(output).toMatchSnapshot();
} finally {
@@ -29,11 +28,10 @@ test('can use mjs library in production', async () => {
try {
const page = await browser.newPage();
await page.goto(`http://localhost:${port}/`);
await page.waitForSelector('.Pokemon-Name-Data', { timeout: 0 });
await page.waitForSelector('.mjs-gql-result', { timeout: 0 });
const output = await page.evaluate(() => {
return Array.from(
document.getElementsByClassName('Pokemon-Name-Data')
).pop().innerHTML;
return Array.from(document.getElementsByClassName('mjs-gql-result')).pop()
.innerHTML;
});
expect(output).toMatchSnapshot();
} finally {

View File

@@ -1,9 +1,6 @@
{
"dependencies": {
"apollo-boost": "0.1.16",
"graphql": "14.0.2",
"react-apollo": "2.2.1",
"apollo-client": "2.4.2",
"react": "latest",
"react-dom": "latest",
"serve": "10.0.2"

View File

@@ -1,62 +1,35 @@
import React, { Component } from 'react';
import ApolloClient, { gql } from 'apollo-boost';
import { ApolloProvider, Query } from 'react-apollo';
import {
graphql,
GraphQLSchema,
GraphQLObjectType,
GraphQLString,
} from 'graphql';
const GET_PIKA = gql`
{
pokemon(name: "Pikachu") {
name
}
}
`;
const client = new ApolloClient({
uri: 'https://graphql-pokemon.now.sh/graphql',
const schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'RootQueryType',
fields: {
hello: {
type: GraphQLString,
resolve() {
return 'world';
},
},
},
}),
});
class Pokemon extends Component {
render() {
const { name } = this.props.pokemon;
return (
<h1>
Pokemon name: <span className="Pokemon-Name-Data">{name}</span>
</h1>
);
}
}
class Data extends Component {
state = {};
componentDidCatch() {
this.setState({ hasError: true });
}
render() {
const { hasError } = this.state;
return hasError ? (
<div className="Pokemon-Name-Data">Error :(</div>
) : (
<Query query={GET_PIKA}>
{({ loading, error, data }) => {
if (loading) {
return <div>Loading...</div>;
}
if (error) {
return <div className="Pokemon-Name-Data">Error :(</div>;
}
return <Pokemon pokemon={data.pokemon} />;
}}
</Query>
);
}
}
class App extends Component {
state = {};
componentDidMount() {
graphql(schema, '{ hello }').then(({ data }) => {
this.setState({ result: data.hello });
});
}
render() {
return (
<ApolloProvider client={client}>
<Data />
</ApolloProvider>
);
const { result } = this.state;
return result ? <div className="mjs-gql-result">{result}</div> : null;
}
}

View File

@@ -59,7 +59,10 @@ test('formats missing package', async () => {
path.join(testSetup.testDirectory, 'src', 'App.js')
);
const { stdout, stderr } = await testSetup.scripts.build();
let { stdout, stderr } = await testSetup.scripts.build();
if (process.platform === 'win32') {
stderr = stderr.replace('.\\src\\App.js', './src/App.js');
}
expect({ stdout, stderr }).toMatchSnapshot();
});
@@ -103,7 +106,12 @@ test('formats file not found error', async () => {
path.join(testSetup.testDirectory, 'src', 'App.js')
);
const { stdout, stderr } = await testSetup.scripts.build();
let { stdout, stderr } = await testSetup.scripts.build();
if (process.platform === 'win32') {
stderr = stderr
.replace('.\\src\\App.js', './src/App.js')
.replace('.\\src', './src');
}
expect({ stdout, stderr }).toMatchSnapshot();
});
@@ -131,6 +139,9 @@ test('formats out of scope error', async () => {
path.join(testSetup.testDirectory, 'src', 'App.js')
);
const { stdout, stderr } = await testSetup.scripts.build();
let { stdout, stderr } = await testSetup.scripts.build();
if (process.platform === 'win32') {
stderr = stderr.replace('.\\src\\App.js', './src/App.js');
}
expect({ stdout, stderr }).toMatchSnapshot();
});