feat(init): publishing

This commit is contained in:
Rodney, Tiara 2025-04-25 15:56:29 +02:00
parent 32636217ee
commit c297e3f4ef
No known key found for this signature in database
GPG key ID: 5CD8EC1D46106723
15 changed files with 9934 additions and 6837 deletions

4
.gitignore vendored
View file

@ -3,3 +3,7 @@
*.swo
*.swp
*~
config.log
config.status
autom4te.cache
/dist

13
.npmignore Normal file
View file

@ -0,0 +1,13 @@
/tests
/tsconfig*.json
/src
/dist
/autom4te.cache
/config.*
/configure*
/scripts
/build
/.gitlab-ci.yml
/CONTRIBUTING.md
/jest.config.js
/Makefile

87
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,87 @@
# Contribution Guidelines
## Configuration
This project uses npm as a build driver.
In POSIX(-esque) shell environments (including *mingw-w64* distros) you may run
`./configure` to configure your build environment.
## Development
For configuring hot-reload transpilation of the Typescript compiler, execute
`npm run watch`.
## Distributing
This project is distributed as a npm package.
```
npm run dist
```
archiving output resides under `dist/`.
## CI/CD
This project uses GNU Automake as a wrapper around the MSBuild build driver to
streamline the build interface for POSIX environments.
Make sure the CI/CD container image contains GNU Make, and that the environment
variables `NPM_REGISTRY` are set.
`NPM_REGISTRY` can be derived from whatever registry service is in use (e.g.
GitLab npm Registry, Sonarqube Nexus, npmjs.com, etc.). If you're using CI/CD
built into your Git host there's a chance the URL is available as shell
environments from within the CI/CD container.
For Gitlab package registries, make sure to define the `NPM_REGISTRY` by
depending on `CI_API_V4_URL`, `CI_PROJECT_ID` inside the CI/CD container:
```sh
export NPM_REGISTRY="$CI_API_V4_URL/api/v4/projects/$CI_PROJECT_ID/packages/npm"
```
should resolve to
`https://gitlab.adesso-group.com/api/v4/projects/3842/packages/npm`
To authenticate against the Gitlab PyPI registry (archive), generate a project
[deploy token](https://docs.gitlab.com/17.8/ee/user/project/deploy_tokens/index.html)
and set it's value to `NPM_AUTH_TOKEN`.
Initialize a pipeline's shell environment through calling `./configure`, then
call each make target required in seperate pipeline steps.
Steps:
1. `sh ./configure`
* `make clean`
* `make build`
* `make test`
* `make doc`
* `make dist`
* `make publish`
Should there be no pipeline, just do this from your workstation if you consider
yourself to be a project maintainer. No worries, if you can publish something
you shouldn't, then there's a misconfiguration somewehere anyway...
Ideally, set up seperate pipelines for `dev`, `master` and default branches.
Only `master` should contain *dist*, and *publish* steps. However, on `dev`,
checking whether the project can be distributed (*dist*) is fine.
## Maintenance (Chores)
Maintaining this repository requires the maintainer to use a POSIX(-esque) shell
environment (*mingw-w64* distros are fine as well), in addition to the
requirements of CI/CD.
Execute all chores, by executing `make`, or `make chores`. Analyze the changes
then commit them.
### Versioning
Versioning relevant for distribution is defined via Git tags. If the HEAD of the
working tree is not tagged, the build environment increments the version to a
development version of the next patch version. Increment versions by applying a
Git tag.

28
Makefile Normal file
View file

@ -0,0 +1,28 @@
NPM=npm
.PHONY: configure chore build dist test publish doc
all: chore
chore: configure
configure:
autoconf
build:
$(NPM) run build
test:
$(NPM) run test
doc:
$(NPM) run doc
dist:
$(NPM) run dist
publish:
$(NPM) run mypublish -- -r '$(NPM_REGISTRY)'
clean:
rm -rvf configure~ config.log config.status autom4te.cache build dist

2654
configure vendored Executable file

File diff suppressed because it is too large Load diff

26
configure.ac Normal file
View file

@ -0,0 +1,26 @@
AC_INIT
AC_CHECK_PROGS([MAKE], [make])
AC_CHECK_PROGS([PYTHON3], [npm])
AC_CHECK_PROGS([AUTOCONF], [autoconf])
AC_CHECK_PROGS([GIT], [git])
AC_MSG_CHECKING([if 'NPM_REGISTRY' is set])
if ! test -z "$NPM_REGISTRY"; then
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
fi
AC_MSG_CHECKING([if 'NPM_AUTH_TOKEN' is set])
if ! test -z "$NPM_AUTH_TOKEN"; then
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
fi
AC_MSG_NOTICE([initializing npm...])
npm install
AC_OUTPUT

13719
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -12,21 +12,27 @@
},
"author": "Tiara Rodney",
"license": "UNLICENSED",
"main": "index.js",
"devDependencies": {
"@types/benchmark": "^2.1.5",
"@types/jest": "^29.5.14",
"@types/yargs": "^17.0.33",
"benchmark": "^2.1.4",
"jest": "^29.7.0",
"ts-jest": "^29.2.5",
"ts-node": "^10.9.2",
"typedoc": "^0.27.7",
"typescript": "^5.7.3"
"typescript": "^5.7.3",
"yargs": "^17.7.2"
},
"scripts": {
"test": "jest",
"build": "npm run build:production",
"build:production": "tsc",
"build:debug": "tsc -p tsconfig.debug.json",
"build:documentation": "typedoc --entryPoints src/index.ts --html build/documentation"
"watch": "npm run watch:debug",
"watch:debug": "npm run build:debug -- --watch",
"doc": "typedoc --entryPoints src/index.ts --html build/doc",
"mypublish": "ts-node -P tsconfig.node.json scripts/publish.ts",
"dist": "ts-node -P tsconfig.node.json scripts/pack.ts build/production dist"
}
}

