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

feat: Allow to configure latestTargetBranch #502

Closed
wants to merge 2 commits into from
Closed
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
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,19 @@ for a release is `{releaseBranchPrefix}/{version}`. The prefix defaults to
releaseBranchPrefix: publish
```

### Latest Branch Name

If configured, only tag releases as "latest" when merging into this branch.
This can be useful to make sure that releases from e.g. a `v1` branch do not get tagged as "latest".
Note that not all targets may use this.

```yaml
latestTargetBranch: main
```

If you specific `minVersion: '1.8.0'` or above, this will default to use the default branch.
If your `minVersion` is older, the previous behavior (of always tagging as latest, for any branch) will continue to be used.

### Changelog Policies

`craft` can help you to maintain change logs for your projects. At the moment,
Expand Down
45 changes: 41 additions & 4 deletions src/commands/publish.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import {
hasExecutable,
spawnProcess,
} from '../utils/system';
import { isValidVersion } from '../utils/version';
import { isValidVersion, parseVersion } from '../utils/version';
import { BaseStatusProvider } from '../status_providers/base';
import { BaseArtifactProvider } from '../artifact_providers/base';
import { SimpleGit } from 'simple-git';
Expand Down Expand Up @@ -160,7 +160,8 @@ function checkVersion(argv: Arguments<any>, _opt: any): any {
async function publishToTarget(
target: BaseTarget,
version: string,
revision: string
revision: string,
isLatest: boolean
): Promise<void> {
const publishMessage = `=== Publishing to target: ${chalk.bold.cyan(
target.id
Expand All @@ -170,7 +171,7 @@ async function publishToTarget(
logger.info(delim);
logger.info(publishMessage);
logger.info(delim);
await target.publish(version, revision);
await target.publish(version, revision, isLatest);
}

/**
Expand Down Expand Up @@ -527,12 +528,27 @@ export async function publishMain(argv: PublishOptions): Promise<any> {
logger.info(' ');
await promptConfirmation();

// Check if latest target & merge target match,
// to determine if we should tag this release as "latest"
const latestTarget =
config.latestTargetBranch ||
getDefaultLatestTargetBranch(git, argv.remote, config.minVersion);
const mergeTarget =
argv.mergeTarget || (await getDefaultBranch(git, argv.remote));
const isLatest = !latestTarget || latestTarget === mergeTarget;

if (!isLatest) {
logger.info(
`Not tagging as "latest" because merge target is: ${mergeTarget}, not ${latestTarget}`
);
}

await withTempDir(async (downloadDirectory: string) => {
artifactProvider.setDownloadDirectory(downloadDirectory);

// Publish to all targets
for (const target of targetList) {
await publishToTarget(target, newVersion, revision);
await publishToTarget(target, newVersion, revision, isLatest);
publishState.published[BaseTarget.getId(target.config)] = true;
if (!isDryRun()) {
writeFileSync(publishStateFile, JSON.stringify(publishState));
Expand Down Expand Up @@ -606,3 +622,24 @@ export const handler = async (args: {
handleGlobalError(e);
}
};

function getDefaultLatestTargetBranch(
git: SimpleGit,
remote: string,
minVersion?: string
): Promise<string> | undefined {
// If running this on an older min version, we stick to the old behavior where we always mark as latest
if (!minVersion) {
return undefined;
}
const parsedMinVersion = parseVersion(minVersion);
if (
!parsedMinVersion ||
parsedMinVersion.major < 1 ||
parsedMinVersion.minor < 8
) {
return undefined;
}

return getDefaultBranch(git, remote);
}
1 change: 1 addition & 0 deletions src/schemas/projectConfig.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const projectConfigJsonSchema = {
preReleaseCommand: { type: 'string' },
postReleaseCommand: { type: 'string' },
releaseBranchPrefix: { type: 'string' },
latestTargetBranch: { type: 'string' },
changelog: { type: 'string' },
changelogPolicy: {
title: 'ChangelogPolicy',
Expand Down
1 change: 1 addition & 0 deletions src/schemas/project_config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export interface CraftProjectConfig {
preReleaseCommand?: string;
postReleaseCommand?: string;
releaseBranchPrefix?: string;
latestTargetBranch?: string;
changelog?: string;
changelogPolicy?: ChangelogPolicy;
minVersion?: string;
Expand Down
2 changes: 1 addition & 1 deletion src/targets/__tests__/upm.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ describe('UPM Target', () => {

test('publish', () => {
return expect(
upmTarget.publish('version', 'revision')
upmTarget.publish('version', 'revision', true)
).resolves.not.toThrow();
});
});
Expand Down
5 changes: 3 additions & 2 deletions src/targets/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,12 @@ export class BaseTarget {
*
* @param version New version to be released
* @param revision Git commit SHA to be published
* @param isLatest If this release should be marked as "latest"
*/
public async publish(
_version: string,

_revision: string
_revision: string,
_isLatest: boolean
): Promise<void> {
throw new Error('Not implemented');
return;
Expand Down
12 changes: 10 additions & 2 deletions src/targets/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ export class GitHubTarget extends BaseTarget {
public async createDraftRelease(
version: string,
revision: string,
isLatest: boolean,
changes?: Changeset
): Promise<GitHubRelease> {
const tag = versionToTag(version, this.githubConfig.tagPrefix);
Expand All @@ -130,6 +131,7 @@ export class GitHubTarget extends BaseTarget {
repo: this.githubConfig.repo,
tag_name: tag,
target_commitish: revision,
make_latest: isLatest && !isPreview ? 'true' : 'false',
...changes,
});
return data;
Expand Down Expand Up @@ -259,7 +261,7 @@ export class GitHubTarget extends BaseTarget {
release: GitHubRelease,
path: string,
contentType?: string,
retries = 3,
retries = 3
): Promise<{ url: string; size: number }> {
const contentTypeProcessed = contentType || DEFAULT_CONTENT_TYPE;
const stats = statSync(path);
Expand Down Expand Up @@ -369,8 +371,13 @@ export class GitHubTarget extends BaseTarget {
*
* @param version New version to be released
* @param revision Git commit SHA to be published
* @param isLatest If this release should be marked as latest
*/
public async publish(version: string, revision: string): Promise<any> {
public async publish(
version: string,
revision: string,
isLatest: boolean
): Promise<any> {
if (this.githubConfig.tagOnly) {
this.logger.info(
`Not creating a GitHub release because "tagOnly" flag was set.`
Expand All @@ -395,6 +402,7 @@ export class GitHubTarget extends BaseTarget {
const draftRelease = await this.createDraftRelease(
version,
revision,
isLatest,
changelog
);

Expand Down
30 changes: 21 additions & 9 deletions src/targets/npm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ interface NpmPublishOptions {
otp?: string;
/** New version to publish */
version: string;
/** If defined, set this tag instead of "latest" */
tag?: string;
}

/**
Expand Down Expand Up @@ -178,14 +180,8 @@ export class NpmTarget extends BaseTarget {
args.push(`--access=${this.npmConfig.access}`);
}

// In case we have a prerelease, there should never be a reason to publish
// it with the latest tag in npm.
if (isPreviewRelease(options.version)) {
this.logger.warn('Detected pre-release version for npm package!');
this.logger.warn(
'Adding tag "next" to not make it "latest" in registry.'
);
args.push('--tag=next');
if (options.tag) {
args.push(`--tag=${options.tag}`);
}

return withTempFile(filePath => {
Expand Down Expand Up @@ -219,7 +215,11 @@ export class NpmTarget extends BaseTarget {
* @param version New version to be released
* @param revision Git commit SHA to be published
*/
public async publish(version: string, revision: string): Promise<any> {
public async publish(
version: string,
revision: string,
isLatest: boolean
): Promise<any> {
this.logger.debug('Fetching artifact list...');
const packageFiles = await this.getArtifactsForRevision(revision, {
includeNames: DEFAULT_PACKAGE_REGEX,
Expand All @@ -235,6 +235,18 @@ export class NpmTarget extends BaseTarget {
publishOptions.otp = await this.requestOtp();
}

// In case we have a prerelease, there should never be a reason to publish
// it with the latest tag in npm.
if (isPreviewRelease(version)) {
this.logger.warn('Detected pre-release version for npm package!');
this.logger.warn(
'Adding tag "next" to not make it "latest" in registry.'
);
publishOptions.tag = 'next';
} else if (!isLatest) {
publishOptions.tag = 'old';
Copy link
Member

Choose a reason for hiding this comment

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

q: I guess we need to set some tag so that NPM doesn't default to latest?

}

await Promise.all(
packageFiles.map(async (file: RemoteArtifact) => {
const path = await this.artifactProvider.downloadArtifact(file);
Expand Down
8 changes: 7 additions & 1 deletion src/targets/upm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,13 @@ export class UpmTarget extends BaseTarget {
*
* @param version New version to be released
* @param revision Git commit SHA to be published
* @param isLatest If this release should be marked as latest
*/
public async publish(version: string, revision: string): Promise<any> {
public async publish(
version: string,
revision: string,
isLatest: boolean
): Promise<any> {
this.logger.info('Fetching artifact...');
const packageFile = await this.fetchArtifact(revision);
if (!packageFile) {
Expand Down Expand Up @@ -147,6 +152,7 @@ export class UpmTarget extends BaseTarget {
const draftRelease = await this.githubTarget.createDraftRelease(
version,
targetRevision,
isLatest,
changes
);
await this.githubTarget.publishRelease(draftRelease);
Expand Down