Internal: Migrate to using rush publish and rush change (#3809)

This commit is contained in:
Timothee Guerin 2021-01-26 12:31:54 -08:00 коммит произвёл GitHub
Родитель 3b80bf9506
Коммит 4dbb3dca5e
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
18 изменённых файлов: 162 добавлений и 358 удалений

Просмотреть файл

@ -1,76 +0,0 @@
const { spawn } = require("child_process");
const { readFileSync } = require("fs");
const { resolve } = require("path");
function read(filename) {
const txt = readFileSync(filename, "utf8")
.replace(/\r/gm, "")
.replace(/\n/gm, "«")
.replace(/\/\*.*?\*\//gm, "")
.replace(/«/gm, "\n")
.replace(/\s+\/\/.*/g, "");
return JSON.parse(txt);
}
const repo = `${__dirname}/..`;
const rush = read(`${repo}/rush.json`);
const pjs = {};
function forEachProject(onEach) {
// load all the projects
for (const each of rush.projects) {
const packageName = each.packageName;
const projectFolder = resolve(`${repo}/${each.projectFolder}`);
const project = JSON.parse(readFileSync(`${projectFolder}/package.json`));
onEach(packageName, projectFolder, project);
}
}
function npmForEach(cmd) {
let count = 0;
let exitCode = 0;
const result = {};
const procs = [];
const t1 = process.uptime() * 100;
forEachProject((name, location, project) => {
// checks for the script first
if (project.scripts[cmd]) {
count++;
const proc = spawn("npm", ["--silent", "run", cmd], { cwd: location, shell: true, stdio: "inherit" });
procs.push(proc);
result[name] = {
name,
location,
project,
proc,
};
}
});
procs.forEach((proc) =>
proc.on("close", (code, signal) => {
count--;
exitCode += code;
if (count === 0) {
const t2 = process.uptime() * 100;
console.log("---------------------------------------------------------");
if (exitCode !== 0) {
console.log(` Done : command '${cmd}' - ${Math.floor(t2 - t1) / 100} s -- Errors ${exitCode} `);
} else {
console.log(` Done : command '${cmd}' - ${Math.floor(t2 - t1) / 100} s -- No Errors `);
}
console.log("---------------------------------------------------------");
process.exit(exitCode);
}
}),
);
return result;
}
module.exports.forEachProject = forEachProject;
module.exports.npm = npmForEach;
module.exports.projectCount = rush.projects.length;

Просмотреть файл

@ -1,2 +0,0 @@
// Runs the npm run command on each project that has it.
require("./for-each").npm(process.argv[2]);

Просмотреть файл

@ -1,44 +0,0 @@
# publishes a package to NPM (passed in as $(pkg) variable)
# you can also customize the tag used for NPM with the $(tag) variable (defaults to 'latest')
# if you want to set a secondary tag on the package (like V2), set the $(altTag) variable
trigger:
- master
pool:
vmImage: "ubuntu-latest"
steps:
- task: NodeTool@0
inputs:
versionSpec: "12.x"
displayName: "Install Node.js"
- script: |
# ensure latest npm is installed
npm install -g npm
npm config set //registry.npmjs.org/:_authToken=$(azure-sdk-npm-token)
# grab the file specified
wget $(pkg)
rc=$?; if [ $rc -ne 0 ]; then exit $rc ; fi
# determine the tag
npmTag="latest"
if [ -n "$(tag)" ]; then
npmTag=$(tag)
fi
# publish it to npm
for file in *.tgz
do
npm publish $file --tag $npmTag --access public
rc=$?; if [ $rc -ne 0 ]; then exit $rc ; fi
# set the alternate tag, if applicable
if [ -n "$(altTag)" ]; then
tar -zxvf $file
cd package/
npm dist-tag add $(npm show . name)@$(npm show . version) --tag $(altTag)
fi
done

Просмотреть файл

@ -1,42 +0,0 @@
const { exec } = require("child_process");
const { writeFileSync } = require("fs");
const { forEachProject, projectCount } = require("./for-each");
let count = projectCount;
function updateVersion(name, project, location, patch) {
const origJson = JSON.stringify(project, null, 2);
// update the third digit
const verInfo = project.version.split(".");
verInfo[2] = patch;
project.version = verInfo.join(".");
// write the file if it's changed
const newJson = JSON.stringify(project, null, 2);
if (origJson !== newJson) {
console.log(`Writing project '${name}' version to '${project.version}' in '${location}'`);
writeFileSync(`${location}/package.json`, newJson);
}
count--;
if (count === 0) {
// last one!
// call sync-versions
require("./sync-versions");
}
}
if (process.argv[2] === "--reset") {
forEachProject((name, location, project) => {
updateVersion(name, project, location, 0);
});
} else {
// Sets the patch version on each package.json in the project.
forEachProject((name, location, project) => {
exec(`git rev-list --parents HEAD --count --full-history .`, { cwd: location }, (o, stdout) => {
const patch = parseInt(stdout.trim()) + (Number(project.patchOffset) || -1);
updateVersion(name, project, location, patch);
});
});
}

Просмотреть файл

@ -1,143 +0,0 @@
const { readFileSync, writeFileSync } = require("fs");
function read(filename) {
const txt = readFileSync(filename, "utf8")
.replace(/\r/gm, "")
.replace(/\n/gm, "«")
.replace(/\/\*.*?\*\//gm, "")
.replace(/«/gm, "\n")
.replace(/\s+\/\/.*/g, "");
return JSON.parse(txt);
}
const packageList = {};
const rush = read(`${__dirname}/../rush.json`);
const pjs = {};
function writeIfChanged(filename, content) {
const orig = JSON.parse(readFileSync(filename));
const origJson = JSON.stringify(orig, null, 2);
const json = JSON.stringify(content, null, 2);
if (origJson !== json) {
console.log(`Writing updated file '${filename}'`);
writeFileSync(filename, json);
return true;
}
return false;
}
function versionToInt(ver) {
let v = ver
.replace(/[^\d\.]/g, "")
.split(".")
.slice(0, 3);
while (v.length < 3) {
v.unshift(0);
}
let n = 0;
for (let i = 0; i < v.length; i++) {
n = n + 2 ** (i * 16) * parseInt(v[v.length - 1 - i]);
}
return n;
}
function setPeerDependencies(dependencies) {
for (const dep in dependencies) {
const ref = pjs[dep];
if (ref) {
if (dependencies[dep] !== `~${ref.version}`) {
console.log(`updating peer depedency ${dep} to ~${ref.version}`);
dependencies[dep] = `~${ref.version}`;
}
}
}
}
function recordDeps(dependencies) {
for (const packageName in dependencies) {
const packageVersion = dependencies[packageName];
if (packageList[packageName]) {
// same version?
if (packageList[packageName] === packageVersion) {
continue;
}
console.log(`${packageName} has ['${packageList[packageName]}','${packageVersion}']`);
// pick the higher one
const v = versionToInt(packageVersion);
if (v === 0) {
console.error(`Unparsed version ${packageName}:${packageVersion}`);
process.exit(1);
}
const v2 = versionToInt(packageList[packageName]);
if (v > v2) {
packageList[packageName] = packageVersion;
}
} else {
packageList[packageName] = packageVersion;
}
}
}
function fixDeps(pj, dependencies) {
for (const packageName in dependencies) {
if (dependencies[packageName] !== packageList[packageName]) {
console.log(`updating ${pj}:${packageName} from '${dependencies[packageName]}' to '${packageList[packageName]}'`);
dependencies[packageName] = packageList[packageName];
}
}
}
// load all the projects
for (const each of rush.projects) {
const packageName = each.packageName;
const projectFolder = each.projectFolder;
pjs[packageName] = JSON.parse(readFileSync(`${__dirname}/../${projectFolder}/package.json`));
}
// verify that peer dependencies are the same version as they are building.
for (const pj of Object.getOwnPropertyNames(pjs)) {
const each = pjs[pj];
setPeerDependencies(each.dependencies);
setPeerDependencies(each.devDependencies);
if (each["static-link"]) {
setPeerDependencies(each["static-link"].dependencies);
}
}
// now compare to see if someone has an exnternal package with different version
// than everyone else.
for (const pj of Object.getOwnPropertyNames(pjs)) {
const each = pjs[pj];
recordDeps(each.dependencies);
recordDeps(each.devDependencies);
if (each["static-link"]) {
recordDeps(each["static-link"].dependencies);
}
}
for (const pj of Object.getOwnPropertyNames(pjs)) {
const each = pjs[pj];
fixDeps(pj, each.dependencies);
fixDeps(pj, each.devDependencies);
if (each["static-link"]) {
fixDeps(pj, each["static-link"].dependencies);
}
}
var changed = 0;
// write out the results.
for (const each of rush.projects) {
const packageName = each.packageName;
const projectFolder = each.projectFolder;
if (writeIfChanged(`${__dirname}/../${projectFolder}/package.json`, pjs[packageName])) {
changed++;
}
}
if (changed) {
console.log(`Updated ${changed} files.`);
} else {
console.log("No changes made");
}

Просмотреть файл

@ -1,23 +0,0 @@
var cp = require("child_process");
require("./for-each").forEachProject((packageName, projectFolder, project) => {
if (project.scripts.watch) {
console.log(`npm run watch {cwd: ${__dirname}/../${projectFolder}}`);
const proc = cp.spawn("npm", ["run", "watch"], { cwd: projectFolder, shell: true, stdio: "inherit" });
proc.on("error", (c, s) => {
console.log(packageName);
console.error(c);
console.error(s);
});
proc.on("exit", (c, s) => {
console.log(packageName);
console.error(c);
console.error(s);
});
proc.on("message", (c, s) => {
console.log(packageName);
console.error(c);
console.error(s);
});
}
});

Просмотреть файл

@ -0,0 +1,114 @@
# Autorest Development
## Requirements
- `node` (LTS recommended)
Optional recommendation:
- VSCode with the following extensions:
- Prettier
- ESLint
- EditorConfig
## First build
1. Install [rush.js](https://rushjs.io/pages/intro/get_started/) using
```bash
npm install -g @microsoft/rush
```
2. Install dependencies
```bash
rush update
```
3. Build
```bash
rush build
# or to do a force rebuild.
rush rebuild
```
## Run in watch mode
When working on autorest it is recommended to have the compiler run in watch mode. This means that on file changes typescript will automatically recompile and produce the output.
```bash
# Run for all packages.
rush watch
# Run for a specific package.
npm run watch
```
## Test
Test framework we used is [jest](https://jestjs.io/)
To run the test you have 2 options:
1. Run all the tests using
```bash
rush test:ci
```
2. Run individual project tests(Recommended when working on test)
```bash
# Go to the package directory
cd packages/<type>/<package>/
# Run test in interactive mode
npm test
# Alternatively you can run them once with coverage(Same as rush test:ci)
npm run test:ci
```
## Other commands
- Linting
```bash
# Run for all packages.
rush lint
# Run for a specific package.
npm run lint
```
- Cleaning
```bash
# Run for all packages.
rush clean
# Run for a specific package.
npm run clean
```
## Use your local changes
You can tell autorest to use your local changes.
- For `@autorest/core`, use the `--version` option
```bash
autorest --version:<path-to-repo>/packages/extensions/core
```
- For `@autorest/modelerfour`, use the `--use` option
```bash
autorest --use:<path-to-repo>/packages/extensions/modelerfour
```
- For `autorest itself`, change the command
```bash
node <path-to-repo>/packages/apps/autorest/entrypoints/app.js
```

Просмотреть файл

@ -0,0 +1,14 @@
# Autorest publishing
This is the instruction to publish a new autorest package.
## Track changes
Autorest pull request validation will check that changes are being documented using `rush change --verify`.
This means that if the pull request include some changes to any packages you will have to run `rush change` to interactively describe what the changes are and how they affect the package(Major, minor, patch).
## Release
If you want to release an update you will then have to run `rush publish`. This will take all pending change files created with `rush change`, update the changelog and bump the package(s) version.
Then in the Pull Request make sure to add the `Publish` label to tell the validation that this is meant to publish and it will ignore the change check above.

4
docs/internal/readme.md Normal file
Просмотреть файл

@ -0,0 +1,4 @@
# Autorest Core developer docs
- [Development](./development.md)
- [Publishing](./publishing.md)

Просмотреть файл

@ -12,7 +12,8 @@ jobs:
- job: main
displayName: "Build and test"
steps:
- template: ./build.yaml
- template: ./templates/verify-changes.yaml
- template: ./templates/build.yaml
- script: npx @microsoft/rush test:ci -v
displayName: Test

Просмотреть файл

@ -10,19 +10,11 @@ pool:
vmImage: "ubuntu-latest"
steps:
- template: ./build.yaml
parameters:
setVersion: true
- template: ./templates/build.yaml
- script: npx @microsoft/rush publish --publish --pack --include-all
displayName: Pack packages
- script: |
# publish the packages (tag as preview by default)
echo "//registry.npmjs.org/:_authToken=$(azure-sdk-npm-token)" > ./.npmrc
for file in common/temp/artifacts/packages/*.tgz
do
echo "Trying to publish $file:"
npm publish $file --tag latest --access public --no-git-checks || echo no-worries
done
NPM_AUTH_TOKEN="$(azure-sdk-npm-token)" rush publish --apply --include-all --set-access-level public
displayName: Publish packages

Просмотреть файл

@ -1,19 +1,10 @@
# Template for building projects
parameters:
- name: setVersion # Update version of packages.
type: boolean
default: false
steps:
- task: NodeTool@0
inputs:
versionSpec: "14.x"
displayName: "Install Node.js"
- ${{ if eq(parameters.setVersion, true) }}:
- script: npx @microsoft/rush set-versions
displayName: Set package versions
- script: |
npm install -g npm
npx @microsoft/rush update

Просмотреть файл

@ -0,0 +1,16 @@
# Steps to verify there is undocumented changes in the PR.
steps:
- script: |
LABEL_NAME=Publish
LABEL_URL=https://api.github.com/repos/$BUILD_REPOSITORY_ID/issues/$SYSTEM_PULLREQUEST_PULLREQUESTNUMBER/labels
echo "Getting labels using $LABEL_URL"
if curl -s "$LABEL_URL" | grep "\"name\": \"$LABEL_NAME\""
then
echo "Publish label was included in the PR, won't be checking for changelog."
else
npx @microsoft/rush change --verify || { echo '\nIf you run the rush publish command locally and meant to publish the changes, add the publish label to the pr.' ; exit 1; }
fi
displayName: Verify change logs
condition: eq(variables['Build.Reason'], 'PullRequest') # only run step if it is a PR

Просмотреть файл

@ -1,7 +1,6 @@
{
"name": "autorest",
"version": "3.0.0",
"patchOffset": 5110,
"version": "3.0.6335",
"description": "The AutoRest tool generates client libraries for accessing RESTful web services. Input to AutoRest is an OpenAPI spec that describes the REST API.",
"engines": {
"node": ">=10.13.0"

Просмотреть файл

@ -1,7 +1,6 @@
{
"name": "@autorest/core",
"version": "3.0.0",
"patchOffset": 5136,
"version": "3.0.6369",
"description": "AutoRest core module",
"engines": {
"node": ">=10.13.0"

Просмотреть файл

@ -1,7 +1,6 @@
{
"name": "@autorest/modelerfour",
"version": "4.15.0",
"patchOffset": -765,
"version": "4.15.454",
"description": "AutoRest Modeler Version Four (component)",
"directories": {
"doc": "docs"

Просмотреть файл

@ -1,7 +1,6 @@
{
"name": "@autorest/codemodel",
"version": "4.14.0",
"patchOffset": -1219,
"version": "4.14.2",
"description": "AutoRest code model library",
"directories": {
"doc": "docs"

Просмотреть файл

@ -10,6 +10,12 @@ AutoRest is an open source tool -- if you need assistance, first check the docum
View our [docs readme][docs_readme] as a starting point to find both general information and language-generator specific information
## Contributing
### Contributing guide
Check our [internal developer docs](./docs/internal/readme.md) to learn about our development process, how to propose bugfixes and improvements, and how to build and test your changes to Autorest.
### Code of Conduct
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.