129
scripts/pack.ts Normal file
View file

@ -0,0 +1,129 @@
import * as yargs from 'yargs';
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import * as child_process from 'child_process';
const usage = `Create a tarball from a package
This script is a wrapper around \`npm pack\`.
It copies the current working directory to a temporary directory, moves the
build artifacts to the root of it and then starts \`npm pack\` from within that
directory.
This is necessary, because traditional directory layout of build environments
isn't really compatible with npm and Typescript transpilation. With
Typescript/npm packages, usually build artifacts are transpiled into the same
directory as their sources and then excluded via e.g. \`.gitignore\`. This is
how the \`npm pack\` workflow expects it. I don't like the isolation between
build artifacts and sources that come with it.`
const argv = require('yargs')
.usage('$0 [args] inputDir outputDir', usage)
.positional('inputDir', {
type: 'string',
default: 'build/production',
describe: 'path to package build'
})
.positional('outputDir', {
type: 'string',
default: 'dist',
describe: 'path to dist directory'
})
.demandOption(['inputDir', 'outputDir'])
.help()
.argv;
var cwd = process.cwd();
if (path.dirname(argv.inputDir) == path.basename(argv.inputDir)) {
throw new Error('inputDir must have a nesting depth of at least 2')
}
if ([path.sep, '.'].includes(argv.inputDir[0])) {
throw new Error(`inputDir must be a relative path inside of '${cwd}'`)
}
const buildDir = path.join(cwd, 'build', 'pack');
const nodeModulesDir = path.join(cwd, 'node_modules');
const gitDir = path.join(cwd, '.git/');
const tempDir = fs.mkdtempSync(path.join(
os.tmpdir(),
`${path.basename(cwd)}-`
));
const tempBuildPath = path.join(tempDir, argv.inputDir)
const tempBuildDir = path.join(tempDir, path.dirname(argv.inputDir))
const tempDistDir = path.join(tempDir, 'dist');
console.log(`cp: ${process.cwd()} > ${tempDir}`);
fs.cpSync(
process.cwd(),
tempDir,
{
recursive: true,
filter: (src: string, dest: string) => {
if (src.startsWith(nodeModulesDir)) { return false }
if (src.startsWith(gitDir)) { return false }
if (src.startsWith(buildDir)) { return false }
console.log(
`cp: ${path.relative(cwd, src)} > ${path.relative(cwd, dest)}`
);
return true;
}
}
);
console.log(`cp: ${tempBuildPath} > ${tempDir}`);
fs.cpSync(
tempBuildPath,
tempDir,
{
recursive: true,
filter: (src: string, dest: string) => {
console.log(
`cp (tmp): ${path.relative(tempDir, src)} > ${path.relative(tempDir, dest)}`
);
return true;
}
}
);
console.log(`rm: ${tempBuildDir}`);
fs.rmSync(tempBuildDir, { recursive: true, force: true });
console.log(`mkdir: ${tempDistDir}`);
fs.mkdirSync(tempDistDir, { recursive: true });
console.log(`npm: pack --pack-destination ${argv.outputDir}`);
if (child_process.spawnSync(
'npm',
[
'pack',
'--pack-destination',
argv.outputDir
],
{
cwd: tempDir,
stdio: "inherit"
}
).status) { process.exit(1) }
console.log(`mkdir: ${argv.outputDir}`);
fs.mkdirSync(argv.outputDir, {recursive: true});
console.log(`cp: ${tempDistDir} > ${argv.outputDir}`);
fs.cpSync(
tempDistDir,
argv.outputDir,
{
recursive: true,
filter: (src: string, dest: string) => {
console.log(
`cp (tmp): ${path.relative(tempDir, src)} > ${path.relative(tempDir, dest)}`
);
return true;
}
}
);

