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

Tweaks the .env implementation #5548

Merged
merged 3 commits into from
Jun 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
36 changes: 36 additions & 0 deletions .yarn/versions/523ca228.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
releases:
"@yarnpkg/cli": patch
"@yarnpkg/core": patch
"@yarnpkg/parsers": patch

declined:
- "@yarnpkg/plugin-compat"
- "@yarnpkg/plugin-constraints"
- "@yarnpkg/plugin-dlx"
- "@yarnpkg/plugin-essentials"
- "@yarnpkg/plugin-exec"
- "@yarnpkg/plugin-file"
- "@yarnpkg/plugin-git"
- "@yarnpkg/plugin-github"
- "@yarnpkg/plugin-http"
- "@yarnpkg/plugin-init"
- "@yarnpkg/plugin-interactive-tools"
- "@yarnpkg/plugin-link"
- "@yarnpkg/plugin-nm"
- "@yarnpkg/plugin-npm"
- "@yarnpkg/plugin-npm-cli"
- "@yarnpkg/plugin-pack"
- "@yarnpkg/plugin-patch"
- "@yarnpkg/plugin-pnp"
- "@yarnpkg/plugin-pnpm"
- "@yarnpkg/plugin-stage"
- "@yarnpkg/plugin-typescript"
- "@yarnpkg/plugin-version"
- "@yarnpkg/plugin-workspace-tools"
- "@yarnpkg/builder"
- "@yarnpkg/doctor"
- "@yarnpkg/extensions"
- "@yarnpkg/nm"
- "@yarnpkg/pnpify"
- "@yarnpkg/sdks"
- "@yarnpkg/shell"
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ The following changes only affect people writing Yarn plugins:

### Features

- `yarn run` now injects the environment variables defined in `.env.yarn` when spawning a process. The list of files thus injected can be controlled using the `injectEnvironmentFiles` variable.
- `yarn workspaces foreach` now automatically enables the `-v,--verbose` flag in interactive terminal environments.

### Bugfixes
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,32 @@
import {PortablePath, xfs} from '@yarnpkg/fslib';
import {EOL} from 'os';
import {Filename, ppath, xfs} from '@yarnpkg/fslib';
import {parseSyml} from '@yarnpkg/parsers';
import {EOL} from 'os';

