Skip to content
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
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ then enforces a specific workflow for managing release branches, changelogs, art
- [Docker (`docker`)](#docker-docker)
- [Ruby Gems Index (`gem`)](#ruby-gems-index-gem)
- [AWS Lambda Layer (`aws-lambda-layer`)](#aws-lambda-layer-aws-lambda-layer)
- [Unity Package Manager (`upm`)](#unity-package-manager-upm)
- [Integrating Your Project with `craft`](#integrating-your-project-with-craft)
- [Pre-release (Version-bumping) Script: Conventions](#pre-release-version-bumping-script-conventions)
- [Post-release Script: Conventions](#post-release-script-conventions)
Expand Down Expand Up @@ -930,6 +931,32 @@ targets:
license: MIT
```

### Unity Package Manager (`upm`)

Pulls the package as a zipped artifact and pushes the unzipped content to the target repository, tagging it with the provided version.

_WARNING!_ The destination repository will be completely overwritten.

**Environment**

_none_

**Configuration**

| Option | Description |
| ------------------ | --------------------------------------- |
| `releaseRepoOwner` | Name of the owner of the release target |
| `releaseRepoName` | Name of the repo of the release target |

**Example**

```yaml
targets:
- name: upm
releaseRepoOwner: 'getsentry'
releaseRepoName: 'unity'
```

## Integrating Your Project with `craft`

Here is how you can integrate your GitHub project with `craft`:
Expand Down
66 changes: 66 additions & 0 deletions src/targets/__tests__/upm.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { NoneArtifactProvider } from '../../artifact_providers/none';
import { UpmTarget } from '../upm';

describe('UPM Target', () => {
const cleanEnv = { ...process.env };
let upmTarget: UpmTarget;

beforeEach(() => {
process.env = {
...cleanEnv,
GITHUB_TOKEN: 'ghp_TAN21WJQkLtYVdHCh5eQJ8hTWoYvNh47gGWH',
DRY_RUN: 'false',
};
jest.resetAllMocks();

upmTarget = new UpmTarget(
{
name: 'upm-test',
releaseRepoOwner: 'getsentry-test',
releaseRepoName: 'unity-test',
},
new NoneArtifactProvider(),
{ owner: 'testSourceOwner', repo: 'testSourceRepo' }
);
});

describe('artifacts', () => {
beforeEach(() => {
process.env.DRY_RUN = 'false';
});
test.each`
artifacts | error
${[]} | ${'Cannot publish UPM: No release artifact found.'}
${['file1', 'file2']} | ${'Cannot publish UPM: Too many release artifacts found:\nfile1\nfile2'}
`(
'error with artifact count $artifacts.length',
async ({ artifacts, error }) => {
upmTarget.getArtifactsForRevision = jest
.fn()
.mockResolvedValueOnce(artifacts);

await expect(upmTarget.fetchArtifact('revision')).rejects.toThrow(
error
);
}
);
});

// TODO(byk): Add more tests for this
describe.skip('publish', () => {
beforeEach(() => {
upmTarget.fetchArtifact = jest
.fn()
.mockResolvedValueOnce({ filename: 'artifact.zip' });
upmTarget.artifactProvider.downloadArtifact = jest
.fn()
.mockResolvedValueOnce('some/test/path');
});

test('publish', () => {
return expect(
upmTarget.publish('version', 'revision')
).resolves.not.toThrow();
});
});
});
58 changes: 39 additions & 19 deletions src/targets/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ import { basename } from 'path';
import { getConfiguration } from '../config';
import { logger as loggerRaw } from '../logger';
import { GithubGlobalConfig, TargetConfig } from '../schemas/project_config';
import { DEFAULT_CHANGELOG_PATH, findChangeset } from '../utils/changes';
import {
Changeset,
DEFAULT_CHANGELOG_PATH,
findChangeset,
} from '../utils/changes';
import {
getFile,
getGithubClient,
Expand Down Expand Up @@ -67,18 +71,25 @@ export class GithubTarget extends BaseTarget {
public readonly githubConfig: GithubTargetConfig;
/** Github client */
public readonly github: Github;
/** Github repo configuration */
public readonly githubRepo: GithubGlobalConfig;

public constructor(
config: TargetConfig,
artifactProvider: BaseArtifactProvider,
githubRepo: GithubGlobalConfig
) {
super(config, artifactProvider, githubRepo);
this.githubRepo = githubRepo;
const owner = config.owner || githubRepo.owner;
const repo = config.repo || githubRepo.repo;

this.githubConfig = {
...githubRepo,
owner,
repo,
annotatedTag:
this.config.annotatedTag === undefined || !!this.config.annotatedTag,
changelog: getConfiguration().changelog || '',
changelog: getConfiguration().changelog || DEFAULT_CHANGELOG_PATH,
previewReleases:
this.config.previewReleases === undefined ||
!!this.config.previewReleases,
Expand Down Expand Up @@ -138,17 +149,19 @@ export class GithubTarget extends BaseTarget {
/**
* Gets an existing or creates a new release for the given version
*
* The release name and description body is loaded from CHANGELOG.md in the
* The release name and description body is brought in from `changes`
* respective tag, if present. Otherwise, the release name defaults to the
* tag and the body to the commit it points to.
*
* @param version The version to release
* @param revision Git commit SHA to be published
* @param changes The changeset information for this release
* @returns The newly created release
*/
public async getOrCreateRelease(
version: string,
revision: string
revision: string,
changes?: Changeset
): Promise<GithubRelease> {
const tag = versionToTag(version, this.githubConfig.tagPrefix);
logger.info(`Git tag: "${tag}"`);
Expand All @@ -170,17 +183,6 @@ export class GithubTarget extends BaseTarget {
logger.debug(`Release for tag "${tag}" not found.`);
}

// Release hasn't been found, so create one
const changelog = await getFile(
this.github,
this.githubConfig.owner,
this.githubConfig.repo,
this.githubConfig.changelog || DEFAULT_CHANGELOG_PATH,
revision
);
const changes = (changelog && findChangeset(changelog, tag)) || {};
logger.debug('Changes extracted from changelog: ', JSON.stringify(changes));

const createReleaseParams = {
draft: false,
name: tag,
Expand Down Expand Up @@ -219,6 +221,25 @@ export class GithubTarget extends BaseTarget {
}
}

public async getRevisionChanges(
version: string,
revision: string
): Promise<Changeset> {
const changelog = await getFile(
this.github,
this.githubRepo.owner,
this.githubRepo.repo,
this.githubConfig.changelog,
revision
);
const changes = (changelog && findChangeset(changelog, version)) || {
name: version,
body: '',
};
logger.debug('Changes extracted from changelog: ', JSON.stringify(changes));
return changes;
}

/**
* Deletes the provided asset from its respective release
*
Expand Down Expand Up @@ -360,9 +381,8 @@ export class GithubTarget extends BaseTarget {
* @param revision Git commit SHA to be published
*/
public async publish(version: string, revision: string): Promise<any> {
logger.info(`Target "${this.name}": publishing version "${version}"...`);
logger.debug(`Revision: ${revision}`);
const release = await this.getOrCreateRelease(version, revision);
const changes = await this.getRevisionChanges(version, revision);
const release = await this.getOrCreateRelease(version, revision, changes);

if (isDryRun()) {
logger.info(
Expand Down
2 changes: 2 additions & 0 deletions src/targets/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { NugetTarget } from './nuget';
import { PypiTarget } from './pypi';
import { RegistryTarget } from './registry';
import { AwsLambdaLayerTarget } from './awsLambdaLayer';
import { UpmTarget } from './upm';

export const TARGET_MAP: { [key: string]: typeof BaseTarget } = {
brew: BrewTarget,
Expand All @@ -28,6 +29,7 @@ export const TARGET_MAP: { [key: string]: typeof BaseTarget } = {
pypi: PypiTarget,
registry: RegistryTarget,
'aws-lambda-layer': AwsLambdaLayerTarget,
upm: UpmTarget,
};

/** Targets that are treated specially */
Expand Down
Loading