diff --git a/API.md b/API.md index fb1a67b..7244f91 100644 --- a/API.md +++ b/API.md @@ -22,7 +22,7 @@ Add that to your `~/.bashrc` or `~/.zshrc` file to make it permanent. Be sure to In a new directory, run: -`projen new ovosskill --from "@mikejgray/ovos-skill-projen@latest"` +`npx projen new ovosskill --from "@mikejgray/ovos-skill-projen@latest"` **NOTE**: This repo is not yet available on NPM. Please add the following to your `~/.npmrc` file (create one if it doesn't exist), with [a GitHub token that has packages:read permissions](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-npm-registry): @@ -52,6 +52,26 @@ Example: After editing `.projenrc.json`, run `pj` to regenerate the project files. This can automatically keep your project up to date with the latest changes, including managing your `setup.py` file. +## Create a new PHAL plugin template + +In a new directory, run: + +`npx projen new ovosphal --from "@mikejgray/ovos-skill-projen@latest"` + +The instructions are the same as for creating a new skill template, except that you have an additional option to set the PHAL plugin as admin or not. The default is `false`, indicating that the PHAL plugin will not run as root. + +**NOTE:** If you do set the PHAL plugin to `admin` and thus run as root, you will also need to update your OVOS config to explicitly allow your root plugins. This is a security risk and should only be done if you understand the implications. For more information about Admin PHAL, [see the OVOS technical manual](https://openvoiceos.github.io/ovos-technical-manual/PHAL/#admin-phal). + +Example OVOS config: + +```json +{ + "PHAL": { + "admin": "ovos-phal-plugin-helloworld": {"enabled": true} + } +} +``` + ### setup.py ownership Note that projen takes ownership of the `setup.py` file, and the expectation is that manual edits are not allowed. If you need to make changes to the `setup.py` file, you should do so by editing `.projenrc.json` and running `pj` to regenerate the file. @@ -91,68 +111,69 @@ If your skill code is not in `__init__.py` in the repository root, the retrofit ## Structs -### OVOSSkillProjectOptions +### OVOSPHALProjectOptions -#### Initializer +#### Initializer ```typescript -import { OVOSSkillProjectOptions } from '@mikejgray/ovos-skill-projen' +import { OVOSPHALProjectOptions } from '@mikejgray/ovos-skill-projen' -const oVOSSkillProjectOptions: OVOSSkillProjectOptions = { ... } +const oVOSPHALProjectOptions: OVOSPHALProjectOptions = { ... } ``` #### Properties | **Name** | **Type** | **Description** | | --- | --- | --- | -| name | string | This is the name of your project. | -| commitGenerated | boolean | Whether to commit the managed files by default. | -| gitIgnoreOptions | projen.IgnoreFileOptions | Configuration options for .gitignore file. | -| gitOptions | projen.GitOptions | Configuration options for git. | -| logging | projen.LoggerOptions | Configure logging options such as verbosity. | -| outdir | string | The root directory of the project. | -| parent | projen.Project | The parent project, if this project is part of a bigger project. | -| projenCommand | string | The shell command to use in order to run the projen CLI. | -| projenrcJson | boolean | Generate (once) .projenrc.json (in JSON). Set to `false` in order to disable .projenrc.json generation. | -| projenrcJsonOptions | projen.ProjenrcJsonOptions | Options for .projenrc.json. | -| renovatebot | boolean | Use renovatebot to handle dependency upgrades. | -| renovatebotOptions | projen.RenovatebotOptions | Options for renovatebot. | -| autoApproveOptions | projen.github.AutoApproveOptions | Enable and configure the 'auto approve' workflow. | -| autoMerge | boolean | Enable automatic merging on GitHub. | -| autoMergeOptions | projen.github.AutoMergeOptions | Configure options for automatic merging on GitHub. | -| clobber | boolean | Add a `clobber` task which resets the repo to origin. | -| devContainer | boolean | Add a VSCode development environment (used for GitHub Codespaces). | -| github | boolean | Enable GitHub integration. | -| githubOptions | projen.github.GitHubOptions | Options for GitHub integration. | -| gitpod | boolean | Add a Gitpod development environment. | -| mergify | boolean | Whether mergify should be enabled on this repository or not. | -| mergifyOptions | projen.github.MergifyOptions | Options for mergify. | -| projectType | projen.ProjectType | Which type of project this is (library/app). | -| projenCredentials | projen.github.GithubCredentials | Choose a method of providing GitHub API access for projen workflows. | -| projenTokenSecret | string | The name of a secret which includes a GitHub Personal Access Token to be used by projen workflows. | -| readme | projen.SampleReadmeProps | The README setup. | -| stale | boolean | Auto-close of stale issues and pull request. | -| staleOptions | projen.github.StaleOptions | Auto-close stale issues and pull requests. | -| vscode | boolean | Enable VSCode integration. | -| author | string | The name of the skill's author. | -| authorAddress | string | The email address of the skill's author. | -| authorHandle | string | The GitHub handle of the skill's author. | -| condenseLocaleFolders | boolean | Restructure locale folders to be more OVOS-like? | -| githubWorkflows | boolean | Add Github Actions workflows? | -| license | string | The license of the skill. | -| packageDir | string | The name of the directory containing the skill's code. | -| pypiName | string | The name of the skill's PyPi package. | -| repositoryUrl | string | The URL of the skill's GitHub repository. | -| retrofit | boolean | Retrofit an existing Mycroft skill to OVOS? | -| sampleCode | boolean | Include sample code? | -| skillClass | string | The name of the skill class. | -| skillDescription | string | The description of the skill. | -| skillKeywords | string | Keywords for your skill package. | -| skillLicenseTest | boolean | Include a test to check that the skill's license is FOSS? | - ---- - -##### `name`Required +| name | string | This is the name of your project. | +| commitGenerated | boolean | Whether to commit the managed files by default. | +| gitIgnoreOptions | projen.IgnoreFileOptions | Configuration options for .gitignore file. | +| gitOptions | projen.GitOptions | Configuration options for git. | +| logging | projen.LoggerOptions | Configure logging options such as verbosity. | +| outdir | string | The root directory of the project. | +| parent | projen.Project | The parent project, if this project is part of a bigger project. | +| projenCommand | string | The shell command to use in order to run the projen CLI. | +| projenrcJson | boolean | Generate (once) .projenrc.json (in JSON). Set to `false` in order to disable .projenrc.json generation. | +| projenrcJsonOptions | projen.ProjenrcJsonOptions | Options for .projenrc.json. | +| renovatebot | boolean | Use renovatebot to handle dependency upgrades. | +| renovatebotOptions | projen.RenovatebotOptions | Options for renovatebot. | +| autoApproveOptions | projen.github.AutoApproveOptions | Enable and configure the 'auto approve' workflow. | +| autoMerge | boolean | Enable automatic merging on GitHub. | +| autoMergeOptions | projen.github.AutoMergeOptions | Configure options for automatic merging on GitHub. | +| clobber | boolean | Add a `clobber` task which resets the repo to origin. | +| devContainer | boolean | Add a VSCode development environment (used for GitHub Codespaces). | +| github | boolean | Enable GitHub integration. | +| githubOptions | projen.github.GitHubOptions | Options for GitHub integration. | +| gitpod | boolean | Add a Gitpod development environment. | +| mergify | boolean | Whether mergify should be enabled on this repository or not. | +| mergifyOptions | projen.github.MergifyOptions | Options for mergify. | +| projectType | projen.ProjectType | Which type of project this is (library/app). | +| projenCredentials | projen.github.GithubCredentials | Choose a method of providing GitHub API access for projen workflows. | +| projenTokenSecret | string | The name of a secret which includes a GitHub Personal Access Token to be used by projen workflows. | +| readme | projen.SampleReadmeProps | The README setup. | +| stale | boolean | Auto-close of stale issues and pull request. | +| staleOptions | projen.github.StaleOptions | Auto-close stale issues and pull requests. | +| vscode | boolean | Enable VSCode integration. | +| author | string | The name of the skill's author. | +| authorAddress | string | The email address of the skill's author. | +| authorHandle | string | The GitHub handle of the skill's author. | +| condenseLocaleFolders | boolean | Restructure locale folders to be more OVOS-like? | +| githubWorkflows | boolean | Add Github Actions workflows? | +| license | string | The license of the skill. | +| packageDir | string | The name of the directory containing the skill's code. | +| pypiName | string | The name of the skill's PyPi package. | +| repositoryUrl | string | The URL of the skill's GitHub repository. | +| retrofit | boolean | Retrofit an existing Mycroft skill to OVOS? | +| sampleCode | boolean | Include sample code? | +| skillClass | string | The name of the skill class. | +| skillDescription | string | The description of the skill. | +| skillKeywords | string | Keywords for your skill package. | +| skillLicenseTest | boolean | Include a test to check that the skill's license is FOSS? | +| admin | boolean | Is this an admin PHAL plugin? | + +--- + +##### `name`Required ```typescript public readonly name: string; @@ -165,7 +186,7 @@ This is the name of your project. --- -##### `commitGenerated`Optional +##### `commitGenerated`Optional ```typescript public readonly commitGenerated: boolean; @@ -178,7 +199,7 @@ Whether to commit the managed files by default. --- -##### `gitIgnoreOptions`Optional +##### `gitIgnoreOptions`Optional ```typescript public readonly gitIgnoreOptions: IgnoreFileOptions; @@ -190,7 +211,7 @@ Configuration options for .gitignore file. --- -##### `gitOptions`Optional +##### `gitOptions`Optional ```typescript public readonly gitOptions: GitOptions; @@ -202,7 +223,7 @@ Configuration options for git. --- -##### `logging`Optional +##### `logging`Optional ```typescript public readonly logging: LoggerOptions; @@ -215,7 +236,7 @@ Configure logging options such as verbosity. --- -##### `outdir`Optional +##### `outdir`Optional ```typescript public readonly outdir: string; @@ -234,7 +255,7 @@ sub-projects. --- -##### `parent`Optional +##### `parent`Optional ```typescript public readonly parent: Project; @@ -246,7 +267,7 @@ The parent project, if this project is part of a bigger project. --- -##### `projenCommand`Optional +##### `projenCommand`Optional ```typescript public readonly projenCommand: string; @@ -261,7 +282,7 @@ Can be used to customize in special environments. --- -##### `projenrcJson`Optional +##### `projenrcJson`Optional ```typescript public readonly projenrcJson: boolean; @@ -274,7 +295,7 @@ Generate (once) .projenrc.json (in JSON). Set to `false` in order to disable .pr --- -##### `projenrcJsonOptions`Optional +##### `projenrcJsonOptions`Optional ```typescript public readonly projenrcJsonOptions: ProjenrcJsonOptions; @@ -287,7 +308,7 @@ Options for .projenrc.json. --- -##### `renovatebot`Optional +##### `renovatebot`Optional ```typescript public readonly renovatebot: boolean; @@ -300,7 +321,7 @@ Use renovatebot to handle dependency upgrades. --- -##### `renovatebotOptions`Optional +##### `renovatebotOptions`Optional ```typescript public readonly renovatebotOptions: RenovatebotOptions; @@ -313,7 +334,7 @@ Options for renovatebot. --- -##### `autoApproveOptions`Optional +##### `autoApproveOptions`Optional ```typescript public readonly autoApproveOptions: AutoApproveOptions; @@ -326,7 +347,7 @@ Enable and configure the 'auto approve' workflow. --- -##### `autoMerge`Optional +##### `autoMerge`Optional ```typescript public readonly autoMerge: boolean; @@ -342,7 +363,7 @@ is set to false. --- -##### `autoMergeOptions`Optional +##### `autoMergeOptions`Optional ```typescript public readonly autoMergeOptions: AutoMergeOptions; @@ -358,7 +379,7 @@ Has no effect if --- -##### `clobber`Optional +##### `clobber`Optional ```typescript public readonly clobber: boolean; @@ -371,7 +392,7 @@ Add a `clobber` task which resets the repo to origin. --- -##### `devContainer`Optional +##### `devContainer`Optional ```typescript public readonly devContainer: boolean; @@ -384,7 +405,7 @@ Add a VSCode development environment (used for GitHub Codespaces). --- -##### `github`Optional +##### `github`Optional ```typescript public readonly github: boolean; @@ -399,7 +420,7 @@ Enabled by default for root projects. Disabled for non-root projects. --- -##### `githubOptions`Optional +##### `githubOptions`Optional ```typescript public readonly githubOptions: GitHubOptions; @@ -412,7 +433,7 @@ Options for GitHub integration. --- -##### `gitpod`Optional +##### `gitpod`Optional ```typescript public readonly gitpod: boolean; @@ -425,7 +446,7 @@ Add a Gitpod development environment. --- -##### ~~`mergify`~~Optional +##### ~~`mergify`~~Optional - *Deprecated:* use `githubOptions.mergify` instead @@ -440,7 +461,7 @@ Whether mergify should be enabled on this repository or not. --- -##### ~~`mergifyOptions`~~Optional +##### ~~`mergifyOptions`~~Optional - *Deprecated:* use `githubOptions.mergifyOptions` instead @@ -455,7 +476,7 @@ Options for mergify. --- -##### ~~`projectType`~~Optional +##### ~~`projectType`~~Optional - *Deprecated:* no longer supported at the base project level @@ -470,7 +491,7 @@ Which type of project this is (library/app). --- -##### `projenCredentials`Optional +##### `projenCredentials`Optional ```typescript public readonly projenCredentials: GithubCredentials; @@ -483,7 +504,7 @@ Choose a method of providing GitHub API access for projen workflows. --- -##### ~~`projenTokenSecret`~~Optional +##### ~~`projenTokenSecret`~~Optional - *Deprecated:* use `projenCredentials` @@ -501,7 +522,7 @@ and `packages` scope. --- -##### `readme`Optional +##### `readme`Optional ```typescript public readonly readme: SampleReadmeProps; @@ -521,7 +542,7 @@ The README setup. ``` -##### `stale`Optional +##### `stale`Optional ```typescript public readonly stale: boolean; @@ -536,7 +557,7 @@ See `staleOptions` for options. --- -##### `staleOptions`Optional +##### `staleOptions`Optional ```typescript public readonly staleOptions: StaleOptions; @@ -551,7 +572,7 @@ To disable set `stale` to `false`. --- -##### `vscode`Optional +##### `vscode`Optional ```typescript public readonly vscode: boolean; @@ -566,7 +587,7 @@ Enabled by default for root projects. Disabled for non-root projects. --- -##### `author`Optional +##### `author`Optional ```typescript public readonly author: string; @@ -586,7 +607,7 @@ The name of the skill's author. ``` -##### `authorAddress`Optional +##### `authorAddress`Optional ```typescript public readonly authorAddress: string; @@ -606,7 +627,7 @@ The email address of the skill's author. ``` -##### `authorHandle`Optional +##### `authorHandle`Optional ```typescript public readonly authorHandle: string; @@ -626,7 +647,7 @@ The GitHub handle of the skill's author. ``` -##### `condenseLocaleFolders`Optional +##### `condenseLocaleFolders`Optional ```typescript public readonly condenseLocaleFolders: boolean; @@ -639,7 +660,7 @@ Restructure locale folders to be more OVOS-like? --- -##### `githubWorkflows`Optional +##### `githubWorkflows`Optional ```typescript public readonly githubWorkflows: boolean; @@ -652,7 +673,7 @@ Add Github Actions workflows? --- -##### `license`Optional +##### `license`Optional ```typescript public readonly license: string; @@ -672,7 +693,7 @@ MIT ``` -##### `packageDir`Optional +##### `packageDir`Optional ```typescript public readonly packageDir: string; @@ -692,7 +713,7 @@ The name of the directory containing the skill's code. ``` -##### `pypiName`Optional +##### `pypiName`Optional ```typescript public readonly pypiName: string; @@ -711,7 +732,7 @@ ovos-hello-world-skill ``` -##### `repositoryUrl`Optional +##### `repositoryUrl`Optional ```typescript public readonly repositoryUrl: string; @@ -731,7 +752,7 @@ The URL of the skill's GitHub repository. ``` -##### `retrofit`Optional +##### `retrofit`Optional ```typescript public readonly retrofit: boolean; @@ -744,7 +765,7 @@ Retrofit an existing Mycroft skill to OVOS? --- -##### `sampleCode`Optional +##### `sampleCode`Optional ```typescript public readonly sampleCode: boolean; @@ -757,7 +778,7 @@ Include sample code? --- -##### `skillClass`Optional +##### `skillClass`Optional ```typescript public readonly skillClass: string; @@ -776,7 +797,7 @@ HelloWorldSkill ``` -##### `skillDescription`Optional +##### `skillDescription`Optional ```typescript public readonly skillDescription: string; @@ -798,7 +819,7 @@ Used in setup.py. ``` -##### `skillKeywords`Optional +##### `skillKeywords`Optional ```typescript public readonly skillKeywords: string; @@ -811,7 +832,7 @@ Keywords for your skill package. --- -##### `skillLicenseTest`Optional +##### `skillLicenseTest`Optional ```typescript public readonly skillLicenseTest: boolean; @@ -824,7 +845,1517 @@ Include a test to check that the skill's license is FOSS? --- -## Classes +##### `admin`Optional + +```typescript +public readonly admin: boolean; +``` + +- *Type:* boolean +- *Default:* false + +Is this an admin PHAL plugin? + +--- + +### OVOSSkillProjectOptions + +#### Initializer + +```typescript +import { OVOSSkillProjectOptions } from '@mikejgray/ovos-skill-projen' + +const oVOSSkillProjectOptions: OVOSSkillProjectOptions = { ... } +``` + +#### Properties + +| **Name** | **Type** | **Description** | +| --- | --- | --- | +| name | string | This is the name of your project. | +| commitGenerated | boolean | Whether to commit the managed files by default. | +| gitIgnoreOptions | projen.IgnoreFileOptions | Configuration options for .gitignore file. | +| gitOptions | projen.GitOptions | Configuration options for git. | +| logging | projen.LoggerOptions | Configure logging options such as verbosity. | +| outdir | string | The root directory of the project. | +| parent | projen.Project | The parent project, if this project is part of a bigger project. | +| projenCommand | string | The shell command to use in order to run the projen CLI. | +| projenrcJson | boolean | Generate (once) .projenrc.json (in JSON). Set to `false` in order to disable .projenrc.json generation. | +| projenrcJsonOptions | projen.ProjenrcJsonOptions | Options for .projenrc.json. | +| renovatebot | boolean | Use renovatebot to handle dependency upgrades. | +| renovatebotOptions | projen.RenovatebotOptions | Options for renovatebot. | +| autoApproveOptions | projen.github.AutoApproveOptions | Enable and configure the 'auto approve' workflow. | +| autoMerge | boolean | Enable automatic merging on GitHub. | +| autoMergeOptions | projen.github.AutoMergeOptions | Configure options for automatic merging on GitHub. | +| clobber | boolean | Add a `clobber` task which resets the repo to origin. | +| devContainer | boolean | Add a VSCode development environment (used for GitHub Codespaces). | +| github | boolean | Enable GitHub integration. | +| githubOptions | projen.github.GitHubOptions | Options for GitHub integration. | +| gitpod | boolean | Add a Gitpod development environment. | +| mergify | boolean | Whether mergify should be enabled on this repository or not. | +| mergifyOptions | projen.github.MergifyOptions | Options for mergify. | +| projectType | projen.ProjectType | Which type of project this is (library/app). | +| projenCredentials | projen.github.GithubCredentials | Choose a method of providing GitHub API access for projen workflows. | +| projenTokenSecret | string | The name of a secret which includes a GitHub Personal Access Token to be used by projen workflows. | +| readme | projen.SampleReadmeProps | The README setup. | +| stale | boolean | Auto-close of stale issues and pull request. | +| staleOptions | projen.github.StaleOptions | Auto-close stale issues and pull requests. | +| vscode | boolean | Enable VSCode integration. | +| author | string | The name of the skill's author. | +| authorAddress | string | The email address of the skill's author. | +| authorHandle | string | The GitHub handle of the skill's author. | +| condenseLocaleFolders | boolean | Restructure locale folders to be more OVOS-like? | +| githubWorkflows | boolean | Add Github Actions workflows? | +| license | string | The license of the skill. | +| packageDir | string | The name of the directory containing the skill's code. | +| pypiName | string | The name of the skill's PyPi package. | +| repositoryUrl | string | The URL of the skill's GitHub repository. | +| retrofit | boolean | Retrofit an existing Mycroft skill to OVOS? | +| sampleCode | boolean | Include sample code? | +| skillClass | string | The name of the skill class. | +| skillDescription | string | The description of the skill. | +| skillKeywords | string | Keywords for your skill package. | +| skillLicenseTest | boolean | Include a test to check that the skill's license is FOSS? | + +--- + +##### `name`Required + +```typescript +public readonly name: string; +``` + +- *Type:* string +- *Default:* $BASEDIR + +This is the name of your project. + +--- + +##### `commitGenerated`Optional + +```typescript +public readonly commitGenerated: boolean; +``` + +- *Type:* boolean +- *Default:* true + +Whether to commit the managed files by default. + +--- + +##### `gitIgnoreOptions`Optional + +```typescript +public readonly gitIgnoreOptions: IgnoreFileOptions; +``` + +- *Type:* projen.IgnoreFileOptions + +Configuration options for .gitignore file. + +--- + +##### `gitOptions`Optional + +```typescript +public readonly gitOptions: GitOptions; +``` + +- *Type:* projen.GitOptions + +Configuration options for git. + +--- + +##### `logging`Optional + +```typescript +public readonly logging: LoggerOptions; +``` + +- *Type:* projen.LoggerOptions +- *Default:* {} + +Configure logging options such as verbosity. + +--- + +##### `outdir`Optional + +```typescript +public readonly outdir: string; +``` + +- *Type:* string +- *Default:* "." + +The root directory of the project. + +Relative to this directory, all files are synthesized. + +If this project has a parent, this directory is relative to the parent +directory and it cannot be the same as the parent or any of it's other +sub-projects. + +--- + +##### `parent`Optional + +```typescript +public readonly parent: Project; +``` + +- *Type:* projen.Project + +The parent project, if this project is part of a bigger project. + +--- + +##### `projenCommand`Optional + +```typescript +public readonly projenCommand: string; +``` + +- *Type:* string +- *Default:* "npx projen" + +The shell command to use in order to run the projen CLI. + +Can be used to customize in special environments. + +--- + +##### `projenrcJson`Optional + +```typescript +public readonly projenrcJson: boolean; +``` + +- *Type:* boolean +- *Default:* false + +Generate (once) .projenrc.json (in JSON). Set to `false` in order to disable .projenrc.json generation. + +--- + +##### `projenrcJsonOptions`Optional + +```typescript +public readonly projenrcJsonOptions: ProjenrcJsonOptions; +``` + +- *Type:* projen.ProjenrcJsonOptions +- *Default:* default options + +Options for .projenrc.json. + +--- + +##### `renovatebot`Optional + +```typescript +public readonly renovatebot: boolean; +``` + +- *Type:* boolean +- *Default:* false + +Use renovatebot to handle dependency upgrades. + +--- + +##### `renovatebotOptions`Optional + +```typescript +public readonly renovatebotOptions: RenovatebotOptions; +``` + +- *Type:* projen.RenovatebotOptions +- *Default:* default options + +Options for renovatebot. + +--- + +##### `autoApproveOptions`Optional + +```typescript +public readonly autoApproveOptions: AutoApproveOptions; +``` + +- *Type:* projen.github.AutoApproveOptions +- *Default:* auto approve is disabled + +Enable and configure the 'auto approve' workflow. + +--- + +##### `autoMerge`Optional + +```typescript +public readonly autoMerge: boolean; +``` + +- *Type:* boolean +- *Default:* true + +Enable automatic merging on GitHub. + +Has no effect if `github.mergify` +is set to false. + +--- + +##### `autoMergeOptions`Optional + +```typescript +public readonly autoMergeOptions: AutoMergeOptions; +``` + +- *Type:* projen.github.AutoMergeOptions +- *Default:* see defaults in `AutoMergeOptions` + +Configure options for automatic merging on GitHub. + +Has no effect if +`github.mergify` or `autoMerge` is set to false. + +--- + +##### `clobber`Optional + +```typescript +public readonly clobber: boolean; +``` + +- *Type:* boolean +- *Default:* true, but false for subprojects + +Add a `clobber` task which resets the repo to origin. + +--- + +##### `devContainer`Optional + +```typescript +public readonly devContainer: boolean; +``` + +- *Type:* boolean +- *Default:* false + +Add a VSCode development environment (used for GitHub Codespaces). + +--- + +##### `github`Optional + +```typescript +public readonly github: boolean; +``` + +- *Type:* boolean +- *Default:* true + +Enable GitHub integration. + +Enabled by default for root projects. Disabled for non-root projects. + +--- + +##### `githubOptions`Optional + +```typescript +public readonly githubOptions: GitHubOptions; +``` + +- *Type:* projen.github.GitHubOptions +- *Default:* see GitHubOptions + +Options for GitHub integration. + +--- + +##### `gitpod`Optional + +```typescript +public readonly gitpod: boolean; +``` + +- *Type:* boolean +- *Default:* false + +Add a Gitpod development environment. + +--- + +##### ~~`mergify`~~Optional + +- *Deprecated:* use `githubOptions.mergify` instead + +```typescript +public readonly mergify: boolean; +``` + +- *Type:* boolean +- *Default:* true + +Whether mergify should be enabled on this repository or not. + +--- + +##### ~~`mergifyOptions`~~Optional + +- *Deprecated:* use `githubOptions.mergifyOptions` instead + +```typescript +public readonly mergifyOptions: MergifyOptions; +``` + +- *Type:* projen.github.MergifyOptions +- *Default:* default options + +Options for mergify. + +--- + +##### ~~`projectType`~~Optional + +- *Deprecated:* no longer supported at the base project level + +```typescript +public readonly projectType: ProjectType; +``` + +- *Type:* projen.ProjectType +- *Default:* ProjectType.UNKNOWN + +Which type of project this is (library/app). + +--- + +##### `projenCredentials`Optional + +```typescript +public readonly projenCredentials: GithubCredentials; +``` + +- *Type:* projen.github.GithubCredentials +- *Default:* use a personal access token named PROJEN_GITHUB_TOKEN + +Choose a method of providing GitHub API access for projen workflows. + +--- + +##### ~~`projenTokenSecret`~~Optional + +- *Deprecated:* use `projenCredentials` + +```typescript +public readonly projenTokenSecret: string; +``` + +- *Type:* string +- *Default:* "PROJEN_GITHUB_TOKEN" + +The name of a secret which includes a GitHub Personal Access Token to be used by projen workflows. + +This token needs to have the `repo`, `workflows` +and `packages` scope. + +--- + +##### `readme`Optional + +```typescript +public readonly readme: SampleReadmeProps; +``` + +- *Type:* projen.SampleReadmeProps +- *Default:* { filename: 'README.md', contents: '# replace this' } + +The README setup. + +--- + +*Example* + +```typescript +"{ filename: 'readme.md', contents: '# title' }" +``` + + +##### `stale`Optional + +```typescript +public readonly stale: boolean; +``` + +- *Type:* boolean +- *Default:* false + +Auto-close of stale issues and pull request. + +See `staleOptions` for options. + +--- + +##### `staleOptions`Optional + +```typescript +public readonly staleOptions: StaleOptions; +``` + +- *Type:* projen.github.StaleOptions +- *Default:* see defaults in `StaleOptions` + +Auto-close stale issues and pull requests. + +To disable set `stale` to `false`. + +--- + +##### `vscode`Optional + +```typescript +public readonly vscode: boolean; +``` + +- *Type:* boolean +- *Default:* true + +Enable VSCode integration. + +Enabled by default for root projects. Disabled for non-root projects. + +--- + +##### `author`Optional + +```typescript +public readonly author: string; +``` + +- *Type:* string +- *Default:* "TODO: Your Name" + +The name of the skill's author. + +--- + +*Example* + +```typescript +"Mike Gray" +``` + + +##### `authorAddress`Optional + +```typescript +public readonly authorAddress: string; +``` + +- *Type:* string +- *Default:* "TODO: Your Email" + +The email address of the skill's author. + +--- + +*Example* + +```typescript +"mike@graywind.org" +``` + + +##### `authorHandle`Optional + +```typescript +public readonly authorHandle: string; +``` + +- *Type:* string +- *Default:* "" + +The GitHub handle of the skill's author. + +--- + +*Example* + +```typescript +"mikejgray" +``` + + +##### `condenseLocaleFolders`Optional + +```typescript +public readonly condenseLocaleFolders: boolean; +``` + +- *Type:* boolean +- *Default:* true + +Restructure locale folders to be more OVOS-like? + +--- + +##### `githubWorkflows`Optional + +```typescript +public readonly githubWorkflows: boolean; +``` + +- *Type:* boolean +- *Default:* true + +Add Github Actions workflows? + +--- + +##### `license`Optional + +```typescript +public readonly license: string; +``` + +- *Type:* string +- *Default:* Apache-2.0 + +The license of the skill. + +--- + +*Example* + +```typescript +MIT +``` + + +##### `packageDir`Optional + +```typescript +public readonly packageDir: string; +``` + +- *Type:* string +- *Default:* "" (root) + +The name of the directory containing the skill's code. + +--- + +*Example* + +```typescript +"hello_world_skill" +``` + + +##### `pypiName`Optional + +```typescript +public readonly pypiName: string; +``` + +- *Type:* string + +The name of the skill's PyPi package. + +--- + +*Example* + +```typescript +ovos-hello-world-skill +``` + + +##### `repositoryUrl`Optional + +```typescript +public readonly repositoryUrl: string; +``` + +- *Type:* string +- *Default:* "TODO: PLACEHOLDER" + +The URL of the skill's GitHub repository. + +--- + +*Example* + +```typescript +"https://github.com/OpenVoiceOS/ovos-hello-world-skill" +``` + + +##### `retrofit`Optional + +```typescript +public readonly retrofit: boolean; +``` + +- *Type:* boolean +- *Default:* false + +Retrofit an existing Mycroft skill to OVOS? + +--- + +##### `sampleCode`Optional + +```typescript +public readonly sampleCode: boolean; +``` + +- *Type:* boolean +- *Default:* true + +Include sample code? + +--- + +##### `skillClass`Optional + +```typescript +public readonly skillClass: string; +``` + +- *Type:* string + +The name of the skill class. + +--- + +*Example* + +```typescript +HelloWorldSkill +``` + + +##### `skillDescription`Optional + +```typescript +public readonly skillDescription: string; +``` + +- *Type:* string +- *Default:* "" + +The description of the skill. + +Used in setup.py. + +--- + +*Example* + +```typescript +"A simple skill that says hello world" +``` + + +##### `skillKeywords`Optional + +```typescript +public readonly skillKeywords: string; +``` + +- *Type:* string +- *Default:* "ovos skill plugin" + +Keywords for your skill package. + +--- + +##### `skillLicenseTest`Optional + +```typescript +public readonly skillLicenseTest: boolean; +``` + +- *Type:* boolean +- *Default:* true + +Include a test to check that the skill's license is FOSS? + +--- + +## Classes + +### OVOSPHALProject + +#### Initializers + +```typescript +import { OVOSPHALProject } from '@mikejgray/ovos-skill-projen' + +new OVOSPHALProject(options: OVOSPHALProjectOptions) +``` + +| **Name** | **Type** | **Description** | +| --- | --- | --- | +| options | OVOSPHALProjectOptions | *No description.* | + +--- + +##### `options`Required + +- *Type:* OVOSPHALProjectOptions + +--- + +#### Methods + +| **Name** | **Description** | +| --- | --- | +| addExcludeFromCleanup | Exclude the matching files from pre-synth cleanup. | +| addGitIgnore | Adds a .gitignore pattern. | +| addPackageIgnore | Exclude these files from the bundled package. | +| addTask | Adds a new task to this project. | +| addTip | Prints a "tip" message during synthesis. | +| annotateGenerated | Marks the provided file(s) as being generated. | +| postSynthesize | Called after all components are synthesized. | +| preSynthesize | Called before all components are synthesized. | +| removeTask | Removes a task from a project. | +| runTaskCommand | Returns the shell command to execute in order to run a task. | +| synth | Synthesize all project files into `outdir`. | +| tryFindFile | Finds a file at the specified relative path within this project and all its subprojects. | +| tryFindJsonFile | Finds a json file by name. | +| tryFindObjectFile | Finds an object file (like JsonFile, YamlFile, etc.) by name. | +| tryRemoveFile | Finds a file at the specified relative path within this project and removes it. | +| addPythonGitIgnore | *No description.* | +| createDevBranch | Create a dev branch if it doesn't already exist, and set it as the default branch. | +| createGenericSkillCode | Create a generic skill with sample code. | + +--- + +##### `addExcludeFromCleanup` + +```typescript +public addExcludeFromCleanup(globs: string): void +``` + +Exclude the matching files from pre-synth cleanup. + +Can be used when, for example, some +source files include the projen marker and we don't want them to be erased during synth. + +###### `globs`Required + +- *Type:* string + +The glob patterns to match. + +--- + +##### `addGitIgnore` + +```typescript +public addGitIgnore(pattern: string): void +``` + +Adds a .gitignore pattern. + +###### `pattern`Required + +- *Type:* string + +The glob pattern to ignore. + +--- + +##### `addPackageIgnore` + +```typescript +public addPackageIgnore(_pattern: string): void +``` + +Exclude these files from the bundled package. + +Implemented by project types based on the +packaging mechanism. For example, `NodeProject` delegates this to `.npmignore`. + +###### `_pattern`Required + +- *Type:* string + +The glob pattern to exclude. + +--- + +##### `addTask` + +```typescript +public addTask(name: string, props?: TaskOptions): Task +``` + +Adds a new task to this project. + +This will fail if the project already has +a task with this name. + +###### `name`Required + +- *Type:* string + +The task name to add. + +--- + +###### `props`Optional + +- *Type:* projen.TaskOptions + +Task properties. + +--- + +##### ~~`addTip`~~ + +```typescript +public addTip(message: string): void +``` + +Prints a "tip" message during synthesis. + +###### `message`Required + +- *Type:* string + +The message. + +--- + +##### `annotateGenerated` + +```typescript +public annotateGenerated(glob: string): void +``` + +Marks the provided file(s) as being generated. + +This is achieved using the +github-linguist attributes. Generated files do not count against the +repository statistics and language breakdown. + +> [https://github.com/github/linguist/blob/master/docs/overrides.md](https://github.com/github/linguist/blob/master/docs/overrides.md) + +###### `glob`Required + +- *Type:* string + +the glob pattern to match (could be a file path). + +--- + +##### `postSynthesize` + +```typescript +public postSynthesize(): void +``` + +Called after all components are synthesized. + +Order is *not* guaranteed. + +##### `preSynthesize` + +```typescript +public preSynthesize(): void +``` + +Called before all components are synthesized. + +##### `removeTask` + +```typescript +public removeTask(name: string): Task +``` + +Removes a task from a project. + +###### `name`Required + +- *Type:* string + +The name of the task to remove. + +--- + +##### `runTaskCommand` + +```typescript +public runTaskCommand(task: Task): string +``` + +Returns the shell command to execute in order to run a task. + +By default, this is `npx projen@ ` + +###### `task`Required + +- *Type:* projen.Task + +The task for which the command is required. + +--- + +##### `synth` + +```typescript +public synth(): void +``` + +Synthesize all project files into `outdir`. + +1. Call "this.preSynthesize()" +2. Delete all generated files +3. Synthesize all sub-projects +4. Synthesize all components of this project +5. Call "postSynthesize()" for all components of this project +6. Call "this.postSynthesize()" + +##### `tryFindFile` + +```typescript +public tryFindFile(filePath: string): FileBase +``` + +Finds a file at the specified relative path within this project and all its subprojects. + +###### `filePath`Required + +- *Type:* string + +The file path. + +If this path is relative, it will be resolved +from the root of _this_ project. + +--- + +##### ~~`tryFindJsonFile`~~ + +```typescript +public tryFindJsonFile(filePath: string): JsonFile +``` + +Finds a json file by name. + +###### `filePath`Required + +- *Type:* string + +The file path. + +--- + +##### `tryFindObjectFile` + +```typescript +public tryFindObjectFile(filePath: string): ObjectFile +``` + +Finds an object file (like JsonFile, YamlFile, etc.) by name. + +###### `filePath`Required + +- *Type:* string + +The file path. + +--- + +##### `tryRemoveFile` + +```typescript +public tryRemoveFile(filePath: string): FileBase +``` + +Finds a file at the specified relative path within this project and removes it. + +###### `filePath`Required + +- *Type:* string + +The file path. + +If this path is relative, it will be +resolved from the root of _this_ project. + +--- + +##### `addPythonGitIgnore` + +```typescript +public addPythonGitIgnore(): void +``` + +##### `createDevBranch` + +```typescript +public createDevBranch(): void +``` + +Create a dev branch if it doesn't already exist, and set it as the default branch. + +##### `createGenericSkillCode` + +```typescript +public createGenericSkillCode(dir: string): void +``` + +Create a generic skill with sample code. + +*Example* + +```typescript +"neon_phal_plugin_audio_receiver" +``` + + +###### `dir`Required + +- *Type:* string + +The name of the directory to create sample code in. + +--- + + +#### Properties + +| **Name** | **Type** | **Description** | +| --- | --- | --- | +| buildTask | projen.Task | *No description.* | +| commitGenerated | boolean | Whether to commit the managed files by default. | +| compileTask | projen.Task | *No description.* | +| components | projen.Component[] | Returns all the components within this project. | +| deps | projen.Dependencies | Project dependencies. | +| ejected | boolean | Whether or not the project is being ejected. | +| files | projen.FileBase[] | All files in this project. | +| gitattributes | projen.GitAttributesFile | The .gitattributes file for this repository. | +| gitignore | projen.IgnoreFile | .gitignore. | +| logger | projen.Logger | Logging utilities. | +| name | string | Project name. | +| outdir | string | Absolute output directory of this project. | +| packageTask | projen.Task | *No description.* | +| postCompileTask | projen.Task | *No description.* | +| preCompileTask | projen.Task | *No description.* | +| projectBuild | projen.ProjectBuild | Manages the build process of the project. | +| projenCommand | string | The command to use in order to run the projen CLI. | +| root | projen.Project | The root project. | +| subprojects | projen.Project[] | Returns all the subprojects within this project. | +| tasks | projen.Tasks | Project tasks. | +| testTask | projen.Task | *No description.* | +| defaultTask | projen.Task | This is the "default" task, the one that executes "projen". | +| initProject | projen.InitProject | The options used when this project is bootstrapped via `projen new`. | +| parent | projen.Project | A parent project. | +| projectType | projen.ProjectType | *No description.* | +| autoApprove | projen.github.AutoApprove | Auto approve set up for this project. | +| devContainer | projen.vscode.DevContainer | Access for .devcontainer.json (used for GitHub Codespaces). | +| github | projen.github.GitHub | Access all github components. | +| gitpod | projen.Gitpod | Access for Gitpod. | +| vscode | projen.vscode.VsCode | Access all VSCode components. | + +--- + +##### `buildTask`Required + +```typescript +public readonly buildTask: Task; +``` + +- *Type:* projen.Task + +--- + +##### `commitGenerated`Required + +```typescript +public readonly commitGenerated: boolean; +``` + +- *Type:* boolean + +Whether to commit the managed files by default. + +--- + +##### `compileTask`Required + +```typescript +public readonly compileTask: Task; +``` + +- *Type:* projen.Task + +--- + +##### `components`Required + +```typescript +public readonly components: Component[]; +``` + +- *Type:* projen.Component[] + +Returns all the components within this project. + +--- + +##### `deps`Required + +```typescript +public readonly deps: Dependencies; +``` + +- *Type:* projen.Dependencies + +Project dependencies. + +--- + +##### `ejected`Required + +```typescript +public readonly ejected: boolean; +``` + +- *Type:* boolean + +Whether or not the project is being ejected. + +--- + +##### `files`Required + +```typescript +public readonly files: FileBase[]; +``` + +- *Type:* projen.FileBase[] + +All files in this project. + +--- + +##### `gitattributes`Required + +```typescript +public readonly gitattributes: GitAttributesFile; +``` + +- *Type:* projen.GitAttributesFile + +The .gitattributes file for this repository. + +--- + +##### `gitignore`Required + +```typescript +public readonly gitignore: IgnoreFile; +``` + +- *Type:* projen.IgnoreFile + +.gitignore. + +--- + +##### `logger`Required + +```typescript +public readonly logger: Logger; +``` + +- *Type:* projen.Logger + +Logging utilities. + +--- + +##### `name`Required + +```typescript +public readonly name: string; +``` + +- *Type:* string + +Project name. + +--- + +##### `outdir`Required + +```typescript +public readonly outdir: string; +``` + +- *Type:* string + +Absolute output directory of this project. + +--- + +##### `packageTask`Required + +```typescript +public readonly packageTask: Task; +``` + +- *Type:* projen.Task + +--- + +##### `postCompileTask`Required + +```typescript +public readonly postCompileTask: Task; +``` + +- *Type:* projen.Task + +--- + +##### `preCompileTask`Required + +```typescript +public readonly preCompileTask: Task; +``` + +- *Type:* projen.Task + +--- + +##### `projectBuild`Required + +```typescript +public readonly projectBuild: ProjectBuild; +``` + +- *Type:* projen.ProjectBuild + +Manages the build process of the project. + +--- + +##### `projenCommand`Required + +```typescript +public readonly projenCommand: string; +``` + +- *Type:* string + +The command to use in order to run the projen CLI. + +--- + +##### `root`Required + +```typescript +public readonly root: Project; +``` + +- *Type:* projen.Project + +The root project. + +--- + +##### `subprojects`Required + +```typescript +public readonly subprojects: Project[]; +``` + +- *Type:* projen.Project[] + +Returns all the subprojects within this project. + +--- + +##### `tasks`Required + +```typescript +public readonly tasks: Tasks; +``` + +- *Type:* projen.Tasks + +Project tasks. + +--- + +##### `testTask`Required + +```typescript +public readonly testTask: Task; +``` + +- *Type:* projen.Task + +--- + +##### `defaultTask`Optional + +```typescript +public readonly defaultTask: Task; +``` + +- *Type:* projen.Task + +This is the "default" task, the one that executes "projen". + +Undefined if +the project is being ejected. + +--- + +##### `initProject`Optional + +```typescript +public readonly initProject: InitProject; +``` + +- *Type:* projen.InitProject + +The options used when this project is bootstrapped via `projen new`. + +It +includes the original set of options passed to the CLI and also the JSII +FQN of the project type. + +--- + +##### `parent`Optional + +```typescript +public readonly parent: Project; +``` + +- *Type:* projen.Project + +A parent project. + +If undefined, this is the root project. + +--- + +##### `projectType`Required + +```typescript +public readonly projectType: ProjectType; +``` + +- *Type:* projen.ProjectType + +--- + +##### `autoApprove`Optional + +```typescript +public readonly autoApprove: AutoApprove; +``` + +- *Type:* projen.github.AutoApprove + +Auto approve set up for this project. + +--- + +##### `devContainer`Optional + +```typescript +public readonly devContainer: DevContainer; +``` + +- *Type:* projen.vscode.DevContainer + +Access for .devcontainer.json (used for GitHub Codespaces). + +This will be `undefined` if devContainer boolean is false + +--- + +##### `github`Optional + +```typescript +public readonly github: GitHub; +``` + +- *Type:* projen.github.GitHub + +Access all github components. + +This will be `undefined` for subprojects. + +--- + +##### `gitpod`Optional + +```typescript +public readonly gitpod: Gitpod; +``` + +- *Type:* projen.Gitpod + +Access for Gitpod. + +This will be `undefined` if gitpod boolean is false + +--- + +##### `vscode`Optional + +```typescript +public readonly vscode: VsCode; +``` + +- *Type:* projen.vscode.VsCode + +Access all VSCode components. + +This will be `undefined` for subprojects. + +--- + +#### Constants + +| **Name** | **Type** | **Description** | +| --- | --- | --- | +| DEFAULT_TASK | string | The name of the default task (the task executed when `projen` is run without arguments). | + +--- + +##### `DEFAULT_TASK`Required + +```typescript +public readonly DEFAULT_TASK: string; +``` + +- *Type:* string + +The name of the default task (the task executed when `projen` is run without arguments). + +Normally +this task should synthesize the project files. + +--- ### OVOSSkillProject diff --git a/README.md b/README.md index 176f18f..49b2704 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Add that to your `~/.bashrc` or `~/.zshrc` file to make it permanent. Be sure to In a new directory, run: -`projen new ovosskill --from "@mikejgray/ovos-skill-projen@latest"` +`npx projen new ovosskill --from "@mikejgray/ovos-skill-projen@latest"` **NOTE**: This repo is not yet available on NPM. Please add the following to your `~/.npmrc` file (create one if it doesn't exist), with [a GitHub token that has packages:read permissions](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-npm-registry): @@ -52,6 +52,26 @@ Example: After editing `.projenrc.json`, run `pj` to regenerate the project files. This can automatically keep your project up to date with the latest changes, including managing your `setup.py` file. +## Create a new PHAL plugin template + +In a new directory, run: + +`npx projen new ovosphal --from "@mikejgray/ovos-skill-projen@latest"` + +The instructions are the same as for creating a new skill template, except that you have an additional option to set the PHAL plugin as admin or not. The default is `false`, indicating that the PHAL plugin will not run as root. + +**NOTE:** If you do set the PHAL plugin to `admin` and thus run as root, you will also need to update your OVOS config to explicitly allow your root plugins. This is a security risk and should only be done if you understand the implications. For more information about Admin PHAL, [see the OVOS technical manual](https://openvoiceos.github.io/ovos-technical-manual/PHAL/#admin-phal). + +Example OVOS config: + +```json +{ + "PHAL": { + "admin": "ovos-phal-plugin-helloworld": {"enabled": true} + } +} +``` + ### setup.py ownership Note that projen takes ownership of the `setup.py` file, and the expectation is that manual edits are not allowed. If you need to make changes to the `setup.py` file, you should do so by editing `.projenrc.json` and running `pj` to regenerate the file. diff --git a/src/files/README.phal.ts b/src/files/README.phal.ts new file mode 100644 index 0000000..de40520 --- /dev/null +++ b/src/files/README.phal.ts @@ -0,0 +1,24 @@ +interface readmePhalInterface { + skillClass: string; + authorName: string; + authorHandle: string; +}; + +export const readmePhalMd = ({ + skillClass, + authorName, + authorHandle, +}: readmePhalInterface): string => { + return `# ${skillClass} + +Template for an OVOS PHAL plugin. + +\`\`\`python +self.bus.on("mycroft.ready", self.on_mycroft_ready) +\`\`\` + +## Credits + +${authorName} (@${authorHandle}) +`; +}; diff --git a/src/files/__init__.phal.py b/src/files/__init__.phal.py new file mode 100644 index 0000000..9f434d9 --- /dev/null +++ b/src/files/__init__.phal.py @@ -0,0 +1,28 @@ +from ovos_bus_client import Message +from ovos_plugin_manager.phal import PHALPlugin + + +class HelloWorldPlugin(PHALPlugin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.bus.on("mycroft.ready", self.on_mycroft_ready) + + @property + def my_setting(self): + """Dynamically get the my_setting from the config file(s). + Example: + { + "PHAL": { + "ovos-phal-plugin-helloworld": { + "my_setting": "my_value" + } + } + } + If it doesn't exist, return the default value. + """ + return self.config.get("my_setting", "default_value") + + def on_mycroft_ready(self, message: Message): + """Take action when OVOS is ready.""" + self.log.info("OVOS reported ready, now I can do something!") + # Implement something here diff --git a/src/files/setup.py.phal.ts b/src/files/setup.py.phal.ts new file mode 100644 index 0000000..76d6e2e --- /dev/null +++ b/src/files/setup.py.phal.ts @@ -0,0 +1,135 @@ +interface setupPyInterface { + /** + * The URL of the plugin's GitHub repository. + */ + repositoryUrl: string; + /** + * The name of the directory containing the plugin's code. + * @default "" (root) + */ + packageDir: string; + /** + * The name of the plugin's author. + */ + author: string; + /** + * The email address of the plugin's author. + */ + authorAddress: string; + /** + * The name of the plugin class. + */ + pluginClass: string; + /** + * The name of the plugin's PyPi package. + */ + pypiName: string; + /** + * The description of the plugin. + */ + description: string; + /** + * The license of the plugin. + */ + license: string; + /** + * Whether the plugin is an admin PHAL plugin, meaning it runs as root. + * @default false + */ + admin?: boolean; +} + +export const setupPhalPy = ({ + repositoryUrl, + packageDir, + author, + authorAddress, + pypiName, + pluginClass, + description, + license, + admin, +}: setupPyInterface): string => { + return `#!/usr/bin/env python3 +from setuptools import setup +from os import walk, path + +BASEDIR = path.abspath(path.dirname(__file__)) +URL = "${repositoryUrl}" +plugin_CLAZZ = "${pluginClass}" # needs to match __init__.py class name +PYPI_NAME = "${pypiName}" # pip install PYPI_NAME + +# below derived from github url to ensure standard plugin_id +plugin_AUTHOR, plugin_NAME = URL.split(".com/")[-1].split("/") +plugin_PKG = plugin_NAME.lower().replace("-", "_") +PLUGIN_ENTRY_POINT = f"{plugin_NAME.lower()}.{plugin_AUTHOR.lower()}={plugin_PKG}:{plugin_CLAZZ}" +# plugin_id=package_name:pluginClass +BASE_PATH = BASE_PATH = path.abspath(path.join(path.dirname(__file__), "${packageDir}")) + + +def get_version(): + """Find the version of the package""" + version = None + version_file = path.join(BASE_PATH, "version.py") + major, minor, build, alpha = (None, None, None, None) + with open(version_file) as f: + for line in f: + if "VERSION_MAJOR" in line: + major = line.split("=")[1].strip() + elif "VERSION_MINOR" in line: + minor = line.split("=")[1].strip() + elif "VERSION_BUILD" in line: + build = line.split("=")[1].strip() + elif "VERSION_ALPHA" in line: + alpha = line.split("=")[1].strip() + + if (major and minor and build and alpha) or "# END_VERSION_BLOCK" in line: + break + version = f"{major}.{minor}.{build}" + if alpha and int(alpha) > 0: + version += f"a{alpha}" + return version + + +def get_requirements(requirements_filename: str): + requirements_file = path.join(path.dirname(__file__), requirements_filename) + with open(requirements_file, "r", encoding="utf-8") as r: + requirements = r.readlines() + requirements = [r.strip() for r in requirements if r.strip() and not r.strip().startswith("#")] + return requirements + + +def find_resource_files(): + resource_base_dirs = ("locale", "intents", "dialog", "vocab", "regex", "ui") + package_data = ["*.json"] + for res in resource_base_dirs: + if path.isdir(path.join(BASE_PATH, res)): + for directory, _, files in walk(path.join(BASE_PATH, res)): + if files: + package_data.append(path.join(directory.replace(BASE_PATH, "").lstrip("/"), "*")) + return package_data + + +with open("README.md", "r") as f: + long_description = f.read() + +setup( + name=PYPI_NAME, + version=get_version(), + description="${description}", + long_description=long_description, + long_description_content_type="text/markdown", + url=URL, + author="${author}", + author_email="${authorAddress}", + license="${license}", + package_dir={plugin_PKG: "${packageDir ?? '.'}"}, + package_data={plugin_PKG: find_resource_files()}, + packages=[plugin_PKG], + include_package_data=True, + install_requires=get_requirements("requirements.txt"), + keywords="ovos plugin voice assistant", + entry_points={${admin ? 'ovos.plugin.phal.admin' : 'ovos.plugin.phal'}: PLUGIN_ENTRY_POINT}, +) +`; +}; \ No newline at end of file diff --git a/src/files/setup.py.ts b/src/files/setup.py.ts index 8866016..0994f41 100644 --- a/src/files/setup.py.ts +++ b/src/files/setup.py.ts @@ -1,4 +1,4 @@ -interface setupPyInterface { +export interface setupPyInterface { /** * The URL of the skill's GitHub repository. */ diff --git a/src/index.ts b/src/index.ts index 46b4992..8f32145 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,7 +5,9 @@ import { ProjenrcJson, SampleDir, SampleFile, TextFile } from 'projen'; import { GitHubProject, GitHubProjectOptions } from 'projen/lib/github'; import { parse } from 'yaml'; import { readmeMd } from './files/README'; +import { readmePhalMd } from './files/README.phal'; import { setupPy } from './files/setup.py'; +import { setupPhalPy } from './files/setup.py.phal'; import { LicenseTestsWorkflow, ProposeReleaseWorkflow, PublishAlphaWorkflow, PublishReleaseWorkflow, SkillTestsWorkflow, UpdateSkillJsonWorkflow } from './GithubWorkflows'; export interface OVOSSkillProjectOptions extends GitHubProjectOptions { @@ -457,3 +459,217 @@ ${line}`; } } + +export interface OVOSPHALProjectOptions extends OVOSSkillProjectOptions { + /** + * Is this an admin PHAL plugin? + * @default false + */ + readonly admin?: boolean; +} +export class OVOSPHALProject extends GitHubProject { + constructor(options: OVOSPHALProjectOptions) { + let superProps = { ...options }; + superProps.readme = { + contents: readmePhalMd({ + skillClass: options.skillClass ?? 'OVOSSkill', + authorName: options.author ?? 'authorName', + authorHandle: options.authorHandle ?? 'githubUsername', + }), + }; + super(superProps); + + const author = options.author ?? 'TODO: Add \'author\' to .projenrc.json and run pj'; + const repositoryUrl = options.repositoryUrl ?? 'TODO: Add \'repositoryUrl\' to .projenrc.json and run pj'; + const authorAddress = options.authorAddress ?? 'TODO: Add \'authorAddress\' to .projenrc.json and run pj'; + const license = options.license ?? '# TODO: Add \'license\' to .projenrc.json and run pj'; + const skillClass = options.skillClass ?? 'TODO: Add \'skillClass\' to .projenrc.json and run pj'; + const pypiName = options.pypiName ?? process.cwd().split('/').pop()!; + const packageDir = options.packageDir ?? 'src'; + const skillDescription = options.skillDescription ?? ''; + const admin = options.admin ?? false; + new TextFile(this, 'setup.py', { + lines: setupPhalPy({ + repositoryUrl, + packageDir, + pypiName, + author, + authorAddress, + license, + description: skillDescription, + pluginClass: skillClass, + admin, + }).split('\n'), + }); + new TextFile(this, 'version.py', { + lines: 'VERSION_MAJOR = 0\nVERSION_MINOR = 0\nVERSION_BUILD = 1\nVERSION_ALPHA = 0'.split('\n'), + }); + // projenrc.json + new ProjenrcJson(this, {}); + // gitignore + this.gitignore.addPatterns('.DS_Store', 'node_modules'); + this.addPythonGitIgnore(); + this.createGenericSkillCode(packageDir); + let requirements = 'ovos-utils\novos-bus-client\novos-workshop\novos-plugin-manager\n# Your requirements here\n'; + new SampleFile(this, 'requirements.txt', { + contents: requirements, + }); + this.createDevBranch(); + } + // Methods + /** + * Create a generic skill with sample code. + * @param dir The name of the directory to create sample code in + * @default "src" + * @example "neon_phal_plugin_audio_receiver" + */ + createGenericSkillCode(dir: string) { + new SampleDir(this, dir, { + files: { + '__init__.py': readFileSync(join(__dirname, 'files', '__init__.phal.py')).toString(), + 'version.py': 'VERSION_MAJOR = 0\nVERSION_MINOR = 0\nVERSION_BUILD = 1\nVERSION_ALPHA = 0', + }, + }); + } + /** + * Create a dev branch if it doesn't already exist, and set it as the default branch. + */ + createDevBranch() { + exec('git rev-parse --verify dev', (err) => { + if (err) { + exec('git checkout -b dev'); + exec('git branch -M dev'); + } + }); + } + addPythonGitIgnore() { + this.gitignore.exclude( + '# Byte-compiled / optimized / DLL files', + '__pycache__/', + '*.py[cod]', + '*$py.class', + '', + '# C extensions', + '*.so', + '', + '# Distribution / packaging', + '.Python', + 'build/', + 'develop-eggs/', + 'dist/', + 'downloads/', + 'eggs/', + '.eggs/', + 'lib/', + 'lib64/', + 'parts/', + 'sdist/', + 'var/', + 'wheels/', + 'share/python-wheels/', + '*.egg-info/', + '.installed.cfg', + '*.egg', + 'MANIFEST', + '', + '# PyInstaller', + '# Usually these files are written by a python script from a template', + '# before PyInstaller builds the exe, so as to inject date/other infos into it.', + '*.manifest', + '*.spec', + '', + '# Installer logs', + 'pip-log.txt', + 'pip-delete-this-directory.txt', + '', + '# Unit test / coverage reports', + 'htmlcov/', + '.tox/', + '.nox/', + '.coverage', + '.coverage.*', + '.cache', + 'nosetests.xml', + 'coverage.xml', + '*.cover', + '*.py,cover', + '.hypothesis/', + '.pytest_cache/', + 'cover/', + '', + '# Translations', + '*.mo', + '*.pot', + '', + '# Django stuff:', + '*.log', + 'local_settings.py', + 'db.sqlite3', + 'db.sqlite3-journal', + '', + '# Flask stuff:', + 'instance/', + '.webassets-cache', + '', + '# Scrapy stuff:', + '.scrapy', + '', + '# Sphinx documentation', + 'docs/_build/', + '', + '# PyBuilder', + '.pybuilder/', + 'target/', + '', + '# Jupyter Notebook', + '.ipynb_checkpoints', + '', + '# IPython', + 'profile_default/', + 'ipython_config.py', + '', + '# PEP 582; used by e.g. github.com/David-OConnor/pyflow', + '__pypackages__/', + '', + '# Celery stuff', + 'celerybeat-schedule', + 'celerybeat.pid', + '', + '# SageMath parsed files', + '*.sage.py', + '', + '# Environments', + '.env', + '.venv', + 'env/', + 'venv/', + 'ENV/', + 'env.bak/', + 'venv.bak/', + '', + '# Spyder project settings', + '.spyderproject', + '.spyproject', + '', + '# Rope project settings', + '.ropeproject', + '', + '# mkdocs documentation', + '/site', + '', + '# mypy', + '.mypy_cache/', + '.dmypy.json', + 'dmypy.json', + '', + '# Pyre type checker', + '.pyre/', + '', + '# pytype static type analyzer', + '.pytype/', + '', + '# Cython debug symbols', + 'cython_debug/', + ); + } +} diff --git a/test/OVOSPHALProject.test.ts b/test/OVOSPHALProject.test.ts new file mode 100644 index 0000000..7d5bd36 --- /dev/null +++ b/test/OVOSPHALProject.test.ts @@ -0,0 +1,15 @@ +import { Testing } from 'projen'; +import { OVOSPHALProject } from '../src'; + +test('snapshot', () => { + const project = new OVOSPHALProject({ + name: 'test', + skillClass: 'TestPlugin', + pypiName: 'test-plugin', + }); + + const synth = Testing.synth(project); + expect(synth).toMatchSnapshot(); + expect(synth['requirements.txt']).toBeDefined(); + expect(synth['requirements.txt']).toContain('ovos-utils\novos-bus-client\novos-workshop'); +}); diff --git a/test/__snapshots__/OVOSPHALProject.test.ts.snap b/test/__snapshots__/OVOSPHALProject.test.ts.snap new file mode 100644 index 0000000..faf8cdc --- /dev/null +++ b/test/__snapshots__/OVOSPHALProject.test.ts.snap @@ -0,0 +1,388 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`snapshot 1`] = ` +Object { + ".gitattributes": "# ~~ Generated by projen. To modify, edit .projenrc.json and run \\"npx projen\\". + +/.gitattributes linguist-generated +/.github/workflows/pull-request-lint.yml linguist-generated +/.gitignore linguist-generated +/.projen/** linguist-generated +/.projen/deps.json linguist-generated +/.projen/files.json linguist-generated +/.projen/tasks.json linguist-generated +/setup.py linguist-generated +/version.py linguist-generated", + ".github/workflows/pull-request-lint.yml": "# ~~ Generated by projen. To modify, edit .projenrc.json and run \\"npx projen\\". + +name: pull-request-lint +on: + pull_request_target: + types: + - labeled + - opened + - synchronize + - reopened + - ready_for_review + - edited +jobs: + validate: + name: Validate PR title + runs-on: ubuntu-latest + permissions: + pull-requests: write + steps: + - uses: amannn/action-semantic-pull-request@v5.0.2 + env: + GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }} + with: + types: |- + feat + fix + chore + requireScope: false +", + ".gitignore": "# ~~ Generated by projen. To modify, edit .projenrc.json and run \\"npx projen\\". +node_modules/ +!/.gitattributes +!/.projen/tasks.json +!/.projen/deps.json +!/.projen/files.json +!/.github/workflows/pull-request-lint.yml +!/setup.py +!/version.py +.DS_Store +node_modules +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST +*.manifest +*.spec +pip-log.txt +pip-delete-this-directory.txt +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ +*.mo +*.pot +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal +instance/ +.webassets-cache +.scrapy +docs/_build/ +.pybuilder/ +target/ +.ipynb_checkpoints +profile_default/ +ipython_config.py +__pypackages__/ +celerybeat-schedule +celerybeat.pid +*.sage.py +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ +.spyderproject +.spyproject +.ropeproject +/site +.mypy_cache/ +.dmypy.json +dmypy.json +.pyre/ +.pytype/ +cython_debug/ +", + ".projen/files.json": Object { + "//": "~~ Generated by projen. To modify, edit .projenrc.json and run \\"npx projen\\".", + "files": Array [ + ".gitattributes", + ".github/workflows/pull-request-lint.yml", + ".gitignore", + ".projen/deps.json", + ".projen/files.json", + ".projen/tasks.json", + "setup.py", + "version.py", + ], + }, + ".projen/tasks.json": Object { + "//": "~~ Generated by projen. To modify, edit .projenrc.json and run \\"npx projen\\".", + "tasks": Object { + "build": Object { + "description": "Full release build", + "name": "build", + "steps": Array [ + Object { + "spawn": "default", + }, + Object { + "spawn": "pre-compile", + }, + Object { + "spawn": "compile", + }, + Object { + "spawn": "post-compile", + }, + Object { + "spawn": "test", + }, + Object { + "spawn": "package", + }, + ], + }, + "clobber": Object { + "condition": "git diff --exit-code > /dev/null", + "description": "hard resets to HEAD of origin and cleans the local repo", + "env": Object { + "BRANCH": "$(git branch --show-current)", + }, + "name": "clobber", + "steps": Array [ + Object { + "exec": "git checkout -b scratch", + "name": "save current HEAD in \\"scratch\\" branch", + }, + Object { + "exec": "git checkout $BRANCH", + }, + Object { + "exec": "git fetch origin", + "name": "fetch latest changes from origin", + }, + Object { + "exec": "git reset --hard origin/$BRANCH", + "name": "hard reset to origin commit", + }, + Object { + "exec": "git clean -fdx", + "name": "clean all untracked files", + }, + Object { + "say": "ready to rock! (unpushed commits are under the \\"scratch\\" branch)", + }, + ], + }, + "compile": Object { + "description": "Only compile", + "name": "compile", + }, + "default": Object { + "description": "Synthesize project files", + "env": Object { + "FILENAME": ".projenrc.json", + }, + "name": "default", + "steps": Array [ + Object { + "builtin": "run-projenrc-json", + }, + ], + }, + "eject": Object { + "description": "Remove projen from the project", + "env": Object { + "PROJEN_EJECTING": "true", + }, + "name": "eject", + "steps": Array [ + Object { + "spawn": "default", + }, + ], + }, + "package": Object { + "description": "Creates the distribution package", + "name": "package", + }, + "post-compile": Object { + "description": "Runs after successful compilation", + "name": "post-compile", + }, + "pre-compile": Object { + "description": "Prepare the project for compilation", + "name": "pre-compile", + }, + "test": Object { + "description": "Run tests", + "name": "test", + }, + }, + }, + "README.md": "# TestPlugin + +Template for an OVOS PHAL plugin. + +\`\`\`python +self.bus.on(\\"mycroft.ready\\", self.on_mycroft_ready) +\`\`\` + +## Credits + +authorName (@githubUsername) +", + "requirements.txt": "ovos-utils +ovos-bus-client +ovos-workshop +ovos-plugin-manager +# Your requirements here +", + "setup.py": "#!/usr/bin/env python3 +from setuptools import setup +from os import walk, path + +BASEDIR = path.abspath(path.dirname(__file__)) +URL = \\"TODO: Add 'repositoryUrl' to .projenrc.json and run pj\\" +plugin_CLAZZ = \\"TestPlugin\\" # needs to match __init__.py class name +PYPI_NAME = \\"test-plugin\\" # pip install PYPI_NAME + +# below derived from github url to ensure standard plugin_id +plugin_AUTHOR, plugin_NAME = URL.split(\\".com/\\")[-1].split(\\"/\\") +plugin_PKG = plugin_NAME.lower().replace(\\"-\\", \\"_\\") +PLUGIN_ENTRY_POINT = f\\"{plugin_NAME.lower()}.{plugin_AUTHOR.lower()}={plugin_PKG}:{plugin_CLAZZ}\\" +# plugin_id=package_name:pluginClass +BASE_PATH = BASE_PATH = path.abspath(path.join(path.dirname(__file__), \\"src\\")) + + +def get_version(): + \\"\\"\\"Find the version of the package\\"\\"\\" + version = None + version_file = path.join(BASE_PATH, \\"version.py\\") + major, minor, build, alpha = (None, None, None, None) + with open(version_file) as f: + for line in f: + if \\"VERSION_MAJOR\\" in line: + major = line.split(\\"=\\")[1].strip() + elif \\"VERSION_MINOR\\" in line: + minor = line.split(\\"=\\")[1].strip() + elif \\"VERSION_BUILD\\" in line: + build = line.split(\\"=\\")[1].strip() + elif \\"VERSION_ALPHA\\" in line: + alpha = line.split(\\"=\\")[1].strip() + + if (major and minor and build and alpha) or \\"# END_VERSION_BLOCK\\" in line: + break + version = f\\"{major}.{minor}.{build}\\" + if alpha and int(alpha) > 0: + version += f\\"a{alpha}\\" + return version + + +def get_requirements(requirements_filename: str): + requirements_file = path.join(path.dirname(__file__), requirements_filename) + with open(requirements_file, \\"r\\", encoding=\\"utf-8\\") as r: + requirements = r.readlines() + requirements = [r.strip() for r in requirements if r.strip() and not r.strip().startswith(\\"#\\")] + return requirements + + +def find_resource_files(): + resource_base_dirs = (\\"locale\\", \\"intents\\", \\"dialog\\", \\"vocab\\", \\"regex\\", \\"ui\\") + package_data = [\\"*.json\\"] + for res in resource_base_dirs: + if path.isdir(path.join(BASE_PATH, res)): + for directory, _, files in walk(path.join(BASE_PATH, res)): + if files: + package_data.append(path.join(directory.replace(BASE_PATH, \\"\\").lstrip(\\"/\\"), \\"*\\")) + return package_data + + +with open(\\"README.md\\", \\"r\\") as f: + long_description = f.read() + +setup( + name=PYPI_NAME, + version=get_version(), + description=\\"\\", + long_description=long_description, + long_description_content_type=\\"text/markdown\\", + url=URL, + author=\\"TODO: Add 'author' to .projenrc.json and run pj\\", + author_email=\\"TODO: Add 'authorAddress' to .projenrc.json and run pj\\", + license=\\"# TODO: Add 'license' to .projenrc.json and run pj\\", + package_dir={plugin_PKG: \\"src\\"}, + package_data={plugin_PKG: find_resource_files()}, + packages=[plugin_PKG], + include_package_data=True, + install_requires=get_requirements(\\"requirements.txt\\"), + keywords=\\"ovos plugin voice assistant\\", + entry_points={ovos.plugin.phal: PLUGIN_ENTRY_POINT}, +) +", + "src/__init__.py": "from ovos_bus_client import Message +from ovos_plugin_manager.phal import PHALPlugin + + +class HelloWorldPlugin(PHALPlugin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.bus.on(\\"mycroft.ready\\", self.on_mycroft_ready) + + @property + def my_setting(self): + \\"\\"\\"Dynamically get the my_setting from the config file(s). + Example: + { + \\"PHAL\\": { + \\"ovos-phal-plugin-helloworld\\": { + \\"my_setting\\": \\"my_value\\" + } + } + } + If it doesn't exist, return the default value. + \\"\\"\\" + return self.config.get(\\"my_setting\\", \\"default_value\\") + + def on_mycroft_ready(self, message: Message): + \\"\\"\\"Take action when OVOS is ready.\\"\\"\\" + self.log.info(\\"OVOS reported ready, now I can do something!\\") + # Implement something here +", + "src/version.py": "VERSION_MAJOR = 0 +VERSION_MINOR = 0 +VERSION_BUILD = 1 +VERSION_ALPHA = 0", + "version.py": "VERSION_MAJOR = 0 +VERSION_MINOR = 0 +VERSION_BUILD = 1 +VERSION_ALPHA = 0", +} +`;