describe(`Commands`, () => {
describe(`config set`, () => {
test(
`it shouldn't remove empty arrays from the files`,
makeTemporaryEnv({}, async ({path, run, source}) => {
await xfs.writeJsonPromise(ppath.join(path, Filename.rc), {
injectEnvironmentFiles: [],
});

await run(`config`, `set`, `pnpShebang`, `#!/usr/bin/env iojs\n`);

expect(parseSyml(await xfs.readFilePromise(ppath.join(path, Filename.rc), `utf8`))).toMatchObject({
injectEnvironmentFiles: [],
});
}),
);

test(
`it should print the configured value for the current directory`,
makeTemporaryEnv({}, async ({path, run, source}) => {
await expect(run(`config`, `set`, `pnpShebang`, `#!/usr/bin/env iojs\n`)).resolves.toMatchObject({
stdout: expect.stringContaining(`#!/usr/bin/env iojs\\n`),
});

await expect(xfs.readFilePromise(`${path}/.yarnrc.yml` as PortablePath, `utf8`)).resolves.toContain(`pnpShebang`);
await expect(xfs.readFilePromise(ppath.join(path, Filename.rc), `utf8`)).resolves.toContain(`pnpShebang`);
}),
);

Expand All @@ -22,7 +38,7 @@ describe(`Commands`, () => {
expect(stdout).not.toContain(`foobar`);
expect(stdout).toContain(`********`);

await expect(xfs.readFilePromise(`${path}/.yarnrc.yml` as PortablePath, `utf8`)).resolves.toContain(`npmAuthToken: foobar`);
await expect(xfs.readFilePromise(ppath.join(path, Filename.rc), `utf8`)).resolves.toContain(`npmAuthToken: foobar`);
}),
);

Expand All @@ -36,7 +52,7 @@ describe(`Commands`, () => {
expect(stdout).toContain(`npmScopes.yarnpkg`);
expect(stdout).toContain(`npmAlwaysAuth: false`);

await expect(xfs.readFilePromise(`${path}/.yarnrc.yml` as PortablePath, `utf8`)).resolves.toContain(
await expect(xfs.readFilePromise(ppath.join(path, Filename.rc), `utf8`)).resolves.toContain(
`npmScopes:${EOL}` +
` yarnpkg:${EOL}` +
` npmAlwaysAuth: false`,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {Filename, ppath, xfs} from '@yarnpkg/fslib';

describe(`DotEnv files`, () => {
it(`should automatically inject a .env file in the environment`, makeTemporaryEnv({}, async ({path, run, source}) => {
it(`should automatically inject a .env.yarn file in the environment`, makeTemporaryEnv({}, async ({path, run, source}) => {
await run(`install`);

await xfs.writeFilePromise(ppath.join(path, `.env`), [
await xfs.writeFilePromise(ppath.join(path, `.env.yarn`), [
`INJECTED_FROM_ENV_FILE=hello\n`,
].join(``));

Expand All @@ -16,7 +16,7 @@ describe(`DotEnv files`, () => {
it(`should allow .env variables to be interpolated`, makeTemporaryEnv({}, async ({path, run, source}) => {
await run(`install`);

await xfs.writeFilePromise(ppath.join(path, `.env`), [
await xfs.writeFilePromise(ppath.join(path, `.env.yarn`), [
`INJECTED_FROM_ENV_FILE=\${FOO}\n`,
].join(``));

Expand All @@ -28,7 +28,7 @@ describe(`DotEnv files`, () => {
it(`should allow .env variables to be used in the next ones`, makeTemporaryEnv({}, async ({path, run, source}) => {
await run(`install`);

await xfs.writeFilePromise(ppath.join(path, `.env`), [
await xfs.writeFilePromise(ppath.join(path, `.env.yarn`), [
`INJECTED_FROM_ENV_FILE_1=hello\n`,
`INJECTED_FROM_ENV_FILE_2=\${INJECTED_FROM_ENV_FILE_1} world\n`,
].join(``));
Expand All @@ -38,7 +38,7 @@ describe(`DotEnv files`, () => {
});
}));

it(`shouldn't read the .env if the injectEnvironmentFiles setting is defined`, makeTemporaryEnv({}, async ({path, run, source}) => {
it(`shouldn't read the .env.yarn file if the injectEnvironmentFiles setting is defined`, makeTemporaryEnv({}, async ({path, run, source}) => {
await xfs.writeJsonPromise(ppath.join(path, Filename.rc), {
injectEnvironmentFiles: [],
});
Expand Down Expand Up @@ -114,7 +114,7 @@ describe(`DotEnv files`, () => {
it(`should allow values from environment files to be reused in other configuration settings`, makeTemporaryEnv({}, async ({path, run, source}) => {
await run(`install`);

await xfs.writeFilePromise(ppath.join(path, `.env`), [
await xfs.writeFilePromise(ppath.join(path, `.env.yarn`), [
`INJECTED_FROM_ENV_FILE=hello\n`,
].join(``));

Expand Down
38 changes: 20 additions & 18 deletions packages/plugin-essentials/sources/commands/install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -519,30 +519,32 @@ async function autofixLegacyPlugins(configuration: Configuration, immutable: boo
const legacyPlugins: Array<PortablePath> = [];
const yarnPluginDir = ppath.join(configuration.projectCwd, `.yarn/plugins/@yarnpkg`);

const changed = await Configuration.updateConfiguration(configuration.projectCwd, current => {
if (!Array.isArray(current.plugins))
return current;
const changed = await Configuration.updateConfiguration(configuration.projectCwd, {
plugins: plugins => {
if (!Array.isArray(plugins))
return plugins;

const plugins = current.plugins.filter((plugin: {spec: string, path: PortablePath}) => {
if (!plugin.path)
return true;
const filteredPlugins = plugins.filter((plugin: {spec: string, path: PortablePath}) => {
if (!plugin.path)
return true;

const resolvedPath = ppath.resolve(configuration.projectCwd!, plugin.path);
const isLegacy = LEGACY_PLUGINS.has(plugin.spec) && ppath.contains(yarnPluginDir, resolvedPath);
const resolvedPath = ppath.resolve(configuration.projectCwd!, plugin.path);
const isLegacy = LEGACY_PLUGINS.has(plugin.spec) && ppath.contains(yarnPluginDir, resolvedPath);

if (isLegacy)
legacyPlugins.push(resolvedPath);
if (isLegacy)
legacyPlugins.push(resolvedPath);

return !isLegacy;
});
return !isLegacy;
});

if (current.plugins.length === plugins.length)
return current;
if (filteredPlugins.length === 0)
return Configuration.deleteProperty;

return {
...current,
plugins,
};
if (filteredPlugins.length === plugins.length)
return plugins;

return filteredPlugins;
},
}, {
immutable,
});
Expand Down
26 changes: 14 additions & 12 deletions packages/plugin-essentials/sources/commands/plugin/remove.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,21 +51,23 @@ export default class PluginRemoveCommand extends BaseCommand {
}

report.reportInfo(MessageName.UNNAMED, `Updating the configuration...`);
await Configuration.updateConfiguration(project.cwd, (current: {[key: string]: unknown}) => {
if (!Array.isArray(current.plugins))
return current;
await Configuration.updateConfiguration(project.cwd, {
plugins: plugins => {
if (!Array.isArray(plugins))
return plugins;

const plugins = current.plugins.filter((plugin: {path: string}) => {
return plugin.path !== relativePath;
});
const filteredPlugins = plugins.filter((plugin: {path: string}) => {
return plugin.path !== relativePath;
});

if (current.plugins.length === plugins.length)
return current;
if (filteredPlugins.length === 0)
return Configuration.deleteProperty;

return {
...current,
plugins,
};
if (filteredPlugins.length === plugins.length)
return plugins;

return filteredPlugins;
},
});
});

Expand Down
2 changes: 1 addition & 1 deletion packages/yarnpkg-core/sources/Configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,7 @@ export const coreDefinitions: {[coreSettingName: string]: SettingsDefinition} =
injectEnvironmentFiles: {
description: `List of all the environment files that Yarn should inject inside the process when it starts`,
type: SettingsType.ABSOLUTE_PATH,
default: [`.env?`],
default: [`.env.yarn?`],
isArray: true,
},

Expand Down
2 changes: 1 addition & 1 deletion packages/yarnpkg-parsers/sources/syml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function isRemovableField(value: any): boolean {
if (typeof value === `undefined`)
return true;

if (typeof value === `object` && value !== null)
if (typeof value === `object` && value !== null && !Array.isArray(value))
return Object.keys(value).every(key => isRemovableField(value[key]));

return false;
Expand Down