Git Product home page Git Product logo

craft's Introduction


Craft: Universal Release Tool (And More)

Travis GitHub release npm version license

craft is a command line tool that helps to automate and pipeline package releases. It suggests, and then enforces a specific workflow for managing release branches, changelogs, artifact publishing, etc.

Table of Contents

Installation

Binary

craft is distributed as a minified single JS binary.

npm (not recommended)

Recommendation is to used this file directly but one can also install craft as an NPM package and can be installed via yarn or npm:

yarn global add @sentry/craft
npm install -g @sentry/craft

Usage

$ craft -h
craft <command>

Commands:
  craft prepare NEW-VERSION  🚢 Prepare a new release branch
                          [aliases: p, prerelease, prepublish, prepare, release]
  craft publish NEW-VERSION  🛫 Publish artifacts         [aliases: pp, publish]
  craft targets              List defined targets as JSON array
  craft config               Print the parsed, processed, and validated Craft
                             config for the current project in pretty-JSON.
  craft artifacts <command>  📦 Manage artifacts          [aliases: a, artifact]

Options:
  --no-input     Suppresses all user prompts                    [default: false]
  --dry-run      Dry run mode: do not perform any real actions
  --log-level    Logging level
          [choices: "Fatal", "Error", "Warn", "Log", "Info", "Success", "Debug",
                                 "Trace", "Silent", "Verbose"] [default: "Info"]
  -v, --version  Show version number                                   [boolean]
  -h, --help     Show help                                             [boolean]

Caveats

  • When interacting with remote GitHub repositories, craft uses the remote origin by default. If you have a different setup, set the CRAFT_REMOTE environment variable or the --remote option to the git remote you are using.

Global Configuration

Global configuration for craft can be done either by using environment variables or by adding values to a configuration file (see below).

All command line flags can be set through environment variables by prefixing them with CRAFT_ and converting them to UPPERCASE_UNDERSCORED versions:

CRAFT_LOG_LEVEL=Debug
CRAFT_DRY_RUN=1
CRAFT_NO_INPUT=0

Since Craft heavily relies on GitHub, it needs the GITHUB_TOKEN environment variable to be set to a proper GitHub Personal Access Token for almost anything. The token only needs repo scope (repo:status and public_repo subscopes, to be precise).

Additional environment variables may be required when publishing to specific targets (e.g. TWINE_USERNAME and TWINE_PASSWORD for PyPI target).

Environment Files

craft will read configuration variables (keys, tokens, etc.) from the following locations:

  • $HOME/.craft.env
  • $PROJECT_DIR/.craft.env
  • the shell's environment

where $HOME is the current user's home directory, and $PROJECT_DIR is the directory where .craft.yml is located.

These locations will be checked in the order specified above, with values found in one location overwriting anything found in previous locations. In other words, environment variables will take precedence over either configuration file, and the project-specific file will take precedence over the file in $HOME.

The env files must be written in shell (sh/bash) format. Leading export is allowed.

Example:

# ~/.craft.env
GITHUB_TOKEN=token123
export NUGET_API_TOKEN=abcdefgh

Workflow

craft prepare: Preparing a New Release

This command will create a new release branch, check the changelog entries, run a version-bumping script, and push this branch to GitHub. We expect that CI triggered by pushing this branch will result in release artifacts being built and uploaded to the artifact provider you wish to use during the subsequent publish step.

craft prepare NEW-VERSION

🚢 Prepare a new release branch

Positionals:
  NEW-VERSION  The new version you want to release           [string] [required]

Options:
  --no-input       Suppresses all user prompts                  [default: false]
  --dry-run        Dry run mode: do not perform any real actions
  --log-level      Logging level
          [choices: "Fatal", "Error", "Warn", "Log", "Info", "Success", "Debug",
                                 "Trace", "Silent", "Verbose"] [default: "Info"]
  --rev, -r        Source revision (git SHA or tag) to prepare from (if not
                   branch head)                                         [string]
  --no-push        Do not push the release branch     [boolean] [default: false]
  --no-git-checks  Ignore local git changes and unsynchronized remotes
                                                      [boolean] [default: false]
  --no-changelog   Do not check for changelog entries [boolean] [default: false]
  --publish        Run "publish" right after "release"[boolean] [default: false]
  --remote         The git remote to use when pushing
                                                    [string] [default: "origin"]
  -v, --version    Show version number                                 [boolean]
  -h, --help       Show help                                           [boolean]

craft publish: Publishing the Release

The command will find a release branch for the provided version. The normal flow is for this release branch to be created automatically by craft prepare, but that's not strictly necessary. Then, it subscribes to the latest status checks on that branch. Once the checks pass, it downloads the release artifacts from the artifact provider configured in .craft.yml and uploads them to the targets named on the command line (and pre-configured in .craft.yml).

craft publish NEW-VERSION

🛫 Publish artifacts

Positionals:
  NEW-VERSION  Version to publish                            [string] [required]

Options:
  --no-input         Suppresses all user prompts                [default: false]
  --dry-run          Dry run mode: do not perform any real actions
  --log-level        Logging level
          [choices: "Fatal", "Error", "Warn", "Log", "Info", "Success", "Debug",
                                 "Trace", "Silent", "Verbose"] [default: "Info"]
  --target, -t       Publish to this target
    [string] [choices: "npm", "gcs", "registry", "docker", "github", "gh-pages",
                                                 "all", "none"] [default: "all"]
  --rev, -r          Source revision (git SHA or tag) to publish (if not release
                     branch head)                                       [string]
  --no-merge         Do not merge the release branch after publishing
                                                      [boolean] [default: false]
  --keep-branch      Do not remove release branch after merging it
                                                      [boolean] [default: false]
  --keep-downloads   Keep all downloaded files        [boolean] [default: false]
  --no-status-check  Do not check for build status    [boolean] [default: false]
  -v, --version      Show version number                               [boolean]
  -h, --help         Show help                                         [boolean]

Example

Let's imagine we want to release a new version of our package, and the version in question is 1.2.3.

We run prepare command first:

$ craft prepare 1.2.3

After some basic sanity checks this command creates a new release branch release/1.2.3, runs the version-bumping script (scripts/bump-version.sh), commits the changes made by the script, and then pushes the new branch to GitHub. At this point CI systems kick in, and the results of those builds, as well as built artifacts (binaries, NPM archives, Python wheels) are gradually uploaded to GitHub.

To publish the built artifacts we run publish:

$ craft publish 1.2.3

This command will find our release branch (release/1.2.3), check the build status of the respective git revision in GitHub, and then publish available artifacts to configured targets (for example, to GitHub and NPM in the case of Craft).

Configuration File: .craft.yml

Project configuration for craft is stored in .craft.yml configuration file, located in the project root.

GitHub project

Craft tries to determine the GitHub repo information from the local git repo and its remotes configuration. However, since publish command does not require a local git checkout, you may want to hard-code this information into the configuration itself:

github:
  owner: getsentry
  repo: sentry-javascript

Pre-release Command

This command will run on your newly created release branch as part of prepare command. By default, it is set to bash scripts/bump-version.sh. Please refer to the Pre-release version bumping script conventions section for more details.

preReleaseCommand: bash scripts/bump-version.sh

Post-release Command

This command will run after a successful publish. By default, it is set to bash scripts/post-release.sh. It will not error if the default script is missing though, as this may not be needed by all projects. Please refer to the Post-release script conventions section for more details.

postReleaseCommand: bash scripts/post-release.sh

Release Branch Name

This overrides the prefix for the release branch name. The full branch name used for a release is {releaseBranchPrefix}/{version}. The prefix defaults to "release".

releaseBranchPrefix: publish

Changelog Policies

craft can help you to maintain change logs for your projects. At the moment, craft supports two approaches: simple, and auto to changelog management.

In simple mode, craft prepare will remind you to add a changelog entry to the changelog file (CHANGELOG.md by default).

In auto mode, craft prepare will use the following logic:

  1. If there's already an entry for the given version, use that
  2. Else if there is an entry named Unreleased, rename that to the given version
  3. Else, create a new section for the version and populate it with the changes since the last version. It uses GitHub Milestones to provide a concise and rich changelog. If the PRs are associated with a milestone, the milestone title and description are used as the changelog entry alongside a brief list of associated PRs. Any individual commits and PRs are listed under the "Various improvements & fixes" section at the bottom. Check out Craft's own releases as example.

Configuration

Option Description
changelog optional. Path to the changelog file. Defaults to CHANGELOG.md
changelogPolicy optional. Changelog management mode (none, simple, or auto). Defaults to none.

Example (simple):

changelog: CHANGES
changelogPolicy: simple

Valid changelog example:

## 1.3.5

* Removed something

## 1.3.4

* Added something

Example (auto):

changelog: CHANGES
changelogPolicy: auto

Changelog with staged changes example:

## Unreleased

* Removed something

## 1.3.4

* Added something

Additionally, .craft.yml is used for listing targets where you want to publish your new release.

Minimal Version

It is possible to specify minimal craft version that is required to work with your configuration.

Example:

minVersion: '0.5.0'

Required Files

You can provide a list of patterns for files that have to be available before proceeding with publishing. In other words, for every pattern in the given list there has to be a file present that matches that pattern. This might be helpful to ensure that we're not trying to do an incomplete release.

Example:

requireNames:
  - /^sentry-craft.*\.tgz$/
  - /^gh-pages.zip$/

Status Provider

You can configure which status providers craft will use to check for your build status. By default, it will use GitHub but you can add more providers if needed.

Configuration

Option Description
name Name of the status provider: only github (default) for now.
config In case of github: may include contexts key that contains a list of required contexts (checks)

Example:

statusProvider:
  name: github
  config:
    contexts:
      - Travis CI - Branch

Artifact Provider

You can configure which artifact providers craft will use to fetch artifacts from. By default, GitHub is used, but in case you don't need use any artifacts in your project, you can set it to none.

Configuration

Option Description
name Name of the artifact provider: github (default), gcs, or none

Example:

artifactProvider:
  name: none

Target Configurations

The configuration specifies which release targets to run for the repository. To run more targets, list the target identifiers under the targets key in .craft.yml.

Example:

targets:
  - name: npm
  - name: github
  - name: registry
    id: browser
    type: sdk
    onlyIfPresent: /^sentry-browser-.*\.tgz$/
    includeNames: /\.js$/
    checksums:
      - algorithm: sha384
        format: base64
    config:
      canonical: 'npm:@sentry/browser'
  - name: registry
    id: node
    type: sdk
    onlyIfPresent: /^sentry-node-.*\.tgz$/
    config:
      canonical: 'npm:@sentry/node'

Per-target options

The following options can be applied to every target individually:

