Github: Migrating Releases Between Organizations

Migrating GitHub Releases Between Organizations: A Step-by-Step Guide


GitHub has become the go-to platform for collaborative software development, offering a plethora of features to streamline project management. One such feature is GitHub Releases, which allows you to package software releases, including binaries, release notes, and other assets. However, if you’re in a situation where you need to migrate these releases from one organization to another, the process might seem daunting at first glance. Fear not, as in this post, we’ll walk you through a seamless migration process using PowerShell and GitHub’s API.

Prerequisites:

  1. GitHub accounts with administrative access to both source and destination organizations.
  2. PowerShell installed on your system.
  3. Personal Access Token (PAT) with appropriate permissions. You can create one in your GitHub account settings.

Step 1: Setup parameters to be used

To begin, let’s setup paramters we need to use to interact with GitHub’s API. Create powershell file and add the following to the file, replaycing <PAT> and <<owner>/<repo>> with correct values.

# Set your personal access token, old and new repository details
$SOURCE_TOKEN = "<PAT>"
$TARGET_TOKEN = "<PAT>"
$SOURCE_REPO = "<owner>/<repo>"
$TARGET_REPO = "<owner>/<repo>"

Step 2: Retrieve Releases from the Source Organization and Target Organization

Now, we’ll retrieve the list of releases from the source organization and the target organizaton.

$url = "https://api.github.com/repos/$OLD_REPO/releases"
# Get the list of releases from the old repository
$releases = Invoke-RestMethod -Uri  $url -Headers @{"Authorization" = "token $SOURCE_TOKEN" }

# Sort the releases by creation date from oldest to newest
$releases = $releases | Sort-Object created_at

The reason we need to sort the releases is to ensure that we recreate them in the same order in the destination organization. This is especially important if the releases are dependent on each other or if they contain specific features or bug fixes that need to be applied in a certain order.

Now lets retrivte the list of releases from the target organization.

$url = "https://api.github.com/repos/$NEW_REPO/releases"
# Get the list of releases from the new repository
$new_releases = Invoke-RestMethod -Uri $url -Headers @{"Authorization" = "token $TARGET_TOKEN" }

Step 3: Create Releases in the Destination Organization

Next, we’ll iterate through the releases retrieved from the source organization and recreate them in the destination organization. We will also check if a release with a same tag name already exisits in the destination repository in that case we wont create a release. In the script we are downloading all the assests for the realse and uploading them to the new repository. After that we are cleaning up the downloaded assets in our local machine.

# For each release
foreach ($release in $releases) {
    # Get the release metadata
    $tag_name = $release.tag_name
    $target_commitish = $release.target_commitish
    $name = $release.name
    $body = $release.body

    # Check if a release with the same tag name already exists in the new repository
    $existing_release = $new_releases | Where-Object { $_.tag_name -eq $tag_name }

    if ($null -eq $existing_release) {
        # Create a new release in the new repository with the same metadata
        $new_release = Invoke-RestMethod -Uri "https://api.github.com/repos/$NEW_REPO/releases" -Method Post -Headers @{"Authorization" = "token $TARGET_TOKEN" } -Body (@{
                tag_name         = $tag_name
                target_commitish = $target_commitish
                name             = $name
                body             = $body
            } | ConvertTo-Json)

        # Get the upload URL for the new release
        $upload_url = $new_release.upload_url -replace '\{.*\}'

        # For each asset in the old release
        foreach ($asset in $release.assets) {
            # Get the asset metadata
            $asset_url = $asset.url
            $asset_name = $asset.name
            $asset_content_type = $asset.content_type

            if ($asset_name -like "*.tar.gz") {
                $asset_content_type = "application/gzip"
            }
            elseif ($asset_name -like "*.zip") {
                $asset_content_type = "application/zip"
            }
            else {
                $asset_content_type = "application/octet-stream"
            }

            # Download the asset
            Invoke-WebRequest -Uri $asset_url -Headers @{"Authorization" = "token $SOURCE_TOKEN"; "Accept" = "application/octet-stream" } -OutFile $asset_name

            # Upload the asset to the new release
            Invoke-RestMethod -Uri "$($upload_url)?name=$asset_name" -Method Post -Headers @{"Authorization" = "token $TARGET_TOKEN"; "Content-Type" = "$asset_content_type" } -InFile $asset_name

            Write-Host "Uploaded $asset_name to the new repository."
            
            # Delete the downloaded asset
            Remove-Item $asset_name
        }
         Write-Host "Release with tag name $tag_name was proccessed successfully."
    }
    else {
        Write-Host "Release with tag name $tag_name already exists in the new repository."
    }
}

Step 4: Conclusion

Congratulations! You’ve successfully migrated GitHub releases from one organization to another using PowerShell and GitHub’s API. This automated process can save you time and effort, especially when dealing with multiple releases across various repositories.

Feel free to customize and extend this script to suit your specific requirements. Additionally, remember to handle error cases and edge scenarios appropriately to ensure a smooth migration process.

By leveraging the power of automation and GitHub’s API, you can streamline your workflow and focus on what matters most—building amazing software.

That concludes my guide on migrating GitHub releases between organizations. I hope you found it helpful! Happy coding!