75
scripts/publish.ts Normal file
View file

@ -0,0 +1,75 @@
import * as yargs from 'yargs';
import * as child_process from 'child_process';
const usage = `Publish a package
This is a wrapper around \`npm publish\`.
It reads a npm registry url, and authentication token from input arguments,
configures npm (in the project context) for publishing, then publishes and
restores the npm configuration.
`
const argv = require('yargs')
.usage('$0 [args]')
.option('registry', {
alias: 'r',
describe: 'URL of npm registry',
type: 'string'
})
.option('authToken', {
alias: 't',
describe: 'authentication token',
type: 'string'
})
.demandOption(['registry'])
.help()
.argv;
argv.authToken = process.env.NPM_AUTH_TOKEN ?? argv.authToken;
if (!argv.registry) { throw new Error('no url provided.')}
if (!argv.authToken) {
throw new Error(
'no authToken or \'NPM_AUTH_TOKEN\' environment variable provided.'
)
}
console.info(`npm: set registry ${argv.registry} --location project`);
if(child_process.spawnSync(
'npm',
['set', 'registry', argv.registry],
{ stdio: "inherit" }
).status) { process.exit(1) }
const registry = argv.registry.replace('https://', '').replace('http://', '');
const authTokenConfigItemName = '${registry}/:_authToken';
console.info(`npm: set _authToken ...`);
if (child_process.spawnSync(
'npm',
['set', authTokenConfigItemName, argv.authToken, '--location', 'project'],
{ stdio: "inherit" }
).status) { process.exit(1) }
console.info(`npm: publish`);
if (child_process.spawnSync('npm', ['publish'], { stdio: "inherit" }).status) {
process.exit(1);
};
console.info(`npm: delete registry --location project`);
if (child_process.spawnSync(
'npm',
['config', 'delete', 'registry', '--location', 'project'],
{ stdio: "inherit" }
).status) { process.exit(1) }
console.info(`npm: delete _authToken ... --location project`);
if (child_process.spawnSync(
'npm',
['config', 'delete', authTokenConfigItemName, '--location', 'project'],
{ stdio: "inherit" }
).status) { process.exit(1) }

View file

@ -0,0 +1,2 @@
export * as logging from './logging'

View file

@ -2,6 +2,6 @@ import * as logging from '../src/logging';
describe('Logger', () => {
it('can be instantiated', () => {
const logger = new logging.Logger('test', 0);
//const logger = new logging.Logger('test', 0);
})
});

View file

@ -5,5 +5,12 @@
"noEmit": false,
"incremental": true,
"outDir": "build/debug"
},
"watchOptions": {
"watchFile": "useFsEvents",
"watchDirectory": "useFsEvents",
"fallbackPolling": "dynamicPriority",
"synchronousWatchDirectory": true,
"excludeDirectories": ["**/node_modules", "build"]
}
}

View file

@ -1,6 +1,6 @@
{
"compilerOptions": {
"target": "ES2015",
"target": "es2015",
"module": "commonjs",
"strict": true,
"sourceMap": false,
@ -11,7 +11,8 @@
"declarationMap": true,
"outDir": "build/production",
"baseUrl": "./",
"paths": { "*": ["node/modules/*"] }
"paths": { "*": ["node/modules/*"] },
"lib": ["esnext.weakref"]
},
"include": [
"src/**/*.ts"

8
tsconfig.node.json Normal file
View file

@ -0,0 +1,8 @@
{
"extends": "./tsconfig.debug.json",
"compilerOptions": {
"target": "es2015",
"module": "commonjs",
"esModuleInterop": true
}
}