Name Description
includeNames optional. Regular expression: only matched files will be processed by the target. There is one special case that includeNames supports.
excludeNames optional. Regular expression: the matched files will be skipped by the target. Matching is performed after testing for inclusion (via includeNames).
id optional. A unique id for the target type so one can refer to that target individually with the -t option with the publish command like -t registry[browser]. (see the example config above)

If neither option is included, all artifacts for the release will be processed by the target.

Example:

targets:
  - name: github
    includeNames: /^.*\.exe$/
    excludeNames: /^test.exe$/

GitHub (github)

Create a release on Github. If a Markdown changelog is present in the repository, this target tries to read the release name and description from the changelog. Otherwise, defaults to the tag name and tag's commit message.

If previewReleases is set to true (which is the default), the release created on GitHub will be marked as a pre-release version if the release name contains any one of preview, pre, rc, dev,alpha, beta, unstable, a, or b.

Environment

Name Description
GITHUB_TOKEN Personal GitHub API token (see https://github.com/settings/tokens)

Configuration

Option Description
tagPrefix optional. Prefix for new git tags (e.g. "v"). Empty by default.
previewReleases optional. Automatically detect and create preview releases. true by default.
tagOnly optional. If set to true, only create a tag (without a GitHub release).false by default.

Example:

targets:
  - name: github
    tagPrefix: v
    previewReleases: false

NPM (npm)

Releases an NPM package to the public registry. This requires a package tarball generated by npm pack in the artifacts. The file will be uploaded to the registry with npm publish, or with yarn publish if npm is not found. This requires NPM to be authenticated with sufficient permissions to publish the package.

Environment

The npm utility must be installed on the system.

Name Description
NPM_TOKEN An automation token allowed to publish.
NPM_BIN optional. Path to the npm executable. Defaults to npm
YARN_BIN optional. Path to the yarn executable. Defaults to yarn
CRAFT_NPM_USE_OTP optional. If set to "1", you will be asked for an OTP (for 2FA)

Configuration

Option Description
access optional. Visibility for scoped packages: restricted (default) or public
checkPackageName optional. If defined, check this package on the registry to get the current latest version to compare for the latest tag. The package(s) to be published will only be tagged with latest if the new version is greater than the checked package's version

Example

targets:
  - name: npm
    access: public

Python Package Index (pypi)

Uploads source dists and wheels to the Python Package Index via twine. The source code bundles and/or wheels must be in the release assets.

Environment

The twine Python package must be installed on the system.

Name Description
TWINE_USERNAME User name for PyPI with access rights for the package
TWINE_PASSWORD Password for the PyPI user
TWINE_BIN optional. Path to twine. Defaults to twine

Configuration

none

Example

targets:
  - name: pypi

Sentry internal PyPI (sentry-pypi)

Creates a GitHub pull request to import the package into a repo set up like getsentry/pypi

Environment

Name Description
GITHUB_TOKEN Personal GitHub API token (see https://github.com/settings/tokens)

Configuration

Option Description
internalPypiRepo GitHub repo containing pypi metadata

Example

targets:
  - name: pypi
  - name: sentry-pypi
    internalPypiRepo: getsentry/pypi

Homebrew (brew)

Pushes a new or updated homebrew formula to a brew tap repository. The formula is committed directly to the master branch of the tap on GitHub, therefore the bot needs rights to commit to master on that repository. Therefore, formulas on homebrew/core are not supported, yet.

The tap is configured with the mandatory tap parameter in the same format as the brew utility. A tap <org>/<name> will expand to the GitHub repository github.com:<org>/homebrew-<name>.

The formula contents are given as configuration value and can be interpolated with Mustache template syntax ({{ variable }}). The interpolation context contains the following variables:

  • version: The new version
  • revision: The tag's commit SHA
  • checksums: A map containing sha256 checksums for every release asset. Use the full filename to access the sha, e.g. checksums.MyProgram-x86. If the filename contains dots (.), they are being replaced with __. If the filename contains the currently released version, it is replaced with __VERSION__. For example, sentry-wizard-v3.9.3.tgz checksums will be accessible by the key checksums.sentry-wizard-v__VERSION____tgz.

Environment

Name Description
GITHUB_TOKEN Personal GitHub API token (seeh ttps://github.com/settings/tokens)

Configuration

Option Description
tap The name of the homebrew tap used to access the GitHub repo
template The template for contents of the formula file (ruby code)
formula optional. Name of the formula. Defaults to the repository name
path optional. Path to store the formula in. Defaults to Formula

Example

targets:
  - name: brew
    tap: octocat/tools # Expands to github.com:octocat/homebrew-tools
    formula: myproject # Creates the file myproject.rb
    path: HomebrewFormula # Creates the file in HomebrewFormula/
    template: >
      class MyProject < Formula
        desc "This is a test for homebrew formulae"
        homepage "https://github.com/octocat/my-project"
        url "https://github.com/octocat/my-project/releases/download/{{version}}/binary-darwin"
        version "{{version}}"
        sha256 "{{checksums.binary-darwin}}"

        def install
          mv "binary-darwin", "myproject"
          bin.install "myproject"
        end
      end

NuGet (nuget)

Uploads packages to NuGet via .NET Core. By default, craft publishes all packages with .nupkg extension.

Environment

The dotnet tool must be available on the system.

Name Description
NUGET_API_TOKEN NuGet personal API token
NUGET_DOTNET_BIN optional. Path to .NET Core. Defaults to dotnet

Configuration

none

Example

targets:
  - name: nuget

Rust Crates (crates)

Publishes a single Rust package or entire workspace on the public crate registry (crates.io). If the workspace contains multiple crates, they are published in an order depending on their dependencies.

Environment

"cargo" must be installed and configured on the system.

Name Description
CRATES_IO_TOKEN The access token to the crates.io account
CARGO_BIN optional. Path to cargo. Defaults to cargo.

Configuration

Option Description
noDevDeps optional. Strips devDependencies from crates before publishing. This is useful if a workspace crate uses circular dependencies for docs. Requires cargo-hack installed. Defaults to false.

Example

targets:
  - name: crates
    noDevDeps: false

Google Cloud Storage (gcs)

Uploads artifacts to a bucket in Google Cloud Storage.

The bucket paths (paths) can be interpolated using Mustache syntax ({{ variable }}). The interpolation context contains the following variables:

  • version: The new project version
  • revision: The SHA revision of the new version

Environment

Google Cloud credentials can be provided using either of the following two environment variables.

Name Description
CRAFT_GCS_TARGET_CREDS_PATH Local filesystem path to Google Cloud credentials (service account file)
CRAFT_GCS_TARGET_CREDS_JSON Full service account file contents, as a JSON string

If defined, CRAFT_GCS_TARGET_CREDS_JSON will be preferred over CRAFT_GCS_TARGET_CREDS_PATH.

Note: CRAFT_GCS_TARGET_CREDS_JSON and CRAFT_GCS_TARGET_CREDS_PATH were formerly called CRAFT_GCS_CREDENTIALS_JSON and CRAFT_GCS_CREDENTIALS_PATH, respectively. While those names will continue to work for the foreseeable future, you'll receive a warning encouraging you to switch to the new names.

Configuration

Option Description
bucket The name of the GCS bucket where artifacts are uploaded.
paths A list of path objects that represent bucket paths.
paths.path Template-aware bucket path, which can contain {{ version }} and/or {{ revision }}.
paths.metadata optional Metadata for uploaded files. By default, it sets Cache-Control to "public, max-age=300".

Example

targets:
  - name: gcs
    bucket: bucket-name
    paths:
      - path: release/{{version}}/download
        metadata:
          cacheControl: `public, max-age=3600`
      - path: release/{{revision}}/platform/package

GitHub Pages (gh-pages)

Extracts an archive with static assets and pushes them to the specified git branch (gh-pages by default). Thus, it can be used to publish documentation or any other assets to GitHub Pages, so they will be later automatically rendered by GitHub.

By default, this target will look for an artifact named gh-pages.zip, extract it, and commit its contents to gh-pages branch.

WARNING! The destination branch will be completely overwritten by the contents of the archive.

Environment

none

Configuration

Option Description
branch optional The name of the branch to push the changes to. gh-pages by default.
githubOwner optional GitHub project owner, defaults to the value from the global configuration.
githubRepo optional GitHub project name, defaults to the value from the global configuration.

Example

targets:
  - name: gh-pages
    branch: gh-pages

Sentry Release Registry (registry)

The target will update the Sentry release registry repo(https://github.com/getsentry/sentry-release-registry/) with the latest version of the project craft is used with. The release registry repository will be checked out locally, and then the new version file will be created there, along with the necessary symbolic links.

Two package types are supported: "sdk" and "app". Type "sdk" means that the package is uploaded to one of the public registries (PyPI, NPM, Nuget, etc.), and that the corresponding package directory can be found inside "packages" directory of the release regsitry. Type "app" indicates that the package's version files are located in "apps" directory of the registry.

It is strongly discouraged to have multiple registry targets in a config as it supports grouping/batching multiple apps and SDKs in a single target.

Environment

none

Configuration

Option Description
apps List of app configs as a dict, keyed by their canonical names (example: app:craft)
sdks List of sdk configs as a dict, keyed by their canonical names (example: maven:io.sentry:sentry)
(sdks|apps).urlTemplate optional URL template that will be used to generate download links for "app" package type.
(sdks|apps).linkPrereleases optional Update package versions even if the release is a preview release, "false" by default.
(sdks|apps).checksums optional A list of checksums that will be computed for matched files (see includeNames). Every checksum entry is an object with two attributes: algorithm (one of sha256, sha384, and sha512) and format (base64 and hex).
(sdks|apps).onlyIfPresent optional A file pattern. The target will be executed only when the matched file is found.

Example

targets:
  - name: registry
    sdks:
      'npm:@sentry/browser':
    apps:
      'npm:@sentry/browser':
        urlTemplate: 'https://example.com/{{version}}/{{file}}'
        checksums:
          - algorithm: sha256
            format: hex

Cocoapods (cocoapods)

Pushes a new podspec to the central cocoapods repository. The Podspec is fetched from the Github repository with the revision that is being released. No release assets are required for this target.

Environment

The cocoapods gem must be installed on the system.

Name Description
COCOAPODS_TRUNK_TOKEN The access token to the cocoapods account
COCOAPODS_BIN optional. Path to pod executable.

Configuration

Option Description
specPath Path to the Podspec file in the repository

Example

targets:
  - name: cocoapods
    specPath: MyProject.podspec

Docker (docker)

Pulls an existing source image tagged with the revision SHA, and then pushed it to a new target tagged with the released version. No release assets are required for this target except for the source image at the provided source image location so it would be a good idea to add a status check that ensures the source image exists, otherwise craft publish will fail at the docker pull step, causing an interrupted publish. This is an issue for other, non-idempotent targets, not for the Docker target.

Environment

docker executable (or something equivalent) must be installed on the system.

Name Description
DOCKER_USERNAME The username for the Docker registry.
DOCKER_PASSWORD The personal access token for the account.
DOCKER_BIN optional. Path to docker executable.

Configuration

Option Description
source Path to the source Docker image to be pulled
sourceFormat Format for the source image name. Default: {{{source}}}:{{{revision}}}
target Path to the target Docker image to be pushed
targetFormat Format for the target image name. Default: {{{target}}}:{{{version}}}

Example

targets:
  - name: docker
    source: us.gcr.io/sentryio/craft
    target: getsentry/craft
# Optional but strongly recommended
statusProvider:
  name: github
  config:
    contexts:
      - Travis CI - Branch # or whatever builds and pushes your source image

Ruby Gems Index (gem)

Pushes a gem Ruby Gems. It also requires you to be logged in with gem login.

Environment

gem must be installed on the system.

Name Description
GEM_BIN optional. Path to "gem" executable. Defaults to gem

Configuration

none

Example

targets:
  - name: gem

AWS Lambda Layer (aws-lambda-layer)

The target will create a new public lambda layer in each available region with the extracted artifact from the artifact provider, and update the Sentry release registry with the new layer versions afterwards.

Environment

Name Description
AWS_ACCESS_KEY The access key of the AWS account to create and publish the layers.
AWS_SECRET_ACCESS_KEY The secret access key of the AWS account to create and publish the layers.

Configuration

Option Description
linkPrereleases optional Updates layer versions even if the release is a preview release, false by default.
includeNames optional Exists for all targets, see here. It must filter exactly one artifact.
layerName The name of the layer to be published.
compatibleRuntimes A list of compatible runtimes for the layer. Each compatible runtime consists on the name of the runtime and a list of compatible versions.
license The license of the layer.

Example

targets:
  - name: aws-lambda-layer
    includeNames: /^sentry-node-serverless-\d+(\.\d+)*\.zip$/
    layerName: SentryNodeServerlessSDK
    compatibleRuntimes:
      - name: node
        versions:
          - nodejs10.x
          - nodejs12.x
    license: MIT

Unity Package Manager (upm)

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

WARNING! The destination repository will be completely overwritten.

Environment

none

Configuration

Option Description
releaseRepoOwner Name of the owner of the release target
releaseRepoName Name of the repo of the release target

Example

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

Maven central (maven)

PGP signs and publishes packages to Maven Central.

Note: in order to see the output of the commands, set the logging level to trace.

Environment

Name Description
OSSRH_USERNAME Username of Sonatype repository.
OSSRH_PASSWORD Password of Sonatype repository.
GPG_PASSPHRASE Passphrase for your default GPG Private Key.
GPG_PRIVATE_KEY optional GPG Private Key generated via gpg --armor --export-secret-keys YOUR_ID. If not provided, default key from your machine will be used.

Configuration

Option Description
mavenCliPath Path to the Maven CLI. It must be executable by the calling process.
mavenSettingsPath Path to the Maven settings.xml file.
mavenRepoId ID of the Maven server in the settings.xml.
mavenRepoUrl URL of the Maven repository.
android Android configuration, see below.
kmp Kotlin Multiplatform configuration, see below.

The Kotlin Multiplatform configuration is optional and false by default. If your project isn't related to Android, you don't need this configuration and can set the option to false. If not, set the following nested elements:

  • distDirRegex: pattern of distribution directory names.
  • fileReplaceeRegex: pattern of substring of distribution module names to be replaced to get the Android distribution file.
  • fileReplacerStr: string to be replaced in the module names to get the Android distribution file.

Example (without Android config)

targets:
  - name: maven
    mavenCliPath: scripts/mvnw.cmd
    mavenSettingsPath: scripts/settings.xml
    mavenRepoId: ossrh
    mavenRepoUrl: https://oss.sonatype.org/service/local/staging/deploy/maven2/
    android: false

Example (with Android config)

targets:
  - name: maven
    mavenCliPath: scripts/mvnw.cmd
    mavenSettingsPath: scripts/settings.xml
    mavenRepoId: ossrh
    mavenRepoUrl: https://oss.sonatype.org/service/local/staging/deploy/maven2/
    android:
      distDirRegex: /^sentry-android-.*$/
      fileReplaceeRegex: /\d\.\d\.\d(-SNAPSHOT)?/
      fileReplacerStr: release.aar

Example (with Kotlin Multiplatform config)

targets:
  - name: maven
    mavenCliPath: scripts/mvnw.cmd
    mavenSettingsPath: scripts/settings.xml
    mavenRepoId: ossrh
    mavenRepoUrl: https://oss.sonatype.org/service/local/staging/deploy/maven2/
    android:
      distDirRegex: /^sentry-android-.*$/
      fileReplaceeRegex: /\d\.\d\.\d(-SNAPSHOT)?/
      fileReplacerStr: release.aar
    kmp:
      rootDistDirRegex: /sentry-kotlin-multiplatform-[0-9]+.*$/
      appleDistDirRegex: /sentry-kotlin-multiplatform-(macos|ios|tvos|watchos).*/

Symbol Collector (symbol-collector)

Using the symbol-collector client, uploads native symbols. The symbol-collector needs to be available in the path.

Configuration

Option Description
serverEndpoint optional The server endpoint. Defaults to https://symbol-collector.services.sentry.io.
batchType The batch type of the symbols to be uploaded. I.e: Android, macOS, iOS.
bundleIdPrefix The prefix of the bundle ID. The new version will be appended to the end of this prefix.

Example

targets:
  - name: symbol-collector
    includeNames: /libsentry(-android)?\.so/
    batchType: Android
    bundleIdPrefix: android-ndk-

pub.dev (pub-dev)

Pushes a new Dart or Flutter package to pub.dev.

Because there is no automated way to login and obtain required tokens, you need to perform a valid release beforehand, for every package that you configure. This will open up your browser and use Google's OAuth to log you in, and generate an appropriate file with stored credentials.

Based on your environment, you can find this file at either $HOME/.pub-cache/credentials.json or $HOME/Library/Application\ Support/dart/pub-credentials.json for OSX and $HOME/.config/dart/pub-credentials.json for Linux, depending on your setup.

For this target to work correctly, either dart must be installed on the system or a valid dartCliPath must be provided.

Environment

Name Description
PUBDEV_ACCESS_TOKEN Value of accessToken obtained from pub-credentials.json
PUBDEV_REFRESH_TOKEN Value of refreshToken obtained from pub-credentials.json

Configuration

Option Description
dartCliPath optional Path to the Dart CLI. It must be executable by the calling process. Defaults to dart.
packages optional List of directories to be released, relative to the root. Useful when a single repository contains multiple packages. When skipped, root directory is assumed as the only package.

Example

targets:
  - name: pub-dev
    packages:
      uno:
      dos:
      tres:

Hex (hex)

Pushes a package to the Elixir / Erlang package manager Hex.

Environment

mix (bundled with the elixir language) must be installed on the system.

Name Description
HEX_API_KEY API Key obtained from hex.pm account
MIX_BIN optional. Path to "mix" executable. Defaults to mix

Configuration

none

Example

targets:
  - name: hex

Commit on Git Repository (commit-on-git-repository)

Takes a tarball and pushes the unpacked contents to a git repository.

Environment

Name Description
GITHUB_API_TOKEN GitHub PAT that will be used for authentication when a the repositoryUrl host is github.com.

Configuration

Option Description
archive Regular expression to match a .tgz file in the build artifacts. The content of the found file will be pushed to the git repository. Needs to match exactly one file.
repositoryUrl Url to the git remote git repository. Must use http or https protocol! (no git@...)
branch Which repository branch to push to.
stripComponents optional. How many leading path elements should be removed when unpacking the tarball. Default: 0 (see tar --strip-components option)
createTag optional. Whether to attach a tag to the created commit. The content of the tag is gonna be equal to the release version passed to craft ("NEW-VERSION"). Default: false

Example

targets:
  - name: commit-on-git-repository
    archive: /^sentry-deno-\d.*\.tgz$/
    repositoryUrl: https://github.com/getsentry/sentry-deno
    stripComponents: 1
    branch: main
    createTag: true

PowerShellGet (powershell)

Uploads a module to PowerShell Gallery or another repository supported by PowerShellGet's Publish-Module.

The action looks for an artifact named <module>.zip and extracts it to a temporary directory. The extracted directory is then published as a module.

Environment

The pwsh executable must be installed on the system.

Name Description Default
POWERSHELL_API_KEY required PowerShell Gallery API key
POWERSHELL_BIN optional Path to PowerShell binary pwsh

Configuration

Option Description Default
module required Module name.
repository optional Repository to publish the package to. PSGallery

Example

targets:
  - name: powershell
    module: Sentry

Integrating Your Project with craft

Here is how you can integrate your GitHub project with craft:

  1. Set up a workflow that builds your assets and runs your tests. Allow building release branches (their names follow release/{VERSION} by default, configurable through releaseBranchPrefix).

    on:
      push:
        branches:
          - 'release/**'
  2. Use the official actions/upload-artifact@v2 action to upload your assets. Here is an example config (step) of an archive job:

    - name: Archive Artifacts
      uses: actions/upload-artifact@v2
      with:
        name: ${{ github.sha }}
        path: |
          ${{ github.workspace }}/*.tgz
          ${{ github.workspace }}/packages/tracing/build/**
          ${{ github.workspace }}/packages/**/*.tgz

    A few important things to note:

    • The name of the artifacts is very important and needs to be name: ${{ github.sha }}. Craft uses this as a unique id to fetch the artifacts.
    • Keep in mind that this action maintains the folder structure and zips everything together. Craft will download the zip and recursively walk it to find all assets.
  3. Add .craft.yml configuration file to your project

    • List there all the targets you want to publish to
    • Configure additional options (changelog management policy, tag prefix, etc.)
  4. Add a pre-release script to your project.

  5. Get various configuration tokens

  6. Run craft prepare <version> --publish and profit!

Pre-release (Version-bumping) Script: Conventions

Among other actions, craft prepare runs an external, project-specific command or script that is responsible for version bumping. By default, this script should be located at: ./scripts/bump-version.sh. The command can be configured by specifying the preReleaseCommand configuration option in craft.yml.

The following requirements are on the script interface and functionality:

  • The script should accept at least two arguments. Craft will pass the old ("from") version and the new ("to") version as the last two arguments, respectively.
  • The script must replace all relevant occurrences of the old version string with the new one.
  • The script must not commit the changes made.
  • The script must not change the state of the git repository (e.g. changing branches)

Example

#!/bin/bash
### Example of a version-bumping script for an NPM project.
### Located at: ./scripts/bump-version.sh
set -eux
OLD_VERSION="${1}"
NEW_VERSION="${2}"

# Do not tag and commit changes made by "npm version"
export npm_config_git_tag_version=false
npm version "${NEW_VERSION}"

Post-release Script: Conventions

Among other actions, craft publish runs an external, project-specific command or script that can do things like bumping the development version. By default, this script should be located at: ./scripts/post-release.sh. Unlike the pre-release command, this script is not mandatory so if the file does not exist, craft will report this fact and then move along as usual. This command can be configured by specifying postReleaseCommand configuration option in craft.yml.

The following requirements are on the script interface and functionality:

  • The script should accept at least two arguments. Craft will pass the old ("from") version and the new ("to") version as the last two arguments, respectively.
  • The script is responsible for any and all git state management as craft will simply exit after running this script as the final step. This means the script is responsible for committing and pushing any changes that it may have made.

Example

#!/bin/bash
### Example of a dev-version-bumping script for a Python project
### Located at: ./scripts/post-release.sh
set -eux
OLD_VERSION="${1}"
NEW_VERSION="${2}"

# Ensure master branch
git checkout master
# Advance the CalVer release by one-month and add the `.dev0` suffix
./scripts/bump-version.sh '' $(date -d "$(echo $NEW_VERSION | sed -e 's/^\([0-9]\{2\}\)\.\([0-9]\{1,2\}\)\.[0-9]\+$/20\1-\2-1/') 1 month" +%y.%-m.0.dev0)
# Only commit if there are changes, make sure to `pull --rebase` before pushing to avoid conflicts
git diff --quiet || git commit -anm 'meta: Bump new development version' && git pull --rebase && git push

Development

Logging Level

Logging level for craft can be configured via setting the CRAFT_LOG_LEVEL environment variable or using the --log-level CLI flag.

Accepted values are: Fatal, Error, Warn, Log, Info, Success, Debug, Trace, Silent, Verbose

Dry-run Mode

Dry-run mode can be enabled via setting the CRAFT_DRY_RUN environment variable to any truthy value (any value other than undefined, null, "", 0, false, and no). One may also use the --dry-run CLI flag.

In dry-run mode no destructive actions will be performed (creating remote branches, pushing tags, committing files, etc.)

Sentry Support

Errors you encounter while using Craft can be sent to Sentry. To use this feature, add CRAFT_SENTRY_DSN variable to your environment (or "craft" configuration file) that contains a Sentry project's DSN.

For example:

export CRAFT_SENTRY_DSN='https://[email protected]/2345'

Releasing

craft obviously uses craft for preparing and publishing new releases!

Did you mean recursion?

craft's People

Contributors

abhiprasad avatar asottile-sentry avatar bitsandfoxes avatar bruno-garcia avatar brustolin avatar buenaflor avatar byk avatar cameronmcefee avatar chadwhitacre avatar dependabot[bot] avatar getsentry-bot avatar hazat avatar iker-barriocanal avatar jan-auer avatar kamilogorek avatar lforst avatar lobsterkatie avatar loewenheim avatar marandaneto avatar mattgauntseo-sentry avatar mattjohnsonpint avatar mitsuhiko avatar mydea avatar philipphofmann avatar rhcarvalho avatar romtsn avatar sl0thentr0py avatar swatinem avatar tonyo avatar vaind avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

craft's Issues

craft thinks GitHub check is PENDING, GitHub shows green PASSED

https://github.com/getsentry/sentry-go/runs/423997330 reported checks PASSED but craft kept looping.

Could it be that the different GitHub APIs consulted were out of sync?

~/s/sentry-go ❯❯❯ CRAFT_LOG_LEVEL=debug craft publish 0.5.0 --skip-status-check                               master ✭
ℹ info craft 0.9.0
… debug Found environment file in the home directory: /Users/rodolfo/.craft.env
… debug Read the following variables from /Users/rodolfo/.craft.env: GITHUB_API_TOKEN,ZEUS_API_TOKEN
… debug No environment file found in the configuration directory: /Users/rodolfo/sentry/sentry-go/.craft.env
… debug Not initializing Sentry SDK
… debug Catching Ctrl-C is disabled by default. See https://github.com/getsentry/craft/issues/21
… debug Argv:
  {"_":["publish"],"no-input":false,"noInput":false,"dry-run":false,"dryRun":false,"no-merge":false,"noMerge":false,"keep-branch":false,"keepBranch":false,"keep-downloads":false,"keepDownloads":false,"no-status-check":false,"noStatusCheck":false,"skip-status-check":true,"skipStatusCheck":true,"target":"all","t":"all","$0":"/usr/local/bin/craft","NEW-VERSION":"0.5.0","newVersion":"0.5.0","new-version":"0.5.0"}
… debug Configuration file found:
  /Users/rodolfo/sentry/sentry-go/.craft.yml
… debug Parsing and validating the configuration file...
ℹ info "craft" version is compatible with the minimal version from the configuration file.
ℹ info Publishing version: "0.5.0"
… debug Fetching branch information
  release/0.5.0
… debug GET /repos/getsentry/sentry-go/branches/release/0.5.0 - 200 in 289ms
… debug Revision to publish:
  70ee6a791978e9e4b96112f30fd2cad7132ecd84
ℹ info Using "GithubStatusProvider" for status checks
… debug Fetching repository information...
… debug GET /repos/getsentry/sentry-go - 200 in 296ms
… debug Repository info received: "{
    "status": 200,
    "url": "https://api.github.com/repos/getsentry/sentry-go",
    "headers": {
        "access-control-allow-origin": "*",
        "access-control-expose-headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type",
        "cache-control": "private, max-age=60, s-maxage=60",
        "connection": "close",
        "content-encoding": "gzip",
        "content-security-policy": "default-src 'none'",
        "content-type": "application/json; charset=utf-8",
        "date": "Mon, 03 Feb 2020 20:26:56 GMT",
        "etag": "W/\"8ae8de0e9d2caf040054fb50123e9a61\"",
        "last-modified": "Mon, 03 Feb 2020 19:59:12 GMT",
        "referrer-policy": "origin-when-cross-origin, strict-origin-when-cross-origin",
        "server": "GitHub.com",
        "status": "200 OK",
        "strict-transport-security": "max-age=31536000; includeSubdomains; preload",
        "transfer-encoding": "chunked",
        "vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding",
        "x-accepted-oauth-scopes": "repo",
        "x-content-type-options": "nosniff",
        "x-frame-options": "deny",
        "x-github-media-type": "github.v3; format=json",
        "x-github-request-id": "DB30:4609:E264865:10E6546F:5E38820F",
        "x-oauth-scopes": "repo",
        "x-ratelimit-limit": "5000",
        "x-ratelimit-remaining": "4921",
        "x-ratelimit-reset": "1580763515",
        "x-xss-protection": "1; mode=block"
    },
    "data": {
        "id": 174522026,
        "node_id": "MDEwOlJlcG9zaXRvcnkxNzQ1MjIwMjY=",
        "name": "sentry-go",
        "full_name": "getsentry/sentry-go",
        "private": false,
        "owner": {
            "login": "getsentry",
            "id": 1396951,
            "node_id": "MDEyOk9yZ2FuaXphdGlvbjEzOTY5NTE=",
            "avatar_url": "https://avatars0.githubusercontent.com/u/1396951?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/getsentry",
            "html_url": "https://github.com/getsentry",
            "followers_url": "https://api.github.com/users/getsentry/followers",
            "following_url": "https://api.github.com/users/getsentry/following{/other_user}",
            "gists_url": "https://api.github.com/users/getsentry/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/getsentry/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/getsentry/subscriptions",
            "organizations_url": "https://api.github.com/users/getsentry/orgs",
            "repos_url": "https://api.github.com/users/getsentry/repos",
            "events_url": "https://api.github.com/users/getsentry/events{/privacy}",
            "received_events_url": "https://api.github.com/users/getsentry/received_events",
            "type": "Organization",
            "site_admin": false
        },
        "html_url": "https://github.com/getsentry/sentry-go",
        "description": "Official Sentry SDK for Go",
        "fork": false,
        "url": "https://api.github.com/repos/getsentry/sentry-go",
        "forks_url": "https://api.github.com/repos/getsentry/sentry-go/forks",
        "keys_url": "https://api.github.com/repos/getsentry/sentry-go/keys{/key_id}",
        "collaborators_url": "https://api.github.com/repos/getsentry/sentry-go/collaborators{/collaborator}",
        "teams_url": "https://api.github.com/repos/getsentry/sentry-go/teams",
        "hooks_url": "https://api.github.com/repos/getsentry/sentry-go/hooks",
        "issue_events_url": "https://api.github.com/repos/getsentry/sentry-go/issues/events{/number}",
        "events_url": "https://api.github.com/repos/getsentry/sentry-go/events",
        "assignees_url": "https://api.github.com/repos/getsentry/sentry-go/assignees{/user}",
        "branches_url": "https://api.github.com/repos/getsentry/sentry-go/branches{/branch}",
        "tags_url": "https://api.github.com/repos/getsentry/sentry-go/tags",
        "blobs_url": "https://api.github.com/repos/getsentry/sentry-go/git/blobs{/sha}",
        "git_tags_url": "https://api.github.com/repos/getsentry/sentry-go/git/tags{/sha}",
        "git_refs_url": "https://api.github.com/repos/getsentry/sentry-go/git/refs{/sha}",
        "trees_url": "https://api.github.com/repos/getsentry/sentry-go/git/trees{/sha}",
        "statuses_url": "https://api.github.com/repos/getsentry/sentry-go/statuses/{sha}",
        "languages_url": "https://api.github.com/repos/getsentry/sentry-go/languages",
        "stargazers_url": "https://api.github.com/repos/getsentry/sentry-go/stargazers",
        "contributors_url": "https://api.github.com/repos/getsentry/sentry-go/contributors",
        "subscribers_url": "https://api.github.com/repos/getsentry/sentry-go/subscribers",
        "subscription_url": "https://api.github.com/repos/getsentry/sentry-go/subscription",
        "commits_url": "https://api.github.com/repos/getsentry/sentry-go/commits{/sha}",
        "git_commits_url": "https://api.github.com/repos/getsentry/sentry-go/git/commits{/sha}",
        "comments_url": "https://api.github.com/repos/getsentry/sentry-go/comments{/number}",
        "issue_comment_url": "https://api.github.com/repos/getsentry/sentry-go/issues/comments{/number}",
        "contents_url": "https://api.github.com/repos/getsentry/sentry-go/contents/{+path}",
        "compare_url": "https://api.github.com/repos/getsentry/sentry-go/compare/{base}...{head}",
        "merges_url": "https://api.github.com/repos/getsentry/sentry-go/merges",
        "archive_url": "https://api.github.com/repos/getsentry/sentry-go/{archive_format}{/ref}",
        "downloads_url": "https://api.github.com/repos/getsentry/sentry-go/downloads",
        "issues_url": "https://api.github.com/repos/getsentry/sentry-go/issues{/number}",
        "pulls_url": "https://api.github.com/repos/getsentry/sentry-go/pulls{/number}",
        "milestones_url": "https://api.github.com/repos/getsentry/sentry-go/milestones{/number}",
        "notifications_url": "https://api.github.com/repos/getsentry/sentry-go/notifications{?since,all,participating}",
        "labels_url": "https://api.github.com/repos/getsentry/sentry-go/labels{/name}",
        "releases_url": "https://api.github.com/repos/getsentry/sentry-go/releases{/id}",
        "deployments_url": "https://api.github.com/repos/getsentry/sentry-go/deployments",
        "created_at": "2019-03-08T11:02:24Z",
        "updated_at": "2020-02-03T19:59:12Z",
        "pushed_at": "2020-02-03T19:59:59Z",
        "git_url": "git://github.com/getsentry/sentry-go.git",
        "ssh_url": "[email protected]:getsentry/sentry-go.git",
        "clone_url": "https://github.com/getsentry/sentry-go.git",
        "svn_url": "https://github.com/getsentry/sentry-go",
        "homepage": "",
        "size": 353,
        "stargazers_count": 199,
        "watchers_count": 199,
        "language": "Go",
        "has_issues": true,
        "has_projects": true,
        "has_downloads": true,
        "has_wiki": true,
        "has_pages": false,
        "forks_count": 33,
        "mirror_url": null,
        "archived": false,
        "disabled": false,
        "open_issues_count": 37,
        "license": {
            "key": "bsd-2-clause",
            "name": "BSD 2-Clause \"Simplified\" License",
            "spdx_id": "BSD-2-Clause",
            "url": "https://api.github.com/licenses/bsd-2-clause",
            "node_id": "MDc6TGljZW5zZTQ="
        },
        "forks": 33,
        "open_issues": 37,
        "watchers": 199,
        "default_branch": "master",
        "permissions": {
            "admin": true,
            "push": true,
            "pull": true
        },
        "temp_clone_token": "",
        "allow_squash_merge": true,
        "allow_merge_commit": true,
        "allow_rebase_merge": true,
        "delete_branch_on_merge": false,
        "organization": {
            "login": "getsentry",
            "id": 1396951,
            "node_id": "MDEyOk9yZ2FuaXphdGlvbjEzOTY5NTE=",
            "avatar_url": "https://avatars0.githubusercontent.com/u/1396951?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/getsentry",
            "html_url": "https://github.com/getsentry",
            "followers_url": "https://api.github.com/users/getsentry/followers",
            "following_url": "https://api.github.com/users/getsentry/following{/other_user}",
            "gists_url": "https://api.github.com/users/getsentry/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/getsentry/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/getsentry/subscriptions",
            "organizations_url": "https://api.github.com/users/getsentry/orgs",
            "repos_url": "https://api.github.com/users/getsentry/repos",
            "events_url": "https://api.github.com/users/getsentry/events{/privacy}",
            "received_events_url": "https://api.github.com/users/getsentry/received_events",
            "type": "Organization",
            "site_admin": false
        },
        "network_count": 33,
        "subscribers_count": 7
    }
}"
… debug Fetching combined revision status...
… debug GET /repos/getsentry/sentry-go/commits/70ee6a791978e9e4b96112f30fd2cad7132ecd84/status - 200 in 262ms
… debug Revision combined status received: "{
    "state": "pending",
    "statuses": [],
    "sha": "70ee6a791978e9e4b96112f30fd2cad7132ecd84",
    "total_count": 0,
    "repository": {
        "id": 174522026,
        "node_id": "MDEwOlJlcG9zaXRvcnkxNzQ1MjIwMjY=",
        "name": "sentry-go",
        "full_name": "getsentry/sentry-go",
        "private": false,
        "owner": {
            "login": "getsentry",
            "id": 1396951,
            "node_id": "MDEyOk9yZ2FuaXphdGlvbjEzOTY5NTE=",
            "avatar_url": "https://avatars0.githubusercontent.com/u/1396951?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/getsentry",
            "html_url": "https://github.com/getsentry",
            "followers_url": "https://api.github.com/users/getsentry/followers",
            "following_url": "https://api.github.com/users/getsentry/following{/other_user}",
            "gists_url": "https://api.github.com/users/getsentry/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/getsentry/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/getsentry/subscriptions",
            "organizations_url": "https://api.github.com/users/getsentry/orgs",
            "repos_url": "https://api.github.com/users/getsentry/repos",
            "events_url": "https://api.github.com/users/getsentry/events{/privacy}",
            "received_events_url": "https://api.github.com/users/getsentry/received_events",
            "type": "Organization",
            "site_admin": false
        },
        "html_url": "https://github.com/getsentry/sentry-go",
        "description": "Official Sentry SDK for Go",
        "fork": false,
        "url": "https://api.github.com/repos/getsentry/sentry-go",
        "forks_url": "https://api.github.com/repos/getsentry/sentry-go/forks",
        "keys_url": "https://api.github.com/repos/getsentry/sentry-go/keys{/key_id}",
        "collaborators_url": "https://api.github.com/repos/getsentry/sentry-go/collaborators{/collaborator}",
        "teams_url": "https://api.github.com/repos/getsentry/sentry-go/teams",
        "hooks_url": "https://api.github.com/repos/getsentry/sentry-go/hooks",
        "issue_events_url": "https://api.github.com/repos/getsentry/sentry-go/issues/events{/number}",
        "events_url": "https://api.github.com/repos/getsentry/sentry-go/events",
        "assignees_url": "https://api.github.com/repos/getsentry/sentry-go/assignees{/user}",
        "branches_url": "https://api.github.com/repos/getsentry/sentry-go/branches{/branch}",
        "tags_url": "https://api.github.com/repos/getsentry/sentry-go/tags",
        "blobs_url": "https://api.github.com/repos/getsentry/sentry-go/git/blobs{/sha}",
        "git_tags_url": "https://api.github.com/repos/getsentry/sentry-go/git/tags{/sha}",
        "git_refs_url": "https://api.github.com/repos/getsentry/sentry-go/git/refs{/sha}",
        "trees_url": "https://api.github.com/repos/getsentry/sentry-go/git/trees{/sha}",
        "statuses_url": "https://api.github.com/repos/getsentry/sentry-go/statuses/{sha}",
        "languages_url": "https://api.github.com/repos/getsentry/sentry-go/languages",
        "stargazers_url": "https://api.github.com/repos/getsentry/sentry-go/stargazers",
        "contributors_url": "https://api.github.com/repos/getsentry/sentry-go/contributors",
        "subscribers_url": "https://api.github.com/repos/getsentry/sentry-go/subscribers",
        "subscription_url": "https://api.github.com/repos/getsentry/sentry-go/subscription",
        "commits_url": "https://api.github.com/repos/getsentry/sentry-go/commits{/sha}",
        "git_commits_url": "https://api.github.com/repos/getsentry/sentry-go/git/commits{/sha}",
        "comments_url": "https://api.github.com/repos/getsentry/sentry-go/comments{/number}",
        "issue_comment_url": "https://api.github.com/repos/getsentry/sentry-go/issues/comments{/number}",
        "contents_url": "https://api.github.com/repos/getsentry/sentry-go/contents/{+path}",
        "compare_url": "https://api.github.com/repos/getsentry/sentry-go/compare/{base}...{head}",
        "merges_url": "https://api.github.com/repos/getsentry/sentry-go/merges",
        "archive_url": "https://api.github.com/repos/getsentry/sentry-go/{archive_format}{/ref}",
        "downloads_url": "https://api.github.com/repos/getsentry/sentry-go/downloads",
        "issues_url": "https://api.github.com/repos/getsentry/sentry-go/issues{/number}",
        "pulls_url": "https://api.github.com/repos/getsentry/sentry-go/pulls{/number}",
        "milestones_url": "https://api.github.com/repos/getsentry/sentry-go/milestones{/number}",
        "notifications_url": "https://api.github.com/repos/getsentry/sentry-go/notifications{?since,all,participating}",
        "labels_url": "https://api.github.com/repos/getsentry/sentry-go/labels{/name}",
        "releases_url": "https://api.github.com/repos/getsentry/sentry-go/releases{/id}",
        "deployments_url": "https://api.github.com/repos/getsentry/sentry-go/deployments"
    },
    "commit_url": "https://api.github.com/repos/getsentry/sentry-go/commits/70ee6a791978e9e4b96112f30fd2cad7132ecd84",
    "url": "https://api.github.com/repos/getsentry/sentry-go/commits/70ee6a791978e9e4b96112f30fd2cad7132ecd84/status"
}"
… debug Fetching Checks API status...
… debug GET /repos/getsentry/sentry-go/commits/70ee6a791978e9e4b96112f30fd2cad7132ecd84/check-runs - 200 in 304ms
… debug Revision checks received: "{
    "total_count": 1,
    "check_runs": [
        {
            "id": 423939391,
            "node_id": "MDg6Q2hlY2tSdW40MjM5MzkzOTE=",
            "head_sha": "70ee6a791978e9e4b96112f30fd2cad7132ecd84",
            "external_id": "147270711",
            "url": "https://api.github.com/repos/getsentry/sentry-go/check-runs/423939391",
            "html_url": "https://github.com/getsentry/sentry-go/runs/423939391",
            "details_url": "https://travis-ci.com/getsentry/sentry-go/builds/147270711",
            "status": "completed",
            "conclusion": "success",
            "started_at": "2020-02-03T20:00:20Z",
            "completed_at": "2020-02-03T20:03:03Z",
            "output": {
                "title": "Build Passed",
                "summary": "<a href='https://travis-ci.com/getsentry/sentry-go/builds/147270711'><img src='https://travis-ci.com/images/stroke-icons/icon-passed.png' height='11'> The build</a> **passed**.",
                "text": "This is a normal build for the release\\/0.5.0 branch. You should be able to reproduce it by checking out the branch locally.\n\n## Jobs and Stages\nThis build has **nine jobs**, running in parallel.\n\n<table>\n<thead>\n  <tr>\n    <th>Job</th>\n    <th>Go</th>\n    <th>ENV</th>\n    <th>State</th>\n    <th>Notes</th>\n  </tr>\n</thead>\n<tbody>\n  <tr>\n    <td><a href='https://travis-ci.com/getsentry/sentry-go/jobs/283142896'><img src='https://travis-ci.com/images/stroke-icons/icon-passed.png' height='11'> 400.1</a></td>\n    <td>1.11.x</td>\n    <td>GO111MODULE=on GOFLAGS=-mod=readonly</td>\n    <td>passed</td>\n    <td></td>\n  </tr>\n  <tr>\n    <td><a href='https://travis-ci.com/getsentry/sentry-go/jobs/283142897'><img src='https://travis-ci.com/images/stroke-icons/icon-passed.png' height='11'> 400.2</a></td>\n    <td>1.11.x</td>\n    <td>GO111MODULE=off</td>\n    <td>passed</td>\n    <td></td>\n  </tr>\n  <tr>\n    <td><a href='https://travis-ci.com/getsentry/sentry-go/jobs/283142898'><img src='https://travis-ci.com/images/stroke-icons/icon-passed.png' height='11'> 400.3</a></td>\n    <td>1.12.x</td>\n    <td>GO111MODULE=on GOFLAGS=-mod=readonly</td>\n    <td>passed</td>\n    <td></td>\n  </tr>\n  <tr>\n    <td><a href='https://travis-ci.com/getsentry/sentry-go/jobs/283142899'><img src='https://travis-ci.com/images/stroke-icons/icon-passed.png' height='11'> 400.4</a></td>\n    <td>1.12.x</td>\n    <td>GO111MODULE=off</td>\n    <td>passed</td>\n    <td></td>\n  </tr>\n  <tr>\n    <td><a href='https://travis-ci.com/getsentry/sentry-go/jobs/283142900'><img src='https://travis-ci.com/images/stroke-icons/icon-passed.png' height='11'> 400.5</a></td>\n    <td>1.13.x</td>\n    <td>GO111MODULE=on GOFLAGS=-mod=readonly</td>\n    <td>passed</td>\n    <td></td>\n  </tr>\n  <tr>\n    <td><a href='https://travis-ci.com/getsentry/sentry-go/jobs/283142901'><img src='https://travis-ci.com/images/stroke-icons/icon-passed.png' height='11'> 400.6</a></td>\n    <td>1.13.x</td>\n    <td>GO111MODULE=off</td>\n    <td>passed</td>\n    <td></td>\n  </tr>\n  <tr>\n    <td><a href='https://travis-ci.com/getsentry/sentry-go/jobs/283142902'><img src='https://travis-ci.com/images/stroke-icons/icon-passed.png' height='11'> 400.7 Module support outside of GOPATH</a></td>\n    <td>1.13.x</td>\n    <td>GO111MODULE=on GOFLAGS=-mod=readonly</td>\n    <td>passed</td>\n    <td></td>\n  </tr>\n  <tr>\n    <td><a href='https://travis-ci.com/getsentry/sentry-go/jobs/283142903'><img src='https://travis-ci.com/images/stroke-icons/icon-passed.png' height='11'> 400.8</a></td>\n    <td>master</td>\n    <td>GO111MODULE=on GOFLAGS=-mod=readonly</td>\n    <td>passed</td>\n    <td>This job is <a href='https://docs.travis-ci.com/user/customizing-the-build#Rows-that-are-Allowed-to-Fail'>allowed to fail</a>.</td>\n  </tr>\n  <tr>\n    <td><a href='https://travis-ci.com/getsentry/sentry-go/jobs/283142904'><img src='https://travis-ci.com/images/stroke-icons/icon-passed.png' height='11'> 400.9</a></td>\n    <td>master</td>\n    <td>GO111MODULE=off</td>\n    <td>passed</td>\n    <td>This job is <a href='https://docs.travis-ci.com/user/customizing-the-build#Rows-that-are-Allowed-to-Fail'>allowed to fail</a>.</td>\n  </tr>\n</tbody>\n</table>\n\n## Build Configuration\n\nBuild Option     | Setting\n-----------------|--------------\nLanguage         | Go\nOperating System | Linux (Xenial)\nGo Versions      | 1.11.x, 1.12.x, 1.13.x, master\n\n<details>\n<summary>Build Configuration</summary>\n<pre lang='yaml'>\n{\n  \"go\": [\n    \"1.11.x\",\n    \"1.12.x\",\n    \"1.13.x\",\n    \"master\"\n  ],\n  \"os\": \"linux\",\n  \"env\": [\n    \"GO111MODULE=on GOFLAGS=-mod=readonly\",\n    \"GO111MODULE=off\"\n  ],\n  \"dist\": \"xenial\",\n  \"jobs\": {\n    \"include\": [\n      {\n        \"go\": \"1.13.x\",\n        \"name\": \"Module support outside of GOPATH\",\n        \"script\": \"go test && go test -race\",\n        \"before_script\": \"mv $GOPATH/src/github.com/getsentry/sentry-go ~/sentry-go && cd ~/sentry-go && export GOPATH= && go env GOPATH\"\n      }\n    ],\n    \"fast_finish\": true,\n    \"allow_failures\": [\n      {\n        \"go\": \"master\"\n      }\n    ]\n  },\n  \"group\": \"stable\",\n  \"script\": [\n    \"golangci-lint run --new-from-rev=$(git merge-base origin/master HEAD)\",\n    \"go build\",\n    \"go test\",\n    \"go test -race\"\n  ],\n  \".result\": \"configured\",\n  \"language\": \"go\",\n  \"notifications\": {\n    \"webhooks\": {\n      \"urls\": [\n        \"https://zeus.ci/hooks/befe9810-9285-11e9-b01a-0a580a281808/public/provider/travis/webhook\"\n      ],\n      \"on_error\": \"always\",\n      \"on_start\": \"always\",\n      \"on_cancel\": \"always\",\n      \"on_failure\": \"always\",\n      \"on_success\": \"always\"\n    }\n  },\n  \"before_install\": [\n    \"curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/v1.19.1/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.19.1\",\n    \"git fetch origin master:remotes/origin/master\"\n  ]\n}\n</pre>\n</details>",
                "annotations_count": 0,
                "annotations_url": "https://api.github.com/repos/getsentry/sentry-go/check-runs/423939391/annotations"
            },
            "name": "Travis CI - Branch",
            "check_suite": {
                "id": 435789300
            },
            "app": {
                "id": 67,
                "slug": "travis-ci",
                "node_id": "MDM6QXBwNjc=",
                "owner": {
                    "login": "travis-ci",
                    "id": 639823,
                    "node_id": "MDEyOk9yZ2FuaXphdGlvbjYzOTgyMw==",
                    "avatar_url": "https://avatars2.githubusercontent.com/u/639823?v=4",
                    "gravatar_id": "",
                    "url": "https://api.github.com/users/travis-ci",
                    "html_url": "https://github.com/travis-ci",
                    "followers_url": "https://api.github.com/users/travis-ci/followers",
                    "following_url": "https://api.github.com/users/travis-ci/following{/other_user}",
                    "gists_url": "https://api.github.com/users/travis-ci/gists{/gist_id}",
                    "starred_url": "https://api.github.com/users/travis-ci/starred{/owner}{/repo}",
                    "subscriptions_url": "https://api.github.com/users/travis-ci/subscriptions",
                    "organizations_url": "https://api.github.com/users/travis-ci/orgs",
                    "repos_url": "https://api.github.com/users/travis-ci/repos",
                    "events_url": "https://api.github.com/users/travis-ci/events{/privacy}",
                    "received_events_url": "https://api.github.com/users/travis-ci/received_events",
                    "type": "Organization",
                    "site_admin": false
                },
                "name": "Travis CI",
                "description": "Test and deploy with confidence. Trusted by over 800,000 users, Travis CI is the leading hosted continuous integration system.\r\n\r\nSupporting over 30 different languages, including Ruby, Mac/iOS, and Docker, Travis CI is built for everyone.\r\n\r\nFree for open source, and with a 100 build trial for private projects, getting setup takes just 2 minutes.",
                "external_url": "https://travis-ci.com",
                "html_url": "https://github.com/apps/travis-ci",
                "created_at": "2016-06-21T16:22:21Z",
                "updated_at": "2018-09-14T20:36:16Z",
                "permissions": {
                    "checks": "write",
                    "contents": "read",
                    "deployments": "write",
                    "members": "read",
                    "metadata": "read",
                    "pull_requests": "read",
                    "repository_hooks": "write",
                    "statuses": "write"
                },
                "events": [
                    "check_run",
                    "check_suite",
                    "create",
                    "delete",
                    "member",
                    "pull_request",
                    "push",
                    "repository"
                ]
            },
            "pull_requests": []
        }
    ]
}"
ℹ info No config provided for Github status provider, calculating the combined status...
ℹ info pending
ℹ info Revision 70ee6a791978e9e4b96112f30fd2cad7132ecd84 has been found.
[==  ] [2/3/2020, 9:26:56 PM] CI builds are still in progress, sleeping for 30 seconds...^C

GH Release target depreacted

ℹ info ======================================
ℹ info === Publishing to target: "github" ===
ℹ info ======================================
ℹ info [github] › Target "github": publishing version "1.0.0-beta4"...
ℹ info [github] › Git tag: "1.0.0-beta4"
`error.code` is deprecated, use `error.status`.
ℹ info [github] › Creating a new *preview* release for tag "1.0.0-beta4"

Pull after merging the release branch

After successfully publishing and merging the release branch, you still have to manually call git pull to get your local branch up to speed. Craft could do that automatically.

The only place where this probably shouldn't happen, is the GitHub Action.

Refuse unknown flags

It would be cool if craft failed when passed unknown flags.

At the moment, it seems that unknown flags are ignored, which can hide typos (or flags that changed across craft versions?!).

Example:

$ craft publish X.X.X --skip-status-check

Ignores the flag and tries to publish a release with status check. The correct flag would have been --no-status-check.

GH Artifact provider: Unable to retrieve artifact list for revision

I'm trying to release Symbol Collector 1.2.2 and it's failing while processing the artifact.

No change to how the artifact is build change since the previous version 1.2.1.

It seems zlib related (log below) but I downloaded the artifact locally and could extract files without any problems.

The issue affects version 0.16.1. I upgraded to the latest 0.17.2 and received the same error.

I've received two different errors that alternate (somewhat randomly) with each other if I retry the command:

ℹ info [artifact-provider/github] › Fetching Github artifacts for getsentry/symbol-collector, revision 0dd644d0d67336217dada5da81c9e1b5fa0aabed
ℹ info [artifact-provider/github] › Requesting archive URL from Github...
ℹ info [artifact-provider/github] › Downloading ZIP from Github artifacts...
ℹ info [artifact-provider/github] › Finished downloading.
ℹ info [artifact-provider/github] › Extracting "/var/folders/3r/9m5hqv695t97rd0qllgcbyjc0000gn/T/craft-601315Z0kfxUZaeb3" to "/var/folders/3r/9m5hqv695t97rd0qllgcbyjc0000gn/T/craft-7b1FS2"...
✖ error [artifact-provider] › Unable to retrieve artifact list for revision 0dd644d0d67336217dada5da81c9e1b5fa0aabed!
✖ error Error: unexpected end of file
  at Zlib.zlibOnError [as onerror] (zlib.js:182:17)

And

ℹ info [artifact-provider/github] › Fetching Github artifacts for getsentry/symbol-collector, revision 0dd644d0d67336217dada5da81c9e1b5fa0aabed
ℹ info [artifact-provider/github] › Requesting archive URL from Github...
ℹ info [artifact-provider/github] › Downloading ZIP from Github artifacts...
ℹ info [artifact-provider/github] › Finished downloading.
ℹ info [artifact-provider/github] › Extracting "/var/folders/3r/9m5hqv695t97rd0qllgcbyjc0000gn/T/craft-60601P38ruEZ8pQlz" to "/var/folders/3r/9m5hqv695t97rd0qllgcbyjc0000gn/T/craft-9Xn1HL"...
✖ error [artifact-provider] › Unable to retrieve artifact list for revision 0dd644d0d67336217dada5da81c9e1b5fa0aabed!
✖ error Error: invalid signature: 0x6f63227b
  at /Users/bruno/.volta/tools/image/packages/@sentry/craft/0.16.1/node_modules/unzipper/lib/parse.js:59:26
  at tryCatcher (/Users/bruno/.volta/tools/image/packages/@sentry/craft/0.16.1/node_modules/bluebird/js/release/util.js:16:23)
  at Promise._settlePromiseFromHandler (/Users/bruno/.volta/tools/image/packages/@sentry/craft/0.16.1/node_modules/bluebird/js/release/promise.js:510:31)
  at Promise._settlePromise (/Users/bruno/.volta/tools/image/packages/@sentry/craft/0.16.1/node_modules/bluebird/js/release/promise.js:567:18)
  at Promise._settlePromise0 (/Users/bruno/.volta/tools/image/packages/@sentry/craft/0.16.1/node_modules/bluebird/js/release/promise.js:612:10)
  at Promise._settlePromises (/Users/bruno/.volta/tools/image/packages/@sentry/craft/0.16.1/node_modules/bluebird/js/release/promise.js:691:18)
  at Async._drainQueue (/Users/bruno/.volta/tools/image/packages/@sentry/craft/0.16.1/node_modules/bluebird/js/release/async.js:133:16)
  at Async._drainQueues (/Users/bruno/.volta/tools/image/packages/@sentry/craft/0.16.1/node_modules/bluebird/js/release/async.js:143:10)
  at Immediate.Async.drainQueues (/Users/bruno/.volta/tools/image/packages/@sentry/craft/0.16.1/node_modules/bluebird/js/release/async.js:17:14)
  at processImmediate (internal/timers.js:461:21)

Crates.io Releases seem to suffer from race conditions

Disclaimer: I'm not 100% sure what's the issue here. When releasing symbolic, I received the following error for the last couple of times:

ℹ info [crates] › Cloning getsentry/symbolic into /var/folders/7p/zvqpr1r53zv_b6tzlz7tw2vw0000gn/T/craft-crates-mDhCL3
ℹ info [crates] › Checking out submodules
ℹ info [crates] › Loading workspace information from /var/folders/7p/zvqpr1r53zv_b6tzlz7tw2vw0000gn/T/craft-crates-mDhCL3/Cargo.toml
✖ error Error: Process "cargo" errored with code 101
  STDOUT: cargo:
  STDERR:cargo:     Updating crates.io index
  cargo:    Packaging symbolic v7.2.0 (/var/folders/7p/zvqpr1r53zv_b6tzlz7tw2vw0000gn/T/craft-crates-mDhCL3)
  cargo: error: failed to prepare local package for uploading
  cargo:
  cargo: Caused by:
  cargo:   failed to select a version for the requirement `symbolic-demangle = "^7.2.0"`
  cargo:   candidate versions found which didn't match: 7.1.1, 6.1.4, 6.1.3, ...
  cargo:   location searched: crates.io index
  cargo: required by package `symbolic v7.2.0 (/var/folders/7p/zvqpr1r53zv_b6tzlz7tw2vw0000gn/T/craft-crates-mDhCL3)`
  cargo:

The error message indicates that a workspace dependency, symbolic-demangle, hadn't been published at the time of publishing symbolic. When checking crates.io, however, that crate is there. I think this might be some lag in caches.

Support monorepos with independently versioned members

I would like to have multiple packages/crates in a monorepo/workspace, but version and release them independently.

Ideally, craft would know about those packages, to bump their own versions individually (#76) and publish them from their respective directory.

Considering git tags, one inspiration might be rollup/plugins, which uses <pkgname>-v<version> as the tag.

Release with GHA artifact missing/wrong file

Trying to deploy sentry-unity but the list of available artifacts is missing the package.

The build in question is: https://github.com/getsentry/sentry-unity/actions/runs/843357161 which contains an artifact named after the commit sha b7e538648f85e65a44a7f6a4c79432ca12ce2576.

Craft finds the build but shows only results.xml.
I downloaded the artifact from GHA and found it contains: package-release.zip, the expected file.

Environment

craft --version
0.22.0

Configuration: https://github.com/getsentry/sentry-unity/blob/b7e538648f85e65a44a7f6a4c79432ca12ce2576/.craft.yml

Steps to Reproduce

➜  sentry-unity git:(main) ✗ craft publish 0.0.14
ℹ Publishing version: "0.0.14"                                                                                                                                                                                              09:42:39
ℹ Revision b7e538648f85e65a44a7f6a4c79432ca12ce2576 has been built successfully.                                                                                                                                            09:42:40
ℹ Fetching Github artifacts for getsentry/sentry-unity, revision b7e538648f85e65a44a7f6a4c79432ca12ce2576                                                                                        [artifact-provider/github] 09:42:40
ℹ Finished downloading.                                                                                                                                                                          [artifact-provider/github] 09:42:41
ℹ                                                                                                                                                                                                                           09:42:41
ℹ Available artifacts:                                                                                                                                                                                                      09:42:41
┌─────────────┬─────────┬─────────┬─────────────┐
│ File Name   │ Size    │ Updated │ ContentType │
├─────────────┼─────────┼─────────┼─────────────┤
│ results.xml │ 18.3 kB │         │             │
└─────────────┴─────────┴─────────┴─────────────┘

ℹ Looking for publish state file for 0.0.14...                                                                                                                                                                              09:42:41
ℹ Publishing to targets:                                                                                                                                                                                                    09:42:41
ℹ   - upm                                                                                                                                                                                                                   09:42:41
  - github
  - registry

Bump versions directly for known package managers

It would be nice if you could avoid having to write a scripts/bump-version.sh script for projects that have a Cargo.toml or a package.json.

Ideally, this should be configurable, in case you actually have a rust project, but with a package.json which might only be used for development.

Implement GCS artifact provider

TODOs:

  • uploadArtifact method in BaseArtifactProvider
  • Figure out the file structure in the bucket
  • "artifacts upload" command
  • GcsArtifactProvider implementation
  • Testing it :)

Make npm & registry target more robust

When publishing we should make the npm and registry target not fail if the version already exists.
It makes the publishing process annoying if it stops working somewhere middle in the process.

npm

npm: npm ERR! 403 403 Forbidden - PUT https://registry.npmjs.org/@sentry%2fangular - You cannot publish over the previously published versions: 6.0.0.

registry

ℹ info [registry] › Adding the version file to the registry for canonical name "npm:@sentry/browser"...
✖ error Error: Version file for "6.0.0" already exists. Aborting.

Allow publishing patch releases from a release branch

Right now craft assumes that all your development happens on master.
However sometimes you want to do feature development on master but still keep a previous release branch around to do point releases that don’t have breaking changes.

Right now I have would suggest releases/0.$N.x, or releases/$N.x as branch names.

Maybe related to #34

Protect against accidental CTRL^C

It would be great if craft would continue after pressing CTRL^C once, similar to node:

> ^C
(To exit, press ^C again or type .exit)
> ^C

Not overriding symlink at release-registry when publishing

When the release-registry already contains a symlink for the specified version craft fails to publish the release. I would expect that it overrides the symlink with the JSON for the specified release.

Steps to reproduce with sentry-cocoa:

  1. craft prepare 5.1.10
  2. Create a symlink for 5.1.10.json in release-registry for cocoa.
  3. craft publish 5.1.10 --target registry
  4. Craft fails with Error: Version file for "5.1.10" already exists. Aborting.

Screenshot 2020-07-22 at 13 41 12

This is related to getsentry/sentry-release-registry#27

Support Public API files for .NET projects

.NET has a Roslyn Analyzer called PublicApiAnalyzer.
This analyzer was added to the .NET project via this pr.

It works by raising compiler error if a public API is added/removed without adding it to controlling files.
There are two files:

PublicAPI.Shipped.txt and PublicAPI.Unshipped.txt
Which means that there's a new step when publishing NuGet packages. We must move the lines from the unshipped file to the shipped file. This should happen only when deploying non preview packages.

Migrate from `tslint` to `eslint`

... as the former is now deprecated in favor of the latter. For more information, see the following:

Blog post explaining the why and when of the deprecation:
https://medium.com/palantir/tslint-in-2019-1a144c2317a9

Tracking issue for deprecation process:
palantir/tslint#4534

Tool for converting config from one to the other:
https://github.com/typescript-eslint/tslint-to-eslint-config

FAQ from maintainers re: migration:
https://github.com/typescript-eslint/tslint-to-eslint-config/blob/master/docs/FAQs.md

Note as of 4/28/20: The converter tool seems to be under active development and just shipped a beta of 1.0.0 yesterday, so perhaps we should wait a few weeks for a stable version before working on this.

Retry uploads to gcs and github targets

Uploads to GitHub release artifacts and gcs are very unreliable for large files. Suggestion:

  • Wrap every file upload in a generous retry loop
  • If a release already exists, do not throw an exception but update files (this could be just implemented by deleting all conflicting files from the release and uploading them again).

Note that a failed upload leaves a broken file in the release, so even just a retry loop would have to delete existing files.

This issue is easiest to reproduce with semaphore.

Registry target, create files if not exist yet

When introducing a new package, craft should try to create the required folder/file structure so this doesn't have to be done manually.

[12:23:18 PM] ======================================
[12:23:18 PM] === Publishing to target: registry ===
[12:23:18 PM] ======================================
[12:23:18 PM] [[REGISTRY]] Cloning "https://github.com/getsentry/sentry-release-registry/" to "/tmp/craft-release-registry-DFIZaD"...
[12:23:19 PM] [[REGISTRY]] Adding the version file to the registry for canonical name "npm:@sentry/wasm"...
[12:23:19 PM] Error: ENOENT: no such file or directory, open '/tmp/craft-release-registry-DFIZaD/packages/npm/@sentry/wasm/latest.json'
at Object.openSync (fs.js:462:3)
at Object.readFileSync (fs.js:364:35)
at RegistryTarget.addVersionToRegistry (/craft/dist/targets/registry.js:335:47)
at RegistryTarget.pushVersionToRegistry (/craft/dist/targets/registry.js:361:20)
at runMicrotasks (<anonymous>)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at async Object.withTempDir (/craft/dist/utils/files.js:76:16)
at async RegistryTarget.publish (/craft/dist/targets/registry.js:398:9)
at async /craft/dist/commands/publish.js:135:13
at async Object.withTempDir (/craft/dist/utils/files.js:76:16)
at async publishToTargets (/craft/dist/commands/publish.js:101:5)
at async publishMain (/craft/dist/commands/publish.js:422:9)
at async Object.handler (/craft/dist/commands/publish.js:449:16)

Preparing release with localized git fails

I have my system language set to de-de, which is also propagated to the shell (which I hate BTW).
Either way, git is actually localized, and craft apparently can’t deal with that.

running git version 2.26.0

> LANG=de_DE CRAFT_LOG_LEVEL=debug craft prepare 0.15.0
ℹ info Preparing to release the version: 0.15.0
✖ error Error: fatal: mehrdeutiges Argument 'release/0.15.0': unbekannter Commit oder Pfad existiert nicht
  im Arbeitsverzeichnis
  Benutzen Sie '--', um Pfade und Commits zu trennen, ähnlich wie:
  'git <Befehl> [<Commit>...] -- [<Datei>...]'

  at toError (/Users/swatinem/.volta/tools/image/packages/@sentry/craft/0.9.2/node_modules/simple-git/promise.js:90:14)
  at /Users/swatinem/.volta/tools/image/packages/@sentry/craft/0.9.2/node_modules/simple-git/promise.js:61:36
  at Git.<anonymous> (/Users/swatinem/.volta/tools/image/packages/@sentry/craft/0.9.2/node_modules/simple-git/src/git.js:1090:18)
  at Function.Git.fail (/Users/swatinem/.volta/tools/image/packages/@sentry/craft/0.9.2/node_modules/simple-git/src/git.js:1475:18)
  at fail (/Users/swatinem/.volta/tools/image/packages/@sentry/craft/0.9.2/node_modules/simple-git/src/git.js:1433:20)
  at /Users/swatinem/.volta/tools/image/packages/@sentry/craft/0.9.2/node_modules/simple-git/src/git.js:1442:16
  at processTicksAndRejections (internal/process/task_queues.js:97:5)

However, when I force no localization, it works just fine:

> LANG=C CRAFT_LOG_LEVEL=debug craft prepare 0.15.0
ℹ info Preparing to release the version: 0.15.0
ℹ info Created a new release branch: "release/0.15.0"
ℹ info Running the pre-release command...
… debug Spawning process:
  /bin/bash "scripts/bump-version.sh" "" "0.15.0"
… debug /bin/bash: Current version:
… debug /bin/bash: Bumping version: 0.15.0
… debug /bin/bash:
… debug /bin/bash:
ℹ info Committing the release changes...
… debug Commit message: "release: 0.15.0"
ℹ info Pushing the release branch "release/0.15.0"...

`craft` target for Unity

We're setting up craft with the new Unity SDK.

CI is already configured in a way that we use the GitHub artifacts provider and craft prepare x.x.x already works as expected. Release registry has a new SDK: upm:sentry-unity and is configured already.

What we're missing now is the target to get craft publish to work.

We've identified two tasks to do that:

  1. The github target currently downloads the artifact, unzip it, and publish all files in that artifact to the github release.
    image
    This isn't the expected behavior for Unity, so ideally we'd just skip attaching anything to the github release altogether.

One alternative is to zip the files before adding as attachment. And having the target (see below) unzip to move to package

  1. The actual 'release' for UPM is to replace all contents of a folder in the repository itself, and push it to the main branch.
    More context about the release process in this issue, and the contributing docs.

Feature Request: Check out master after publish

When I run craft release, the tool creates a branch locally and pushes it to the remote. However, there is no reason to keep this branch locally (other than troubleshooting). So at least during publish, it would be great if craft could detect that the branch is still checked out go back to master.

I'm also thinking if it might make sense to check out master right away after craft release ran.

Store debug logs to disk

I would prefer to run craft without debug logs on the console. Especially when publishing to crates.io, the output is enormously large. When errors occur, it would still be great to have debug logs around - sometimes with even more information than what debug currently logs.

Would it be an option to create a file like craft-debug.log in the cwd and delete it upon successful completion. This way, we can easily attach debug logs to bug reports.

Besides, it might be nice to have @sentry/node in craft and log everything that goes into the error stream, maybe even attach previous logs as breadcrumbs (automatically done with the "console" integration).

Skip to publish crates with publish=false

When a crate is configured like this in Cargo.toml:

[package]
name = "foo"
publish = false

Then craft still invokes cargo publish which errors with the following message:

… debug cargo: error: `symbolic-testutils` cannot be published.
… debug cargo: The registry `crates-io` is not listed in the `publish` value in Cargo.toml.

Instead, craft should skip this package.

add repository parameters to pypi

would it be possible to add additional parameters to the pypi upload?
specifically TWINE_REPOSITORY_URL for uploading to private/internal repositories

can submit PR

Bug: 0.13.3 rejects all targets and no longer publishes

Version 0.13.3 no longer publishes any package with the following message.

CRAFT_LOG=debug craft publish 8.0.0
ℹ info craft 0.13.3
ℹ info "craft" version is compatible with the minimal version from the configuration file.
ℹ info Publishing version: "8.0.0"
ℹ info Using "GithubStatusProvider" for status checks
ℹ info Using "GithubArtifactProvider" for artifacts
ℹ info No config provided for Github status provider, calculating the combined status...
ℹ info Revision 4b8e22baaa35414ad48ddc872bbd2a565a952c86 has been built successfully.
⚠ warn No valid targets detected! Exiting.

I believe the culprit to be in #137

Always print the version and force updates

Craft should always print its version on the top to make debugging easier. This way, developers can easily see if someone is running an outdated version of the package. I'm thinking similar to yarn:

$ yarn info
yarn info v1.9.4

Also, we should check for updates and inform the user. The package update-nagger implements this functionality with nice visuals.

Document `id` field for targets

We have added an optional (but very useful) id field for target configurations and use this with the -t option in #128 and a follow up PR. That said this is not documented properly.

Thanks @jan-auer for reporting.

Make Craft more idempotent and add option to skip "completed" things

For example tag creation could be skipped when the sha would be the same instead of being a halting error.
Resuming a partial release is a more common release than trying to overwrite an existing release.

Ideas:

  1. Make publish steps independent so one failure does not stop others
  2. Persist publish state on disk as it progresses and then pick it up on subsequent runs
  3. Make getsentry/publish parse the issue body which will have the targets listed as checkboxes
  4. getsentry/publish action uses the the persistence file to sync the issue body to Craft

Integrate with GitHub release drafter

https://github.com/marketplace/actions/release-drafter

Possible course of action is to add an option to pull the changelog from the draft release instead of reading it from a file.

One concern with using release drafter for future SDK releases is that the changelog will no longer be distributed as part of source bundles such as the sdist for the Python SDK. We could fix that by making craft write the changelog back into a file. It would have to do that when creating the release branch and writing the version bump commit.

Bug: Changelog auto generates "no changes" when sub-headings are used

In some projects we generate sub-headings in changelog entries. In such a case, craft generates the "No documented changes" message.

Example:

## Unreleased

### Features

- Add support for DWARF in WASM. ([#301](https://github.com/getsentry/symbolicator/pull/301))
- Support symbolication of native Dart stack traces by prioritizing DWARF function names over symbol table entries.

### Tools

- Add `wasm-split`, which splits WASM files into code and debug information. ([#303](https://github.com/getsentry/symbolicator/pull/303))

Cannot use --no-status-check

$ yarn cli publish --no-status-check 123                                                                                                                                  ✘ 1 master ✚
yarn run v1.21.1
$ run-s build
$ yarn run compile-config-schema && tsc -p tsconfig.build.json
$ node ./scripts/config-json-schema-to-ts.js
$ node dist publish --no-status-check 123
ℹ info craft 0.9.0
dist publish NEW-VERSION

🛫 Publish artifacts

Positionals:
  NEW-VERSION  Version to publish                            [string] [required]

Options:
  [...]
  --keep-downloads   Keep all downloaded files        [boolean] [default: false]
  --no-status-check  Do not check for build status in Zeus
                                                      [boolean] [default: false]
  -v, --version      Show version number                               [boolean]
  -h, --help         Show help                                         [boolean]

Unknown arguments: status-check, statusCheck

bug: `-t` flag does not accept the new `targetId[targetName]` format

Initially reported by @jan-auer on Slack:

craft publish 0.3.0 -t gcs -t 'release[docker]' -t 'latest[docker]'
Invalid values:
  Argument: target, Given: "release[docker]", "latest[docker]", Choices: "brew", "cocoapods", "crates", "docker", "gcs", "gem", "gh-pages", "github", "npm", "nuget", "pypi", "registry", "all", "none"

This is a fallout from #128.

Print better messages for generic HTTP errors

For generic HTTP errors, it would be better to print additional information, rather than:

✖ error HttpError
  at response.text.then.message (/Users/jauer/.config/yarn/global/node_modules/@octokit/rest/lib/request/request.js:72:19)
  at process._tickCallback (internal/process/next_tick.js:68:7)

Desirable user information (INFO log level) would be:

  • The operation that was executing
  • Potential reasons, if known

Desirable debug information (DEBUG/trace log level) would be:

  • The request URL
  • Status code, potentially part of the response body if feasible
  • The calling function and ideally its stack trace

Show aborted commands after failed publish

When publishing fails, craft stops to proceed to the remaining targets. It would be great to list a summary of the targets, like:

Publish report:
  ✓ gcs
  ✓ npm
  ✕ brew: HttpError
  ⚠ github
  ⚠ registry

To retry, please run:
 $ craft publish 1.36.3 -t brew -t github -t registry --finish

Right now, we have to open the .craft.yml and check for the remaining targets.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.