Add support for Scoped Registries (#261)

* add: new inputs and method params

* feat: add scoped registry to manifest

* feat: setup test job

* fix(workflow): revert change from license to serial

* feat: support private scoped registries

* fix: multiple scopes
pull/263/head
nic van dessel 2024-03-14 09:13:12 -07:00 committed by GitHub
parent 7c242f70d9
commit 9d8ff067a3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
42 changed files with 704 additions and 7 deletions

View File

@ -653,3 +653,103 @@ jobs:
name: Package test results (combined)
path: packageArtifacts/
retention-days: 14
testPackageRunnerWithScopeRegistry:
name: Test package mode in all modes with Scoped Registry 📦✨
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
projectPath:
- unity-package-with-correct-tests/com.dependencyexample.testpackage
unityVersion:
- 2022.3.13f1
- 2023.1.19f1
- 2023.2.2f1
steps:
###########################
# Checkout #
###########################
- uses: actions/checkout@v4
with:
lfs: true
# Configure test runner
- name: Run tests
id: packageAllTests
uses: ./
with:
projectPath: ${{ matrix.projectPath }}
unityVersion: ${{ matrix.unityVersion }}
testMode: all
coverageOptions: 'generateAdditionalMetrics;generateHtmlReport;generateBadgeReport;assemblyFilters:+dependencyexample.testpackage.*,-*Tests*'
packageMode: true
scopedRegistryUrl: https://package.openupm.com
registryScopes: 'com.cysharp.unitask'
# Test implicit artifactsPath, by not setting it
# Upload artifacts
- name: Upload test results
uses: actions/upload-artifact@v3
with:
name: Package test results (all)
path: ${{ steps.packageAllTests.outputs.artifactsPath }}
retention-days: 14
# Upload coverage
- name: Upload coverage results
uses: actions/upload-artifact@v3
with:
name: Package Coverage results (all)
path: ${{ steps.packageAllTests.outputs.coveragePath }}
retention-days: 14
testPackageRunnerWithScopeRegistryAndMultipleScopes:
name: Test package mode in all modes with Scoped Registry and Multiple Scopes 🔎📦✨
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
projectPath:
- unity-package-with-correct-tests/com.dependencyexample.testpackage
unityVersion:
- 2022.3.13f1
- 2023.1.19f1
- 2023.2.2f1
steps:
###########################
# Checkout #
###########################
- uses: actions/checkout@v4
with:
lfs: true
# Configure test runner
- name: Run tests
id: packageAllTests
uses: ./
with:
projectPath: ${{ matrix.projectPath }}
unityVersion: ${{ matrix.unityVersion }}
testMode: all
coverageOptions: 'generateAdditionalMetrics;generateHtmlReport;generateBadgeReport;assemblyFilters:+dependencyexample.testpackage.*,-*Tests*'
packageMode: true
scopedRegistryUrl: https://package.openupm.com
registryScopes: 'com.cysharp, com.cysharp.unitask'
# Test implicit artifactsPath, by not setting it
# Upload artifacts
- name: Upload test results
uses: actions/upload-artifact@v3
with:
name: Package test results (all)
path: ${{ steps.packageAllTests.outputs.artifactsPath }}
retention-days: 14
# Upload coverage
- name: Upload coverage results
uses: actions/upload-artifact@v3
with:
name: Package Coverage results (all)
path: ${{ steps.packageAllTests.outputs.coveragePath }}
retention-days: 14

View File

@ -56,6 +56,14 @@ inputs:
required: false
default: false
description: 'Whether the tests are being run for a Unity package instead of a Unity project. If true, the action can only be run on Linux runners, and any custom docker image passed to this action must have `jq` installed. NOTE: may not work properly for packages with dependencies outside of the Unity Registry.'
scopedRegistryUrl:
required: false
default: ''
description: 'Scoped registry to use for resolving package dependencies. Only applicable if packageMode is true.'
registryScopes:
required: false
default: ''
description: 'Registry scopes to use for resolving package dependencies. Only applicable if packageMode is true. Required if scopedRegistry is set.'
chownFilesTo:
required: false
default: ''

18
dist/index.js generated vendored
View File

@ -98,7 +98,7 @@ function run() {
try {
model_1.Action.checkCompatibility();
const { workspace, actionFolder } = model_1.Action;
const { editorVersion, customImage, projectPath, customParameters, testMode, coverageOptions, artifactsPath, useHostNetwork, sshAgent, sshPublicKeysDirectoryPath, gitPrivateToken, githubToken, checkName, packageMode, packageName, chownFilesTo, dockerCpuLimit, dockerMemoryLimit, dockerIsolationMode, unityLicensingServer, runAsHostUser, containerRegistryRepository, containerRegistryImageVersion, unitySerial, } = model_1.Input.getFromUser();
const { editorVersion, customImage, projectPath, customParameters, testMode, coverageOptions, artifactsPath, useHostNetwork, sshAgent, sshPublicKeysDirectoryPath, gitPrivateToken, githubToken, checkName, packageMode, packageName, scopedRegistryUrl, registryScopes, chownFilesTo, dockerCpuLimit, dockerMemoryLimit, dockerIsolationMode, unityLicensingServer, runAsHostUser, containerRegistryRepository, containerRegistryImageVersion, unitySerial, } = model_1.Input.getFromUser();
const baseImage = new model_1.ImageTag({
editorVersion,
customImage,
@ -120,6 +120,8 @@ function run() {
sshPublicKeysDirectoryPath,
packageMode,
packageName,
scopedRegistryUrl,
registryScopes,
gitPrivateToken,
githubToken,
chownFilesTo,
@ -398,6 +400,9 @@ class ImageEnvironmentFactory {
{ name: 'ARTIFACTS_PATH', value: parameters.artifactsPath },
{ name: 'PACKAGE_MODE', value: parameters.packageMode },
{ name: 'PACKAGE_NAME', value: parameters.packageName },
{ name: 'SCOPED_REGISTRY_URL', value: parameters.scopedRegistryUrl },
{ name: 'REGISTRY_SCOPES', value: parameters.registryScopes },
{ name: 'PRIVATE_REGISTRY_TOKEN', value: process.env.UPM_REGISTRY_TOKEN },
{ name: 'GIT_PRIVATE_TOKEN', value: parameters.gitPrivateToken },
{ name: 'VERSION', value: parameters.buildVersion },
{ name: 'CUSTOM_PARAMETERS', value: parameters.customParameters },
@ -711,6 +716,9 @@ class Input {
const checkName = (0, core_1.getInput)('checkName') || 'Test Results';
const rawPackageMode = (0, core_1.getInput)('packageMode') || 'false';
let packageName = '';
const scopedRegistryUrl = (0, core_1.getInput)('scopedRegistryUrl') || '';
const rawScopes = (0, core_1.getInput)('registryScopes') || '';
let registryScopes = [];
const chownFilesTo = (0, core_1.getInput)('chownFilesTo') || '';
const dockerCpuLimit = (0, core_1.getInput)('dockerCpuLimit') || os_1.default.cpus().length.toString();
const bytesInMegabyte = 1024 * 1024;
@ -765,6 +773,12 @@ class Input {
}
packageName = this.getPackageNameFromPackageJson(projectPath);
this.verifyTestsFolderIsPresent(projectPath);
if (scopedRegistryUrl !== '') {
if (rawScopes === '') {
throw new Error('Scoped registry is set, but registryScopes is not set. registryScopes is required when using scopedRegistryUrl.');
}
registryScopes = rawScopes.split(',').map(scope => scope.trim());
}
}
if (runAsHostUser !== 'true' && runAsHostUser !== 'false') {
throw new Error(`Invalid runAsHostUser "${runAsHostUser}"`);
@ -805,6 +819,8 @@ class Input {
checkName,
packageMode,
packageName,
scopedRegistryUrl,
registryScopes,
chownFilesTo,
dockerCpuLimit,
dockerMemoryLimit,

2
dist/index.js.map generated vendored

File diff suppressed because one or more lines are too long

View File

@ -96,13 +96,34 @@ if [ "$PACKAGE_MODE" = "true" ]; then
PACKAGE_MANIFEST_JSON=$(cat "$PACKAGE_MANIFEST_PATH")
echo "$PACKAGE_MANIFEST_JSON" | \
jq \
--arg packageName "$PACKAGE_NAME" \
--arg projectPath "$UNITY_PROJECT_PATH" \
'.dependencies += {"com.unity.testtools.codecoverage": "1.1.1"} | .dependencies += {"\($packageName)": "file:\($projectPath)"} | . += {testables: ["\($packageName)"]}' \
> "$PACKAGE_MANIFEST_PATH"
jq \
--arg packageName "$PACKAGE_NAME" \
--arg projectPath "$UNITY_PROJECT_PATH" \
--arg scopedRegistryUrl "$SCOPED_REGISTRY_URL" \
--argjson registryScopes "$(echo "[\"$REGISTRY_SCOPES\"]" | sed 's/,/","/g')" \
'.dependencies += {"com.unity.testtools.codecoverage": "1.1.1"} |
.dependencies += {"\($packageName)": "file:\($projectPath)"} |
. += {testables: ["\($packageName)"]} |
. += {scopedRegistries: [{"name":"dependency", "url":"\($scopedRegistryUrl)", scopes: $registryScopes}] }' \
> "$PACKAGE_MANIFEST_PATH"
UNITY_PROJECT_PATH="$TEMP_PROJECT_PATH"
if [ -n "$PRIVATE_REGISTRY_TOKEN" ]; then
echo "Private registry token detected, creating .upmconfig.toml"
UPM_CONFIG_TOML_PATH="$HOME/.upmconfig.toml"
echo "Creating toml at path: $UPM_CONFIG_TOML_PATH"
touch $UPM_CONFIG_TOML_PATH
cat > "$UPM_CONFIG_TOML_PATH" <<EOF
[npmAuth."$SCOPED_REGISTRY_URL"]
token = "$PRIVATE_REGISTRY_TOKEN"
alwaysAuth = true
EOF
fi
fi

View File

@ -22,6 +22,8 @@ export async function run() {
checkName,
packageMode,
packageName,
scopedRegistryUrl,
registryScopes,
chownFilesTo,
dockerCpuLimit,
dockerMemoryLimit,
@ -55,6 +57,8 @@ export async function run() {
sshPublicKeysDirectoryPath,
packageMode,
packageName,
scopedRegistryUrl,
registryScopes,
gitPrivateToken,
githubToken,
chownFilesTo,

View File

@ -38,6 +38,9 @@ class ImageEnvironmentFactory {
{ name: 'ARTIFACTS_PATH', value: parameters.artifactsPath },
{ name: 'PACKAGE_MODE', value: parameters.packageMode },
{ name: 'PACKAGE_NAME', value: parameters.packageName },
{ name: 'SCOPED_REGISTRY_URL', value: parameters.scopedRegistryUrl },
{ name: 'REGISTRY_SCOPES', value: parameters.registryScopes },
{ name: 'PRIVATE_REGISTRY_TOKEN', value: process.env.UPM_REGISTRY_TOKEN },
{ name: 'GIT_PRIVATE_TOKEN', value: parameters.gitPrivateToken },
{ name: 'VERSION', value: parameters.buildVersion },
{ name: 'CUSTOM_PARAMETERS', value: parameters.customParameters },

View File

@ -101,6 +101,9 @@ class Input {
const checkName = getInput('checkName') || 'Test Results';
const rawPackageMode = getInput('packageMode') || 'false';
let packageName = '';
const scopedRegistryUrl = getInput('scopedRegistryUrl') || '';
const rawScopes = getInput('registryScopes') || '';
let registryScopes: string[] = [];
const chownFilesTo = getInput('chownFilesTo') || '';
const dockerCpuLimit = getInput('dockerCpuLimit') || os.cpus().length.toString();
const bytesInMegabyte = 1024 * 1024;
@ -171,6 +174,16 @@ class Input {
packageName = this.getPackageNameFromPackageJson(projectPath);
this.verifyTestsFolderIsPresent(projectPath);
if (scopedRegistryUrl !== '') {
if (rawScopes === '') {
throw new Error(
'Scoped registry is set, but registryScopes is not set. registryScopes is required when using scopedRegistryUrl.',
);
}
registryScopes = rawScopes.split(',').map(scope => scope.trim());
}
}
if (runAsHostUser !== 'true' && runAsHostUser !== 'false') {
@ -219,6 +232,8 @@ class Input {
checkName,
packageMode,
packageName,
scopedRegistryUrl,
registryScopes,
chownFilesTo,
dockerCpuLimit,
dockerMemoryLimit,

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a62b511ba12825d4d9f992b4ed37a533
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e3a65787d84893340b9dc38af5b7c31f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,15 @@
using UnityEngine;
using System.Collections;
using UnityEditor;
[CustomEditor(typeof(TimerComponent))]
public class LevelScriptEditor : Editor
{
public override void OnInspectorGUI()
{
TimerComponent myTarget = (TimerComponent)target;
EditorGUILayout.LabelField("Timer", myTarget.Timer.ToString());
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f0a715d2f35ea4c40a6f1cdae355c61c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,16 @@
{
"name": "example.testpackage.Editor",
"rootNamespace": "",
"references": [
"example.testpackage.Runtime"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 8223b1b52474b674a87c6113b6384f10
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e472ec5749e60ca4db87f10cec905d2c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 21861106477d38342a589fc525c4e0bb
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6c6729c46a2a6594da2ce1182420ab81
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,18 @@
using System;
public class BasicCounter
{
public const int MaxCount = 10;
public BasicCounter(int count = 0)
{
Count = count;
}
public void Increment()
{
Count = Math.Min(MaxCount, Count + 1);
}
public int Count { get; private set; }
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0bd8dfbd5c7fc9e439246091668234b0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,17 @@
using UnityEngine;
public class SampleComponent : MonoBehaviour
{
public BasicCounter Counter;
void Start()
{
Counter = new BasicCounter(5);
}
// Update is called once per frame
void Update()
{
Counter.Increment();
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 121f2ede62657a84082c012941df22d5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,18 @@
using UnityEngine;
public class TimerComponent : MonoBehaviour
{
public BasicCounter Counter = new BasicCounter();
public float Timer = 1f;
void Update()
{
Timer -= Time.deltaTime;
if (Timer > 0)
return;
Counter.Increment();
Timer = 1f;
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 563e4fb514abf6141b80ca1b71c08889
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,14 @@
{
"name": "example.testpackage.Runtime",
"rootNamespace": "",
"references": [],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: b20629d7e725e1e449076020f132df2a
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d0f3a0ff2938264498234e4aaa66cf5f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7644cfe4cdc2d0f4ebc7ab351323a576
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,38 @@
using System.Collections;
using System.Collections.Generic;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
namespace Tests
{
public class SampleEditModeTest
{
[Test]
public void TestIncrement()
{
// Given
var counter = new BasicCounter(0);
// When
counter.Increment();
// Then
Assert.AreEqual(1, counter.Count);
}
[Test]
public void TestMaxCount()
{
// Given
var counter = new BasicCounter(BasicCounter.MaxCount);
// When
counter.Increment();
// Then
Assert.AreEqual(BasicCounter.MaxCount, counter.Count);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 88de94cc1489d83488ce54f71b512989
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,25 @@
{
"name": "example.testpackage.EditorTests",
"rootNamespace": "",
"references": [
"UnityEngine.TestRunner",
"UnityEditor.TestRunner",
"example.testpackage.Editor",
"example.testpackage.Runtime"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": true,
"precompiledReferences": [
"nunit.framework.dll"
],
"autoReferenced": false,
"defineConstraints": [
"UNITY_INCLUDE_TESTS"
],
"versionDefines": [],
"noEngineReferences": false
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: b5712d2009ce3b34a8ca077667b16764
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b4f774583b1374a4abe450c7100726bd
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,31 @@
using System.Collections;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
namespace Tests
{
public class SampleComponentTest
{
private GameObject target;
private SampleComponent component;
[SetUp]
public void Setup()
{
target = GameObject.Instantiate(new GameObject());
component = target.AddComponent<SampleComponent>();
}
[UnityTest]
public IEnumerator TestIncrementOnUpdateAfterNextFrame()
{
// Save the current value, since it was updated after component Start() method called
var count = component.Counter.Count;
// Skip frame and assert the new value
yield return null;
Assert.AreEqual(count + 1, component.Counter.Count);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b551b84934711564eb78aab8c16425ac
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,42 @@
using System.Collections;
using NUnit.Framework;
using UnityEngine.TestTools;
namespace Tests
{
public class SamplePlayModeTest
{
// A Test behaves as an ordinary method
[Test]
public void NewTestScriptSimplePasses()
{
// Given
var counter = new BasicCounter(0);
// When
counter.Increment();
// Then
Assert.AreEqual(1, counter.Count);
}
// A UnityTest behaves like a coroutine in Play Mode. In Edit Mode you can use
// `yield return null;` to skip a frame.
[UnityTest]
public IEnumerator NewTestScriptWithEnumeratorPasses()
{
// Given
var counter = new BasicCounter(3);
// Use the Assert class to test conditions.
// Use yield to skip a frame.
yield return null;
// When
counter.Increment();
// Then
Assert.AreEqual(4, counter.Count);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4dbe2d2dc79550c4d81602bcf94a9824
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,66 @@
using System.Collections;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
namespace Tests
{
public class TimerComponentTest
{
private GameObject target;
private TimerComponent component;
[SetUp]
public void Setup()
{
target = GameObject.Instantiate(new GameObject());
component = target.AddComponent<TimerComponent>();
}
[UnityTest]
public IEnumerator TestIncrementAfterSomeTime()
{
// Save the current value, since it was updated after component Start() method called
var count = component.Counter.Count;
// Skip frame and assert the new value
yield return null;
Assert.AreEqual(count, component.Counter.Count);
yield return new WaitForSeconds(1.1f);
Assert.AreEqual(count + 1, component.Counter.Count);
yield return new WaitForSeconds(1.1f);
Assert.AreEqual(count + 2, component.Counter.Count);
}
[UnityTest]
public IEnumerator TestTimeScaleIsAffectingIncrement()
{
// Save the current value, since it was updated after component Start() method called
var count = component.Counter.Count;
Time.timeScale = .5f;
// Skip frame and assert the new value
yield return null;
Assert.AreEqual(count, component.Counter.Count);
yield return WaitForRealSeconds(1.1f);
Assert.AreEqual(count, component.Counter.Count);
yield return WaitForRealSeconds(1.1f);
Assert.AreEqual(count + 1, component.Counter.Count);
}
// Skipping time ignoring Time.scale
// https://answers.unity.com/questions/301868/yield-waitforseconds-outside-of-timescale.html
public static IEnumerator WaitForRealSeconds(float time)
{
float start = Time.realtimeSinceStartup;
while (Time.realtimeSinceStartup < start + time)
{
yield return null;
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 010121a56a70d60428dc89307eb77b54
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,22 @@
{
"name": "example.testpackage.RuntimeTests",
"rootNamespace": "",
"references": [
"UnityEngine.TestRunner",
"UnityEditor.TestRunner",
"example.testpackage.Runtime"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": true,
"precompiledReferences": [
"nunit.framework.dll"
],
"autoReferenced": false,
"defineConstraints": [
"UNITY_INCLUDE_TESTS"
],
"versionDefines": [],
"noEngineReferences": false
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 902aaaf7a59149243b2f4e38fc9f388e
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,21 @@
{
"name": "com.dependencyexample.testpackage",
"version": "0.0.1",
"displayName": "Test Package",
"description": "Test Package",
"unity": "2022.3",
"unityRelease": "7f1",
"dependencies": {
"com.cysharp.unitask": "2.5.3"
},
"keywords": [
"nothing"
],
"author": {
"name": "Example Author",
"email": "author@example.com",
"url": "example.com"
},
"type": "tool",
"hideInEditor": false
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 4232dbd3889ab6a4393e846291288fb0
PackageManifestImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: