Harness Open-Source Development Platform

repository·main·Indexed 12 days ago

https://github.com/harness/drone

An open-source development platform integrating code hosting, automated DevOps pipelines, hosted development environments (Gitspaces), and artifact registries. Includes the gitness CLI for server management, user registration, and database migrations, as well as a REST API with Swagger documentation.

Tokens
20.5K
Snippets
79
Records
101
Agent score
98%

What's inside Harness

  1. Understand the .gitignore template organization

    main

    The .gitignore templates are organized into three main categories based on their scope and usage:

    • Root templates: Contains templates for popular programming languages and technologies. These are intended to be used as the primary starting point for new repositories.
    • Global directory: Contains templates for editors, tools, and operating systems. It is recommended to add these to your global Git configuration or merge them into your project-specific templates.
    • community directory: Contains specialized templates for less mainstream languages, tools, or specific versions of frameworks. These should be added to your project-specific templates when you adopt the relevant tool.
  2. Backfill license headers on existing files

    main

    Use the insert-license-headers.sh script to apply license headers to existing source files. You can target a single file directly or provide a list of files/path prefixes via a text file.

    Single file usage

    Pass the license header template using -l and the target file path using -f.

    Batch usage

    Pass a file containing a list of files or path prefixes using the -s flag.

    # For a single file
    ./insert-license-headers.sh -l license-header.txt -f "$PATH_TO_CODE_FILE"
    
    # For a list of files or path prefixes
    ./insert-license-headers.sh -l license-header.txt -s "$PATH_TO_LIST_FILE"
  3. Guidelines for contributing .gitignore templates

    main

    When proposing new or updated templates, follow these requirements:

    • Documentation: Provide a link to the application/project homepage and canonical documentation explaining which files should be ignored.
    • Rationale: Explain why the change is necessary and why it applies to everyone using that technology.
    • Scope: Ensure changes are made to the correct template (e.g., language-specific rules go in the language template, not the editor template).
    • Atomicity: Modify only one template per pull request.
    • Versioned Templates:
      • The root template should be the current "evergreen" version (no version in filename).
      • Previous versions should be moved to the community/ directory and must include the version in the filename.

    Contribution Workflow:

    1. Fork the project.
    2. Create a branch for your change.
    3. Apply changes.
    4. Submit a pull request to the main branch.
  4. Build and run Harness from source

    main

    Harness supports all operating systems and architectures supported by Go. You can build and run the system locally without Docker.

    1. Build the User Interface

    Navigate to the web directory to build the UI artifacts:

    pushd web
    yarn install
    yarn build
    popd

    2. Build the Harness Binary

    Use the provided Makefile to build the main binary:

    make build

    3. Run the Server

    Start the server at localhost:3000 using the gitness command and a local environment file:

    ./gitness server .local.env
  5. Run Harness locally using Docker

    main

    To run a complete Harness instance locally, use the official Docker image. The image uses volumes to store the database and repositories; it is highly recommended to use a bind mount or named volume to prevent data loss when the container stops.

    Access the interface at http://localhost:3000 once the container is running.

    docker run -d \
      -p 3000:3000 \
      -p 3022:3022 \
      -v /var/run/docker.sock:/var/run/docker.sock \
      -v /tmp/harness:/data \
      --name harness \
      --restart always \
      harness/harness
  6. Configure Redis connection modes

    main

    The server supports two Redis connection modes: standard client mode and Sentinel mode for high availability.

    Standard Mode

    Used when SentinelMode is disabled. It connects to a single Redis endpoint.

    • Endpoint: The address of the Redis server.
    • Password: Optional authentication.
    • Pool Settings: Configurable MaxRetries, MinIdleConnections, and MaxConnections (PoolSize).

    Sentinel Mode

    Used when SentinelMode is enabled. It uses Redis Sentinels to manage failover.

    • SentinelEndpoint: A comma-separated list of Sentinel addresses.
    • SentinelMaster: The name of the Redis master to monitor.
    • Password: Optional authentication.
    • Pool Settings: Configurable MaxRetries, MinIdleConnections, and MaxConnections (PoolSize).
  7. Configure Docker for Harness pipelines

    main

    Harness pipelines execute inside Docker containers. While it automatically negotiates the Docker API version, you may need to manually configure the socket location if you are not using native Linux Docker or Docker Desktop.

    Docker Socket Locations

    RuntimeSocket LocationConfiguration
    Docker Desktop/var/run/docker.sockWorks by default
    Rancher Desktop~/.rd/docker.sockCreate symlink or set GITNESS_DOCKER_HOST
    Colima~/.colima/default/docker.sockCreate symlink or set GITNESS_DOCKER_HOST
    Linux (native)/var/run/docker.sockWorks by default

    Configuration Options

    # For Rancher Desktop
    sudo ln -sf ~/.rd/docker.sock /var/run/docker.sock
    
    # For Colima
    sudo ln -sf ~/.colima/default/docker.sock /var/run/docker.sock

    Option 2: Set environment variables

    Add the following to your .local.env file:

    # For Rancher Desktop
    GITNESS_DOCKER_HOST=unix:///Users/<username>/.rd/docker.sock
    
    # For Colima
    GITNESS_DOCKER_HOST=unix:///Users/<username>/.colima/default/docker.sock

    Pinning Docker API Version

    To pin a specific version for compatibility testing, set the GITNESS_DOCKER_API_VERSION environment variable:

    GITNESS_DOCKER_API_VERSION=1.45
  8. Use DeserializedImageIndex for stable JSON payloads

    main

    The DeserializedImageIndex type is a wrapper around ImageIndex designed to maintain a canonical byte representation of the JSON. This ensures that when you marshal the object back to JSON, you get the exact same bytes used during unmarshaling, which is critical for maintaining stable content digests.

    Methods:

    • UnmarshalJSON(b []byte): Populates the struct and stores the raw bytes in the canonical field.
    • MarshalJSON(): Returns the canonical bytes if they exist; otherwise, it returns an error. This prevents accidental re-marshaling that might change the byte order or formatting.
    • Payload(): Returns the MediaType and the raw canonical byte slice. This is the preferred way to retrieve the content for calculating content identifiers (digests).
    // Retrieve the raw payload for digest calculation
    mediaType, payload, err := deserializedIndex.Payload()
  9. Use the Gitness CLI with Git Hooks

    main

    The Gitness CLI is designed to be compatible with Git hooks. When invoked by Git, the CLI automatically detects the Git hook context and translates the arguments to work with Gitness's internal hook system. This is handled by the GetArguments function, which sanitizes arguments and prepends the hooks parameter if a Git hook is detected.

    // The CLI automatically handles Git hook argument translation via GetArguments()
    // If detected as a Git hook, it prepends the 'hooks' parameter.
    // Example internal transformation logic:
    // gitArgs, fromGit := hook.SanitizeArgsForGit(command, args)
    // if fromGit { return append([]string{hooks.ParamHooks}, gitArgs...) }
  10. Use PostSepArgs for safe handling of user-controlled input

    main

    When passing arguments that may start with a dash (-)—such as file paths or branch names provided by a user—do not use the Args field. Instead, use PostSepArgs.

    Using PostSepArgs ensures that the arguments are appended after the -- separator in the final command string. This prevents Git from misinterpreting a path like -my-file as a command-line flag.

    // Safe way to pass a path that might look like a flag
    cmd := command.New("cat-file", 
        command.WithAction("blob"),
        command.WithPostSepArgs("--", "-user-file"), // Results in: git cat-file blob -- -user-file
    )
  11. Manage CLI sessions with the Session type

    main

    The Session type is used to manage authentication state for the CLI. It handles storing and loading session data (including the URI, expiration timestamp, and access token) to and from a local file.

    Key behaviors:

    • Persistence: Sessions are stored as JSON files with 0600 permissions (read/write for the owner only).
    • Expiration: When loading a session via LoadFromPath, the system automatically checks if the current time has exceeded ExpiresAt. If the token is expired, it returns ErrTokenExpired.
    • Immutability/Fluent API: Methods like SetURI, SetExpiresAt, and SetAccessToken return a copy of the Session object, allowing for a fluent configuration pattern.
    // Example: Creating and storing a new session
    session := session.New("/path/to/session.json")
    session = session.SetURI("https://drone.example.com").
    	SetAccessToken("my-access-token").
    	SetExpiresAt(1723300000)
    
    err := session.Store()
    if err != nil {
    	// handle error
    }
  12. Handle disabled githooks

    main

    If the githook loading function returns ErrDisabled, the execution should be treated as a successful no-op. This allows the system to skip githook execution without causing the Git push/operation to fail.

    When ErrDisabled is encountered, the CLI will return nil (success) and perform no server calls.